element-web/src/stores/ThreepidInviteStore.ts

134 lines
4.9 KiB
TypeScript

/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import EventEmitter from "events";
import { base32 } from "rfc4648";
import { RoomType } from "matrix-js-sdk/src/matrix";
// Dev note: the interface is split in two so we don't have to disable the
// linter across the whole project.
export interface IThreepidInviteWireFormat {
email: string;
signurl: string;
room_name: string; // eslint-disable-line camelcase
room_avatar_url: string; // eslint-disable-line camelcase
inviter_name: string; // eslint-disable-line camelcase
// TODO: Figure out if these are ever populated
guest_access_token?: string; // eslint-disable-line camelcase
guest_user_id?: string; // eslint-disable-line camelcase
}
interface IPersistedThreepidInvite extends IThreepidInviteWireFormat {
roomId: string;
}
export interface IThreepidInvite {
id: string; // generated by us
roomId: string;
toEmail: string;
signUrl: string;
roomName: string;
roomAvatarUrl: string;
inviterName: string;
}
// Any data about the room that would normally come from the homeserver
// but has been passed out-of-band, eg. the room name and avatar URL
// from an email invite (a workaround for the fact that we can't
// get this information from the HS using an email invite).
export interface IOOBData {
name?: string; // The room's name
avatarUrl?: string; // The mxc:// avatar URL for the room
inviterName?: string; // The display name of the person who invited us to the room
// eslint-disable-next-line camelcase
room_name?: string; // The name of the room, to be used until we are told better by the server
roomType?: RoomType | string; // The type of the room, to be used until we are told better by the server
}
const STORAGE_PREFIX = "mx_threepid_invite_";
export default class ThreepidInviteStore extends EventEmitter {
private static _instance: ThreepidInviteStore;
public static get instance(): ThreepidInviteStore {
if (!ThreepidInviteStore._instance) {
ThreepidInviteStore._instance = new ThreepidInviteStore();
}
return ThreepidInviteStore._instance;
}
public storeInvite(roomId: string, wireInvite: IThreepidInviteWireFormat): IThreepidInvite {
const invite = <IPersistedThreepidInvite>{ roomId, ...wireInvite };
const id = this.generateIdOf(invite);
localStorage.setItem(`${STORAGE_PREFIX}${id}`, JSON.stringify(invite));
return this.translateInvite(invite);
}
public getWireInvites(): IPersistedThreepidInvite[] {
const results: IPersistedThreepidInvite[] = [];
for (let i = 0; i < localStorage.length; i++) {
const keyName = localStorage.key(i);
if (!keyName?.startsWith(STORAGE_PREFIX)) continue;
try {
results.push(JSON.parse(localStorage.getItem(keyName)!) as IPersistedThreepidInvite);
} catch (e) {
console.warn("Failed to parse 3pid invite", e);
}
}
return results;
}
public getInvites(): IThreepidInvite[] {
return this.getWireInvites().map((i) => this.translateInvite(i));
}
// Currently Element can only handle one invite at a time, so handle that
public pickBestInvite(): IThreepidInvite {
return this.getInvites()[0];
}
public resolveInvite(invite: IThreepidInvite): void {
localStorage.removeItem(`${STORAGE_PREFIX}${invite.id}`);
}
private generateIdOf(persisted: IPersistedThreepidInvite): string {
// Use a consistent "hash" to form an ID.
return base32.stringify(Buffer.from(JSON.stringify(persisted)));
}
private translateInvite(persisted: IPersistedThreepidInvite): IThreepidInvite {
return {
id: this.generateIdOf(persisted),
roomId: persisted.roomId,
toEmail: persisted.email,
signUrl: persisted.signurl,
roomName: persisted.room_name,
roomAvatarUrl: persisted.room_avatar_url,
inviterName: persisted.inviter_name,
};
}
public translateToWireFormat(invite: IThreepidInvite): IThreepidInviteWireFormat {
return {
email: invite.toEmail,
signurl: invite.signUrl,
room_name: invite.roomName,
room_avatar_url: invite.roomAvatarUrl,
inviter_name: invite.inviterName,
};
}
}