浏览代码

Fixes #3299

Properly escape user inputs before creating XML stanza.
JC Brand 11 月之前
父节点
当前提交
0c73e29c57
共有 3 个文件被更改,包括 79 次插入5 次删除
  1. 1 0
      CHANGES.md
  2. 2 2
      src/headless/utils/form.js
  3. 76 3
      src/plugins/register/tests/register.js

+ 1 - 0
CHANGES.md

@@ -10,6 +10,7 @@
 - #3033: Add the `muc_grouped_by_domain` option to display MUCs on the same domain in collapsible groups
 - #3155: Some ad-hoc commands not working
 - #3155: Some adhoc commands aren't working
+- #3299: Registration fails when a password contains an &
 - #3300: Adding the maxWait option for `debouncedPruneHistory`
 - #3302: debounce MUC sidebar rendering
 - #3305: New config option [muc_search_service](https://conversejs.org/docs/html/configuration.html#muc-search-service)

+ 2 - 2
src/headless/utils/form.js

@@ -3,7 +3,7 @@
  * @license Mozilla Public License (MPLv2)
  * @description This is the form utilities module.
  */
-import { toStanza } from 'strophe.js';
+import { Strophe, toStanza } from 'strophe.js';
 
 /**
  * @param {string} name
@@ -12,7 +12,7 @@ import { toStanza } from 'strophe.js';
 const tplXformField = (name, value) => `<field var="${name}">${value}</field>`;
 
 /** @param {string} value */
-const tplXformValue = (value) => `<value>${value}</value>`;
+const tplXformValue = (value) => `<value>${Strophe.xmlescape(value)}</value>`;
 
 /**
  * @param {HTMLSelectElement} select

+ 76 - 3
src/plugins/register/tests/register.js

@@ -5,6 +5,8 @@ const { stx, Strophe, $iq, sizzle, u } = converse.env;
 
 describe("The Registration Panel", function () {
 
+    beforeEach(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza }));
+
     afterEach(() => {
         // Remove the hash
         history.pushState("", document.title, window.location.pathname + window.location.search);
@@ -273,9 +275,7 @@ describe("The Registration Panel", function () {
 
         const toggle = document.querySelector(".toggle-controlbox");
         if (!u.isVisible(document.querySelector("#controlbox"))) {
-            if (!u.isVisible(toggle)) {
-                u.removeClass('hidden', toggle);
-            }
+            if (!u.isVisible(toggle)) u.removeClass('hidden', toggle);
             toggle.click();
         }
         const cbview = _converse.api.controlbox.get();
@@ -298,6 +298,7 @@ describe("The Registration Panel", function () {
             .c('register',  {xmlns: "http://jabber.org/features/iq-register"}).up()
             .c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
         _converse.api.connection.get()._connect_cb(mock.createRequest(stanza));
+
         stanza = $iq({
                 'type': 'result',
                 'id': 'reg1'
@@ -556,4 +557,76 @@ describe("The Registration Panel", function () {
         u.addClass('hidden', _converse.chatboxviews.get('controlbox'));
         _converse.api.connection.destroy();
     }));
+
+    it("properly escapes an ampersand from an input field",
+        mock.initConverse(
+            ['chatBoxesInitialized'],
+            { auto_login: false,
+              view_mode: 'fullscreen',
+              discover_connection_methods: false,
+              allow_registration: true },
+            async function (_converse) {
+
+        await mock.toggleControlBox();
+        const cbview = _converse.api.controlbox.get();
+        const login_form = await u.waitUntil(() => cbview.querySelector('.toggle-register-login'));
+        login_form.click();
+
+        const registerview = await u.waitUntil(() => cbview.querySelector('converse-register-panel'));
+        spyOn(registerview, 'fetchRegistrationForm').and.callThrough();
+
+        expect(registerview._registering).toBeFalsy();
+        expect(_converse.api.connection.connected()).toBeFalsy();
+        registerview.querySelector('input[name=domain]').value  = 'conversejs.org';
+        registerview.querySelector('input[type=submit]').click();
+        expect(registerview._registering).toBeTruthy();
+        await u.waitUntil(() => registerview.fetchRegistrationForm.calls.count());
+
+        let stanza = new Strophe.Builder("stream:features", {
+                    'xmlns:stream': "http://etherx.jabber.org/streams",
+                    'xmlns': "jabber:client"
+                })
+            .c('register',  {xmlns: "http://jabber.org/features/iq-register"}).up()
+            .c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
+        _converse.api.connection.get()._connect_cb(mock.createRequest(stanza));
+
+        stanza = $iq({
+                'type': 'result',
+                'id': 'reg1'
+            }).c('query', {'xmlns': 'jabber:iq:register'})
+                .c('instructions')
+                    .t('Using xform data').up()
+                .c('x', { 'xmlns': 'jabber:x:data', 'type': 'form' })
+                    .c('instructions').t('Please enter a username and password').up()
+                    .c('field', {'type': 'text-single', 'var': 'username'}).c('required').up().up()
+                    .c('field', {'type': 'text-private', 'var': 'password'}).c('required');
+        _converse.api.connection.get()._dataRecv(mock.createRequest(stanza));
+        await u.waitUntil(() => registerview.querySelectorAll('input').length === 4);
+
+        const username = registerview.querySelector('input[name="username"]');
+        const password = registerview.querySelector('input[name="password"]');
+
+        username.value = 'me';
+        password.value = '123&456';
+
+        const form = registerview.querySelector('#converse-register');
+        const submit_button = form.querySelector('input[type=submit]');
+
+        const sent_stanzas = _converse.api.connection.get().sent_stanzas;
+        while (sent_stanzas.length) { sent_stanzas.pop(); }
+
+        submit_button.click();
+
+        const iq = await u.waitUntil(() => sent_stanzas.filter(iq => sizzle('x[type="submit"]', iq).length).pop());
+        expect(iq).toEqualStanza(stx`
+            <iq type="set" id="${iq.getAttribute('id')}" xmlns="jabber:client">
+                <query xmlns="jabber:iq:register">
+                    <x xmlns="jabber:x:data" type="submit">
+                        <field var="username"><value>me</value></field>
+                        <field var="password"><value>123&amp;456</value></field>
+                    </x>
+                </query>
+            </iq>`
+        );
+    }));
 });