UNPKG

@signalapp/mock-server

Version:
305 lines (304 loc) 14.3 kB
/// <reference types="node" /> /// <reference types="node" /> /// <reference types="node" /> import { SenderCertificate } from '@signalapp/libsignal-client'; import { AuthCredentialPresentation, CreateCallLinkCredentialRequest, CreateCallLinkCredentialResponse, GenericServerSecretParams, ProfileKeyCredentialRequest, ServerSecretParams } from '@signalapp/libsignal-client/zkgroup'; import https from 'https'; import Long from 'long'; import { AddressInfo } from 'net'; import { signalservice as Proto } from '../../protos/compiled'; import { ServerCertificate } from '../crypto'; import { ChangeNumberOptions, Device, DeviceKeys } from '../data/device'; import { BackupHeaders, BackupMediaBatch, CreateCallLink, DeleteCallLink, Message, SetBackupId, SetBackupKey, UpdateCallLink, UsernameConfirmation, UsernameReservation } from '../data/schemas'; import { AciString, AttachmentId, DeviceId, PniString, ProvisionIdString, ProvisioningCode, RegistrationId, ServiceIdKind, ServiceIdString } from '../types'; import { ModifyGroupResult, ServerGroup } from './group'; export declare enum EnvelopeType { CipherText = "CipherText", Plaintext = "Plaintext", PreKey = "PreKey", SealedSender = "SealedSender", SenderKey = "SenderKey" } export type ProvisioningResponse = Readonly<{ envelope: Buffer; }>; export type CredentialsRange = Readonly<{ from: number; to: number; }>; export type StorageCredentials = Readonly<{ username: string; password: string; }>; export type Credentials = Array<{ credential: string; redemptionTime: number; }>; export type BackupCredentials = Readonly<{ messages: Credentials; media: Credentials; }>; export type ChallengeResponse = Readonly<{ code: number; data: unknown; }>; export type PreparedMultiDeviceMessage = ReadonlyArray<[Device, Message]>; export type ProvisionDeviceOptions = Readonly<{ number: string; password: string; provisioningCode: ProvisioningCode; registrationId: RegistrationId; pniRegistrationId: RegistrationId; }>; export type RegisterDeviceOptions = Readonly<({ primary?: undefined; provisionId?: ProvisionIdString; number: string; password: string; } | { primary: Device; provisionId?: undefined; number?: undefined; password?: string; }) & { registrationId: RegistrationId; pniRegistrationId: RegistrationId; }>; export type PrepareMultiDeviceMessageResult = Readonly<{ status: 'stale'; staleDevices: ReadonlyArray<number>; } | { status: 'incomplete'; missingDevices: ReadonlyArray<number>; extraDevices: ReadonlyArray<number>; } | { status: 'unknown'; } | { status: 'ok'; targetServiceId: ServiceIdString; result: PreparedMultiDeviceMessage; }>; export type ConfirmUsernameResult = Readonly<{ usernameLinkHandle?: string; }>; export type SetUsernameLinkResult = Readonly<{ entropy: Uint8Array; serverId: string; }>; export type StorageWriteResult = Readonly<{ updated: false; manifest: Proto.IStorageManifest; error?: void; } | { updated: true; manifest?: void; error?: void; } | { updated?: void; error: string; }>; export type ModifyGroupOptions = Readonly<{ group: ServerGroup; actions: Proto.GroupChange.IActions; aciCiphertext: Uint8Array; pniCiphertext: Uint8Array; }>; export type EncryptedStickerPack = Readonly<{ id: Buffer; manifest: Buffer; stickers: ReadonlyArray<Buffer>; }>; export type IsSendRateLimitedOptions = Readonly<{ source: ServiceIdString; target: ServiceIdString; }>; export { type ModifyGroupResult }; interface WebSocket { sendMessage(message: Buffer | 'empty'): Promise<void>; } export type CallLinkEntry = Readonly<{ adminPasskey: Buffer; encryptedName: string; restrictions: 'none' | 'adminApproval'; revoked: boolean; expiration: number; }>; export type BackupInfo = Readonly<{ cdn: 3; backupDir: string; mediaDir: string; backupName: string; usedSpace?: number; }>; export type BackupMediaObject = Readonly<{ cdn: 3; mediaId: string; objectLength: number; }>; export type BackupMediaList = Readonly<{ storedMediaObjects: ReadonlyArray<BackupMediaObject>; backupDir: string; mediaDir: string; cursor: string | undefined; }>; export type BackupMediaCursor = { readonly backupId: string; remainingMedia: ReadonlyArray<BackupMediaObject>; }; export type ListBackupMediaOptions = Readonly<{ cursor: string | undefined; limit: number; }>; export type BackupMediaBatchResponse = Readonly<{ status: number; failureReason?: string; cdn: 3; mediaId: string; }>; export type BackupMediaBatchResult = Readonly<{ responses: ReadonlyArray<BackupMediaBatchResponse>; }>; export type TransferArchiveResponse = Readonly<{ error: 'RELINK_REQUESTED' | 'CONTINUE_WITHOUT_UPLOAD'; } | { cdn: 3; key: string; }>; export type AttachmentUploadForm = Readonly<{ cdn: 3; key: string; headers: Record<string, string>; signedUploadLocation: string; }>; export type RemoteConfigValueType = { enabled: boolean; value?: string; }; export declare abstract class Server { private readonly devices; private readonly devicesByServiceId; private readonly devicesByAuth; private readonly usedServiceIds; private readonly usedProvisionIds; private readonly storageAuthByUsername; private readonly storageAuthByDevice; private readonly storageManifestByAci; private readonly storageItemsByAci; private readonly provisioningCodes; private readonly attachments; private readonly stickerPacks; private readonly webSockets; private readonly messageQueue; private readonly groups; private readonly aciByUsername; private readonly aciByReservedUsername; private readonly usernameByAci; private readonly reservedUsernameByAci; private readonly usernameLinkIdByServiceId; private readonly usernameLinkById; private readonly callLinksByRoomId; private readonly backupAuthReqByAci; private readonly backupKeyById; private readonly backupCDNPasswordById; private readonly backupMediaById; private readonly backupMediaCursorById; private readonly remoteConfig; protected privCertificate: ServerCertificate | undefined; protected privZKSecret: ServerSecretParams | undefined; protected privGenericServerSecret: GenericServerSecretParams | undefined; protected privBackupServerSecret: GenericServerSecretParams | undefined; protected https: https.Server | undefined; address(): AddressInfo; generateAci(): Promise<AciString>; generatePni(): Promise<PniString>; generateProvisionId(): Promise<ProvisionIdString>; releaseProvisionId(id: ProvisionIdString): Promise<void>; abstract getProvisioningResponse(id: ProvisionIdString): Promise<ProvisioningResponse>; registerDevice({ primary, provisionId, number: maybeNumber, registrationId, pniRegistrationId, password, }: RegisterDeviceOptions): Promise<Device>; getProvisioningCode(id: ProvisionIdString, number: string): Promise<ProvisioningCode>; provisionDevice({ number, password, provisioningCode, registrationId, pniRegistrationId, }: ProvisionDeviceOptions): Promise<Device>; private setDeviceAuthPassword; updateDeviceKeys(device: Device, serviceIdKind: ServiceIdKind, keys: Omit<DeviceKeys, 'identityKey'>): Promise<void>; changeDeviceNumber(device: Device, options: ChangeNumberOptions): Promise<void>; auth(username: string, password: string): Promise<Device | undefined>; setRemoteConfig(key: string, value: RemoteConfigValueType): void; getRemoteConfig(): Map<string, RemoteConfigValueType>; protected storeAttachment(attachment: Buffer): Promise<AttachmentId>; fetchAttachment(id: AttachmentId): Promise<Buffer | undefined>; fetchStickerPack(packId: string): Promise<Buffer | undefined>; fetchSticker(packId: string, stickerId: number): Promise<Buffer | undefined>; storeStickerPack(pack: EncryptedStickerPack): Promise<void>; getAttachmentUploadForm(folder: string, key: string): Promise<AttachmentUploadForm>; prepareMultiDeviceMessage(source: Device | undefined, targetServiceId: ServiceIdString, messages: ReadonlyArray<Message>): Promise<PrepareMultiDeviceMessageResult>; handlePreparedMultiDeviceMessage(source: Device | undefined, targetServiceId: ServiceIdString, prepared: PreparedMultiDeviceMessage): Promise<void>; abstract handleMessage(source: Device | undefined, serviceIdKind: ServiceIdKind, envelopeType: EnvelopeType, target: Device, encrypted: Buffer): Promise<void>; addWebSocket(device: Device, socket: WebSocket): Promise<void>; removeWebSocket(device: Device, socket: WebSocket): void; send(target: Device, message: Buffer): Promise<void>; createGroup(group: Proto.IGroup): Promise<ServerGroup>; modifyGroup({ group, actions, aciCiphertext, pniCiphertext, }: ModifyGroupOptions): Promise<ModifyGroupResult>; getGroup(publicParams: Buffer): Promise<ServerGroup | undefined>; getStorageAuth(device: Device): Promise<StorageCredentials>; storageAuth(username: string, password: string): Promise<Device | undefined>; getStorageManifest(device: Device): Promise<Proto.IStorageManifest | undefined>; applyStorageWrite(device: Device, { manifest, clearAll, insertItem, deleteKey }: Proto.IWriteOperation, shouldNotify?: boolean): Promise<StorageWriteResult>; private clearStorageItems; private setStorageItem; getStorageItem(device: Device, key: Buffer): Promise<Buffer | undefined>; getAllStorageKeys(device: Device): Promise<Array<Buffer>>; getStorageItems(device: Device, keys: ReadonlyArray<Buffer>): Promise<Array<Proto.IStorageItem> | undefined>; deleteStorageItem(device: Device, key: Buffer): Promise<void>; protected abstract onStorageManifestUpdate(device: Device, version: Long): Promise<void>; reserveUsername(aci: AciString, { usernameHashes }: UsernameReservation): Promise<Buffer | undefined>; confirmUsername(aci: AciString, { usernameHash, zkProof, encryptedUsername }: UsernameConfirmation): Promise<ConfirmUsernameResult | undefined>; deleteUsername(aci: AciString): Promise<void>; lookupByUsernameHash(usernameHash: Buffer): Promise<AciString | undefined>; replaceUsernameLink(aci: AciString, encryptedValue: Buffer): Promise<string>; lookupByUsernameLink(lookupId: string): Promise<Buffer | undefined>; lookupByUsername(username: string): Promise<AciString | undefined>; setUsername(aci: AciString, username: string): Promise<void>; setUsernameLink(aci: AciString, username: string): Promise<SetUsernameLinkResult>; createCallLinkAuth(device: Device, request: CreateCallLinkCredentialRequest): Promise<CreateCallLinkCredentialResponse>; hasCallLink(roomId: string): boolean; createCallLink(roomId: string, { adminPasskey }: CreateCallLink): Promise<CallLinkEntry>; getCallLink(roomId: string): Promise<CallLinkEntry | undefined>; updateCallLink(roomId: string, { adminPasskey, name, restrictions, revoked }: UpdateCallLink): Promise<CallLinkEntry>; deleteCallLink(roomId: string, { adminPasskey }: DeleteCallLink): Promise<void>; getDevice(number: string, deviceId: DeviceId): Promise<Device | undefined>; removeDevice(number: string, deviceId: DeviceId): Promise<void>; getDeviceByServiceId(serviceId: ServiceIdString, deviceId?: DeviceId): Promise<Device | undefined>; getAllDevicesByServiceId(serviceId: ServiceIdString): Promise<ReadonlyArray<Device>>; getSenderCertificate(device: Device): Promise<SenderCertificate>; getGroupCredentials({ aci, pni }: Device, range: CredentialsRange): Promise<Credentials>; verifyGroupCredentials(publicParams: Buffer, credential: Buffer): Promise<AuthCredentialPresentation>; getCallLinkAuthCredentials({ aci }: Device, range: CredentialsRange): Promise<Credentials>; issueExpiringProfileKeyCredential({ aci, profileKeyCommitment }: Device, request: ProfileKeyCredentialRequest): Promise<Buffer | undefined>; setBackupId({ aci }: Device, { messagesBackupAuthCredentialRequest, mediaBackupAuthCredentialRequest, }: SetBackupId): Promise<void>; setBackupKey(headers: BackupHeaders, { backupIdPublicKey }: SetBackupKey): Promise<void>; refreshBackup(headers: BackupHeaders): Promise<void>; getBackupInfo(headers: BackupHeaders): Promise<BackupInfo>; listBackupMedia(headers: BackupHeaders, { cursor, limit }: ListBackupMediaOptions): Promise<BackupMediaList>; getBackupMediaUploadForm(headers: BackupHeaders): Promise<AttachmentUploadForm>; getBackupUploadForm(headers: BackupHeaders): Promise<AttachmentUploadForm>; backupMediaBatch(headers: BackupHeaders, batch: BackupMediaBatch): Promise<BackupMediaBatchResult>; getBackupCDNAuth(headers: BackupHeaders): Promise<Record<string, string>>; authorizeBackupCDN(backupId: string, password: string): Promise<boolean>; getBackupCredentials({ aci, backupLevel }: Device, range: CredentialsRange): Promise<BackupCredentials | undefined>; protected onNewBackupMediaObject(backupId: string, media: BackupMediaObject): Promise<void>; protected abstract backupTransitAttachments(backupId: string, batch: BackupMediaBatch): Promise<Array<BackupMediaBatchResponse>>; abstract getTransferArchive(device: Device): Promise<TransferArchiveResponse>; abstract isUnregistered(serviceId: ServiceIdString): boolean; abstract isSendRateLimited(options: IsSendRateLimitedOptions): boolean; abstract getResponseForChallenges(): ChallengeResponse | undefined; protected set certificate(value: ServerCertificate); protected get certificate(): ServerCertificate; protected set genericServerSecret(value: GenericServerSecretParams); protected get genericServerSecret(): GenericServerSecretParams; protected set backupServerSecret(value: GenericServerSecretParams); protected get backupServerSecret(): GenericServerSecretParams; protected set zkSecret(value: ServerSecretParams); protected get zkSecret(): ServerSecretParams; private sendQueue; private issueCredentials; private authenticateBackup; }