/**
* 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 .
*/
// Types used for the Threema Webclient.
declare const angular: ng.IAngularStatic;
declare namespace threema {
interface Avatar {
// Low resolution avatar path
low?: string;
// High resolution avatar path
high?: string;
}
interface AvatarRegistry {
contact: Avatar;
group: Avatar;
distributionList: Avatar;
}
/**
* Messages that are sent through the secure data channel as encrypted msgpack bytes.
*/
interface WireMessage {
type: string;
subType: string;
args?: any;
data?: any;
}
type WireMessageCallback = (message: WireMessage, result: any) => boolean;
type MessageType = 'text' | 'image' | 'video' | 'audio' | 'location' | 'status' | 'ballot' | 'file';
type MessageState = 'delivered' | 'read' | 'send-failed' | 'sent' | 'user-ack' | 'user-dec' | 'pending' | 'sending';
interface Thumbnail {
img?: string;
preview: string;
width: number;
height: number;
}
/**
* A Threema chat message.
*/
interface Message {
type: MessageType;
id: number;
body: string;
thumbnail?: Thumbnail;
date: string;
partnerId: string;
isOutbox: boolean;
isStatus: boolean;
caption?: string;
statusType?: 'text' | 'firstUnreadMessage';
unread?: boolean;
state?: MessageState;
quote?: Quote;
file?: FileInfo;
video?: VideoInfo;
audio?: AudioInfo;
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;
}
interface LocationInfo {
lat: number;
lon: number;
accuracy: number;
address: string;
poi: 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;
}
/**
* 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 {
type?: ReceiverType;
id: string;
displayName: string;
color: string;
avatar?: Avatar; // May be set if already fetched
access: ReceiverAccess;
locked?: boolean;
visible?: boolean;
}
/**
* A contact.
*/
interface ContactReceiver extends Receiver {
type?: 'contact' | 'me';
publicNickname?: string;
firstName?: string;
lastName?: string;
verificationLevel?: number;
state: string;
featureLevel: number | null;
publicKey: ArrayBuffer;
systemContact?: SystemContact;
access: ContactReceiverAccess;
}
/**
* Own contact.
*/
interface MeReceiver extends ContactReceiver {
type?: 'me';
}
/**
* A group.
*/
interface GroupReceiver extends Receiver {
type?: 'group';
disabled: boolean;
members: string[];
administrator: string;
access: GroupReceiverAccess;
}
/**
* 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;
}
/**
* Connection state in the welcome dialog.
*/
type ConnectionBuildupState = 'new' | 'push' | 'manual_start' | 'connecting' | 'waiting'
| 'peer_handshake' | 'loading' | 'done' | 'closed';
/**
* Connection state of the WebRTC peer connection.
*/
type RTCConnectionState = 'new' | 'connecting' | 'connected' | 'disconnected';
/**
* Connection state of the WebRTC peer connection.
*/
type GlobalConnectionState = 'ok' | 'warning' | 'error';
/**
* Type of message to be sent to a receiver.
*/
type MessageContentType = 'text' | 'file';
/**
* Possible message types sent to the receiver.
*/
type MessageDataType = '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;
}
/**
* The $stateParams format used for the welcome controller.
*/
interface WelcomeStateParams extends ng.ui.IStateParamsService {
initParams: null | {keyStore: saltyrtc.KeyStore, peerTrustedKey: Uint8Array};
}
interface CreateReceiverStateParams extends ng.ui.IStateParamsService {
type: string;
initParams: null | {identity: null};
}
/**
* State service.
*/
interface StateService {
// WebRTC states
signalingConnectionState: saltyrtc.SignalingState;
rtcConnectionState: RTCConnectionState;
// Global connection state
state: 'ok' | 'warning' | 'error';
stage: 'signaling' | 'rtc';
wasConnected: boolean;
// Connection buildup
connectionBuildupState: ConnectionBuildupState;
progress: number;
slowConnect: boolean;
// Update states
updateSignalingConnectionState(state: saltyrtc.SignalingState): void;
updateRtcConnectionState(state: RTCConnectionState): void;
updateConnectionBuildupState(state: ConnectionBuildupState): void;
reset(): void;
}
/**
* Notification service.
*/
interface NotificationService {
requestNotificationPermission(): void;
showNotification(id: string, title: string, body: string,
avatar: string | null, clickCallback: any | null): boolean;
clearCache(tag: string): void;
}
interface MessageService {
getAccess(message: Message, receiver: Receiver): MessageAccess;
createTemporary(receiver: Receiver, type: string, messageData: MessageData): Message;
showStatusIcon(message: Message, receiver: Receiver): boolean;
getFileName(message: Message): string;
}
interface MessageAccess {
quote: boolean;
ack: boolean;
dec: boolean;
delete: boolean;
download: boolean;
copy: boolean;
}
interface Quote {
identity: string;
text: string;
}
interface Identity {
identity: string;
publicNickname: String;
publicKey: ArrayBuffer;
fingerprint: string;
}
interface TrustedKeyStoreData {
ownPublicKey: Uint8Array;
ownSecretKey: Uint8Array;
peerPublicKey: Uint8Array;
pushToken: string | null;
}
interface TrustedKeyStoreService {
blocked: boolean;
storeTrustedKey(ownPublicKey: Uint8Array, ownSecretKey: Uint8Array, peerPublicKey: Uint8Array,
pushToken: string | null, password: string): void;
hasTrustedKey(): boolean;
retrieveTrustedKey(password: string): TrustedKeyStoreData;
clearTrustedKey(): void;
}
interface PushService {
init(pushToken: string): void;
reset(): void;
isAvailable(): boolean;
sendPush(session: Uint8Array): Promise;
}
interface BrowserInfo {
chrome: boolean;
firefox: boolean;
msie: boolean;
opera: boolean;
safari: boolean;
version: string;
textInfo: string;
}
interface BrowserService {
getBrowser(): BrowserInfo;
isVisible(): boolean;
}
interface TitleService {
updateUnreadCount(count: number): void;
}
interface FingerPrintService {
generate(publicKey: ArrayBuffer): string;
}
interface ContactService {
requiredDetails(contactReceiver: ContactReceiver): Promise;
}
interface ControllerModelService {
contact(receiver: ContactReceiver, mode: any): ControllerModel;
group(receiver: GroupReceiver, mode: any): ControllerModel;
distributionList(receiver: DistributionListReceiver, mode: any): ControllerModel;
}
interface QrCodeService {
buildQrCodePayload(initiatorKey: Uint8Array, authToken: Uint8Array, serverKey: Uint8Array | null,
host: string, port: number,
persistent: boolean): string;
}
interface PromiseCallbacks {
resolve: (arg: any) => void;
reject: (arg: any) => void;
}
interface PromiseRequestResult {
success: boolean;
message?: string;
data?: T;
}
interface ControllerModel {
subject: string;
isLoading: boolean;
save(): any;
isValid(): boolean;
canEdit(): boolean;
getMode(): number;
setOnRemoved(callback: any): void;
}
interface AvatarControllerModel {
onChangeAvatar: (image: ArrayBuffer) => void;
getAvatar(): ArrayBuffer | null;
}
interface Alert {
source: string;
type: string;
message: string;
}
interface ReceiverListener {
onRemoved(receiver: Receiver);
}
interface Config {
SELF_HOSTED: boolean;
SALTYRTC_PORT: number;
SALTYRTC_SERVER_KEY: string | null;
SALTYRTC_HOST: string | null;
SALTYRTC_HOST_PREFIX: string | null;
SALTYRTC_HOST_SUFFIX: string | null;
SALTYRTC_STUN: RTCIceServer;
SALTYRTC_TURN: RTCIceServer;
PUSH_URL: string;
}
interface BrowserMinVersions {
FF: number;
CHROME: number;
OPERA: number;
}
interface MimeService {
isImage(mimeType: string): boolean;
isAudio(mimeType: string): boolean;
isVideo(mimeType: string): boolean;
getLabel(mimeType: string): string;
getIconUrl(mimeType: string): string;
}
interface ReceiverService {
setActive(activeReceiver: Receiver): void;
getActive(): Receiver;
isConversationActive(conversation: Conversation): boolean;
compare(a: Conversation | Receiver, b: Conversation| Receiver): boolean;
isContact(receiver: Receiver): boolean;
isGroup(receiver: Receiver): boolean;
isDistributionList(receiver: Receiver): boolean;
isBusinessContact(receiver: Receiver): boolean;
}
interface WebClientDefault {
getAvatar(type: string, highResolution: boolean): string;
}
interface WebClientService {
salty: saltyrtc.SaltyRTC;
messages: Container.Messages;
conversations: Container.Conversations;
receivers: Container.Receivers;
alerts: Alert[];
defaults: WebClientDefault;
receiverListener: ReceiverListener[];
me: MeReceiver;
contacts: Map;
groups: Map;
distributionLists: Map;
typing: Container.Typing;
buildQrCodePayload(persistent: boolean): string;
init(keyStore?: saltyrtc.KeyStore, peerTrustedKey?: Uint8Array, resetField?: boolean): void;
start(): ng.IPromise;
stop(requestedByUs: boolean, deleteStoredData?: boolean, resetPush?: boolean, redirect?: boolean): void;
registerInitializationStep(name: string): void;
setReceiverListener(listener: ReceiverListener): void;
requestClientInfo(): void;
requestReceivers(): void;
requestConversations(): void;
requestMessages(receiver: Receiver, reloadExisting?: boolean): number;
requestAvatar(receiver: Receiver, highResolution: boolean): Promise;
requestThumbnail(receiver: Receiver, message: Message): Promise;
requestBlob(msgId: number, receiver: Receiver): Promise;
requestRead(receiver, newestMessageId: number): void;
requestContactDetail(contactReceiver: ContactReceiver): Promise;
sendMessage(receiver, type: MessageContentType, message: MessageData): Promise>;
ackMessage(receiver, message: Message, acknowledged?: boolean): void;
deleteMessage(receiver, message: Message): void;
sendMeIsTyping(receiver, isTyping: boolean): void;
sendKeyPersisted(): void;
addContact(threemaId: String): Promise;
modifyContact(threemaId: String, firstName: String, lastName: String, avatar?: ArrayBuffer):
Promise;
createGroup(members: String[], name: String, avatar?: ArrayBuffer): Promise;
modifyGroup(id: string, members: String[], name: String, avatar?: ArrayBuffer): Promise;
leaveGroup(group: GroupReceiver): Promise;
deleteGroup(group: GroupReceiver): Promise;
syncGroup(group: GroupReceiver): Promise;
createDistributionList(members: String[], name: String): Promise;
modifyDistributionList(id: string, members: String[], name: String): Promise;
deleteDistributionList(distributionList: DistributionListReceiver): Promise;
isTyping(receiver: ContactReceiver): boolean;
getMyIdentity(): Identity;
getQuote(receiver: Receiver): Quote;
setQuote(receiver: Receiver, message?: Message): void;
setDraft(receiver: Receiver, message: string): void;
getDraft(receiver: Receiver): string;
setPassword(password: string): void;
clearCache(): void;
getMaxTextLength(): number;
}
interface ControllerService {
setControllerName(name: string): void;
getControllerName(): string;
}
interface StringService {
/**
* create chunks of a string by counting the used bytes
* @param str
* @param byteLength
* @param offset
*/
byteChunk(str: string, byteLength: number, offset: number): string[];
}
namespace Container {
interface ReceiverData {
me: MeReceiver;
contacts: ContactReceiver[];
groups: GroupReceiver[];
distributionLists: DistributionListReceiver[];
}
interface Converter {
unicodeToEmoji(message);
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: Receiver): 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;
add(conversation: Conversation): void;
updateOrAdd(conversation: Conversation): void;
remove(conversation: Conversation): void;
setFilter(filter: (data: Conversation[]) => Conversation[]): void;
setConverter(converter: (data: Conversation) => Conversation): void;
}
interface Messages {
converter: (data: Message) => Message;
getList(receiver: Receiver): Message[];
clear($scope: ng.IScope): void;
clearReceiverMessages(receiver: Receiver): Number;
contains(receiver: Receiver): boolean;
hasMore(receiver: Receiver): boolean;
setMore(receiver: Receiver, more: boolean): void;
getReferenceMsgId(receiver: Receiver): number;
isRequested(receiver: Receiver): boolean;
setRequested(receiver: Receiver): void;
clearRequested(receiver): void;
addNewer(receiver: Receiver, messages: Message[]): void;
addOlder(receiver: Receiver, messages: Message[]): void;
update(receiver: Receiver, message: Message): boolean;
setThumbnail(receiver: Receiver, messageId: number, thumbnailImage: string): boolean;
remove(receiver: Receiver, messageId: number): boolean;
removeTemporary(receiver: Receiver, temporaryMessageId: string): boolean;
bindTemporaryToMessageId(receiver: Receiver, temporaryId: string, messageId: number): boolean;
notify(receiver: Receiver, $scope: ng.IScope): void;
register(receiver: Receiver, $scope: ng.IScope, callback: any): Message[];
updateFirstUnreadMessage(receiver: Receiver);
}
interface Typing {
setTyping(receiver: ContactReceiver): void;
unsetTyping(receiver: ContactReceiver): void;
isTyping(receiver: ContactReceiver): 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;
}
}
}