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

Rework how disambiguation is handled #1730

Merged
merged 9 commits into from
Jun 15, 2021
67 changes: 39 additions & 28 deletions src/models/room-member.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import * as utils from "../utils";
* @prop {string} membership The membership state for this room member e.g. 'join'.
* @prop {Object} events The events describing this RoomMember.
* @prop {MatrixEvent} events.member The m.room.member event for this RoomMember.
* @prop {boolean} disambiguate True if the member's name is disambiguated.
*/
export function RoomMember(roomId, userId) {
this.roomId = roomId;
Expand All @@ -61,6 +62,7 @@ export function RoomMember(roomId, userId) {
};
this._isOutOfBand = false;
this._updateModifiedTime();
this.disambiguate = false;
}
utils.inherits(RoomMember, EventEmitter);

Expand Down Expand Up @@ -90,6 +92,8 @@ RoomMember.prototype.isOutOfBand = function() {
* @fires module:client~MatrixClient#event:"RoomMember.membership"
*/
RoomMember.prototype.setMembershipEvent = function(event, roomState) {
const displayName = event.getDirectionalContent().displayname;

if (event.getType() !== "m.room.member") {
return;
}
Expand All @@ -101,11 +105,19 @@ RoomMember.prototype.setMembershipEvent = function(event, roomState) {
const oldMembership = this.membership;
this.membership = event.getDirectionalContent().membership;

this.disambiguate = shouldDisambiguate(
this.userId,
displayName,
roomState,
);

const oldName = this.name;
this.name = calculateDisplayName(
this.userId,
event.getDirectionalContent().displayname,
roomState);
displayName,
roomState,
this.disambiguate,
);

this.rawDisplayName = event.getDirectionalContent().displayname || this.userId;
if (oldMembership !== this.membership) {
Expand Down Expand Up @@ -292,43 +304,42 @@ RoomMember.prototype.getMxcAvatarUrl = function() {
const MXID_PATTERN = /@.+:.+/;
const LTR_RTL_PATTERN = /[\u200E\u200F\u202A-\u202F]/;

function calculateDisplayName(selfUserId, displayName, roomState) {
if (!displayName || displayName === selfUserId) {
return selfUserId;
}
function shouldDisambiguate(selfUserId, displayName, roomState) {
if (!displayName || displayName === selfUserId) return false;

// First check if the displayname is something we consider truthy
// after stripping it of zero width characters and padding spaces
if (!utils.removeHiddenChars(displayName)) {
return selfUserId;
}
if (!utils.removeHiddenChars(displayName)) return false;

if (!roomState) {
return displayName;
}
if (!roomState) return false;

// Next check if the name contains something that look like a mxid
// If it does, it may be someone trying to impersonate someone else
// Show full mxid in this case
let disambiguate = MXID_PATTERN.test(displayName);
if (MXID_PATTERN.test(displayName)) return true;

if (!disambiguate) {
// Also show mxid if the display name contains any LTR/RTL characters as these
// make it very difficult for us to find similar *looking* display names
// E.g "Mark" could be cloned by writing "kraM" but in RTL.
disambiguate = LTR_RTL_PATTERN.test(displayName);
}
// Also show mxid if the display name contains any LTR/RTL characters as these
// make it very difficult for us to find similar *looking* display names
// E.g "Mark" could be cloned by writing "kraM" but in RTL.
if (LTR_RTL_PATTERN.test(displayName)) return true;

if (!disambiguate) {
// Also show mxid if there are other people with the same or similar
// displayname, after hidden character removal.
const userIds = roomState.getUserIdsWithDisplayName(displayName);
disambiguate = userIds.some((u) => u !== selfUserId);
}
// Also show mxid if there are other people with the same or similar
// displayname, after hidden character removal.
const userIds = roomState.getUserIdsWithDisplayName(displayName);
if (userIds.some((u) => u !== selfUserId)) return true;

return false;
}

function calculateDisplayName(selfUserId, displayName, roomState, disambiguate) {
if (disambiguate) return displayName + " (" + selfUserId + ")";

if (!displayName || displayName === selfUserId) return selfUserId;

// First check if the displayname is something we consider truthy
// after stripping it of zero width characters and padding spaces
if (!utils.removeHiddenChars(displayName)) return selfUserId;

if (disambiguate) {
return displayName + " (" + selfUserId + ")";
}
return displayName;
}

Expand Down