@ethora/chat-component-rn 26.10.6 → 26.10.7
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/CHANGELOG.md +3 -1
- package/README.md +6 -3
- package/lib/commonjs/helpers/secureStoreRuntime.js +10 -1
- package/lib/commonjs/helpers/secureStoreRuntime.js.map +1 -1
- package/lib/commonjs/main.js +81 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/push.api.js +22 -7
- package/lib/commonjs/networking/api-requests/push.api.js.map +1 -1
- package/lib/commonjs/push/pushKeyStore.js +169 -0
- package/lib/commonjs/push/pushKeyStore.js.map +1 -0
- package/lib/commonjs/push/sealedBox.js +106 -0
- package/lib/commonjs/push/sealedBox.js.map +1 -0
- package/lib/commonjs/push/sealedPush.js +124 -0
- package/lib/commonjs/push/sealedPush.js.map +1 -0
- package/lib/commonjs/push/sealedPushTask.js +195 -0
- package/lib/commonjs/push/sealedPushTask.js.map +1 -0
- package/lib/commonjs/services/pushRegistration.js +12 -7
- package/lib/commonjs/services/pushRegistration.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/helpers/secureStoreRuntime.js +10 -1
- package/lib/module/helpers/secureStoreRuntime.js.map +1 -1
- package/lib/module/main.js +6 -0
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/push.api.js +21 -6
- package/lib/module/networking/api-requests/push.api.js.map +1 -1
- package/lib/module/push/pushKeyStore.js +159 -0
- package/lib/module/push/pushKeyStore.js.map +1 -0
- package/lib/module/push/sealedBox.js +97 -0
- package/lib/module/push/sealedBox.js.map +1 -0
- package/lib/module/push/sealedPush.js +117 -0
- package/lib/module/push/sealedPush.js.map +1 -0
- package/lib/module/push/sealedPushTask.js +187 -0
- package/lib/module/push/sealedPushTask.js.map +1 -0
- package/lib/module/services/pushRegistration.js +12 -7
- package/lib/module/services/pushRegistration.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/helpers/secureStoreRuntime.d.ts +17 -3
- package/lib/typescript/helpers/secureStoreRuntime.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +6 -0
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/push.api.d.ts +14 -2
- package/lib/typescript/networking/api-requests/push.api.d.ts.map +1 -1
- package/lib/typescript/push/pushKeyStore.d.ts +35 -0
- package/lib/typescript/push/pushKeyStore.d.ts.map +1 -0
- package/lib/typescript/push/sealedBox.d.ts +24 -0
- package/lib/typescript/push/sealedBox.d.ts.map +1 -0
- package/lib/typescript/push/sealedPush.d.ts +61 -0
- package/lib/typescript/push/sealedPush.d.ts.map +1 -0
- package/lib/typescript/push/sealedPushTask.d.ts +33 -0
- package/lib/typescript/push/sealedPushTask.d.ts.map +1 -0
- package/lib/typescript/services/pushRegistration.d.ts +8 -0
- package/lib/typescript/services/pushRegistration.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +6 -0
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +11 -1
- package/plugins/notification-service/NotificationService.swift +113 -0
- package/plugins/notification-service/SealedBox.swift +355 -0
- package/plugins/notification-service/check/gen-vectors.mjs +24 -0
- package/plugins/notification-service/check/main.swift +37 -0
- package/plugins/notification-service/check/run.sh +12 -0
- package/plugins/notification-service/check/vectors.json +1 -0
- package/plugins/withNotificationServiceExtension.js +70 -18
- package/src/helpers/secureStoreRuntime.ts +21 -3
- package/src/main.ts +30 -0
- package/src/networking/api-requests/push.api.ts +29 -4
- package/src/push/pushKeyStore.ts +163 -0
- package/src/push/sealedBox.ts +104 -0
- package/src/push/sealedPush.ts +127 -0
- package/src/push/sealedPushTask.ts +175 -0
- package/src/services/pushRegistration.ts +25 -5
- package/src/types/types.ts +6 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this pr
|
|
|
7
7
|
|
|
8
8
|
### Added
|
|
9
9
|
|
|
10
|
-
- **
|
|
10
|
+
- **Encrypted pushes.** A device key per install (`ensurePushKeyPair`, X25519 in expo-secure-store) sent with the token as `pushKey` (`registerPushToken(token, { pushKey })`, `getPushTokens` entries, `PushSubscriptionPayload`); the push service then seals every chat push for it (libsodium sealed box) and Google and Apple relay ciphertext only. iOS: the notification service extension from the config plugin opens the box (plain Swift, CryptoKit X25519 and tweetnacl ports, no pod) and shows the real title and text; the plugin now shares a keychain access group between the app and the extension. Android: `registerSealedPushTask({ channelId })` defines the expo-task-manager task that opens the box and posts one notification per chat, also with the app killed. A box that does not open leaves the "New message" placeholder. A backend without `pushKey` refuses the registration instead of delivering in the clear. New optional peers `expo-notifications` and `expo-task-manager` (Android only). Setup and checks in docs/push-encryption.md.
|
|
11
|
+
|
|
12
|
+
- **Attachment previews in iOS pushes.** New Expo config plugin (`"plugins": ["@ethora/chat-component-rn"]` in the host app.json) that adds a Notification Service Extension target, `EthoraNotificationService`, on `expo prebuild`. It downloads the thumbnail the push service sends as `previewUrl` for photo and video messages and shows it in the notification, the way Android already does. Text pushes and failed downloads show the notification unchanged. Setup in the README, Install, step 4.
|
|
11
13
|
|
|
12
14
|
- **Sending several files in one message.** The composer picks several files at once (documents and the library; the camera adds one shot), and every pick adds to the tray instead of replacing it. A message carries up to `config.attachments.maxFiles` files (default and hard ceiling 10), and `config.attachments.maxSizeMB` can lower the per-file size below the 50 MB upload limit; both refuse with a localized message. The files upload in parallel (fewer at a time in an e2ee room, where each is sealed first) and go out as ONE message in selection order. Text typed with the files is their caption: a plain room carries it on `<data>`, an e2ee room inside the sealed body. Each file shows its own upload progress on the bubble, and a file that did not upload gets its own Retry; a failed send keeps every file, so Retry re-uploads only what failed, also after a restart. A single file sends exactly the stanza it always did.
|
|
13
15
|
|
package/README.md
CHANGED
|
@@ -96,9 +96,9 @@ cd ios && pod install
|
|
|
96
96
|
|
|
97
97
|
After `npx expo prebuild` (or first `npm run ios` in an Expo project), the pods install runs automatically.
|
|
98
98
|
|
|
99
|
-
### 4.
|
|
99
|
+
### 4. Pushes: the iOS extension, encrypted pushes (optional)
|
|
100
100
|
|
|
101
|
-
The
|
|
101
|
+
The SDK ships an Expo config plugin that adds a Notification Service Extension, `EthoraNotificationService`, to the app:
|
|
102
102
|
|
|
103
103
|
```json
|
|
104
104
|
{
|
|
@@ -109,7 +109,10 @@ The push service sends a photo or video message with its thumbnail (`previewUrl`
|
|
|
109
109
|
}
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
`npx expo prebuild` then adds the
|
|
112
|
+
`npx expo prebuild` then adds the target (bundle id `<app bundle id>.EthoraNotificationService`), embeds it in the app, shares a keychain access group between the two and registers the extension for EAS Build credentials (`extra.eas.build.experimental.ios.appExtensions`). The signing team comes from the plugin option `appleTeamId`, else `ios.appleTeamId`, else the team already set on the app target. The extension does two things:
|
|
113
|
+
|
|
114
|
+
- **Attachment previews.** A photo or video push carries its thumbnail (`previewUrl`, `mutable-content: 1`); Android shows it by itself, the extension attaches it on iOS. Text pushes and failed downloads show the notification unchanged.
|
|
115
|
+
- **Encrypted pushes.** A device that registers an X25519 public key with its token gets its chat pushes sealed (libsodium sealed box), so Google and Apple relay ciphertext only; the extension decrypts and shows the real text. Android does the same in a background task. Setup, the API (`ensurePushKeyPair`, `registerPushToken(token, { pushKey })`, `registerSealedPushTask`) and what to check are in [docs/push-encryption.md](docs/push-encryption.md).
|
|
113
116
|
|
|
114
117
|
## Quick start
|
|
115
118
|
|
|
@@ -18,6 +18,12 @@ exports.loadSecureStore = exports.isSecureStoreAvailable = exports.__resetSecure
|
|
|
18
18
|
* AsyncStorage rather than crash (see `secureKeyValue.ts`).
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* The subset of expo-secure-store's options the SDK uses. `keychainService`
|
|
23
|
+
* must be repeated on every read of an item written with it; the
|
|
24
|
+
* accessibility constants come from `SecureStoreRuntime.accessible`.
|
|
25
|
+
*/
|
|
26
|
+
|
|
21
27
|
let cached;
|
|
22
28
|
|
|
23
29
|
/**
|
|
@@ -39,7 +45,10 @@ const loadSecureStore = () => {
|
|
|
39
45
|
cached = {
|
|
40
46
|
getItemAsync: mod.getItemAsync,
|
|
41
47
|
setItemAsync: mod.setItemAsync,
|
|
42
|
-
deleteItemAsync: mod.deleteItemAsync
|
|
48
|
+
deleteItemAsync: mod.deleteItemAsync,
|
|
49
|
+
accessible: {
|
|
50
|
+
afterFirstUnlockThisDeviceOnly: mod.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY
|
|
51
|
+
}
|
|
43
52
|
};
|
|
44
53
|
}
|
|
45
54
|
} catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["cached","loadSecureStore","undefined","mod","require","getItemAsync","setItemAsync","deleteItemAsync","exports","isSecureStoreAvailable","__resetSecureStoreRuntimeForTests"],"sourceRoot":"../../../src","sources":["helpers/secureStoreRuntime.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;
|
|
1
|
+
{"version":3,"names":["cached","loadSecureStore","undefined","mod","require","getItemAsync","setItemAsync","deleteItemAsync","accessible","afterFirstUnlockThisDeviceOnly","AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY","exports","isSecureStoreAvailable","__resetSecureStoreRuntimeForTests"],"sourceRoot":"../../../src","sources":["helpers/secureStoreRuntime.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAiBA,IAAIA,MAA6C;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,eAAe,GAAGA,CAAA,KAAiC;EAC9D,IAAID,MAAM,KAAKE,SAAS,EAAE;IACxB,OAAOF,MAAM;EACf;EAEA,IAAI;IACF;IACA,MAAMG,GAAG,GAAGC,OAAO,CAAC,mBAAmB,CAAC;IACxC,IACE,OAAOD,GAAG,EAAEE,YAAY,KAAK,UAAU,IACvC,OAAOF,GAAG,EAAEG,YAAY,KAAK,UAAU,IACvC,OAAOH,GAAG,EAAEI,eAAe,KAAK,UAAU,EAC1C;MACAP,MAAM,GAAG,IAAI;IACf,CAAC,MAAM;MACLA,MAAM,GAAG;QACPK,YAAY,EAAEF,GAAG,CAACE,YAAY;QAC9BC,YAAY,EAAEH,GAAG,CAACG,YAAY;QAC9BC,eAAe,EAAEJ,GAAG,CAACI,eAAe;QACpCC,UAAU,EAAE;UACVC,8BAA8B,EAAEN,GAAG,CAACO;QACtC;MACF,CAAC;IACH;EACF,CAAC,CAAC,MAAM;IACNV,MAAM,GAAG,IAAI;EACf;EAEA,OAAOA,MAAM;AACf,CAAC;AAACW,OAAA,CAAAV,eAAA,GAAAA,eAAA;AAEK,MAAMW,sBAAsB,GAAGA,CAAA,KAAeX,eAAe,CAAC,CAAC,KAAK,IAAI;;AAE/E;AAAAU,OAAA,CAAAC,sBAAA,GAAAA,sBAAA;AACO,MAAMC,iCAAiC,GAAGA,CAAA,KAAY;EAC3Db,MAAM,GAAGE,SAAS;AACpB,CAAC;AAACS,OAAA,CAAAE,iCAAA,GAAAA,iCAAA","ignoreList":[]}
|
package/lib/commonjs/main.js
CHANGED
|
@@ -33,6 +33,18 @@ Object.defineProperty(exports, "LIGHT_THEME", {
|
|
|
33
33
|
return _theme.LIGHT_THEME;
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
|
+
Object.defineProperty(exports, "PUSH_KEY_KEYCHAIN_SERVICE", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _pushKeyStore.PUSH_KEY_KEYCHAIN_SERVICE;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(exports, "PUSH_SECRET_KEY_ITEM", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function () {
|
|
45
|
+
return _pushKeyStore.PUSH_SECRET_KEY_ITEM;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
36
48
|
Object.defineProperty(exports, "PushRegistrationError", {
|
|
37
49
|
enumerable: true,
|
|
38
50
|
get: function () {
|
|
@@ -45,18 +57,48 @@ Object.defineProperty(exports, "RefreshFatalError", {
|
|
|
45
57
|
return _authRefresh.RefreshFatalError;
|
|
46
58
|
}
|
|
47
59
|
});
|
|
60
|
+
Object.defineProperty(exports, "SEALED_PUSH_ALG", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
get: function () {
|
|
63
|
+
return _sealedPush.SEALED_PUSH_ALG;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
Object.defineProperty(exports, "SEALED_PUSH_TASK", {
|
|
67
|
+
enumerable: true,
|
|
68
|
+
get: function () {
|
|
69
|
+
return _sealedPushTask.SEALED_PUSH_TASK;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
48
72
|
Object.defineProperty(exports, "XmppProvider", {
|
|
49
73
|
enumerable: true,
|
|
50
74
|
get: function () {
|
|
51
75
|
return _xmppProvider.XmppProvider;
|
|
52
76
|
}
|
|
53
77
|
});
|
|
78
|
+
Object.defineProperty(exports, "clearPushKeyPair", {
|
|
79
|
+
enumerable: true,
|
|
80
|
+
get: function () {
|
|
81
|
+
return _pushKeyStore.clearPushKeyPair;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
54
84
|
Object.defineProperty(exports, "detectPushTokenType", {
|
|
55
85
|
enumerable: true,
|
|
56
86
|
get: function () {
|
|
57
87
|
return _push.detectPushTokenType;
|
|
58
88
|
}
|
|
59
89
|
});
|
|
90
|
+
Object.defineProperty(exports, "ensurePushKeyPair", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
get: function () {
|
|
93
|
+
return _pushKeyStore.ensurePushKeyPair;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
Object.defineProperty(exports, "getPushKeyPair", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
get: function () {
|
|
99
|
+
return _pushKeyStore.getPushKeyPair;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
60
102
|
Object.defineProperty(exports, "getRegisteredPushToken", {
|
|
61
103
|
enumerable: true,
|
|
62
104
|
get: function () {
|
|
@@ -105,6 +147,12 @@ Object.defineProperty(exports, "isRefreshFatalError", {
|
|
|
105
147
|
return _authRefresh.isRefreshFatalError;
|
|
106
148
|
}
|
|
107
149
|
});
|
|
150
|
+
Object.defineProperty(exports, "isSealedPush", {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
get: function () {
|
|
153
|
+
return _sealedPush.isSealedPush;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
108
156
|
Object.defineProperty(exports, "logoutService", {
|
|
109
157
|
enumerable: true,
|
|
110
158
|
get: function () {
|
|
@@ -123,6 +171,18 @@ Object.defineProperty(exports, "openRoomFromPush", {
|
|
|
123
171
|
return _pushPayload.openRoomFromPush;
|
|
124
172
|
}
|
|
125
173
|
});
|
|
174
|
+
Object.defineProperty(exports, "openSealedPush", {
|
|
175
|
+
enumerable: true,
|
|
176
|
+
get: function () {
|
|
177
|
+
return _sealedPush.openSealedPush;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
Object.defineProperty(exports, "presentSealedPush", {
|
|
181
|
+
enumerable: true,
|
|
182
|
+
get: function () {
|
|
183
|
+
return _sealedPushTask.presentSealedPush;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
126
186
|
Object.defineProperty(exports, "refreshAuthTokens", {
|
|
127
187
|
enumerable: true,
|
|
128
188
|
get: function () {
|
|
@@ -141,12 +201,24 @@ Object.defineProperty(exports, "registerPushToken", {
|
|
|
141
201
|
return _pushRegistration.registerPushToken;
|
|
142
202
|
}
|
|
143
203
|
});
|
|
204
|
+
Object.defineProperty(exports, "registerSealedPushTask", {
|
|
205
|
+
enumerable: true,
|
|
206
|
+
get: function () {
|
|
207
|
+
return _sealedPushTask.registerSealedPushTask;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
144
210
|
Object.defineProperty(exports, "resendMessage", {
|
|
145
211
|
enumerable: true,
|
|
146
212
|
get: function () {
|
|
147
213
|
return _resendMessage.resendMessage;
|
|
148
214
|
}
|
|
149
215
|
});
|
|
216
|
+
Object.defineProperty(exports, "resetPushKeyPair", {
|
|
217
|
+
enumerable: true,
|
|
218
|
+
get: function () {
|
|
219
|
+
return _pushKeyStore.resetPushKeyPair;
|
|
220
|
+
}
|
|
221
|
+
});
|
|
150
222
|
Object.defineProperty(exports, "resolveStringTable", {
|
|
151
223
|
enumerable: true,
|
|
152
224
|
get: function () {
|
|
@@ -159,6 +231,12 @@ Object.defineProperty(exports, "resolveTheme", {
|
|
|
159
231
|
return _theme.resolveTheme;
|
|
160
232
|
}
|
|
161
233
|
});
|
|
234
|
+
Object.defineProperty(exports, "sealedPushEnvelopeOf", {
|
|
235
|
+
enumerable: true,
|
|
236
|
+
get: function () {
|
|
237
|
+
return _sealedPush.sealedPushEnvelopeOf;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
162
240
|
Object.defineProperty(exports, "setPushEnabled", {
|
|
163
241
|
enumerable: true,
|
|
164
242
|
get: function () {
|
|
@@ -244,6 +322,9 @@ var _useUnreadMessagesCounter = require("./hooks/useUnreadMessagesCounter");
|
|
|
244
322
|
var _pushPayload = require("./helpers/pushPayload");
|
|
245
323
|
var _pushRegistration = require("./services/pushRegistration");
|
|
246
324
|
var _push = require("./networking/api-requests/push.api");
|
|
325
|
+
var _pushKeyStore = require("./push/pushKeyStore");
|
|
326
|
+
var _sealedPushTask = require("./push/sealedPushTask");
|
|
327
|
+
var _sealedPush = require("./push/sealedPush");
|
|
247
328
|
var _useChatRoomFocus = require("./hooks/useChatRoomFocus");
|
|
248
329
|
var _useLogout = require("./hooks/useLogout");
|
|
249
330
|
var _useQRCodeChatHandler = require("./hooks/useQRCodeChatHandler");
|
package/lib/commonjs/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["require","_ReduxWrapper","_xmppProvider","_useUnreadMessagesCounter","_pushPayload","_pushRegistration","_push","_useChatRoomFocus","_useLogout","_useQRCodeChatHandler","_resendMessage","_useChatFonts","_useT","_strings","_authRefresh","_theme","_chatSettingsSlice","_e2ee"],"sourceRoot":"../../src","sources":["main.ts"],"mappings":"
|
|
1
|
+
{"version":3,"names":["require","_ReduxWrapper","_xmppProvider","_useUnreadMessagesCounter","_pushPayload","_pushRegistration","_push","_pushKeyStore","_sealedPushTask","_sealedPush","_useChatRoomFocus","_useLogout","_useQRCodeChatHandler","_resendMessage","_useChatFonts","_useT","_strings","_authRefresh","_theme","_chatSettingsSlice","_e2ee"],"sourceRoot":"../../src","sources":["main.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBAA,OAAA;AAGA,IAAAC,aAAA,GAAAD,OAAA;AACA,IAAAE,aAAA,GAAAF,OAAA;AAGA,IAAAG,yBAAA,GAAAH,OAAA;AAEA,IAAAI,YAAA,GAAAJ,OAAA;AAEA,IAAAK,iBAAA,GAAAL,OAAA;AAYA,IAAAM,KAAA,GAAAN,OAAA;AAaA,IAAAO,aAAA,GAAAP,OAAA;AASA,IAAAQ,eAAA,GAAAR,OAAA;AAMA,IAAAS,WAAA,GAAAT,OAAA;AAYA,IAAAU,iBAAA,GAAAV,OAAA;AACA,IAAAW,UAAA,GAAAX,OAAA;AACA,IAAAY,qBAAA,GAAAZ,OAAA;AACA,IAAAa,cAAA,GAAAb,OAAA;AAEA,IAAAc,aAAA,GAAAd,OAAA;AAKA,IAAAe,KAAA,GAAAf,OAAA;AACA,IAAAgB,QAAA,GAAAhB,OAAA;AAqCA,IAAAiB,YAAA,GAAAjB,OAAA;AAYA,IAAAkB,MAAA,GAAAlB,OAAA;AASA,IAAAmB,kBAAA,GAAAnB,OAAA;AACA,IAAAoB,KAAA,GAAApB,OAAA","ignoreList":[]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.isPushRegistrationError = exports.detectPushTokenType = exports.buildPushSubscriptionPayload = exports.buildPushGatewayPayload = exports.PushRegistrationError = void 0;
|
|
6
|
+
exports.isPushRegistrationError = exports.detectPushTokenType = exports.buildPushSubscriptionPayload = exports.buildPushGatewayPayload = exports.PushRegistrationError = exports.PUSH_KEY_ALG = void 0;
|
|
7
7
|
exports.registerPushSubscription = registerPushSubscription;
|
|
8
8
|
exports.resolvePushDeviceType = void 0;
|
|
9
9
|
exports.subscribeToPushGateway = subscribeToPushGateway;
|
|
@@ -51,32 +51,47 @@ const toRegistrationError = (error, what) => {
|
|
|
51
51
|
return new PushRegistrationError(status ? `${what} refused (HTTP ${status}): ${detail}` : `${what} failed: ${detail}`, status, body);
|
|
52
52
|
};
|
|
53
53
|
const isUnknownFieldError = error => error?.response?.status === 422 && /not allowed/i.test(String(error?.response?.data?.error ?? ''));
|
|
54
|
-
|
|
54
|
+
|
|
55
|
+
/** The only sealing scheme the push service knows (README, "Encrypted pushes"). */
|
|
56
|
+
const PUSH_KEY_ALG = exports.PUSH_KEY_ALG = 'sealed-box-x25519';
|
|
57
|
+
const buildPushSubscriptionPayload = (token, tokenType, pushKey, pushKeyId) => ({
|
|
55
58
|
registrationToken: token,
|
|
56
59
|
deviceType: resolvePushDeviceType(),
|
|
57
|
-
tokenType
|
|
60
|
+
tokenType,
|
|
61
|
+
...(pushKey ? {
|
|
62
|
+
pushKey,
|
|
63
|
+
pushKeyAlg: PUSH_KEY_ALG,
|
|
64
|
+
...(pushKeyId ? {
|
|
65
|
+
pushKeyId
|
|
66
|
+
} : {})
|
|
67
|
+
} : {})
|
|
58
68
|
});
|
|
59
69
|
exports.buildPushSubscriptionPayload = buildPushSubscriptionPayload;
|
|
60
70
|
async function registerPushSubscription({
|
|
61
71
|
appId,
|
|
62
72
|
token,
|
|
63
73
|
tokenType,
|
|
64
|
-
authToken
|
|
74
|
+
authToken,
|
|
75
|
+
pushKey,
|
|
76
|
+
pushKeyId
|
|
65
77
|
}) {
|
|
66
78
|
const path = `/v1/push/subscription/${encodeURIComponent(appId)}`;
|
|
67
79
|
const headers = {
|
|
68
80
|
Authorization: authToken
|
|
69
81
|
};
|
|
70
|
-
const payload = buildPushSubscriptionPayload(token, tokenType);
|
|
82
|
+
const payload = buildPushSubscriptionPayload(token, tokenType, pushKey, pushKeyId);
|
|
71
83
|
try {
|
|
72
84
|
await _apiClient.default.post(path, payload, {
|
|
73
85
|
headers
|
|
74
86
|
});
|
|
75
87
|
return;
|
|
76
88
|
} catch (error) {
|
|
77
|
-
|
|
89
|
+
// A backend that predates `tokenType` still delivers to apns / fcm
|
|
90
|
+
// tokens. One that predates `pushKey` would deliver in the clear: the
|
|
91
|
+
// host asked for encryption, so that is an error, never a quiet fallback.
|
|
92
|
+
const canDowngrade = (tokenType === 'apns' || tokenType === 'fcm') && !pushKey;
|
|
78
93
|
if (!(canDowngrade && isUnknownFieldError(error))) {
|
|
79
|
-
throw toRegistrationError(error, tokenType === 'expo' ? 'Push registration (the backend does not accept Expo push tokens yet)' : 'Push registration');
|
|
94
|
+
throw toRegistrationError(error, tokenType === 'expo' ? 'Push registration (the backend does not accept Expo push tokens yet)' : pushKey && isUnknownFieldError(error) ? 'Push registration (the backend does not support encrypted pushes)' : 'Push registration');
|
|
80
95
|
}
|
|
81
96
|
}
|
|
82
97
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_axios","_interopRequireDefault","require","_reactNative","_roomStore","_apiClient","e","__esModule","default","PushRegistrationError","Error","constructor","message","status","body","name","exports","isPushRegistrationError","error","EXPO_PUSH_TOKEN","APNS_TOKEN","detectPushTokenType","token","t","trim","test","resolvePushDeviceType","Platform","OS","toRegistrationError","what","response","data","detail","isUnknownFieldError","String","buildPushSubscriptionPayload","tokenType","registrationToken","deviceType","registerPushSubscription","appId","authToken","path","encodeURIComponent","headers","Authorization","payload","http","post","canDowngrade","unregisterPushSubscription","delete","endpoint","DEFAULT_XMPP_HOST","resolveXmppHost","config","store","getState","chatSettingStore","xmppSettings","host","gatewayAxios","axios","create","buildPushGatewayPayload","userJid","projectName","jid","includes","subscribeToPushGateway","args","baseURL","apiUrl"],"sourceRoot":"../../../../src","sources":["networking/api-requests/push.api.ts"],"mappings":";;;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AACA,IAAAG,UAAA,GAAAJ,sBAAA,CAAAC,OAAA;AAAgC,SAAAD,uBAAAK,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAOhC;AACA;AACA;AACA;AACA;AACO,MAAMG,qBAAqB,SAASC,KAAK,CAAC;EAI/CC,WAAWA,CAACC,OAAe,EAAEC,MAAe,EAAEC,IAAc,EAAE;IAC5D,KAAK,CAACF,OAAO,CAAC;IACd,IAAI,CAACG,IAAI,GAAG,uBAAuB;IACnC,IAAI,CAACF,MAAM,GAAGA,MAAM;IACpB,IAAI,CAACC,IAAI,GAAGA,IAAI;EAClB;AACF;AAACE,OAAA,CAAAP,qBAAA,GAAAA,qBAAA;AAEM,MAAMQ,uBAAuB,GAClCC,KAAc,IAEbA,KAAK,EAA4BH,IAAI,KAAK,uBAAuB;AAACC,OAAA,CAAAC,uBAAA,GAAAA,uBAAA;AAErE,MAAME,eAAe,GAAG,oCAAoC;AAC5D,MAAMC,UAAU,GAAG,kBAAkB;AAE9B,MAAMC,mBAAmB,GAAIC,KAAa,IAAoB;EACnE,MAAMC,CAAC,GAAGD,KAAK,CAACE,IAAI,CAAC,CAAC;EACtB,IAAIL,eAAe,CAACM,IAAI,CAACF,CAAC,CAAC,EAAE;IAC3B,OAAO,MAAM;EACf;EACA,IAAIH,UAAU,CAACK,IAAI,CAACF,CAAC,CAAC,EAAE;IACtB,OAAO,MAAM;EACf;EACA,OAAO,KAAK;AACd,CAAC;AAACP,OAAA,CAAAK,mBAAA,GAAAA,mBAAA;AAEK,MAAMK,qBAAqB,GAAGA,CAAA,KACnCC,qBAAQ,CAACC,EAAE,KAAK,KAAK,GAAG,KAAK,GAAG,SAAS;AAACZ,OAAA,CAAAU,qBAAA,GAAAA,qBAAA;AAE5C,MAAMG,mBAAmB,GAAGA,CAACX,KAAU,EAAEY,IAAY,KAA4B;EAC/E,MAAMjB,MAA0B,GAAGK,KAAK,EAAEa,QAAQ,EAAElB,MAAM;EAC1D,MAAMC,IAAI,GAAGI,KAAK,EAAEa,QAAQ,EAAEC,IAAI;EAClC,MAAMC,MAAM,GACT,OAAOnB,IAAI,EAAEI,KAAK,KAAK,QAAQ,IAAIJ,IAAI,CAACI,KAAK,IAC9CA,KAAK,EAAEN,OAAO,IACd,eAAe;EACjB,OAAO,IAAIH,qBAAqB,CAC9BI,MAAM,GACF,GAAGiB,IAAI,kBAAkBjB,MAAM,MAAMoB,MAAM,EAAE,GAC7C,GAAGH,IAAI,YAAYG,MAAM,EAAE,EAC/BpB,MAAM,EACNC,IACF,CAAC;AACH,CAAC;AAED,MAAMoB,mBAAmB,GAAIhB,KAAU,IACrCA,KAAK,EAAEa,QAAQ,EAAElB,MAAM,KAAK,GAAG,IAC/B,cAAc,CAACY,IAAI,CAACU,MAAM,CAACjB,KAAK,EAAEa,QAAQ,EAAEC,IAAI,EAAEd,KAAK,IAAI,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"names":["_axios","_interopRequireDefault","require","_reactNative","_roomStore","_apiClient","e","__esModule","default","PushRegistrationError","Error","constructor","message","status","body","name","exports","isPushRegistrationError","error","EXPO_PUSH_TOKEN","APNS_TOKEN","detectPushTokenType","token","t","trim","test","resolvePushDeviceType","Platform","OS","toRegistrationError","what","response","data","detail","isUnknownFieldError","String","PUSH_KEY_ALG","buildPushSubscriptionPayload","tokenType","pushKey","pushKeyId","registrationToken","deviceType","pushKeyAlg","registerPushSubscription","appId","authToken","path","encodeURIComponent","headers","Authorization","payload","http","post","canDowngrade","unregisterPushSubscription","delete","endpoint","DEFAULT_XMPP_HOST","resolveXmppHost","config","store","getState","chatSettingStore","xmppSettings","host","gatewayAxios","axios","create","buildPushGatewayPayload","userJid","projectName","jid","includes","subscribeToPushGateway","args","baseURL","apiUrl"],"sourceRoot":"../../../../src","sources":["networking/api-requests/push.api.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.__resetPushKeyStoreForTests = exports.PUSH_SECRET_KEY_ITEM = exports.PUSH_PUBLIC_KEY_ITEM = exports.PUSH_KEY_KEYCHAIN_SERVICE = void 0;
|
|
7
|
+
exports.clearPushKeyPair = clearPushKeyPair;
|
|
8
|
+
exports.ensurePushKeyPair = ensurePushKeyPair;
|
|
9
|
+
exports.getPushKeyPair = getPushKeyPair;
|
|
10
|
+
exports.loadPushSecretKey = loadPushSecretKey;
|
|
11
|
+
exports.resetPushKeyPair = resetPushKeyPair;
|
|
12
|
+
var _crypto = require("../e2ee/crypto");
|
|
13
|
+
var _secureStoreRuntime = require("../helpers/secureStoreRuntime");
|
|
14
|
+
var _devLogger = require("../utils/devLogger");
|
|
15
|
+
var _sealedBox = require("./sealedBox");
|
|
16
|
+
// The device key for encrypted pushes: one X25519 pair per install, in the
|
|
17
|
+
// platform keychain / keystore through expo-secure-store. The public half
|
|
18
|
+
// goes to the push service with the token (`pushKey`); the secret half
|
|
19
|
+
// never leaves the device and is read by whoever renders a sealed push —
|
|
20
|
+
// the Android background task (`sealedPushTask.ts`, same process, same
|
|
21
|
+
// store) and the iOS notification service extension, which reads the
|
|
22
|
+
// keychain item directly (plugins/notification-service), so the item's
|
|
23
|
+
// attributes below are a contract with the Swift side:
|
|
24
|
+
// service `ethora.push` (expo-secure-store stores it as `ethora.push:no-auth`)
|
|
25
|
+
// account `ethora_push_secret_key`, UTF-8
|
|
26
|
+
// value base64 of the 32-byte secret key, UTF-8
|
|
27
|
+
// group the app's first keychain access group, which the config
|
|
28
|
+
// plugin shares with the extension
|
|
29
|
+
// Readable after the first unlock so a push that arrives while the phone
|
|
30
|
+
// is locked still decrypts; this device only, so an iCloud keychain copy
|
|
31
|
+
// on another device is never a key for pushes that go to this one.
|
|
32
|
+
|
|
33
|
+
const PUSH_KEY_KEYCHAIN_SERVICE = exports.PUSH_KEY_KEYCHAIN_SERVICE = 'ethora.push';
|
|
34
|
+
const PUSH_SECRET_KEY_ITEM = exports.PUSH_SECRET_KEY_ITEM = 'ethora_push_secret_key';
|
|
35
|
+
const PUSH_PUBLIC_KEY_ITEM = exports.PUSH_PUBLIC_KEY_ITEM = 'ethora_push_public_key';
|
|
36
|
+
let warnedMissingStore = false;
|
|
37
|
+
const warnMissingStoreOnce = () => {
|
|
38
|
+
if (warnedMissingStore) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
warnedMissingStore = true;
|
|
42
|
+
(0, _devLogger.pushLog)('warn', 'push: expo-secure-store is not installed, so no device key for encrypted ' + 'pushes can be kept; pushes stay in the clear.');
|
|
43
|
+
};
|
|
44
|
+
const storeOptions = () => {
|
|
45
|
+
const store = (0, _secureStoreRuntime.loadSecureStore)();
|
|
46
|
+
if (!store) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const accessible = store.accessible.afterFirstUnlockThisDeviceOnly;
|
|
50
|
+
return {
|
|
51
|
+
keychainService: PUSH_KEY_KEYCHAIN_SERVICE,
|
|
52
|
+
...(accessible !== undefined ? {
|
|
53
|
+
keychainAccessible: accessible
|
|
54
|
+
} : {})
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const readItem = async item => {
|
|
58
|
+
const store = (0, _secureStoreRuntime.loadSecureStore)();
|
|
59
|
+
const options = storeOptions();
|
|
60
|
+
if (!store || !options) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return await store.getItemAsync(item, options);
|
|
65
|
+
} catch (e) {
|
|
66
|
+
(0, _devLogger.pushLog)('warn', `push: reading ${item} failed`, e);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const decodeKey = (raw, length) => {
|
|
71
|
+
if (!raw) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const bytes = (0, _crypto.fromBase64)(raw);
|
|
76
|
+
return bytes.length === length ? bytes : null;
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The stored pair, or null when there is none (or it is unreadable).
|
|
84
|
+
* The public key is re-derived from the secret, so the pair is consistent
|
|
85
|
+
* even if only the secret item survived.
|
|
86
|
+
*/
|
|
87
|
+
async function loadPushSecretKey() {
|
|
88
|
+
const secretKey = decodeKey(await readItem(PUSH_SECRET_KEY_ITEM), _sealedBox.SEALED_BOX_SECRET_KEY_BYTES);
|
|
89
|
+
if (!secretKey) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const stored = decodeKey(await readItem(PUSH_PUBLIC_KEY_ITEM), _sealedBox.SEALED_BOX_PUBLIC_KEY_BYTES);
|
|
93
|
+
return {
|
|
94
|
+
publicKey: stored ?? (0, _sealedBox.sealedBoxPublicKeyOf)(secretKey),
|
|
95
|
+
secretKey
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const describe = publicKey => ({
|
|
99
|
+
publicKey: (0, _crypto.toBase64)(publicKey),
|
|
100
|
+
keyId: (0, _sealedBox.sealedBoxKeyId)(publicKey)
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/** The public half of the stored pair, null when the device has no key. */
|
|
104
|
+
async function getPushKeyPair() {
|
|
105
|
+
const key = await loadPushSecretKey();
|
|
106
|
+
return key ? describe(key.publicKey) : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Generate and store a new pair, replacing any existing one. Pushes sealed
|
|
111
|
+
* for the old key stop opening at once, so re-register the token with the
|
|
112
|
+
* new `publicKey` right after. Null when expo-secure-store is missing or
|
|
113
|
+
* the keychain refused the write.
|
|
114
|
+
*/
|
|
115
|
+
async function resetPushKeyPair() {
|
|
116
|
+
const store = (0, _secureStoreRuntime.loadSecureStore)();
|
|
117
|
+
const options = storeOptions();
|
|
118
|
+
if (!store || !options) {
|
|
119
|
+
warnMissingStoreOnce();
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const pair = (0, _sealedBox.generateSealedBoxKeyPair)();
|
|
123
|
+
try {
|
|
124
|
+
await store.setItemAsync(PUSH_SECRET_KEY_ITEM, (0, _crypto.toBase64)(pair.secretKey), options);
|
|
125
|
+
await store.setItemAsync(PUSH_PUBLIC_KEY_ITEM, (0, _crypto.toBase64)(pair.publicKey), options);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
(0, _devLogger.pushLog)('warn', 'push: storing the device key failed', e);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const check = await loadPushSecretKey();
|
|
131
|
+
if (!check || (0, _crypto.toBase64)(check.publicKey) !== (0, _crypto.toBase64)(pair.publicKey)) {
|
|
132
|
+
(0, _devLogger.pushLog)('warn', 'push: the device key was not kept');
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
(0, _devLogger.pushLog)('rn', `push: new device key ${(0, _sealedBox.sealedBoxKeyId)(pair.publicKey)}`);
|
|
136
|
+
return describe(pair.publicKey);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The device key for encrypted pushes, created on first call. Hand
|
|
141
|
+
* `publicKey` to `registerPushToken` (or send it as `pushKey` yourself).
|
|
142
|
+
*/
|
|
143
|
+
async function ensurePushKeyPair() {
|
|
144
|
+
const existing = await getPushKeyPair();
|
|
145
|
+
return existing ?? resetPushKeyPair();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Remove the pair; the next `ensurePushKeyPair` creates a new one. */
|
|
149
|
+
async function clearPushKeyPair() {
|
|
150
|
+
const store = (0, _secureStoreRuntime.loadSecureStore)();
|
|
151
|
+
const options = storeOptions();
|
|
152
|
+
if (!store || !options) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
for (const item of [PUSH_SECRET_KEY_ITEM, PUSH_PUBLIC_KEY_ITEM]) {
|
|
156
|
+
try {
|
|
157
|
+
await store.deleteItemAsync(item, options);
|
|
158
|
+
} catch {
|
|
159
|
+
// Not there — nothing to remove.
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Test seam only. */
|
|
165
|
+
const __resetPushKeyStoreForTests = () => {
|
|
166
|
+
warnedMissingStore = false;
|
|
167
|
+
};
|
|
168
|
+
exports.__resetPushKeyStoreForTests = __resetPushKeyStoreForTests;
|
|
169
|
+
//# sourceMappingURL=pushKeyStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_crypto","require","_secureStoreRuntime","_devLogger","_sealedBox","PUSH_KEY_KEYCHAIN_SERVICE","exports","PUSH_SECRET_KEY_ITEM","PUSH_PUBLIC_KEY_ITEM","warnedMissingStore","warnMissingStoreOnce","pushLog","storeOptions","store","loadSecureStore","accessible","afterFirstUnlockThisDeviceOnly","keychainService","undefined","keychainAccessible","readItem","item","options","getItemAsync","e","decodeKey","raw","length","bytes","fromBase64","loadPushSecretKey","secretKey","SEALED_BOX_SECRET_KEY_BYTES","stored","SEALED_BOX_PUBLIC_KEY_BYTES","publicKey","sealedBoxPublicKeyOf","describe","toBase64","keyId","sealedBoxKeyId","getPushKeyPair","key","resetPushKeyPair","pair","generateSealedBoxKeyPair","setItemAsync","check","ensurePushKeyPair","existing","clearPushKeyPair","deleteItemAsync","__resetPushKeyStoreForTests"],"sourceRoot":"../../../src","sources":["push/pushKeyStore.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.sealedBoxKeyId = exports.generateSealedBoxKeyPair = exports.SEALED_BOX_SECRET_KEY_BYTES = exports.SEALED_BOX_PUBLIC_KEY_BYTES = exports.SEALED_BOX_OVERHEAD_BYTES = void 0;
|
|
7
|
+
exports.sealedBoxOpen = sealedBoxOpen;
|
|
8
|
+
exports.sealedBoxPublicKeyOf = void 0;
|
|
9
|
+
exports.sealedBoxSeal = sealedBoxSeal;
|
|
10
|
+
var _salsa = require("@noble/ciphers/salsa.js");
|
|
11
|
+
var _utils = require("@noble/ciphers/utils.js");
|
|
12
|
+
var _ed = require("@noble/curves/ed25519.js");
|
|
13
|
+
var _blake = require("@noble/hashes/blake2.js");
|
|
14
|
+
var _sha = require("@noble/hashes/sha2.js");
|
|
15
|
+
var _utils2 = require("@noble/hashes/utils.js");
|
|
16
|
+
// libsodium's sealed box (`crypto_box_seal` / `crypto_box_seal_open`) on
|
|
17
|
+
// the noble primitives the e2ee code already ships, so the JS side needs
|
|
18
|
+
// no native libsodium. The push service seals every chat push for a
|
|
19
|
+
// device that registered an X25519 public key (ethora-backend,
|
|
20
|
+
// services/push/README.md, "Encrypted pushes"); this is the matching
|
|
21
|
+
// receiver. The iOS notification service extension decrypts the same
|
|
22
|
+
// boxes in Swift with libsodium (plugins/notification-service).
|
|
23
|
+
//
|
|
24
|
+
// Layout: ephemeral public key (32) || crypto_box(message, nonce,
|
|
25
|
+
// recipient pk, ephemeral sk), with crypto_box = XSalsa20-Poly1305 under
|
|
26
|
+
// HSalsa20(X25519 shared secret) and nonce = BLAKE2b-192(epk || rpk).
|
|
27
|
+
// `__tests__/sealedBox.test.ts` pins this against libsodium itself.
|
|
28
|
+
|
|
29
|
+
const SEALED_BOX_PUBLIC_KEY_BYTES = exports.SEALED_BOX_PUBLIC_KEY_BYTES = 32;
|
|
30
|
+
const SEALED_BOX_SECRET_KEY_BYTES = exports.SEALED_BOX_SECRET_KEY_BYTES = 32;
|
|
31
|
+
/** Ephemeral public key (32) + Poly1305 tag (16). */
|
|
32
|
+
const SEALED_BOX_OVERHEAD_BYTES = exports.SEALED_BOX_OVERHEAD_BYTES = 48;
|
|
33
|
+
const NONCE_BYTES = 24;
|
|
34
|
+
const SIGMA = (0, _utils.u32)((0, _utils.utf8ToBytes)('expand 32-byte k'));
|
|
35
|
+
const ZERO_NONCE_PREFIX = new Uint32Array(4);
|
|
36
|
+
const generateSealedBoxKeyPair = () => {
|
|
37
|
+
const {
|
|
38
|
+
secretKey,
|
|
39
|
+
publicKey
|
|
40
|
+
} = _ed.x25519.keygen();
|
|
41
|
+
return {
|
|
42
|
+
publicKey,
|
|
43
|
+
secretKey
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
exports.generateSealedBoxKeyPair = generateSealedBoxKeyPair;
|
|
47
|
+
const sealedBoxPublicKeyOf = secretKey => _ed.x25519.getPublicKey(secretKey);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The key id the push service derives when the registration carries none:
|
|
51
|
+
* the first 16 hex characters of SHA-256 over the raw public key. Sent back
|
|
52
|
+
* as `kid` in every sealed push.
|
|
53
|
+
*/
|
|
54
|
+
exports.sealedBoxPublicKeyOf = sealedBoxPublicKeyOf;
|
|
55
|
+
const sealedBoxKeyId = publicKey => (0, _utils2.bytesToHex)((0, _sha.sha256)(publicKey)).slice(0, 16);
|
|
56
|
+
|
|
57
|
+
// crypto_box_beforenm: HSalsa20 over the X25519 shared secret.
|
|
58
|
+
exports.sealedBoxKeyId = sealedBoxKeyId;
|
|
59
|
+
const boxSharedKey = (theirPublicKey, mySecretKey) => {
|
|
60
|
+
const shared = _ed.x25519.getSharedSecret(mySecretKey, theirPublicKey);
|
|
61
|
+
const words = new Uint32Array(8);
|
|
62
|
+
(0, _salsa.hsalsa)(SIGMA, (0, _utils.u32)(shared), ZERO_NONCE_PREFIX, words);
|
|
63
|
+
(0, _utils.clean)(shared);
|
|
64
|
+
return (0, _utils.u8)(words);
|
|
65
|
+
};
|
|
66
|
+
const sealNonce = (ephemeralPublicKey, recipientPublicKey) => (0, _blake.blake2b)((0, _utils.concatBytes)(ephemeralPublicKey, recipientPublicKey), {
|
|
67
|
+
dkLen: NONCE_BYTES
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/** `crypto_box_seal`: used by the tests and the key tool, not by the app. */
|
|
71
|
+
function sealedBoxSeal(message, recipientPublicKey) {
|
|
72
|
+
if (recipientPublicKey.length !== SEALED_BOX_PUBLIC_KEY_BYTES) {
|
|
73
|
+
throw new Error('sealedBoxSeal: the public key must be 32 bytes');
|
|
74
|
+
}
|
|
75
|
+
const ephemeral = generateSealedBoxKeyPair();
|
|
76
|
+
const key = boxSharedKey(recipientPublicKey, ephemeral.secretKey);
|
|
77
|
+
const nonce = sealNonce(ephemeral.publicKey, recipientPublicKey);
|
|
78
|
+
const box = (0, _salsa.xsalsa20poly1305)(key, nonce).encrypt(message);
|
|
79
|
+
(0, _utils.clean)(key, ephemeral.secretKey);
|
|
80
|
+
return (0, _utils.concatBytes)(ephemeral.publicKey, box);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* `crypto_box_seal_open`. Returns null for anything that does not open:
|
|
85
|
+
* a wrong key, a box for another key, a damaged or truncated box.
|
|
86
|
+
*/
|
|
87
|
+
function sealedBoxOpen(sealed, publicKey, secretKey) {
|
|
88
|
+
if (sealed.length < SEALED_BOX_OVERHEAD_BYTES || publicKey.length !== SEALED_BOX_PUBLIC_KEY_BYTES || secretKey.length !== SEALED_BOX_SECRET_KEY_BYTES) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const ephemeralPublicKey = sealed.subarray(0, SEALED_BOX_PUBLIC_KEY_BYTES);
|
|
92
|
+
const box = sealed.subarray(SEALED_BOX_PUBLIC_KEY_BYTES);
|
|
93
|
+
let key = null;
|
|
94
|
+
try {
|
|
95
|
+
key = boxSharedKey(ephemeralPublicKey, secretKey);
|
|
96
|
+
const nonce = sealNonce(ephemeralPublicKey, publicKey);
|
|
97
|
+
return (0, _salsa.xsalsa20poly1305)(key, nonce).decrypt(box);
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
} finally {
|
|
101
|
+
if (key) {
|
|
102
|
+
(0, _utils.clean)(key);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=sealedBox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_salsa","require","_utils","_ed","_blake","_sha","_utils2","SEALED_BOX_PUBLIC_KEY_BYTES","exports","SEALED_BOX_SECRET_KEY_BYTES","SEALED_BOX_OVERHEAD_BYTES","NONCE_BYTES","SIGMA","u32","utf8ToBytes","ZERO_NONCE_PREFIX","Uint32Array","generateSealedBoxKeyPair","secretKey","publicKey","x25519","keygen","sealedBoxPublicKeyOf","getPublicKey","sealedBoxKeyId","bytesToHex","sha256","slice","boxSharedKey","theirPublicKey","mySecretKey","shared","getSharedSecret","words","hsalsa","clean","u8","sealNonce","ephemeralPublicKey","recipientPublicKey","blake2b","concatBytes","dkLen","sealedBoxSeal","message","length","Error","ephemeral","key","nonce","box","xsalsa20poly1305","encrypt","sealedBoxOpen","sealed","subarray","decrypt"],"sourceRoot":"../../../src","sources":["push/sealedBox.ts"],"mappings":"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","ignoreList":[]}
|