Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Escape user IDs correctly #112

Merged
merged 4 commits into from
Jun 28, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions lib/models/users/matrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* @constructor
* @param {string} userId The user_id of the user.
* @param {Object=} data Serialized data values
* @param {boolean} escape [true] Escape the user's localpart.
* @param {boolean} escape [true] Escape the user's localpart. Modify {@link MatrixUser~ESCAPE_DEFAULT}
* to change the default value.
*/
function MatrixUser(userId, data, escape=true) {
function MatrixUser(userId, data, escape=MatrixUser.ESCAPE_DEFAULT) {
if (!userId) {
throw new Error("Missing user_id");
}
Expand Down Expand Up @@ -58,7 +59,7 @@ MatrixUser.prototype.set = function(key, val) {
this._data[key] = val;
};

/**
/**u
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

u

* Get the data value for the given key.
* @param {string} key An arbitrary bridge-specific key.
* @return {*} Stored data for this key. May be undefined.
Expand All @@ -75,13 +76,15 @@ MatrixUser.prototype.serialize = function() {
this._data.localpart = this.localpart;
return this._data;
};

/**
* Make a userId conform to the matrix spec using QP escaping.
* Grammar taken from: https://matrix.org/docs/spec/appendices.html#identifier-grammar
*/
MatrixUser.prototype.escapeUserId = function() {
// Currently Matrix accepts / in the userId, although going forward it will be removed.
const badChars = new Set(this.localpart.replace(/([A-z0-9]|-|\.|=|_)+/g, ""));
// NOTE: Currently Matrix accepts / in the userId, although going forward it will be removed.
// NOTE: We also allow uppercase for the time being.
const badChars = new Set(this.localpart.replace(/([A-Z]|[a-z]|[0-9]|-|\.|=|_)+/g, ""));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should remove characters which aren't allowed, such as uppercase. I'm pretty sure Synapse has started failing to register uppercase usernames by now.

let res = this.localpart;
badChars.forEach((c) => {
const hex = c.charCodeAt(0).toString(16).toLowerCase();
Expand All @@ -93,5 +96,13 @@ MatrixUser.prototype.escapeUserId = function() {
this.localpart = res;
this.userId = `@${this.localpart}:${this.host}`;
};

/**
* @static
* This is a global variable to modify the default escaping behaviour of MatrixUser.
*/
MatrixUser.ESCAPE_DEFAULT = true;


/** The MatrixUser class */
module.exports = MatrixUser;
12 changes: 11 additions & 1 deletion spec/unit/matrix-user.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,27 @@ describe("MatrixUser", function() {
"@woah=2a=2a=2a:localhost",
"@=d83d:localhost",
"@matrix.org=2fspec:localhost",
"@=5bdoggo=5d:localhost"
];
[
new MatrixUser("@$:localhost", null, false),
new MatrixUser("@500$ dog:localhost", null, false),
new MatrixUser("@woah***:localhost", null, false),
new MatrixUser("@🐶:localhost", null, false),
new MatrixUser("@matrix.org/spec:localhost", null, false)
new MatrixUser("@matrix.org/spec:localhost", null, false),
new MatrixUser("@[doggo]:localhost", null, false)
].forEach((user, i) => {
user.escapeUserId();
expect(user.getId()).toBe(expected[i]);
})
});
it("should not escape if ESCAPE_DEFAULT is false", function() {
MatrixUser.ESCAPE_DEFAULT = false;
expect(new MatrixUser("@$:localhost", null).getId()).toBe("@$:localhost");
});
it("should escape if ESCAPE_DEFAULT is true", function() {
MatrixUser.ESCAPE_DEFAULT = true;
expect(new MatrixUser("@$:localhost", null).getId()).toBe("@=24:localhost");
});
});
});