/** * This file is part of Threema Web. * * Threema Web is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero * General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Threema Web. If not, see . */ declare const angular: ng.IAngularStatic; declare namespace threema { interface Avatar { // Low resolution avatar URI low?: ArrayBuffer; // High resolution avatar URI high?: ArrayBuffer; } interface WireMessageAcknowledgement { id: string, success: boolean, error?: string, } /** * Messages that are sent through the secure data channel as encrypted msgpack bytes. */ interface WireMessage { type: string; subType: string; id?: string; ack?: WireMessageAcknowledgement; args?: any; data?: any; } type MessageType = 'text' | 'image' | 'video' | 'audio' | 'location' | 'contact' | 'status' | 'ballot' | 'file' | 'voipStatus' | 'unknown'; type MessageState = 'delivered' | 'read' | 'send-failed' | 'sent' | 'user-ack' | 'user-dec' | 'pending' | 'timeout' | 'sending'; const enum InitializationStep { ClientInfo = 'client info', Conversations = 'conversations', Receivers = 'receivers', Profile = 'profile', } interface InitializationStepRoutine { requiredSteps: InitializationStep[]; callback: any; } interface Thumbnail { img?: string; preview: ArrayBuffer; width: number; height: number; } const enum EventType { Created = 'created', Sent = 'sent', Delivered = 'delivered', Read = 'read', Acked = 'acked', Modified = 'modified', } /** * A message event, e.g. when it was delivered, read or modified. */ interface MessageEvent { // The event type type: EventType; // Unix timestamp in seconds date: number; } /** * A Threema chat message. */ interface Message { type: MessageType; id: string; body: string; thumbnail?: Thumbnail; date?: number; events?: MessageEvent[]; sortKey: number; partnerId: string; isOutbox: boolean; isStatus: boolean; caption?: string; statusType?: 'text' | 'firstUnreadMessage'; unread?: boolean; state?: MessageState; quote?: Quote; file?: FileInfo; video?: VideoInfo; audio?: AudioInfo; voip?: VoipStatusInfo; location?: LocationInfo; // only for temporary Messages temporaryId?: string; errorMessage?: string; } interface FileInfo { description: string; name: string; size: number; type: string; inApp: boolean; } interface VideoInfo { duration: number; size?: number; } interface AudioInfo { duration: number; } const enum VoipStatus { Missed = 1, Finished = 2, Rejected = 3, Aborted = 4, } const enum VoipRejectReason { Unknown = 0, Busy = 1, Timeout = 2, Rejected = 3, Disabled = 4, } interface VoipStatusInfo { status: VoipStatus; duration?: number; reason?: VoipRejectReason; } interface LocationInfo { lat: number; lon: number; accuracy: number; description: string; address?: string; } interface BlobInfo { buffer: ArrayBuffer; mimetype: string; filename: string; } /** * All possible receiver types. */ type ReceiverType = 'me' | 'contact' | 'group' | 'distributionList'; /** * Access Object for receivers */ interface ReceiverAccess { canDelete?: boolean; } interface ContactReceiverAccess extends ReceiverAccess { canChangeAvatar: boolean; canChangeFirstName: boolean; canChangeLastName: boolean; } interface GroupReceiverAccess extends ReceiverAccess { canChangeAvatar: boolean; canChangeName: boolean; canChangeMembers?: boolean; canLeave?: boolean; canSync?: boolean; } interface DistributionListReceiverAccess extends ReceiverAccess { canChangeMembers?: boolean; } const enum IdentityType { Regular = 0, Work = 1, } /** * The base class for a receiver. Only type and id. */ interface BaseReceiver { id: string; type: ReceiverType; } /** * A generic receiver. * * Note that the id is not unique for all receivers, only for all receivers * of a certain type. The primary key for a receiver is the tuple (type, id). */ interface Receiver extends BaseReceiver { // The display name displayName: string; // The color used for the avatar color: string; // The avatar, may be set if already fetched avatar?: Avatar; // Permissions towards this receiver access: ReceiverAccess; // Whether the chat with this receiver is locked. Used for private chats. locked: boolean; // Whether the chat with this receiver is visible. Used for private chats. visible: boolean; } /** * A contact. */ interface ContactReceiver extends Receiver { // Flag indicating whether this is the own profile or another contact type: 'contact' | 'me'; // Public nickname, if set publicNickname?: string; // First name, if set firstName?: string; // Last name, if set lastName?: string; // Verification level integer (1-3) verificationLevel?: number; // Feature mask featureMask: number; // The identity state state: 'ACTIVE' | 'INACTIVE'; // Contact hidden? hidden: boolean; // The Threema public key publicKey: ArrayBuffer; // System confact information systemContact?: SystemContact; // Permissions towards this contact access: ContactReceiverAccess; // Whether this is a contact from the same Threema Work package. // Only relevant for Threema Work users. isWork?: boolean; // Whether this contact is blocked isBlocked?: boolean; // The identity type. // 0 - Regular Threema user. // 1 - Threema Work user. identityType?: IdentityType; } /** * Own contact. */ interface MeReceiver extends ContactReceiver { type: 'me'; } /** * A group. */ interface GroupReceiver extends Receiver { type: 'group'; disabled: boolean; members: string[]; administrator: string; access: GroupReceiverAccess; createdAt: number; } /** * A distribution list. */ interface DistributionListReceiver extends Receiver { type: 'distributionList'; members: string[]; access: DistributionListReceiverAccess; } interface SystemContact { emails?: SystemContactEmail[]; phoneNumbers?: SystemContactPhone[]; } interface SystemContactEmail { label: string; address: string; } interface SystemContactPhone { label: string; number: string; } /** * A conversation. */ interface Conversation { type: ReceiverType; id: string; position?: number; messageCount: number; unreadCount: number; latestMessage?: Message; receiver?: Receiver; avatar?: ArrayBuffer; notifications?: NotificationSettings; isStarred?: boolean; } /** * A conversation with a position field, used for updating a conversation. */ interface ConversationWithPosition extends Conversation { position: number; } interface NotificationSettings { sound: NotificationSound; dnd: NotificationDnd; } interface NotificationSound { mode: NotificationSoundMode; } const enum NotificationSoundMode { Default = 'default', Muted = 'muted', } interface NotificationDnd { mode: NotificationDndMode; mentionOnly?: boolean; until?: number; } const enum NotificationDndMode { Off = 'off', On = 'on', Until = 'until', } /** * A form of the notification settings where things like the "until" mode * have been processed already. */ interface SimplifiedNotificationSettings { sound: { muted: boolean, }; dnd: { enabled: boolean, mentionOnly: boolean, }; } /** * Connection state in the welcome dialog. * * States: * * - new: Initial state * - connecting: Connecting to signaling server * - push: When trying to reconnect, waiting for push notification to arrive * - manual_start: When trying to reconnect, waiting for manual session start * - already_connected: When the user is already connected in another tab or window * - waiting: Waiting for new-responder message from signaling server * - peer_handshake: Doing SaltyRTC handshake with the peer * - loading: Loading initial data * - done: Initial loading is finished * - closed: Connection is closed * - reconnect_failed: Reconnecting failed after several attempts * */ type ConnectionBuildupState = 'new' | 'connecting' | 'push' | 'manual_start' | 'already_connected' | 'waiting' | 'peer_handshake' | 'loading' | 'done' | 'closed' | 'reconnect_failed'; interface ConnectionBuildupStateChange { state: ConnectionBuildupState; prevState: ConnectionBuildupState; } /** * Connection state of the task peer connection. */ const enum TaskConnectionState { New = 'new', Connecting = 'connecting', Connected = 'connected', Reconnecting = 'reconnecting', Disconnected = 'disconnected', } /** * Connection state of the WebRTC peer connection. */ const enum GlobalConnectionState { Ok = 'ok', Warning = 'warning', Error = 'error', } interface GlobalConnectionStateChange { state: GlobalConnectionState; prevState: GlobalConnectionState; } /** * Type of message to be sent to a receiver. */ type MessageContentType = 'text' | 'file'; interface MessageData { // optional quote object quote?: Quote; } /** * Payload for a file message. */ interface FileMessageData extends MessageData { // File name name: string; // File MIME type fileType: string; // Size in bytes size: number; // File bytes data: ArrayBuffer; // Caption string caption?: string; // Send as file message sendAsFile?: boolean; } /** * Payload for a text message. */ interface TextMessageData extends MessageData { // Text to be sent text: string; } interface Quote { identity: string; text: string; } const enum PushTokenType { Gcm = 'gcm', Apns = 'apns', } const enum PushTokenPrefix { Gcm = 'g', Apns = 'a', } interface TrustedKeyStoreData { ownPublicKey: Uint8Array; ownSecretKey: Uint8Array; peerPublicKey: Uint8Array; pushToken: string | null; pushTokenType: PushTokenType | null; } const enum BrowserName { Chrome = 'chrome', ChromeIos = 'chromeIos', Firefox = 'firefox', FirefoxIos = 'firefoxIos', InternetExplorer = 'ie', Edge = 'edge', Opera = 'opera', Safari = 'safari', } interface PromiseRequestResult { success: boolean; error?: string; data?: T; } type OnRemovedCallback = (identity: string) => void; const enum ControllerModelMode { NEW = 'new', VIEW = 'view', EDIT = 'edit', CHAT = 'chat', } const enum ContactReceiverFeature { AUDIO = 0x01, GROUP_CHAT = 0x02, BALLOT = 0x04, FILE = 0x08, VOIP = 0x10, } interface ControllerModel { /** * The title shown in the header. */ subject: string; /** * Loading state. */ isLoading: boolean; /** * Save the changes, return a promise with the receiver. */ save(): Promise; /** * Delete all messages in this conversation. */ clean(ev: any): any; /** * Validate this receiver. */ isValid(): boolean; /* * Return whether this receiver can be chatted with. */ canChat(): boolean; /** * Can this receiver be edited? */ canEdit(): boolean; /** * Can this receiver be cleaned? */ canClean(): boolean; /* * Return whether this receiver can show a QR code of the public key. */ canShowQr(): boolean; /** * The editing mode, e.g. view or edit this receiver. */ getMode(): ControllerModelMode; /** * Set the on removed callback. */ setOnRemoved(callback: OnRemovedCallback): void; /** * Callback called when the members change. */ onChangeMembers(identities: string[]): void; /** * Return the members of this receiver. */ getMembers(): string[]; } interface Alert { source: string; type: string; message: string; } interface ReceiverListener { onConversationRemoved(receiver: Receiver); } interface Config { SELF_HOSTED: boolean; PREV_PROTOCOL_LAST_VERSION: string | null; VERSION_MOUNTAIN: string; VERSION_MOUNTAIN_URL: string; VERSION_MOUNTAIN_IMAGE_URL: string; VERSION_MOUNTAIN_IMAGE_COPYRIGHT: string; VERSION_MOUNTAIN_HEIGHT: number; GIT_BRANCH: string; SALTYRTC_PORT: number; SALTYRTC_SERVER_KEY: string | null; SALTYRTC_HOST: string | null; SALTYRTC_HOST_PREFIX: string | null; SALTYRTC_HOST_SUFFIX: string | null; SALTYRTC_LOG_LEVEL: saltyrtc.LogLevel; ICE_SERVERS: RTCIceServer[]; PUSH_URL: string; DEBUG: boolean; MSG_DEBUGGING: boolean; MSGPACK_DEBUGGING: boolean; ICE_DEBUGGING: boolean; } interface InitialConversationData { draft: string; initialText: string; } interface BrowserMinVersions { FF: number; CHROME: number; OPERA: number; SAFARI: number; } interface BatteryStatus { percent: number | null; isCharging: boolean; } const enum OperatingSystem { Android = 'android', Ios = 'ios', } interface ClientInfo { // The device name device: string; // The operating system os: OperatingSystem; // The operating system version (e.g. "5.1") osVersion: string; // Whether the app is the *work* variant of Threema isWork: boolean; // The GCM / APNS push token pushToken?: string; // The device configuration configuration: AppConfig; // The device capabilities capabilities: AppCapabilities; } interface AppConfig { voipEnabled: boolean; voipForceTurn: boolean; largeSingleEmoji: boolean; showInactiveIDs: boolean; } interface AppCapabilities { maxGroupSize: number; maxFileSize: number; distributionLists: boolean; imageFormat: ImageFormat; mdm?: MdmRestrictions; } /** * MIME types for the images exchanged between app and browser. */ interface ImageFormat { avatar: string; thumbnail: string; } interface MdmRestrictions { disableAddContact?: boolean; disableCreateGroup?: boolean; disableSaveToGallery?: boolean; disableExport?: boolean; disableMessagePreview?: boolean; disableCalls?: boolean; readonlyProfile?: boolean; } interface ProfileUpdate { publicNickname?: string; avatar?: ArrayBuffer; } interface Profile extends ProfileUpdate { identity: string; publicKey: ArrayBuffer; } interface Mention { identity: string; query: string; isAll: boolean; } interface WordResult { // The trimmed word word: string; // The length of the untrimmed word realLength: number; } interface WebClientServiceStopArguments { reason: DisconnectReason, send: boolean, close: boolean | string, connectionBuildupState?: ConnectionBuildupState, } const enum ChosenTask { None = 'none', WebRTC = 'webrtc', RelayedData = 'relayed-data', } const enum DisconnectReason { SessionStopped = 'stop', SessionDeleted = 'delete', WebclientDisabled = 'disable', SessionReplaced = 'replace', SessionError = 'error', } namespace Container { interface ReceiverData { contacts: ContactReceiver[]; groups: GroupReceiver[]; distributionLists: DistributionListReceiver[]; } interface Converter { addReceiverToConversation(receivers: Receivers); } interface Filters { hasData(receivers); hasContact(contacts); isValidMessage(contacts); } interface Receivers { me: MeReceiver; contacts: Map; groups: Map; distributionLists: Map; get(receiverType: ReceiverType): Receiver | Map; getData(receiver: BaseReceiver): Receiver | null; set(data: ReceiverData): void; setMe(data: MeReceiver): void; setContacts(data: ContactReceiver[]): void; setGroups(data: GroupReceiver[]): void; setDistributionLists(data: DistributionListReceiver[]): void; extend(receiverType: ReceiverType, data: Receiver): Receiver; extendDistributionList(data: DistributionListReceiver): DistributionListReceiver; extendGroup(data: GroupReceiver): GroupReceiver; extendMe(data: MeReceiver): MeReceiver; extendContact(data: ContactReceiver): ContactReceiver; } interface Conversations { get(): Conversation[]; set(data: Conversation[]): void; find(pattern: Conversation | Receiver): Conversation | null; add(conversation: Conversation): void; updateOrAdd(conversation: Conversation, returnOld?: boolean): Conversation | null; remove(conversation: Conversation): void; setFilter(filter: (data: Conversation[]) => Conversation[]): void; setConverter(converter: (data: Conversation) => Conversation): void; } interface Messages { converter: (data: Message) => Message; getList(receiver: BaseReceiver): Message[]; clear($scope: ng.IScope): void; clearReceiverMessages(receiver: BaseReceiver): number; contains(receiver: BaseReceiver): boolean; hasMore(receiver: BaseReceiver): boolean; setMore(receiver: BaseReceiver, more: boolean): void; getReferenceMsgId(receiver: BaseReceiver): string; isRequested(receiver: BaseReceiver): boolean; setRequested(receiver: BaseReceiver): void; clearRequested(receiver: BaseReceiver): void; addNewer(receiver: BaseReceiver, messages: Message[]): void; addOlder(receiver: BaseReceiver, messages: Message[]): void; update(receiver: BaseReceiver, message: Message): boolean; setThumbnail(receiver: BaseReceiver, messageId: string, thumbnailImage: string): boolean; remove(receiver: BaseReceiver, messageId: string): boolean; removeTemporary(receiver: BaseReceiver, temporaryMessageId: string): boolean; bindTemporaryToMessageId(receiver: BaseReceiver, temporaryId: string, messageId: string): boolean; notify(receiver: BaseReceiver, $scope: ng.IScope): void; register(receiver: BaseReceiver, $scope: ng.IScope, callback: any): Message[]; updateFirstUnreadMessage(receiver: BaseReceiver); } interface Typing { setTyping(receiver: BaseReceiver): void; unsetTyping(receiver: BaseReceiver): void; clearAll(): void; isTyping(receiver: BaseReceiver): boolean; } interface Drafts { setQuote(receiver: Receiver, quote: Quote): void; removeQuote(receiver: Receiver): void; getQuote(receiver: Receiver): Quote; setText(receiver: Receiver, draftMessage: string): void; removeText(receiver: Receiver): void; getText(receiver: Receiver): string; } interface Factory { Converter: Container.Converter; Filters: Container.Filters; createReceivers: () => Receivers; createConversations: () => Conversations; createMessages: () => Messages; createTyping: () => Typing; createDrafts: () => Drafts; } } }