@wireapp/core 38.15.2 → 39.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Account.d.ts.map +1 -1
- package/lib/Account.js +1 -3
- package/lib/broadcast/BroadcastService.d.ts +2 -2
- package/lib/broadcast/BroadcastService.d.ts.map +1 -1
- package/lib/broadcast/BroadcastService.js +5 -12
- package/lib/client/ClientDatabaseRepository.d.ts +5 -5
- package/lib/client/ClientDatabaseRepository.d.ts.map +1 -1
- package/lib/client/ClientDatabaseRepository.js +9 -16
- package/lib/client/ClientService.d.ts.map +1 -1
- package/lib/client/ClientService.js +2 -2
- package/lib/connection/ConnectionService.d.ts +2 -2
- package/lib/connection/ConnectionService.d.ts.map +1 -1
- package/lib/connection/ConnectionService.js +2 -2
- package/lib/conversation/ConversationService/ConversationService.d.ts +1 -1
- package/lib/conversation/ConversationService/ConversationService.d.ts.map +1 -1
- package/lib/conversation/ConversationService/ConversationService.test.js +1 -1
- package/lib/conversation/ConversationService/ConversationService.types.d.ts +2 -6
- package/lib/conversation/ConversationService/ConversationService.types.d.ts.map +1 -1
- package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.d.ts +1 -1
- package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.d.ts.map +1 -1
- package/lib/conversation/message/MessageService.d.ts +5 -31
- package/lib/conversation/message/MessageService.d.ts.map +1 -1
- package/lib/conversation/message/MessageService.js +9 -151
- package/lib/conversation/message/MessageService.test.js +107 -156
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts +7 -11
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.js +16 -35
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.js +1 -2
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.test.js +55 -94
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.types.d.ts +5 -8
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.types.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/Utility/Recipients.d.ts +4 -10
- package/lib/messagingProtocols/proteus/Utility/Recipients.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/Utility/Recipients.js +2 -13
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.d.ts +8 -11
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.js +54 -75
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.test.js +26 -33
- package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.d.ts +5 -14
- package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.js +3 -35
- package/lib/user/UserService.d.ts +1 -16
- package/lib/user/UserService.d.ts.map +1 -1
- package/lib/user/UserService.js +1 -43
- package/package.json +3 -3
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { PreKey } from '@wireapp/api-client/lib/auth';
|
|
2
|
-
import {
|
|
3
|
-
import { QualifiedId,
|
|
2
|
+
import { QualifiedUserClients } from '@wireapp/api-client/lib/conversation';
|
|
3
|
+
import { QualifiedId, QualifiedUserPreKeyBundleMap } from '@wireapp/api-client/lib/user';
|
|
4
4
|
import { Logger } from 'logdown';
|
|
5
5
|
import { APIClient } from '@wireapp/api-client';
|
|
6
6
|
import { CryptoClient } from '../../ProteusService/CryptoClient';
|
|
7
7
|
interface ConstructSessionIdParams {
|
|
8
|
-
userId:
|
|
8
|
+
userId: QualifiedId;
|
|
9
9
|
clientId: string;
|
|
10
|
-
useQualifiedIds: boolean;
|
|
11
10
|
domain?: string;
|
|
12
11
|
}
|
|
13
12
|
type InitSessionsResult = {
|
|
14
13
|
/** valid sessions that either already existed or have been freshly created */
|
|
15
14
|
sessions: string[];
|
|
16
15
|
/** client that do we do not have sessions with and that do not have existence on backend (deleted clients) */
|
|
17
|
-
unknowns?:
|
|
16
|
+
unknowns?: QualifiedUserClients;
|
|
18
17
|
};
|
|
19
|
-
declare const constructSessionId: ({ userId, clientId
|
|
18
|
+
declare const constructSessionId: ({ userId, clientId }: ConstructSessionIdParams) => string;
|
|
20
19
|
/**
|
|
21
20
|
* Will make sure the session is available in cryptoClient
|
|
22
21
|
* @param sessionId the session to init
|
|
@@ -30,8 +29,7 @@ declare const initSession: ({ userId, clientId, initialPrekey }: {
|
|
|
30
29
|
cryptoClient: CryptoClient;
|
|
31
30
|
}) => Promise<string>;
|
|
32
31
|
interface GetSessionsAndClientsFromRecipientsProps {
|
|
33
|
-
recipients:
|
|
34
|
-
domain?: string;
|
|
32
|
+
recipients: QualifiedUserClients | QualifiedUserPreKeyBundleMap;
|
|
35
33
|
apiClient: APIClient;
|
|
36
34
|
cryptoClient: CryptoClient;
|
|
37
35
|
logger?: Logger;
|
|
@@ -39,15 +37,14 @@ interface GetSessionsAndClientsFromRecipientsProps {
|
|
|
39
37
|
/**
|
|
40
38
|
* Will make sure all the sessions need to encrypt for those user/clients pair are set
|
|
41
39
|
*/
|
|
42
|
-
declare const initSessions: ({ recipients,
|
|
40
|
+
declare const initSessions: ({ recipients, apiClient, cryptoClient, logger, }: GetSessionsAndClientsFromRecipientsProps) => Promise<InitSessionsResult>;
|
|
43
41
|
interface DeleteSessionParams {
|
|
44
42
|
userId: QualifiedId;
|
|
45
43
|
clientId: string;
|
|
46
44
|
cryptoClient: CryptoClient;
|
|
47
|
-
useQualifiedIds: boolean;
|
|
48
45
|
}
|
|
49
46
|
declare function deleteSession(params: DeleteSessionParams): Promise<void>;
|
|
50
|
-
type EncryptedPayloads<T> = Record<string, Record<string, T
|
|
47
|
+
type EncryptedPayloads<T> = Record<string, Record<string, Record<string, T>>>;
|
|
51
48
|
/**
|
|
52
49
|
* creates an encrypted payload that can be sent to backend from a bunch of sessionIds/encrypted payload
|
|
53
50
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionHandler.d.ts","sourceRoot":"","sources":["../../../../../src/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,MAAM,EAAC,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"SessionHandler.d.ts","sourceRoot":"","sources":["../../../../../src/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,MAAM,EAAC,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAC,oBAAoB,EAAC,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAC,WAAW,EAAE,4BAA4B,EAAC,MAAM,8BAA8B,CAAC;AAEvF,OAAO,EAAC,MAAM,EAAC,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAK9C,OAAO,EAAC,YAAY,EAAC,MAAM,mCAAmC,CAAC;AAE/D,UAAU,wBAAwB;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,kBAAkB,GAAG;IACxB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8GAA8G;IAC9G,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC,CAAC;AAEF,QAAA,MAAM,kBAAkB,yBAAwB,wBAAwB,KAAG,MAI1E,CAAC;AA6BF;;;GAGG;AACH,QAAA,MAAM,WAAW;YAC6B,WAAW;cAAY,MAAM;;;eAClC,SAAS;kBAAgB,YAAY;MAC3E,QAAQ,MAAM,CAUhB,CAAC;AAeF,UAAU,wCAAwC;IAChD,UAAU,EAAE,oBAAoB,GAAG,4BAA4B,CAAC;IAChE,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,QAAA,MAAM,YAAY,qDAKf,wCAAwC,KAAG,QAAQ,kBAAkB,CAoDvE,CAAC;AAEF,UAAU,mBAAmB;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,YAAY,CAAC;CAC5B;AACD,iBAAe,aAAa,CAAC,MAAM,EAAE,mBAAmB,iBAGvD;AA4CD,KAAK,iBAAiB,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E;;GAEG;AACH,QAAA,MAAM,sBAAsB,uDAY3B,CAAC;AAEF,OAAO,EAAC,kBAAkB,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAC,CAAC"}
|
|
@@ -21,11 +21,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
21
21
|
exports.buildEncryptedPayloads = exports.deleteSession = exports.initSessions = exports.initSession = exports.constructSessionId = void 0;
|
|
22
22
|
const bazinga64_1 = require("bazinga64");
|
|
23
23
|
const UserClientsUtil_1 = require("../../../../conversation/message/UserClientsUtil");
|
|
24
|
-
const constructSessionId = ({ userId, clientId
|
|
25
|
-
const id
|
|
26
|
-
const baseDomain = typeof userId === 'string' ? domain : userId.domain;
|
|
24
|
+
const constructSessionId = ({ userId, clientId }) => {
|
|
25
|
+
const { id, domain } = userId;
|
|
27
26
|
const baseId = `${id}@${clientId}`;
|
|
28
|
-
return
|
|
27
|
+
return domain ? `${domain}@${baseId}` : baseId;
|
|
29
28
|
};
|
|
30
29
|
exports.constructSessionId = constructSessionId;
|
|
31
30
|
const isSessionId = (object) => {
|
|
@@ -43,45 +42,16 @@ const parseSessionId = (sessionId) => {
|
|
|
43
42
|
}
|
|
44
43
|
return match.groups;
|
|
45
44
|
};
|
|
46
|
-
const createLegacySessions = async ({ userClients, apiClient, cryptoClient, }) => {
|
|
47
|
-
const preKeyBundleMap = await apiClient.api.user.postMultiPreKeyBundles(userClients);
|
|
48
|
-
const sessions = await createSessionsFromPreKeys({
|
|
49
|
-
preKeyBundleMap,
|
|
50
|
-
useQualifiedIds: false,
|
|
51
|
-
cryptoClient,
|
|
52
|
-
});
|
|
53
|
-
return sessions;
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Create sessions for the qualified clients.
|
|
57
|
-
* @param {userClientMap} map of domain to (map of user IDs to client IDs)
|
|
58
|
-
*/
|
|
59
|
-
const createQualifiedSessions = async ({ userClientMap, domain, apiClient, cryptoClient, }) => {
|
|
60
|
-
const prekeyBundleMap = await apiClient.api.user.postQualifiedMultiPreKeyBundles({ [domain]: userClientMap });
|
|
61
|
-
const sessions = [];
|
|
62
|
-
let unknowns = {};
|
|
63
|
-
for (const domain in prekeyBundleMap) {
|
|
64
|
-
const domainUsers = prekeyBundleMap[domain];
|
|
65
|
-
const { sessions: createdSessions, unknowns: domainUnknowns } = await createSessionsFromPreKeys({
|
|
66
|
-
preKeyBundleMap: domainUsers,
|
|
67
|
-
domain,
|
|
68
|
-
useQualifiedIds: true,
|
|
69
|
-
cryptoClient,
|
|
70
|
-
});
|
|
71
|
-
sessions.push(...createdSessions);
|
|
72
|
-
unknowns = Object.assign(Object.assign({}, unknowns), domainUnknowns);
|
|
73
|
-
}
|
|
74
|
-
return { sessions, unknowns };
|
|
75
|
-
};
|
|
76
45
|
/**
|
|
77
46
|
* Will make sure the session is available in cryptoClient
|
|
78
47
|
* @param sessionId the session to init
|
|
79
48
|
*/
|
|
80
49
|
const initSession = async ({ userId, clientId, initialPrekey }, { cryptoClient, apiClient }) => {
|
|
81
|
-
const recipients = initialPrekey
|
|
50
|
+
const recipients = initialPrekey
|
|
51
|
+
? { [userId.domain]: { [userId.id]: { [clientId]: initialPrekey } } }
|
|
52
|
+
: { [userId.domain]: { [userId.id]: [clientId] } };
|
|
82
53
|
const { sessions } = await initSessions({
|
|
83
54
|
recipients,
|
|
84
|
-
domain: userId.domain,
|
|
85
55
|
apiClient,
|
|
86
56
|
cryptoClient,
|
|
87
57
|
});
|
|
@@ -90,56 +60,55 @@ const initSession = async ({ userId, clientId, initialPrekey }, { cryptoClient,
|
|
|
90
60
|
exports.initSession = initSession;
|
|
91
61
|
/**
|
|
92
62
|
* Create sessions for legacy/qualified clients (umberella function).
|
|
93
|
-
* Will call createQualifiedSessions or createLegacySessions based on passed userClientMap.
|
|
94
63
|
* @param {userClientMap} map of domain to (map of user IDs to client IDs) or map of user IDs containg the lists of clients
|
|
95
64
|
*/
|
|
96
|
-
const createSessions = async ({
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
cryptoClient,
|
|
103
|
-
});
|
|
65
|
+
const createSessions = async ({ recipients, apiClient, cryptoClient }) => {
|
|
66
|
+
const prekeyBundleMap = await apiClient.api.user.postMultiPreKeyBundles(recipients);
|
|
67
|
+
return await createSessionsFromPreKeys({
|
|
68
|
+
recipients: prekeyBundleMap,
|
|
69
|
+
cryptoClient,
|
|
70
|
+
});
|
|
104
71
|
};
|
|
105
72
|
/**
|
|
106
73
|
* Will make sure all the sessions need to encrypt for those user/clients pair are set
|
|
107
74
|
*/
|
|
108
|
-
const initSessions = async ({ recipients,
|
|
75
|
+
const initSessions = async ({ recipients, apiClient, cryptoClient, logger, }) => {
|
|
76
|
+
var _a, _b, _c;
|
|
109
77
|
const missingClients = {};
|
|
110
78
|
const missingClientsWithPrekeys = {};
|
|
111
79
|
const existingSessions = [];
|
|
112
|
-
const users = (0, UserClientsUtil_1.
|
|
80
|
+
const users = (0, UserClientsUtil_1.flattenQualifiedUserClients)(recipients);
|
|
113
81
|
for (const user of users) {
|
|
114
82
|
const { userId, data } = user;
|
|
115
83
|
const clients = Array.isArray(data) ? data : Object.keys(data);
|
|
116
84
|
for (const clientId of clients) {
|
|
117
|
-
const sessionId = constructSessionId({ userId, clientId
|
|
85
|
+
const sessionId = constructSessionId({ userId, clientId });
|
|
118
86
|
if (await cryptoClient.sessionExists(sessionId)) {
|
|
119
87
|
existingSessions.push(sessionId);
|
|
120
88
|
continue;
|
|
121
89
|
}
|
|
122
90
|
if (!Array.isArray(data)) {
|
|
123
|
-
|
|
124
|
-
|
|
91
|
+
const domainMissingWithPrekey = (_a = missingClientsWithPrekeys[userId.domain]) !== null && _a !== void 0 ? _a : {};
|
|
92
|
+
domainMissingWithPrekey[userId.id] = (_b = domainMissingWithPrekey[userId.id]) !== null && _b !== void 0 ? _b : {};
|
|
93
|
+
domainMissingWithPrekey[userId.id][clientId] = data[clientId];
|
|
94
|
+
missingClientsWithPrekeys[userId.domain] = domainMissingWithPrekey;
|
|
125
95
|
continue;
|
|
126
96
|
}
|
|
127
|
-
|
|
128
|
-
|
|
97
|
+
const domainMissing = (_c = missingClients[userId.domain]) !== null && _c !== void 0 ? _c : {};
|
|
98
|
+
domainMissing[userId.id] = domainMissing[userId.id] || [];
|
|
99
|
+
domainMissing[userId.id].push(clientId);
|
|
100
|
+
missingClients[userId.domain] = domainMissing;
|
|
129
101
|
}
|
|
130
102
|
}
|
|
131
103
|
const { sessions: prekeyCreated, unknowns: prekeyUnknows } = Object.keys(missingClientsWithPrekeys).length > 0
|
|
132
104
|
? await createSessionsFromPreKeys({
|
|
133
|
-
|
|
134
|
-
domain,
|
|
135
|
-
useQualifiedIds: !!domain,
|
|
105
|
+
recipients: missingClientsWithPrekeys,
|
|
136
106
|
cryptoClient,
|
|
137
107
|
})
|
|
138
108
|
: { sessions: [], unknowns: {} };
|
|
139
109
|
const { sessions: created, unknowns } = Object.keys(missingClients).length > 0
|
|
140
110
|
? await createSessions({
|
|
141
|
-
|
|
142
|
-
domain,
|
|
111
|
+
recipients: missingClients,
|
|
143
112
|
apiClient,
|
|
144
113
|
cryptoClient,
|
|
145
114
|
logger,
|
|
@@ -157,23 +126,28 @@ async function deleteSession(params) {
|
|
|
157
126
|
await params.cryptoClient.deleteSession(sessionId);
|
|
158
127
|
}
|
|
159
128
|
exports.deleteSession = deleteSession;
|
|
160
|
-
const createSessionsFromPreKeys = async ({
|
|
129
|
+
const createSessionsFromPreKeys = async ({ recipients, cryptoClient, }) => {
|
|
130
|
+
var _a, _b;
|
|
161
131
|
const sessions = [];
|
|
162
132
|
const unknowns = {};
|
|
163
|
-
for (const
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
133
|
+
for (const domain in recipients) {
|
|
134
|
+
for (const userId in recipients[domain]) {
|
|
135
|
+
const userClients = recipients[domain][userId];
|
|
136
|
+
for (const clientId in userClients) {
|
|
137
|
+
const sessionId = constructSessionId({ userId: { id: userId, domain }, clientId });
|
|
138
|
+
const prekey = userClients[clientId];
|
|
139
|
+
if (!prekey) {
|
|
140
|
+
const domainUnknowns = (_a = unknowns[domain]) !== null && _a !== void 0 ? _a : {};
|
|
141
|
+
domainUnknowns[userId] = (_b = domainUnknowns[userId]) !== null && _b !== void 0 ? _b : [];
|
|
142
|
+
domainUnknowns[userId].push(clientId);
|
|
143
|
+
unknowns[domain] = domainUnknowns;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const prekeyBuffer = bazinga64_1.Decoder.fromBase64(prekey.key).asBytes;
|
|
147
|
+
await cryptoClient.sessionFromPrekey(sessionId, prekeyBuffer);
|
|
148
|
+
await cryptoClient.saveSession(sessionId);
|
|
149
|
+
sessions.push(sessionId);
|
|
172
150
|
}
|
|
173
|
-
const prekeyBuffer = bazinga64_1.Decoder.fromBase64(prekey.key).asBytes;
|
|
174
|
-
await cryptoClient.sessionFromPrekey(sessionId, prekeyBuffer);
|
|
175
|
-
await cryptoClient.saveSession(sessionId);
|
|
176
|
-
sessions.push(sessionId);
|
|
177
151
|
}
|
|
178
152
|
}
|
|
179
153
|
return { sessions, unknowns };
|
|
@@ -183,10 +157,15 @@ const createSessionsFromPreKeys = async ({ preKeyBundleMap, domain = '', useQual
|
|
|
183
157
|
*/
|
|
184
158
|
const buildEncryptedPayloads = (payloads) => {
|
|
185
159
|
return [...payloads].reduce((acc, [sessionId, payload]) => {
|
|
186
|
-
var _a;
|
|
187
|
-
const { userId, clientId } = parseSessionId(sessionId);
|
|
188
|
-
|
|
189
|
-
|
|
160
|
+
var _a, _b;
|
|
161
|
+
const { userId, domain, clientId } = parseSessionId(sessionId);
|
|
162
|
+
if (!domain) {
|
|
163
|
+
throw new Error('Invalid session ID');
|
|
164
|
+
}
|
|
165
|
+
const domainPayloads = (_a = acc[domain]) !== null && _a !== void 0 ? _a : {};
|
|
166
|
+
domainPayloads[userId] = (_b = domainPayloads[userId]) !== null && _b !== void 0 ? _b : {};
|
|
167
|
+
domainPayloads[userId][clientId] = payload;
|
|
168
|
+
acc[domain] = domainPayloads;
|
|
190
169
|
return acc;
|
|
191
170
|
}, {});
|
|
192
171
|
};
|
|
@@ -41,40 +41,20 @@ describe('SessionHandler', () => {
|
|
|
41
41
|
describe('constructSessionId', () => {
|
|
42
42
|
describe('constructs a session ID', () => {
|
|
43
43
|
it('without a domain', () => {
|
|
44
|
-
const sessionId = (0, SessionHandler_1.constructSessionId)({ userId: 'user-id', clientId: 'client-id'
|
|
44
|
+
const sessionId = (0, SessionHandler_1.constructSessionId)({ userId: { id: 'user-id', domain: '' }, clientId: 'client-id' });
|
|
45
45
|
expect(sessionId).toBe('user-id@client-id');
|
|
46
46
|
});
|
|
47
47
|
it('with a domain', () => {
|
|
48
|
-
const sessionId = (0, SessionHandler_1.constructSessionId)({
|
|
49
|
-
userId: 'user-id',
|
|
50
|
-
clientId: 'client-id',
|
|
51
|
-
domain: 'domain',
|
|
52
|
-
useQualifiedIds: true,
|
|
53
|
-
});
|
|
54
|
-
expect(sessionId).toBe('domain@user-id@client-id');
|
|
55
|
-
});
|
|
56
|
-
it('with a domain and useQualifiedIds', () => {
|
|
57
|
-
const sessionId = (0, SessionHandler_1.constructSessionId)({
|
|
58
|
-
userId: 'user-id',
|
|
59
|
-
clientId: 'client-id',
|
|
60
|
-
domain: 'domain',
|
|
61
|
-
useQualifiedIds: true,
|
|
62
|
-
});
|
|
63
|
-
expect(sessionId).toBe('domain@user-id@client-id');
|
|
64
|
-
});
|
|
65
|
-
it('with a qualified ID', () => {
|
|
66
48
|
const sessionId = (0, SessionHandler_1.constructSessionId)({
|
|
67
49
|
userId: { id: 'user-id', domain: 'domain' },
|
|
68
50
|
clientId: 'client-id',
|
|
69
|
-
useQualifiedIds: true,
|
|
70
51
|
});
|
|
71
52
|
expect(sessionId).toBe('domain@user-id@client-id');
|
|
72
53
|
});
|
|
73
|
-
it('with a qualified ID
|
|
54
|
+
it('with a qualified ID', () => {
|
|
74
55
|
const sessionId = (0, SessionHandler_1.constructSessionId)({
|
|
75
56
|
userId: { id: 'user-id', domain: 'domain' },
|
|
76
57
|
clientId: 'client-id',
|
|
77
|
-
useQualifiedIds: true,
|
|
78
58
|
});
|
|
79
59
|
expect(sessionId).toBe('domain@user-id@client-id');
|
|
80
60
|
});
|
|
@@ -91,12 +71,11 @@ describe('SessionHandler', () => {
|
|
|
91
71
|
const clientId = 'client1';
|
|
92
72
|
jest.spyOn(cryptoClient, 'sessionExists').mockResolvedValue(false);
|
|
93
73
|
jest
|
|
94
|
-
.spyOn(apiClient.api.user, '
|
|
74
|
+
.spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
|
|
95
75
|
.mockResolvedValue({ domain: generatePrekeys(userId, [clientId]) });
|
|
96
76
|
const sessionId = (0, SessionHandler_1.constructSessionId)({
|
|
97
77
|
userId,
|
|
98
78
|
clientId,
|
|
99
|
-
useQualifiedIds: true,
|
|
100
79
|
});
|
|
101
80
|
await (0, SessionHandler_1.initSession)({ userId, clientId }, { apiClient, cryptoClient });
|
|
102
81
|
expect(cryptoClient.sessionFromPrekey).toHaveBeenCalledWith(sessionId, expect.any(Object));
|
|
@@ -105,12 +84,11 @@ describe('SessionHandler', () => {
|
|
|
105
84
|
const userId = { id: 'user1', domain: 'domain' };
|
|
106
85
|
const clientId = 'client1';
|
|
107
86
|
jest
|
|
108
|
-
.spyOn(apiClient.api.user, '
|
|
87
|
+
.spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
|
|
109
88
|
.mockResolvedValue({ domain: generatePrekeys(userId, [clientId]) });
|
|
110
89
|
const sessionId = (0, SessionHandler_1.constructSessionId)({
|
|
111
90
|
userId,
|
|
112
91
|
clientId,
|
|
113
|
-
useQualifiedIds: true,
|
|
114
92
|
});
|
|
115
93
|
await (0, SessionHandler_1.initSession)({ userId, clientId }, { apiClient, cryptoClient });
|
|
116
94
|
expect(cryptoClient.sessionFromPrekey).toHaveBeenCalledWith(sessionId, expect.any(Object));
|
|
@@ -126,14 +104,15 @@ describe('SessionHandler', () => {
|
|
|
126
104
|
'missing-user1': ['client1'],
|
|
127
105
|
'missing-user2': ['client1', 'client2'],
|
|
128
106
|
};
|
|
129
|
-
jest.spyOn(apiClient.api.user, '
|
|
130
|
-
|
|
107
|
+
jest.spyOn(apiClient.api.user, 'postMultiPreKeyBundles').mockResolvedValue({
|
|
108
|
+
domain: Object.assign(Object.assign({}, generatePrekeys({ id: 'missing-user1', domain: '' }, ['client1'])), generatePrekeys({ id: 'missing-user2', domain: '' }, ['client1', 'client2'])),
|
|
109
|
+
});
|
|
131
110
|
jest
|
|
132
111
|
.spyOn(cryptoClient, 'sessionExists')
|
|
133
112
|
.mockImplementation(sessionId => Promise.resolve(sessionId.includes('missing')));
|
|
134
113
|
const sessionFromPrekeySpy = jest.spyOn(cryptoClient, 'sessionFromPrekey');
|
|
135
114
|
const { sessions } = await (0, SessionHandler_1.initSessions)({
|
|
136
|
-
recipients: Object.assign(Object.assign({}, existingUserClients), missingUserClients),
|
|
115
|
+
recipients: { domain: Object.assign(Object.assign({}, existingUserClients), missingUserClients) },
|
|
137
116
|
apiClient,
|
|
138
117
|
cryptoClient,
|
|
139
118
|
});
|
|
@@ -144,16 +123,30 @@ describe('SessionHandler', () => {
|
|
|
144
123
|
const userClients = {
|
|
145
124
|
'existing-user1': ['client1', 'deleteclient'],
|
|
146
125
|
};
|
|
147
|
-
const allKeys = generatePrekeys({ id: 'existing-user1', domain: '' }, ['client1']);
|
|
148
|
-
allKeys['existing-user1']['deleteclient'] = null;
|
|
126
|
+
const allKeys = { domain: generatePrekeys({ id: 'existing-user1', domain: 'domain' }, ['client1']) };
|
|
127
|
+
allKeys['domain']['existing-user1']['deleteclient'] = null;
|
|
149
128
|
jest.spyOn(apiClient.api.user, 'postMultiPreKeyBundles').mockResolvedValue(allKeys);
|
|
129
|
+
const { sessions, unknowns } = await (0, SessionHandler_1.initSessions)({
|
|
130
|
+
recipients: { domain: userClients },
|
|
131
|
+
apiClient,
|
|
132
|
+
cryptoClient,
|
|
133
|
+
});
|
|
134
|
+
expect(sessions).toEqual(['domain@existing-user1@client1']);
|
|
135
|
+
expect(unknowns).toEqual({ domain: { 'existing-user1': ['deleteclient'] } });
|
|
136
|
+
});
|
|
137
|
+
it('initializes sessions across multiple domains', async () => {
|
|
138
|
+
const userClients = {
|
|
139
|
+
domain1: { 'existing-user1': ['client11'] },
|
|
140
|
+
domain2: { 'existing-user2': ['client21'] },
|
|
141
|
+
};
|
|
142
|
+
jest.spyOn(cryptoClient, 'sessionExists').mockResolvedValue(true);
|
|
150
143
|
const { sessions, unknowns } = await (0, SessionHandler_1.initSessions)({
|
|
151
144
|
recipients: userClients,
|
|
152
145
|
apiClient,
|
|
153
146
|
cryptoClient,
|
|
154
147
|
});
|
|
155
|
-
expect(sessions).toEqual(['existing-user1@
|
|
156
|
-
expect(unknowns).
|
|
148
|
+
expect(sessions).toEqual(['domain1@existing-user1@client11', 'domain2@existing-user2@client21']);
|
|
149
|
+
expect(unknowns).toBeUndefined();
|
|
157
150
|
});
|
|
158
151
|
});
|
|
159
152
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { APIClient } from '@wireapp/api-client/lib/APIClient';
|
|
2
|
-
import { QualifiedUserClients
|
|
3
|
-
import { QualifiedId, QualifiedUserPreKeyBundleMap
|
|
2
|
+
import { QualifiedUserClients } from '@wireapp/api-client/lib/conversation';
|
|
3
|
+
import { QualifiedId, QualifiedUserPreKeyBundleMap } from '@wireapp/api-client/lib/user';
|
|
4
4
|
import { GenericMessage } from '@wireapp/protocol-messaging';
|
|
5
5
|
import { MessageSendingOptions } from '../../../conversation';
|
|
6
|
-
export type
|
|
7
|
-
federated: true;
|
|
6
|
+
export type MessageParams = {
|
|
8
7
|
sendingClientId: string;
|
|
9
8
|
recipients: QualifiedUserClients | QualifiedUserPreKeyBundleMap;
|
|
10
9
|
plainText: Uint8Array;
|
|
@@ -14,22 +13,14 @@ export type FederatedMessageParams = {
|
|
|
14
13
|
reportMissing: boolean | QualifiedId[] | undefined;
|
|
15
14
|
};
|
|
16
15
|
};
|
|
17
|
-
export type MessageParams = Omit<FederatedMessageParams, 'recipients' | 'options' | 'federated'> & {
|
|
18
|
-
federated: false;
|
|
19
|
-
recipients: UserClients | UserPreKeyBundleMap;
|
|
20
|
-
options: Omit<FederatedMessageParams['options'], 'reportMissing'> & {
|
|
21
|
-
reportMissing: boolean | string[] | undefined;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
16
|
interface GetGenericMessageParamsParams {
|
|
25
17
|
sendingClientId: string;
|
|
26
18
|
conversationId: QualifiedId;
|
|
27
19
|
genericMessage: GenericMessage;
|
|
28
20
|
options: MessageSendingOptions;
|
|
29
|
-
useQualifiedIds: boolean;
|
|
30
21
|
apiClient: APIClient;
|
|
31
22
|
}
|
|
32
|
-
type GetGenericMessageParamsReturnType = Promise<MessageParams
|
|
33
|
-
declare const getGenericMessageParams: ({ sendingClientId, conversationId, genericMessage, options: { targetMode, userIds, nativePush },
|
|
23
|
+
type GetGenericMessageParamsReturnType = Promise<MessageParams>;
|
|
24
|
+
declare const getGenericMessageParams: ({ sendingClientId, conversationId, genericMessage, options: { targetMode, userIds, nativePush }, apiClient, }: GetGenericMessageParamsParams) => GetGenericMessageParamsReturnType;
|
|
34
25
|
export { getGenericMessageParams };
|
|
35
26
|
//# sourceMappingURL=getGenericMessageParams.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getGenericMessageParams.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/proteus/Utility/getGenericMessageParams.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,SAAS,EAAC,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"getGenericMessageParams.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/proteus/Utility/getGenericMessageParams.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,SAAS,EAAC,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAC,oBAAoB,EAAC,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAC,WAAW,EAAE,4BAA4B,EAAC,MAAM,8BAA8B,CAAC;AAEvF,OAAO,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAK3D,OAAO,EAAoB,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAG/E,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,oBAAoB,GAAG,4BAA4B,CAAC;IAChE,SAAS,EAAE,UAAU,CAAC;IACtB,OAAO,EAAE;QACP,cAAc,EAAE,WAAW,CAAC;QAC5B,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;QAChC,aAAa,EAAE,OAAO,GAAG,WAAW,EAAE,GAAG,SAAS,CAAC;KACpD,CAAC;CACH,CAAC;AACF,UAAU,6BAA6B;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,WAAW,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,qBAAqB,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC;CACtB;AACD,KAAK,iCAAiC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAEhE,QAAA,MAAM,uBAAuB,kHAM1B,6BAA6B,sCA0B/B,CAAC;AAEF,OAAO,EAAC,uBAAuB,EAAC,CAAC"}
|
|
@@ -24,56 +24,24 @@ const Recipients_1 = require("./Recipients");
|
|
|
24
24
|
const UserIds_1 = require("./UserIds");
|
|
25
25
|
const conversation_1 = require("../../../conversation");
|
|
26
26
|
const util_1 = require("../../../util");
|
|
27
|
-
const getGenericMessageParams = async ({ sendingClientId, conversationId, genericMessage, options: { targetMode = conversation_1.MessageTargetMode.NONE, userIds, nativePush },
|
|
27
|
+
const getGenericMessageParams = async ({ sendingClientId, conversationId, genericMessage, options: { targetMode = conversation_1.MessageTargetMode.NONE, userIds, nativePush }, apiClient, }) => {
|
|
28
28
|
const plainText = protocol_messaging_1.GenericMessage.encode(genericMessage).finish();
|
|
29
29
|
if (targetMode !== conversation_1.MessageTargetMode.NONE && !userIds) {
|
|
30
30
|
throw new Error('Cannot send targetted message when no userIds are given');
|
|
31
31
|
}
|
|
32
|
-
if (conversationId.domain && useQualifiedIds) {
|
|
33
|
-
if ((0, util_1.isStringArray)(userIds) || (0, util_1.isUserClients)(userIds)) {
|
|
34
|
-
throw new Error('Invalid userIds option for sending to federated backend');
|
|
35
|
-
}
|
|
36
|
-
const recipients = await (0, Recipients_1.getQualifiedRecipientsForConversation)({ apiClient, conversationId, userIds });
|
|
37
|
-
let reportMissing;
|
|
38
|
-
if (targetMode === conversation_1.MessageTargetMode.NONE) {
|
|
39
|
-
reportMissing = (0, util_1.isQualifiedUserClients)(userIds); // we want to check mismatch in case the consumer gave an exact list of users/devices
|
|
40
|
-
}
|
|
41
|
-
else if (targetMode === conversation_1.MessageTargetMode.USERS) {
|
|
42
|
-
reportMissing = (0, UserIds_1.extractQualifiedUserIds)({ userIds });
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
// in case the message is fully targetted at user/client pairs, we do not want to report the missing clients or users at all
|
|
46
|
-
reportMissing = false;
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
federated: true,
|
|
50
|
-
sendingClientId,
|
|
51
|
-
recipients,
|
|
52
|
-
plainText,
|
|
53
|
-
options: {
|
|
54
|
-
conversationId,
|
|
55
|
-
nativePush,
|
|
56
|
-
reportMissing,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
if ((0, util_1.isQualifiedIdArray)(userIds) || (0, util_1.isQualifiedUserClients)(userIds)) {
|
|
61
|
-
throw new Error('Invalid userIds option for sending');
|
|
62
|
-
}
|
|
63
32
|
const recipients = await (0, Recipients_1.getRecipientsForConversation)({ apiClient, conversationId, userIds });
|
|
64
33
|
let reportMissing;
|
|
65
34
|
if (targetMode === conversation_1.MessageTargetMode.NONE) {
|
|
66
|
-
reportMissing = (0, util_1.
|
|
35
|
+
reportMissing = (0, util_1.isQualifiedUserClients)(userIds); // we want to check mismatch in case the consumer gave an exact list of users/devices
|
|
67
36
|
}
|
|
68
37
|
else if (targetMode === conversation_1.MessageTargetMode.USERS) {
|
|
69
|
-
reportMissing = (0, UserIds_1.
|
|
38
|
+
reportMissing = (0, UserIds_1.extractQualifiedUserIds)({ userIds });
|
|
70
39
|
}
|
|
71
40
|
else {
|
|
72
41
|
// in case the message is fully targetted at user/client pairs, we do not want to report the missing clients or users at all
|
|
73
42
|
reportMissing = false;
|
|
74
43
|
}
|
|
75
44
|
return {
|
|
76
|
-
federated: false,
|
|
77
45
|
sendingClientId,
|
|
78
46
|
recipients,
|
|
79
47
|
plainText,
|
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
import { QualifiedId, User } from '@wireapp/api-client/lib/user/';
|
|
2
2
|
import { APIClient } from '@wireapp/api-client';
|
|
3
|
-
import { AvailabilityType, BroadcastService } from '../broadcast/';
|
|
4
|
-
import { ConnectionService } from '../connection';
|
|
5
3
|
export declare class UserService {
|
|
6
4
|
private readonly apiClient;
|
|
7
|
-
|
|
8
|
-
private readonly connectionService;
|
|
9
|
-
constructor(apiClient: APIClient, broadcastService: BroadcastService, connectionService: ConnectionService);
|
|
5
|
+
constructor(apiClient: APIClient);
|
|
10
6
|
getUser(userId: string | QualifiedId): Promise<User>;
|
|
11
7
|
getUsers(userIds: string[] | QualifiedId[]): Promise<User[]>;
|
|
12
|
-
/**
|
|
13
|
-
* Sends a availability update to members of the same team
|
|
14
|
-
* @param teamId
|
|
15
|
-
* @param type
|
|
16
|
-
* @param options.sendAll=false will broadcast the message to all the members of the team (instead of just direct connections). Should be avoided in a big team
|
|
17
|
-
* @param options.sendAsProtobuf=false
|
|
18
|
-
*/
|
|
19
|
-
setAvailability(teamId: string, type: AvailabilityType, { sendAll, sendAsProtobuf }?: {
|
|
20
|
-
sendAll?: boolean | undefined;
|
|
21
|
-
sendAsProtobuf?: boolean | undefined;
|
|
22
|
-
}): Promise<void>;
|
|
23
8
|
}
|
|
24
9
|
//# sourceMappingURL=UserService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserService.d.ts","sourceRoot":"","sources":["../../src/user/UserService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UserService.d.ts","sourceRoot":"","sources":["../../src/user/UserService.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,WAAW,EAAE,IAAI,EAAC,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAI9C,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,SAAS,EAAE,SAAS;IAIzB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;CAQ1E"}
|
package/lib/user/UserService.js
CHANGED
|
@@ -19,16 +19,10 @@
|
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.UserService = void 0;
|
|
22
|
-
const connection_1 = require("@wireapp/api-client/lib/connection");
|
|
23
|
-
const protocol_messaging_1 = require("@wireapp/protocol-messaging");
|
|
24
|
-
const MessageBuilder_1 = require("../conversation/message/MessageBuilder");
|
|
25
|
-
const PreKeyBundle_1 = require("../messagingProtocols/proteus/Utility/PreKeyBundle");
|
|
26
22
|
const TypePredicateUtil_1 = require("../util/TypePredicateUtil");
|
|
27
23
|
class UserService {
|
|
28
|
-
constructor(apiClient
|
|
24
|
+
constructor(apiClient) {
|
|
29
25
|
this.apiClient = apiClient;
|
|
30
|
-
this.broadcastService = broadcastService;
|
|
31
|
-
this.connectionService = connectionService;
|
|
32
26
|
}
|
|
33
27
|
getUser(userId) {
|
|
34
28
|
return this.apiClient.api.user.getUser(userId);
|
|
@@ -41,41 +35,5 @@ class UserService {
|
|
|
41
35
|
? this.apiClient.api.user.postListUsers({ qualified_ids: userIds })
|
|
42
36
|
: this.apiClient.api.user.getUsers({ ids: userIds });
|
|
43
37
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Sends a availability update to members of the same team
|
|
46
|
-
* @param teamId
|
|
47
|
-
* @param type
|
|
48
|
-
* @param options.sendAll=false will broadcast the message to all the members of the team (instead of just direct connections). Should be avoided in a big team
|
|
49
|
-
* @param options.sendAsProtobuf=false
|
|
50
|
-
*/
|
|
51
|
-
async setAvailability(teamId, type, { sendAll = false, sendAsProtobuf = false } = {}) {
|
|
52
|
-
// Get pre-key bundles for members of your own team
|
|
53
|
-
const preKeyBundlesFromTeam = await this.broadcastService.getPreKeyBundlesFromTeam(teamId, false, !sendAll);
|
|
54
|
-
// Get pre-key bundles for all of your other 1:1 connections
|
|
55
|
-
const connections = await this.connectionService.getConnections();
|
|
56
|
-
const acceptedConnections = connections.filter(connection => connection.status === connection_1.ConnectionStatus.ACCEPTED);
|
|
57
|
-
const preKeyBundlePromises = acceptedConnections.map(connection => {
|
|
58
|
-
const mappedConnection = {
|
|
59
|
-
userId: connection.to,
|
|
60
|
-
conversationId: connection.conversation,
|
|
61
|
-
};
|
|
62
|
-
return (0, PreKeyBundle_1.getPreKeyBundleMap)({
|
|
63
|
-
apiClient: this.apiClient,
|
|
64
|
-
conversationId: { id: mappedConnection.conversationId, domain: '' },
|
|
65
|
-
userIds: [mappedConnection.userId],
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
const preKeyBundlesFromConnections = await Promise.all(preKeyBundlePromises);
|
|
69
|
-
// Merge pre-key bundles
|
|
70
|
-
const allPreKeyBundles = preKeyBundlesFromConnections.reduce((accumulator, preKeyBundleMap) => {
|
|
71
|
-
return Object.assign(Object.assign({}, accumulator), preKeyBundleMap);
|
|
72
|
-
}, preKeyBundlesFromTeam);
|
|
73
|
-
const genericMessage = protocol_messaging_1.GenericMessage.create({
|
|
74
|
-
availability: new protocol_messaging_1.Availability({ type }),
|
|
75
|
-
messageId: (0, MessageBuilder_1.createId)(),
|
|
76
|
-
});
|
|
77
|
-
// Broadcast availability status to your team members & external 1:1 connections
|
|
78
|
-
await this.broadcastService.broadcastGenericMessage(genericMessage, allPreKeyBundles, sendAsProtobuf);
|
|
79
|
-
}
|
|
80
38
|
}
|
|
81
39
|
exports.UserService = UserService;
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"./lib/cryptography/AssetCryptography/crypto.node": "./lib/cryptography/AssetCryptography/crypto.browser.js"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@wireapp/api-client": "^
|
|
14
|
+
"@wireapp/api-client": "^23.0.0",
|
|
15
15
|
"@wireapp/commons": "^5.0.4",
|
|
16
16
|
"@wireapp/core-crypto": "0.6.2",
|
|
17
17
|
"@wireapp/cryptobox": "12.8.0",
|
|
@@ -60,6 +60,6 @@
|
|
|
60
60
|
"test:coverage": "jest --coverage",
|
|
61
61
|
"watch": "tsc --watch"
|
|
62
62
|
},
|
|
63
|
-
"version": "
|
|
64
|
-
"gitHead": "
|
|
63
|
+
"version": "39.0.0",
|
|
64
|
+
"gitHead": "5e86fc700f348bd1f6d477b5eae88bb6d8bb5fb0"
|
|
65
65
|
}
|