import type { MLSPublicKeyRecord, RegisteredClient } from '@wireapp/api-client/lib/client'; import { SUBCONVERSATION_ID } from '@wireapp/api-client/lib/conversation'; import { ConversationMLSMessageAddEvent, ConversationMLSWelcomeEvent } from '@wireapp/api-client/lib/event'; import { QualifiedId } from '@wireapp/api-client/lib/user'; import { APIClient } from '@wireapp/api-client'; import { TypedEventEmitter } from '@wireapp/commons'; import { Ciphersuite, ConversationId, CoreCrypto, DecryptedMessage } from '@wireapp/core-crypto'; import { AddUsersFailure, KeyPackageClaimUser } from '../../../conversation'; import { CoreDatabase } from '../../../storage/CoreDB'; import { RecurringTaskScheduler } from '../../../util/RecurringTaskScheduler'; import { User } from '../E2EIdentityService'; import { getAllConversationsCallback, getTokenCallback } from '../E2EIdentityService/E2EIServiceInternal'; import { ClientId, HandlePendingProposalsParams } from '../types'; type Optional = Pick, K> & Omit; interface MLSConfig { /** List of ciphersuites that could be used for MLS */ ciphersuites: Ciphersuite[]; /** preferred ciphersuite to use */ defaultCiphersuite: Ciphersuite; /** * (milliseconds) period of time between automatic updates of the keying material (30 days by default) */ keyingMaterialUpdateThreshold: number; /** * number of key packages client should upload to the server (100 by default) */ nbKeyPackages: number; } export type InitClientOptions = Optional & { skipInitIdentity?: boolean; }; export declare const optionalToUint8Array: (array: Uint8Array | []) => Uint8Array; export declare enum MLSServiceEvents { NEW_EPOCH = "newEpoch", MLS_CLIENT_MISMATCH = "mlsClientMismatch", NEW_CRL_DISTRIBUTION_POINTS = "newCrlDistributionPoints", MLS_EVENT_DISTRIBUTED = "mlsEventDistributed", KEY_MATERIAL_UPDATE_FAILURE = "keyMaterialUpdateFailure" } type Events = { [MLSServiceEvents.KEY_MATERIAL_UPDATE_FAILURE]: { error: unknown; groupId: string; }; [MLSServiceEvents.NEW_EPOCH]: { epoch: number; groupId: string; }; [MLSServiceEvents.NEW_CRL_DISTRIBUTION_POINTS]: string[]; [MLSServiceEvents.MLS_CLIENT_MISMATCH]: void; [MLSServiceEvents.MLS_EVENT_DISTRIBUTED]: { events: any; time: string; }; }; export declare class MLSService extends TypedEventEmitter { private readonly apiClient; private readonly coreCryptoClient; private readonly coreDatabase; private readonly recurringTaskScheduler; logger: import("logdown").Logger; private _config?; private readonly textEncoder; private readonly textDecoder; constructor(apiClient: APIClient, coreCryptoClient: CoreCrypto, coreDatabase: CoreDatabase, recurringTaskScheduler: RecurringTaskScheduler); /** * return true if the MLS service if configured and ready to be used */ get isEnabled(): boolean; get config(): MLSConfig; private get minRequiredKeyPackages(); /** * Will initialize an MLS client * @param userId the user owning the client * @param client id of the client to initialize * @param skipInitIdentity avoid registering the client's identity to the backend (needed for e2eidentity as the identity will be uploaded and signed only when enrollment is successful) */ initClient(userId: QualifiedId, client: RegisteredClient, { skipInitIdentity, ...mlsConfig }: InitClientOptions): Promise; /** * returns true if the client has a valid MLS identity in regard of the default ciphersuite set * @param client the client to check */ isInitializedMLSClient: (client: RegisteredClient) => boolean; private getCredentialType; private readonly _uploadCommitBundle; /** * Will add users to an existing MLS group and send a commit bundle to backend. * Cannot be called with an empty array of keys. * * @param groupId - the group id of the MLS group * @param keyPackages - the list of keys of clients to add to the MLS group */ addUsersToExistingConversation(groupId: string, keyPackages: Uint8Array[]): Promise; /** * Will return a list of client ids which are already in the group at core crypto level * * @param groupId - the group id of the MLS group * @returns list of client ids */ getClientIdsInGroup(groupId: string): Promise; getKeyPackagesPayload(qualifiedUsers: KeyPackageClaimUser[], skipClientIds?: string[]): Promise<{ keyPackages: Uint8Array[]; failures: AddUsersFailure[]; }>; getEpoch(groupId: string | Uint8Array): Promise; joinByExternalCommit(getGroupInfo: () => Promise): Promise; exportSecretKey(groupId: string, keyLength: number): Promise; private dispatchNewCrlDistributionPoints; processWelcomeMessage(welcomeMessage: Uint8Array): Promise; decryptMessage(conversationId: ConversationId, payload: Uint8Array): Promise; encryptMessage(conversationId: ConversationId, message: Uint8Array): Promise; private updateKeyingMaterial; /** * Will create an empty conversation inside of coreCrypto. * @param groupId the id of the group to create inside of coreCrypto * @param parentGroupId in case the conversation is a subconversation, the id of the parent conversation */ registerEmptyConversation(groupId: string, parentGroupId?: string, removalKeyFor1to1Signature?: MLSPublicKeyRecord): Promise; /** * Will create a conversation inside of coreCrypto, add users to it or update the keying material if empty key packages list is provided. * @param groupId the id of the group to create inside of coreCrypto * @param users the list of users that will be members of the conversation (including the self user) * @param options.creator the creator of the list. Most of the time will be the self user (or empty if the conversation was created by backend first) * @param options.parentGroupId in case the conversation is a subconversation, the id of the parent conversation */ registerConversation(groupId: string, users: QualifiedId[], options?: { creator?: { user: QualifiedId; client?: string; }; parentGroupId?: string; }): Promise; /** * Will create a 1:1 conversation inside of coreCrypto, try claiming key packages for user and (if succesfull) add them to the MLS group. * @param groupId the id of the group to create inside of coreCrypto * @param userId the id of the user to register the conversation with * @param selfUser the self user that is creating the 1:1 conversation (user and client ids) */ register1to1Conversation(groupId: string, userId: QualifiedId, selfUser: { user: QualifiedId; client: string; }, removalKeyFor1to1Signature?: MLSPublicKeyRecord): Promise; /** * Will try to register mls group and send an empty commit to establish it. * * @param groupId - id of the MLS group * @returns true if the client has successfully established the group, false otherwise */ readonly tryEstablishingMLSGroup: (groupId: string) => Promise; /** * Will send a removal commit for given clients * @param groupId groupId of the conversation * @param clientIds the list of **qualified** ids of the clients we want to remove from the group */ removeClientsFromConversation(groupId: string, clientIds: ClientId[]): Promise; /** * Will check if mls group exists in corecrypto. * @param groupId groupId of the conversation */ conversationExists(groupId: string): Promise; /** * Will check if mls group is established in coreCrypto. * Group is established after the first commit was sent in the group and epoch number is at least 1. * @param groupId groupId of the conversation */ isConversationEstablished(groupId: string): Promise; clientValidKeypackagesCount(): Promise; clientKeypackages(amountRequested: number): Promise; /** * Will send an empty commit into a group (renew key material) * * @param groupId groupId of the conversation */ renewKeyMaterial(groupId: string): Promise; private createKeyMaterialUpdateTaskSchedulerId; /** * Will reset the renewal to the threshold given as config * @param groupId The group that should have its key material updated */ resetKeyMaterialRenewal(groupId: string): Promise; /** * Will cancel the renewal of the key material for a given groupId * @param groupId The group that should stop having its key material updated */ private cancelKeyMaterialRenewal; /** * Will schedule a task to update the key material of the conversation according to the threshold given as config * @param groupId */ scheduleKeyMaterialRenewal(groupId: string): Promise; /** * Get all keying material last update dates and schedule tasks for renewal * Function must only be called once, after application start */ schedulePeriodicKeyMaterialRenewals(groupIds: string[]): void; /** * Schedules a task to periodically (every 24h) check if new key packages should be generated and uploaded to backend. * Function must only be called once, after application start * @param clientId id of the client */ schedulePeriodicKeyPackagesBackendSync(clientId: string): Promise; /** * Checks if there are enough key packages locally and if not, * checks the number of keys available on backend and (if needed) generates new keys and uploads them. * @param clientId id of the client */ private verifyLocalMLSKeyPackagesAmount; private verifyRemoteMLSKeyPackagesAmount; private getRemoteMLSKeyPackageCount; private getCCClientSignatureString; /** * Will update the given client on backend with its public key. * * @param mlsClient Intance of the coreCrypto that represents the mls client * @param client Backend client data */ private uploadMLSPublicKeys; private replaceKeyPackages; private uploadMLSKeyPackages; wipeConversation(groupId: string): Promise; /** * If there are pending proposals, we need to either process them, * or save them in the database for later processing * * @param groupId groupId of the mls conversation * @param delayInMs delay in ms before processing proposals * @param eventTime time of the event that had the proposals */ handlePendingProposals({ delayInMs, groupId, eventTime }: HandlePendingProposalsParams): Promise; private schedulePendingProposalsTask; private cancelPendingProposalsTask; private createPendingProposalsTaskKey; /** * Commit all pending proposals for a given groupId * * @param groupId groupId of the conversation */ commitPendingProposals(groupId: string, shouldRetry?: boolean): Promise; /** * Get all pending proposals from the database and schedule them * Function must only be called once, after application start * */ initialisePendingProposalsTasks(): Promise; /** * Get all conversation members client ids. * * @param groupId groupId of the conversation */ getClientIds(groupId: string): Promise<{ userId: string; clientId: ClientId; domain: string; }[]>; handleMLSMessageAddEvent(event: ConversationMLSMessageAddEvent, groupIdFromConversationId: (conversationId: QualifiedId, subconversationId?: SUBCONVERSATION_ID) => Promise): Promise; handleMLSWelcomeMessageEvent(event: ConversationMLSWelcomeEvent, clientId: string): Promise; /** * * @param discoveryUrl URL of the acme server * @param user User object * @param clientId The client id of the current device * @param nbPrekeys Amount of prekeys to generate * @param oAuthIdToken The OAuth id token if the user is already authenticated * @returns AcmeChallenge if the user is not authenticated, true if the user is authenticated */ enrollE2EI(discoveryUrl: string, user: User, client: RegisteredClient, nbPrekeys: number, certificateTtl: number, getOAuthToken: getTokenCallback, getAllConversations: getAllConversationsCallback): Promise; } export {}; //# sourceMappingURL=MLSService.d.ts.map