You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			203 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			203 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			TypeScript
		
	
// this is not a very good name, but a configuration message is a message sent to our other devices so sync our current public and closed groups
 | 
						|
 | 
						|
import { SignalService } from '../../../../protobuf';
 | 
						|
import { MessageParams } from '../Message';
 | 
						|
import { ECKeyPair } from '../../../../receiver/keypairs';
 | 
						|
import { fromHexToArray } from '../../../utils/String';
 | 
						|
import { PubKey } from '../../../types';
 | 
						|
import { ContentMessage } from '..';
 | 
						|
 | 
						|
interface ConfigurationMessageParams extends MessageParams {
 | 
						|
  activeClosedGroups: Array<ConfigurationMessageClosedGroup>;
 | 
						|
  activeOpenGroups: Array<string>;
 | 
						|
  displayName: string;
 | 
						|
  profilePicture?: string;
 | 
						|
  profileKey?: Uint8Array;
 | 
						|
  contacts: Array<ConfigurationMessageContact>;
 | 
						|
}
 | 
						|
 | 
						|
export class ConfigurationMessage extends ContentMessage {
 | 
						|
  public readonly activeClosedGroups: Array<ConfigurationMessageClosedGroup>;
 | 
						|
  public readonly activeOpenGroups: Array<string>;
 | 
						|
  public readonly displayName: string;
 | 
						|
  public readonly profilePicture?: string;
 | 
						|
  public readonly profileKey?: Uint8Array;
 | 
						|
  public readonly contacts: Array<ConfigurationMessageContact>;
 | 
						|
 | 
						|
  constructor(params: ConfigurationMessageParams) {
 | 
						|
    super({ timestamp: params.timestamp, identifier: params.identifier });
 | 
						|
    this.activeClosedGroups = params.activeClosedGroups;
 | 
						|
    this.activeOpenGroups = params.activeOpenGroups;
 | 
						|
    this.displayName = params.displayName;
 | 
						|
    this.profilePicture = params.profilePicture;
 | 
						|
    this.profileKey = params.profileKey;
 | 
						|
    this.contacts = params.contacts;
 | 
						|
 | 
						|
    if (!this.activeClosedGroups) {
 | 
						|
      throw new Error('closed group must be set');
 | 
						|
    }
 | 
						|
 | 
						|
    if (!this.activeOpenGroups) {
 | 
						|
      throw new Error('open group must be set');
 | 
						|
    }
 | 
						|
 | 
						|
    if (!this.displayName || !this.displayName?.length) {
 | 
						|
      throw new Error('displayName must be set');
 | 
						|
    }
 | 
						|
 | 
						|
    if (this.profilePicture && typeof this.profilePicture !== 'string') {
 | 
						|
      throw new Error('profilePicture set but not an Uin8Array');
 | 
						|
    }
 | 
						|
 | 
						|
    if (this.profileKey && !(this.profileKey instanceof Uint8Array)) {
 | 
						|
      throw new Error('profileKey set but not an Uin8Array');
 | 
						|
    }
 | 
						|
 | 
						|
    if (!this.contacts) {
 | 
						|
      throw new Error('contacts must be set');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public contentProto(): SignalService.Content {
 | 
						|
    return new SignalService.Content({
 | 
						|
      configurationMessage: this.configurationProto(),
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  protected configurationProto(): SignalService.ConfigurationMessage {
 | 
						|
    return new SignalService.ConfigurationMessage({
 | 
						|
      closedGroups: this.mapClosedGroupsObjectToProto(this.activeClosedGroups),
 | 
						|
      openGroups: this.activeOpenGroups,
 | 
						|
      displayName: this.displayName,
 | 
						|
      profilePicture: this.profilePicture,
 | 
						|
      profileKey: this.profileKey,
 | 
						|
      contacts: this.mapContactsObjectToProto(this.contacts),
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  private mapClosedGroupsObjectToProto(
 | 
						|
    closedGroups: Array<ConfigurationMessageClosedGroup>
 | 
						|
  ): Array<SignalService.ConfigurationMessage.ClosedGroup> {
 | 
						|
    return (closedGroups || []).map(m => m.toProto());
 | 
						|
  }
 | 
						|
 | 
						|
  private mapContactsObjectToProto(
 | 
						|
    contacts: Array<ConfigurationMessageContact>
 | 
						|
  ): Array<SignalService.ConfigurationMessage.Contact> {
 | 
						|
    return (contacts || []).map(m => m.toProto());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class ConfigurationMessageContact {
 | 
						|
  public publicKey: string;
 | 
						|
  public displayName: string;
 | 
						|
  public profilePictureURL?: string;
 | 
						|
  public profileKey?: Uint8Array;
 | 
						|
 | 
						|
  public constructor({
 | 
						|
    publicKey,
 | 
						|
    displayName,
 | 
						|
    profilePictureURL,
 | 
						|
    profileKey,
 | 
						|
  }: {
 | 
						|
    publicKey: string;
 | 
						|
    displayName: string;
 | 
						|
    profilePictureURL?: string;
 | 
						|
    profileKey?: Uint8Array;
 | 
						|
  }) {
 | 
						|
    this.publicKey = publicKey;
 | 
						|
    this.displayName = displayName;
 | 
						|
    this.profilePictureURL = profilePictureURL;
 | 
						|
    this.profileKey = profileKey;
 | 
						|
 | 
						|
    // will throw if public key is invalid
 | 
						|
    PubKey.cast(publicKey);
 | 
						|
 | 
						|
    if (this.displayName?.length === 0) {
 | 
						|
      throw new Error('displayName must be set or undefined');
 | 
						|
    }
 | 
						|
 | 
						|
    if (this.profilePictureURL !== undefined && this.profilePictureURL?.length === 0) {
 | 
						|
      throw new Error('profilePictureURL must either undefined or not empty');
 | 
						|
    }
 | 
						|
    if (this.profileKey !== undefined && this.profileKey?.length === 0) {
 | 
						|
      throw new Error('profileKey must either undefined or not empty');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public toProto(): SignalService.ConfigurationMessage.Contact {
 | 
						|
    return new SignalService.ConfigurationMessage.Contact({
 | 
						|
      publicKey: fromHexToArray(this.publicKey),
 | 
						|
      name: this.displayName,
 | 
						|
      profilePicture: this.profilePictureURL,
 | 
						|
      profileKey: this.profileKey,
 | 
						|
    });
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class ConfigurationMessageClosedGroup {
 | 
						|
  public publicKey: string;
 | 
						|
  public name: string;
 | 
						|
  public encryptionKeyPair: ECKeyPair;
 | 
						|
  public members: Array<string>;
 | 
						|
  public admins: Array<string>;
 | 
						|
 | 
						|
  public constructor({
 | 
						|
    publicKey,
 | 
						|
    name,
 | 
						|
    encryptionKeyPair,
 | 
						|
    members,
 | 
						|
    admins,
 | 
						|
  }: {
 | 
						|
    publicKey: string;
 | 
						|
    name: string;
 | 
						|
    encryptionKeyPair: ECKeyPair;
 | 
						|
    members: Array<string>;
 | 
						|
    admins: Array<string>;
 | 
						|
  }) {
 | 
						|
    this.publicKey = publicKey;
 | 
						|
    this.name = name;
 | 
						|
    this.encryptionKeyPair = encryptionKeyPair;
 | 
						|
    this.members = members;
 | 
						|
    this.admins = admins;
 | 
						|
 | 
						|
    // will throw if publik key is invalid
 | 
						|
    PubKey.cast(publicKey);
 | 
						|
 | 
						|
    if (
 | 
						|
      !encryptionKeyPair?.privateKeyData?.byteLength ||
 | 
						|
      !encryptionKeyPair?.publicKeyData?.byteLength
 | 
						|
    ) {
 | 
						|
      throw new Error('Encryption key pair looks invalid');
 | 
						|
    }
 | 
						|
 | 
						|
    if (!this.name?.length) {
 | 
						|
      throw new Error('name must be set');
 | 
						|
    }
 | 
						|
 | 
						|
    if (!this.members?.length) {
 | 
						|
      throw new Error('members must be set');
 | 
						|
    }
 | 
						|
    if (!this.admins?.length) {
 | 
						|
      throw new Error('admins must be set');
 | 
						|
    }
 | 
						|
 | 
						|
    if (this.admins.some(a => !this.members.includes(a))) {
 | 
						|
      throw new Error('some admins are not members');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public toProto(): SignalService.ConfigurationMessage.ClosedGroup {
 | 
						|
    return new SignalService.ConfigurationMessage.ClosedGroup({
 | 
						|
      publicKey: fromHexToArray(this.publicKey),
 | 
						|
      name: this.name,
 | 
						|
      encryptionKeyPair: {
 | 
						|
        publicKey: this.encryptionKeyPair.publicKeyData,
 | 
						|
        privateKey: this.encryptionKeyPair.privateKeyData,
 | 
						|
      },
 | 
						|
      members: this.members.map(fromHexToArray),
 | 
						|
      admins: this.admins.map(fromHexToArray),
 | 
						|
    });
 | 
						|
  }
 | 
						|
}
 |