p2party 0.6.15 → 0.7.1
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/README.md +110 -40
- package/lib/api/webrtc/disconnectFromPeerChannelLabelQuery.d.ts.map +1 -1
- package/lib/db.worker.js +1 -1
- package/lib/handlers/handleReceiveMessage.d.ts +2 -1
- package/lib/index.js +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.mjs +1 -1
- package/lib/utils/channelLabel.d.ts +2 -4
- package/lib/utils/metadata.d.ts +1 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
[![code-style-prettier][code-style-prettier-image]][code-style-prettier-url]
|
|
10
10
|
<br>
|
|
11
11
|

|
|
12
|
-
|
|
13
|
-
<!-- [](https://www.jsdelivr.com/package/npm/@deliberative/crypto) -->
|
|
12
|
+
[](https://www.jsdelivr.com/package/npm/p2party)
|
|
14
13
|
|
|
15
14
|
<!-- [codecov-image]: https://codecov.io/gh/deliberative/crypto/branch/master/graph/badge.svg -->
|
|
16
15
|
<!-- [codecov-url]: https://codecov.io/gh/deliberative/crypto -->
|
|
@@ -20,7 +19,7 @@
|
|
|
20
19
|
|
|
21
20
|
> Peer-to-peer WebRTC mesh communication with offensive cryptographic encoding.
|
|
22
21
|
|
|
23
|
-
**p2party** connects peers visiting the same URL into a WebRTC mesh network and enables secure, chunked message exchange over ephemeral data channels. Unlike traditional privacy libraries, `p2party` actively obfuscates traffic using randomized padding
|
|
22
|
+
**p2party** connects peers visiting the same URL into a WebRTC mesh network and enables secure, chunked message exchange over ephemeral data channels. Unlike traditional privacy libraries, `p2party` actively obfuscates traffic using randomized padding, byte-level noise, isomorphic packet transmission (64kb), making message intent opaque. Of course it also adds a layer of ChaChaPoly1305 end-to-end encryption with ephemeral Ed25519 sender keys.
|
|
24
23
|
|
|
25
24
|
---
|
|
26
25
|
|
|
@@ -34,7 +33,7 @@ The API is not completely stable and the code has not undergone external securit
|
|
|
34
33
|
- 🔀 WebRTC mesh topology (no central servers except for signaling and STUN/TURN)
|
|
35
34
|
- 🔐 Offensive cryptography: every message can be split in multiple 64KB chunks so the attacker needs to store a lot of useless info
|
|
36
35
|
- 🧩 Supports `File` and `string` messages via chunked encoding
|
|
37
|
-
- 🧠 Built-in address book, blacklist, and room memory, all stored in the browser's IndexedDB
|
|
36
|
+
- 🧠 Built-in address book (whitelist), blacklist, and room memory, all stored in the browser's IndexedDB
|
|
38
37
|
- 🛠 Easy API and integration with React via custom hooks
|
|
39
38
|
|
|
40
39
|
---
|
|
@@ -43,25 +42,44 @@ The API is not completely stable and the code has not undergone external securit
|
|
|
43
42
|
|
|
44
43
|
This library relies heavily on [libsodium](https://github.com/jedisct1/libsodium) for cryptographic operations, which is a battle-tested project, compiled to WebAssembly for speed.
|
|
45
44
|
|
|
46
|
-
The library offers mnemonic generation, validation and Ed25519 key pair from mnemonic functionality that was inspired by [bip39](https://github.com/bitcoinjs/bip39) but instead of Blake2b we use Argon2 and instead of SHA256 we use SHA512
|
|
45
|
+
The library offers mnemonic generation, validation and Ed25519 key pair from mnemonic functionality that was inspired by [bip39](https://github.com/bitcoinjs/bip39) but instead of Blake2b we use Argon2, provided by libsodium, and instead of SHA256 we use SHA512 (native browser functionality).
|
|
47
46
|
|
|
48
|
-
On the js side, the library depends on [Redux](https://
|
|
47
|
+
On the js side, the library depends on [Redux](https://github.com/redux) for state management,
|
|
49
48
|
|
|
50
49
|
## Install
|
|
51
50
|
|
|
51
|
+
To start, you install by typing in your project
|
|
52
|
+
|
|
52
53
|
```bash
|
|
53
54
|
npm install p2party
|
|
54
55
|
```
|
|
55
56
|
|
|
57
|
+
and include as ES module
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import dcrypto from "@deliberative/crypto";
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
as CommonJS module
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
const dcrypto = require("@deliberative/crypto");
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
or as UMD in the browser
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<script src="https://cdn.jsdelivr.net/npm/p2party@latest/lib/index.min.js"></script>
|
|
73
|
+
```
|
|
74
|
+
|
|
56
75
|
## Usage
|
|
57
76
|
|
|
58
77
|
The official website [p2party.com](https://p2party.com), which is an SPA written in React, consumes the library with a hook in the following way:
|
|
59
78
|
|
|
60
|
-
```
|
|
79
|
+
```typescript
|
|
61
80
|
import p2party from "p2party";
|
|
62
81
|
|
|
63
82
|
import { useState } from "react";
|
|
64
|
-
import { useNavigate } from "react-router";
|
|
65
83
|
import { useSelector } from "react-redux";
|
|
66
84
|
|
|
67
85
|
import type { Message } from "p2party";
|
|
@@ -71,8 +89,6 @@ export interface MessageWithData extends Message {
|
|
|
71
89
|
}
|
|
72
90
|
|
|
73
91
|
export const useRoom = () => {
|
|
74
|
-
const navigate = useNavigate();
|
|
75
|
-
|
|
76
92
|
const [roomIndex, setRoomIndex] = useState(-1);
|
|
77
93
|
const keyPair = useSelector(p2party.keyPairSelector);
|
|
78
94
|
const rooms = useSelector(p2party.roomSelector);
|
|
@@ -80,11 +96,6 @@ export const useRoom = () => {
|
|
|
80
96
|
p2party.signalingServerSelector,
|
|
81
97
|
);
|
|
82
98
|
|
|
83
|
-
const goToRandomRoom = async (replace = false) => {
|
|
84
|
-
const random = await p2party.generateRandomRoomUrl();
|
|
85
|
-
navigate("/rooms/" + random, { replace });
|
|
86
|
-
};
|
|
87
|
-
|
|
88
99
|
const openChannel = async (name: string) => {
|
|
89
100
|
if (roomIndex === -1) throw new Error("No room was selected");
|
|
90
101
|
|
|
@@ -115,7 +126,6 @@ export const useRoom = () => {
|
|
|
115
126
|
peers: roomIndex > -1 ? rooms[roomIndex].peers : [],
|
|
116
127
|
channels: roomIndex > -1 ? rooms[roomIndex].channels : [],
|
|
117
128
|
messages: roomIndex > -1 ? rooms[roomIndex].messages : [],
|
|
118
|
-
goToRandomRoom,
|
|
119
129
|
connect: p2party.connect,
|
|
120
130
|
connectToSignalingServer: p2party.connectToSignalingServer,
|
|
121
131
|
disconnect: p2party.disconnectFromRoom,
|
|
@@ -136,9 +146,34 @@ export const useRoom = () => {
|
|
|
136
146
|
};
|
|
137
147
|
```
|
|
138
148
|
|
|
139
|
-
|
|
149
|
+
In the [p2party.com](https://p2party.com) SPA, where we use [React-Router](https://github.com/remix-run/react-router) for navigation, we use the following function to navigate to a new room that is randomly generated. We implement it inside the hook and export it with it.
|
|
140
150
|
|
|
141
|
-
|
|
151
|
+
```typescript
|
|
152
|
+
/**
|
|
153
|
+
* Previous imports
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
import { useNavigate } from "react-router";
|
|
157
|
+
|
|
158
|
+
export const useRoom = () => {
|
|
159
|
+
const navigate = useNavigate();
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Previous functions
|
|
163
|
+
*/
|
|
164
|
+
|
|
165
|
+
const goToRandomRoom = async (replace = false) => {
|
|
166
|
+
const random = await p2party.generateRandomRoomUrl();
|
|
167
|
+
navigate("/rooms/" + random, { replace });
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
goToRandomRoom,
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The most important exported functions by p2party, with their types, are:
|
|
142
177
|
|
|
143
178
|
```typescript
|
|
144
179
|
|
|
@@ -166,10 +201,6 @@ const connectToSignalingServer = (
|
|
|
166
201
|
signalingServerUrl = "wss://signaling.p2party.com/ws",
|
|
167
202
|
) => void;
|
|
168
203
|
|
|
169
|
-
/**
|
|
170
|
-
* If no toChannel then broadcast the message everywhere to everyone.
|
|
171
|
-
* If toChannel then broadcast to all peers with that channel.
|
|
172
|
-
*/
|
|
173
204
|
const sendMessage = (
|
|
174
205
|
data: string | File,
|
|
175
206
|
toChannel: string,
|
|
@@ -201,15 +232,20 @@ const cancelMessage = async (
|
|
|
201
232
|
|
|
202
233
|
```
|
|
203
234
|
|
|
235
|
+
For a complete reference of the API you can check the library output file [index.ts](src/index.ts).
|
|
236
|
+
|
|
204
237
|
To load all the past room data you call
|
|
205
238
|
|
|
206
239
|
```typescript
|
|
207
240
|
const rooms = await p2party.getAllExistingRooms();
|
|
208
241
|
```
|
|
209
242
|
|
|
210
|
-
To load the contents of a private message you can
|
|
243
|
+
To load the contents of a private message you can use the following React item with the react hook:
|
|
211
244
|
|
|
212
245
|
```tsx
|
|
246
|
+
// Suppose Text React element exists
|
|
247
|
+
import { Text } from "./Text";
|
|
248
|
+
|
|
213
249
|
// {{ message }} comes from const { messages } = useRoom();
|
|
214
250
|
const MessageItem: FC<MessageItemProps> = ({ message }) => {
|
|
215
251
|
const [state, setState] = useState<{
|
|
@@ -236,6 +272,11 @@ const MessageItem: FC<MessageItemProps> = ({ message }) => {
|
|
|
236
272
|
const setMessage = async () => {
|
|
237
273
|
const m = await readMessage(message.merkleRootHex, message.sha512Hex);
|
|
238
274
|
|
|
275
|
+
/**
|
|
276
|
+
* In this situation the user is the sender and before they
|
|
277
|
+
* send the message they need to split it into chunks
|
|
278
|
+
* in order to calculate the Merkle root and proof before send.
|
|
279
|
+
*/
|
|
239
280
|
if (
|
|
240
281
|
message.fromPeerId === peerId &&
|
|
241
282
|
message.totalChunks > 0 &&
|
|
@@ -262,6 +303,10 @@ const MessageItem: FC<MessageItemProps> = ({ message }) => {
|
|
|
262
303
|
),
|
|
263
304
|
}));
|
|
264
305
|
} else {
|
|
306
|
+
/**
|
|
307
|
+
* Here the user is the receiver and they can read the message since they have
|
|
308
|
+
* all the necessary chunks
|
|
309
|
+
*/
|
|
265
310
|
if (m.percentage === 100) {
|
|
266
311
|
setState((prevState) => ({
|
|
267
312
|
...prevState,
|
|
@@ -279,6 +324,9 @@ const MessageItem: FC<MessageItemProps> = ({ message }) => {
|
|
|
279
324
|
msgPercentage: m.percentage, // 100,
|
|
280
325
|
}));
|
|
281
326
|
} else {
|
|
327
|
+
/**
|
|
328
|
+
* Here the receiver does not have all the chunks necessary to read the message
|
|
329
|
+
**/
|
|
282
330
|
setState((prevState) => ({
|
|
283
331
|
...prevState,
|
|
284
332
|
msgSize: m.size,
|
|
@@ -324,27 +372,15 @@ const MessageItem: FC<MessageItemProps> = ({ message }) => {
|
|
|
324
372
|
return (
|
|
325
373
|
<div>
|
|
326
374
|
{msgCategory === p2party.MessageCategory.Text && url.length === 0 && (
|
|
327
|
-
<Text
|
|
328
|
-
className={`text-left tracking-wide break-words whitespace-pre-line ${message.fromPeerId === peerId ? "font-medium text-black dark:font-semibold dark:text-black" : "font-normal text-white dark:text-white"} text-pretty break-words text-clip hyphens-auto antialiased select-text`}
|
|
329
|
-
>
|
|
330
|
-
{msg as string}
|
|
331
|
-
</Text>
|
|
375
|
+
<Text>{msg as string}</Text>
|
|
332
376
|
)}
|
|
333
377
|
|
|
334
378
|
{msgCategory === p2party.MessageCategory.Text && url.length > 0 && (
|
|
335
|
-
<Text
|
|
336
|
-
className={`text-left font-semibold tracking-wide text-pretty break-words break-all text-clip hyphens-auto whitespace-normal text-sky-700 underline decoration-sky-400 antialiased select-text dark:font-normal dark:text-sky-400`}
|
|
337
|
-
>
|
|
338
|
-
{msg as string}
|
|
339
|
-
</Text>
|
|
379
|
+
<Text>{msg as string}</Text>
|
|
340
380
|
)}
|
|
341
381
|
|
|
342
382
|
{msgCategory !== p2party.MessageCategory.Text && (
|
|
343
|
-
<Text
|
|
344
|
-
className={`text-left tracking-wide break-words whitespace-pre-wrap ${message.fromPeerId === peerId ? "font-medium text-black dark:font-semibold dark:text-black" : "font-normal text-white dark:text-white"} antialiased`}
|
|
345
|
-
>
|
|
346
|
-
{msgFilename}
|
|
347
|
-
</Text>
|
|
383
|
+
<Text>{msgFilename}</Text>
|
|
348
384
|
)}
|
|
349
385
|
</div>
|
|
350
386
|
);
|
|
@@ -354,21 +390,47 @@ const MessageItem: FC<MessageItemProps> = ({ message }) => {
|
|
|
354
390
|
For privacy features like whitelist, blacklist and room purging we have the following APIs:
|
|
355
391
|
|
|
356
392
|
```typescript
|
|
357
|
-
|
|
393
|
+
/**
|
|
394
|
+
* This deletes the user's private key but keeps all the messages.
|
|
395
|
+
* A side effect is that the user is disconnected from all their rooms.
|
|
396
|
+
*/
|
|
358
397
|
const purgeIdentity = () => void;
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* This deletes all the data of a room and disconnects the user from it.
|
|
401
|
+
*/
|
|
359
402
|
const purgeRoom = (roomUrl: string) => void;
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* This deletes both private keys and messages and gives a clean state.
|
|
406
|
+
*/
|
|
360
407
|
const purge = async () => void;
|
|
361
408
|
|
|
409
|
+
/**
|
|
410
|
+
* This deletes a specific message (merkle root) or all instances of
|
|
411
|
+
* a specific message (hash).
|
|
412
|
+
*/
|
|
362
413
|
const deleteMessage = async (
|
|
363
414
|
merkleRoot?: string | Uint8Array,
|
|
364
415
|
hash?: string | Uint8Array,
|
|
365
416
|
) => void;
|
|
366
417
|
|
|
418
|
+
/**
|
|
419
|
+
* This does not do anything by itself unless the next function is called.
|
|
420
|
+
*/
|
|
367
421
|
const addPeerToAddressBook = async (
|
|
368
422
|
username: string,
|
|
369
423
|
peerId: string,
|
|
370
424
|
peerPublicKey: string,
|
|
371
425
|
) => void;
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Once this function is called with onlyAllow: true,
|
|
429
|
+
* the user can only connect to peers in their whitelist in a specific room.
|
|
430
|
+
* Everyone else cannot even see if the user is connected in the same URL.
|
|
431
|
+
* Can be reverted by calling the function with onlyAllow: false.
|
|
432
|
+
* Default state for new rooms is onlyAllow: false.
|
|
433
|
+
*/
|
|
372
434
|
const onlyAllowConnectionsFromAddressBook = async (
|
|
373
435
|
roomUrl: string,
|
|
374
436
|
onlyAllow: boolean,
|
|
@@ -378,13 +440,21 @@ const deletePeerFromAddressBook = async (
|
|
|
378
440
|
peerId?: string,
|
|
379
441
|
peerPublicKey?: string,
|
|
380
442
|
) => void;
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Once the user is here they cannot connect with us
|
|
446
|
+
* and they cannot even see if we are connected in the room at the same time as them.
|
|
447
|
+
* They can theoretically receive the same messages as us from our common peers who have
|
|
448
|
+
* not blacklisted them.
|
|
449
|
+
*/
|
|
381
450
|
const blacklistPeer = async (peerId: string, peerPublicKey: string) => void;
|
|
451
|
+
const removePeerFromBlacklist = async (peerId?: string, peerPublicKey?: string) => void;
|
|
382
452
|
|
|
383
453
|
```
|
|
384
454
|
|
|
385
455
|
## Development
|
|
386
456
|
|
|
387
|
-
If you want to
|
|
457
|
+
If you want to build the library yourselves, you need to have [Emscripten](https://github.com/emscripten-core/emscripten)
|
|
388
458
|
installed on your machine in order to compile the C code into WebAssembly.
|
|
389
459
|
We have the `-s SINGLE_FILE=1` option for the `emcc` compiler, which converts the `wasm` file to a `base64` string
|
|
390
460
|
that will be compiled by the glue js code into a WebAssembly module. This was done for the purpose of interoperability
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disconnectFromPeerChannelLabelQuery.d.ts","sourceRoot":"","sources":["../../../src/api/webrtc/disconnectFromPeerChannelLabelQuery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"disconnectFromPeerChannelLabelQuery.d.ts","sourceRoot":"","sources":["../../../src/api/webrtc/disconnectFromPeerChannelLabelQuery.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,uCAAuC,EACxC,MAAM,cAAc,CAAC;AAGtB,MAAM,WAAW,gDACf,SAAQ,uCAAuC;IAC/C,eAAe,EAAE,kBAAkB,EAAE,CAAC;IACtC,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC;AAED,QAAA,MAAM,yCAAyC,EAAE,WAAW,CAC1D,gDAAgD,EAChD,IAAI,EACJ,OAAO,CA+IR,CAAC;AAEF,eAAe,yCAAyC,CAAC"}
|
package/lib/db.worker.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=(e,t)=>t.some(t=>e instanceof t);let t,a;const n=new WeakMap,o=new WeakMap,r=new WeakMap;let s={get(e,t,a){if(e instanceof IDBTransaction){if("done"===t)return n.get(e);if("store"===t)return a.objectStoreNames[1]?void 0:a.objectStore(a.objectStoreNames[0])}return d(e[t])},set:(e,t,a)=>(e[t]=a,!0),has:(e,t)=>e instanceof IDBTransaction&&("done"===t||"store"===t)||t in e};function i(e){s=e(s)}function c(e){return(a||(a=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(e)?function(...t){return e.apply(l(this),t),d(this.request)}:function(...t){return d(e.apply(l(this),t))}}function u(a){return"function"==typeof a?c(a):(a instanceof IDBTransaction&&function(e){if(n.has(e))return;const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("complete",o),e.removeEventListener("error",r),e.removeEventListener("abort",r)},o=()=>{t(),n()},r=()=>{a(e.error||new DOMException("AbortError","AbortError")),n()};e.addEventListener("complete",o),e.addEventListener("error",r),e.addEventListener("abort",r)});n.set(e,t)}(a),e(a,t||(t=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]))?new Proxy(a,s):a)}function d(e){if(e instanceof IDBRequest)return function(e){const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("success",o),e.removeEventListener("error",r)},o=()=>{t(d(e.result)),n()},r=()=>{a(e.error),n()};e.addEventListener("success",o),e.addEventListener("error",r)});return r.set(t,e),t}(e);if(o.has(e))return o.get(e);const t=u(e);return t!==e&&(o.set(e,t),r.set(t,e)),t}const l=e=>r.get(e);const w=["get","getKey","getAll","getAllKeys","count"],h=["put","add","delete","clear"],g=new Map;function m(e,t){if(!(e instanceof IDBDatabase)||t in e||"string"!=typeof t)return;if(g.get(t))return g.get(t);const a=t.replace(/FromIndex$/,""),n=t!==a,o=h.includes(a);if(!(a in(n?IDBIndex:IDBObjectStore).prototype)||!o&&!w.includes(a))return;const r=async function(e,...t){const r=this.transaction(e,o?"readwrite":"readonly");let s=r.store;return n&&(s=s.index(t.shift())),(await Promise.all([s[a](...t),o&&r.done]))[0]};return g.set(t,r),r}i(e=>({...e,get:(t,a,n)=>m(t,a)||e.get(t,a,n),has:(t,a)=>!!m(t,a)||e.has(t,a)}));const k=["continue","continuePrimaryKey","advance"],y={},b=new WeakMap,f=new WeakMap,I={get(e,t){if(!k.includes(t))return e[t];let a=y[t];return a||(a=y[t]=function(...e){b.set(this,f.get(this)[t](...e))}),a}};async function*x(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;const a=new Proxy(t,I);for(f.set(a,t),r.set(a,l(t));t;)yield a,t=await(b.get(a)||t.continue()),b.delete(a)}function p(t,a){return a===Symbol.asyncIterator&&e(t,[IDBIndex,IDBObjectStore,IDBCursor])||"iterate"===a&&e(t,[IDBIndex,IDBObjectStore])}i(e=>({...e,get:(t,a,n)=>p(t,a)?x:e.get(t,a,n),has:(t,a)=>p(t,a)||e.has(t,a)}));const D=64*Uint8Array.BYTES_PER_ELEMENT,B="p2party";async function S(){return function(e,t,{blocked:a,upgrade:n,blocking:o,terminated:r}={}){const s=indexedDB.open(e,t),i=d(s);return n&&s.addEventListener("upgradeneeded",e=>{n(d(s.result),e.oldVersion,e.newVersion,d(s.transaction),e)}),a&&s.addEventListener("blocked",e=>a(e.oldVersion,e.newVersion,e)),i.then(e=>{r&&e.addEventListener("close",()=>r()),o&&e.addEventListener("versionchange",e=>o(e.oldVersion,e.newVersion,e))}).catch(()=>{}),i}(B,16,{upgrade(e,t,a,n){if(e.objectStoreNames.contains("addressBook")){const e=n.objectStore("addressBook");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("addressBook",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("blacklist")){const e=n.objectStore("blacklist");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("blacklist",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("uniqueRoom")){const e=n.objectStore("uniqueRoom");e.indexNames.contains("roomUrl")||e.createIndex("roomUrl","roomUrl",{unique:!0}),e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!0})}else{const t=e.createObjectStore("uniqueRoom",{keyPath:["roomId"]});t.createIndex("roomUrl","roomUrl",{unique:!0}),t.createIndex("roomId","roomId",{unique:!0})}if(e.objectStoreNames.contains("messageData")){const e=n.objectStore("messageData");e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!0}),e.indexNames.contains("fromPeerId")||e.createIndex("fromPeerId","fromPeerId",{unique:!1})}else{const t=e.createObjectStore("messageData",{keyPath:["timestamp","roomId","merkleRoot"]});t.createIndex("roomId","roomId",{unique:!1}),t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!0}),t.createIndex("fromPeerId","fromPeerId",{unique:!1})}if(e.objectStoreNames.contains("chunks")){const e=n.objectStore("chunks");e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1})}else{const t=e.createObjectStore("chunks",{keyPath:["merkleRoot","chunkIndex"]});t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("hash","hash",{unique:!1})}if(e.objectStoreNames.contains("newChunks")){const e=n.objectStore("newChunks");e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("realChunkHash")||e.createIndex("realChunkHash","realChunkHash",{unique:!0})}else{const t=e.createObjectStore("newChunks",{keyPath:["hash","chunkIndex"]});t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("realChunkHash","realChunkHash",{unique:!0})}if(e.objectStoreNames.contains("sendQueue")){const e=n.objectStore("sendQueue");e.indexNames.contains("labelPeer")||e.createIndex("labelPeer",["label","toPeerId"],{unique:!1})}else{e.createObjectStore("sendQueue",{keyPath:["position","label","toPeerId"]}).createIndex("labelPeer",["label","toPeerId"],{unique:!1})}}})}async function R(){await function(e,{blocked:t}={}){const a=indexedDB.deleteDatabase(e);return t&&a.addEventListener("blocked",e=>t(e.oldVersion,e)),d(a).then(()=>{})}(B,{blocked(){console.error("DB deletion BLOCKED")}})}onmessage=async e=>{const t=e.data,{id:a,method:n}=t;try{let e;switch(n){case"getDBAddressBookEntry":e=await async function(e,t){if(!e&&!t)return;if(e&&e.length<10&&!t)return;if(t&&64!==t.length&&!e)return;const a=await S();try{const n=a.transaction("addressBook","readonly"),o=e?n.objectStore("addressBook").index("peerId"):n.objectStore("addressBook").index("peerPublicKey"),r=e?await o.get(e):await o.get(t);return await n.done,a.close(),r?{username:r.username,peerId:r.peerId,peerPublicKey:r.peerPublicKey}:void 0}catch(e){return void a.close()}}(...t.args);break;case"getAllDBAddressBookEntries":e=await async function(){try{const e=await S(),t=await e.getAll("addressBook");return e.close(),t}catch(e){return[]}}(...t.args);break;case"setDBAddressBookEntry":e=await async function(e,t,a){try{const n=await S(),o=n.transaction(["addressBook"],"readwrite"),r=o.objectStore("addressBook"),s=r.index("peerId"),i=r.index("peerPublicKey"),c=await s.get(t),u=await i.get(a);(!c&&!u||c&&!u||!c&&u)&&await r.put({username:e,peerId:t,peerPublicKey:a,dateAdded:Date.now()}),await o.done,n.close()}catch(e){console.error(e)}}(...t.args);break;case"deleteDBAddressBookEntry":e=await async function(e,t,a){const n=!e||0===e.length,o=!t||t.length<10,r=!a||64!==a.length;if(n&&o&&r)throw new Error("Cannot delete address book with no data");let s=t??"";try{const n=await S(),i=n.transaction("addressBook","readwrite"),c=i.objectStore("addressBook");if(o)if(r){const t=c.index("username"),a=await t.getKey(e);if(a){const n=await t.get(e);s=n?.peerId??"",await c.delete(a)}}else{const e=c.index("peerPublicKey"),t=await e.getKey(a);if(t){const n=await e.get(a);s=n?.peerId??"",await c.delete(t)}}else{const e=c.index("peerId"),a=await e.getKey(t);a&&await c.delete(a)}await i.done,n.close()}catch{}return s}(...t.args);break;case"getDBPeerIsBlacklisted":e=await async function(e,t){if(!e&&!t)return!1;if(e&&e.length<10&&!t)return!1;if(t&&64!==t.length&&!e)return!1;try{const a=await S(),n=a.transaction("blacklist","readonly"),o=e?n.objectStore("blacklist").index("peerId"):n.objectStore("blacklist").index("peerPublicKey"),r=e?await o.get(e):await o.get(t);return await n.done,a.close(),!!r}catch(e){return!1}}(...t.args);break;case"getAllDBBlacklisted":e=await async function(){const e=await S();try{const t=await e.getAll("blacklist");return e.close(),t}catch(t){return e.close(),[]}}(...t.args);break;case"setDBPeerInBlacklist":e=await async function(e,t){try{const a=await S(),n=a.transaction(["blacklist"],"readwrite"),o=n.objectStore("blacklist"),r=o.index("peerId"),s=o.index("peerPublicKey"),i=await r.get(e),c=await s.get(t);(!i&&!c||i&&!c||!i&&c)&&await o.put({peerId:e,peerPublicKey:t,dateAdded:Date.now()}),await n.done,a.close()}catch(e){console.error(e)}}(...t.args);break;case"deleteDBPeerFromBlacklist":e=await async function(e,t){const a=!e||e.length<10,n=!t||64!==t.length;if(a&&n)throw new Error("Cannot delete blacklisted with no data");try{const n=await S(),o=n.transaction("blacklist","readwrite"),r=o.objectStore("blacklist");if(a){const e=r.index("peerPublicKey"),a=await e.getKey(t);a&&await r.delete(a)}else{const t=r.index("peerId"),a=await t.getKey(e);a&&await r.delete(a)}await o.done,n.close()}catch(e){console.error(e)}}(...t.args);break;case"getAllDBUniqueRooms":e=await async function(){const e=await S();try{const t=await e.getAll("uniqueRoom");return e.close(),t}catch(t){return e.close(),[]}}(...t.args);break;case"setDBUniqueRoom":e=await async function(e,t){try{const a=await S(),n=a.transaction(["uniqueRoom"],"readwrite"),o=n.objectStore("uniqueRoom"),r=o.index("roomUrl"),s=o.index("roomId"),i=await r.get(e),c=await s.get(t);if(!i&&!c){const a=Date.now();await o.put({roomId:t,roomUrl:e,messageCount:0,lastMessageMerkleRoot:"",createdAt:a,updatedAt:a})}await n.done,a.close()}catch(e){console.error(e)}}(...t.args);break;case"getDBMessageData":e=await async function(e,t){try{const a=await S(),n=a.transaction(["messageData"],"readonly"),o=n.objectStore("messageData"),r=o.index("merkleRoot"),s=o.index("hash");if(e&&e.length===2*D){const o=await r.get(e);if(o)return await n.done,a.close(),o;if(t&&t.length===2*D){const e=await s.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}if(t&&t.length===2*D){const e=await s.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}catch(e){return void console.error(e)}}(...t.args);break;case"getDBRoomMessageData":e=await async function(e){const t=await S(),a=await t.getAllFromIndex("messageData","roomId",e);t.close();const n=a.length,o=[];for(let t=0;t<n;t++)o.push({roomId:e,merkleRoot:a[t].merkleRoot,hash:a[t].hash,fromPeerId:a[t].fromPeerId,filename:a[t].filename,messageType:a[t].messageType,savedSize:a[t].savedSize,totalSize:a[t].totalSize,channelLabel:a[t].channelLabel,timestamp:a[t].timestamp});return o}(...t.args);break;case"setDBRoomMessageData":e=await async function(e,t,a,n,o,r,s,i,c,u){try{const d=await S(),l=d.transaction(["messageData","uniqueRoom"],"readwrite"),w=l.objectStore("messageData"),h=l.objectStore("uniqueRoom"),g=await w.index("merkleRoot").get(t),m=g?.savedSize??0;try{await w.put({roomId:e,timestamp:u,merkleRoot:t,hash:a,fromPeerId:n,filename:i,messageType:s,savedSize:m!==r?o+m:o,totalSize:r,channelLabel:c})}catch(e){throw e}if(!g){const a=await h.index("roomId").get(e);if(a&&a.lastMessageMerkleRoot!==t)try{await h.put({...a,lastMessageMerkleRoot:t,messageCount:a.messageCount+1,updatedAt:Date.now()})}catch(e){throw e}}await l.done,d.close()}catch(e){throw console.error(e),e}}(...t.args);break;case"getDBChunk":e=await async function(e,t){const a=await S(),n=await a.get("chunks",[e,t]);return a.close(),n?.data}(...t.args);break;case"existsDBChunk":e=await async function(e,t){const a=await S(),n=await a.count("chunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBNewChunk":e=await async function(e,t){try{const a=await S(),n=t??-1;if(n>-1){const t=await a.get("newChunks",[e,n]);return a.close(),t}{const t=a.transaction("newChunks"),n=t.objectStore("newChunks").index("realChunkHash"),o=await n.get(e);return await t.done,a.close(),o}}catch(e){return void console.error(e)}}(...t.args);break;case"existsDBNewChunk":e=await async function(e,t){const a=await S(),n=await a.count("newChunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBSendQueue":e=await async function(e,t,a){const n=await S();if(a){const o=await n.get("sendQueue",[a,e,t]);return n.close(),o?[o]:[]}const o=n.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),r=IDBKeyRange.only([e,t]),s=await o.getAll(r);return n.close(),s}(...t.args);break;case"getDBAllChunks":e=await async function(e,t){try{const a=await S(),n=a.transaction("chunks","readonly"),o=n.objectStore("chunks"),r=o.index("hash"),s=o.index("merkleRoot");if(e&&e.length===2*D){const o=await s.getAll(e);if(0===o.length){if(t&&t.length===2*D){const e=await r.getAll(t);return await n.done,a.close(),e}return await n.done,a.close(),[]}return await n.done,a.close(),o}if(t&&t.length===2*D){const e=await r.getAll(t);return await n.done,a.close(),e}return await n.done,a.close(),[]}catch(e){return console.error(e),[]}}(...t.args);break;case"getDBAllChunksCount":e=await async function(e,t){try{const a=await S(),n=a.transaction(["chunks"],"readonly"),o=n.objectStore("chunks"),r=o.index("hash"),s=o.index("merkleRoot");if(t&&t.length===2*D){const o=await r.count(t);if(0===o){if(e&&e.length===2*D){const t=await s.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}return await n.done,a.close(),o}if(e&&e.length===2*D){const t=await s.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}catch(e){return 0}}(...t.args);break;case"setDBChunk":e=await async function(e){const t=await S();await t.add("chunks",e),t.close()}(...t.args);break;case"getDBAllNewChunks":e=await async function(e,t){if(!e&&!t)return[];if(e?.length!==2*D&&t?.length!==2*D)return[];const a=await S();if((e?await a.countFromIndex("newChunks","hash",e):await a.countFromIndex("newChunks","merkleRoot",t))>0){const n=e?await a.getAllFromIndex("newChunks","hash",e):await a.getAllFromIndex("newChunks","merkleRoot",t);return a.close(),n}{const n=a.transaction("newChunks","readonly").objectStore("newChunks"),o=e?n.index("hash"):n.index("merkleRoot"),r=e?IDBKeyRange.only(e):IDBKeyRange.only(t),s=await o.getAll(r);return a.close(),s}}(...t.args);break;case"getDBAllNewChunksCount":e=await async function(e){const t=await S(),a=await t.countFromIndex("newChunks","hash",e);return t.close(),a}(...t.args);break;case"setDBNewChunk":e=await async function(e){const t=await S();await t.put("newChunks",e),t.close()}(...t.args);break;case"setDBSendQueue":e=await async function(e){const t=await S();await t.put("sendQueue",e),t.close()}(...t.args);break;case"countDBSendQueue":e=await async function(e,t){const a=await S(),n=a.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),o=IDBKeyRange.only([e,t]),r=await n.count(o);return a.close(),r}(...t.args);break;case"deleteDBChunk":e=await async function(e,t){try{const a=await S(),n=a.transaction("chunks","readwrite"),o=n.objectStore("chunks");if(t){const a=IDBKeyRange.only([e,t]);await o.delete(a)}else{const t=o.index("hash"),a=await t.getAllKeys(e),n=a.length;if(0===n){const t=o.index("merkleRoot"),a=await t.getAllKeys(e),n=a.length;for(let e=0;e<n;e++)await o.delete(a[e])}else for(let e=0;e<n;e++)await o.delete(a[e])}await n.done,a.close()}catch(e){}}(...t.args);break;case"deleteDBNewChunk":e=await async function(e,t,a,n){try{const o=await S(),r=o.transaction("newChunks","readwrite"),s=r.objectStore("newChunks");if(e){const t=s.index("merkleRoot"),a=await t.getAllKeys(e),n=a.length;for(let e=0;e<n;e++)await s.delete(a[e])}else if(a&&n)await s.delete([a,n]);else if(a){const e=s.index("hash"),t=await e.getAllKeys(a),n=t.length;for(let e=0;e<n;e++)await s.delete(t[e])}else if(t){const e=s.index("realChunkHash"),a=await e.getKey(t);a&&await s.delete(a)}await r.done,o.close()}catch(e){console.error(e)}}(...t.args);break;case"deleteDBMessageData":e=await async function(e){try{const t=await S(),a=t.transaction(["messageData","uniqueRoom"],"readwrite"),n=a.objectStore("messageData"),o=a.objectStore("uniqueRoom"),r=n.index("merkleRoot"),s=await r.getAllKeys(e),i=s.length;let c="";for(let e=0;e<i;e++){if(0===e||0===c.length){const t=await n.get(s[e]);c=t?.roomId??""}await n.delete(s[e])}if(c.length>0){const e=o.index("roomId"),t=await e.get(c);if(t){const e=n.index("roomId"),a=await e.getAllKeys(c),r=a.length,s=r>0?await n.get(a[r-1]):void 0;await o.put({...t,messageCount:t.messageCount>0?t.messageCount-1:0,updatedAt:s?.timestamp??Date.now(),lastMessageMerkleRoot:s?.merkleRoot??""})}}await a.done,t.close()}catch(e){}}(...t.args);break;case"deleteDBUniqueRoom":e=await async function(e){try{const t=await S(),a=t.transaction("uniqueRoom","readwrite"),n=a.objectStore("uniqueRoom"),o=n.index("roomId"),r=await o.getKey(e);r&&await n.delete(r),await a.done,t.close()}catch(e){}}(...t.args);break;case"deleteDBSendQueue":e=await async function(e,t,a){try{const n=await S();if(a)await n.delete("sendQueue",[a,e,t]);else{const a=IDBKeyRange.only([e,t]);await n.delete("sendQueue",a)}n.close()}catch(e){}}(...t.args);break;case"deleteDB":e=await R();break;default:return void postMessage({id:a,error:"Method not found"})}postMessage({id:a,result:e})}catch(e){postMessage({id:a,error:String(e)})}};
|
|
1
|
+
const e=(e,t)=>t.some(t=>e instanceof t);let t,a;const n=new WeakMap,o=new WeakMap,r=new WeakMap;let s={get(e,t,a){if(e instanceof IDBTransaction){if("done"===t)return n.get(e);if("store"===t)return a.objectStoreNames[1]?void 0:a.objectStore(a.objectStoreNames[0])}return d(e[t])},set:(e,t,a)=>(e[t]=a,!0),has:(e,t)=>e instanceof IDBTransaction&&("done"===t||"store"===t)||t in e};function i(e){s=e(s)}function c(e){return(a||(a=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(e)?function(...t){return e.apply(l(this),t),d(this.request)}:function(...t){return d(e.apply(l(this),t))}}function u(a){return"function"==typeof a?c(a):(a instanceof IDBTransaction&&function(e){if(n.has(e))return;const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("complete",o),e.removeEventListener("error",r),e.removeEventListener("abort",r)},o=()=>{t(),n()},r=()=>{a(e.error||new DOMException("AbortError","AbortError")),n()};e.addEventListener("complete",o),e.addEventListener("error",r),e.addEventListener("abort",r)});n.set(e,t)}(a),e(a,t||(t=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]))?new Proxy(a,s):a)}function d(e){if(e instanceof IDBRequest)return function(e){const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("success",o),e.removeEventListener("error",r)},o=()=>{t(d(e.result)),n()},r=()=>{a(e.error),n()};e.addEventListener("success",o),e.addEventListener("error",r)});return r.set(t,e),t}(e);if(o.has(e))return o.get(e);const t=u(e);return t!==e&&(o.set(e,t),r.set(t,e)),t}const l=e=>r.get(e);const w=["get","getKey","getAll","getAllKeys","count"],h=["put","add","delete","clear"],m=new Map;function g(e,t){if(!(e instanceof IDBDatabase)||t in e||"string"!=typeof t)return;if(m.get(t))return m.get(t);const a=t.replace(/FromIndex$/,""),n=t!==a,o=h.includes(a);if(!(a in(n?IDBIndex:IDBObjectStore).prototype)||!o&&!w.includes(a))return;const r=async function(e,...t){const r=this.transaction(e,o?"readwrite":"readonly");let s=r.store;return n&&(s=s.index(t.shift())),(await Promise.all([s[a](...t),o&&r.done]))[0]};return m.set(t,r),r}i(e=>({...e,get:(t,a,n)=>g(t,a)||e.get(t,a,n),has:(t,a)=>!!g(t,a)||e.has(t,a)}));const k=["continue","continuePrimaryKey","advance"],y={},b=new WeakMap,f=new WeakMap,I={get(e,t){if(!k.includes(t))return e[t];let a=y[t];return a||(a=y[t]=function(...e){b.set(this,f.get(this)[t](...e))}),a}};async function*x(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;const a=new Proxy(t,I);for(f.set(a,t),r.set(a,l(t));t;)yield a,t=await(b.get(a)||t.continue()),b.delete(a)}function p(t,a){return a===Symbol.asyncIterator&&e(t,[IDBIndex,IDBObjectStore,IDBCursor])||"iterate"===a&&e(t,[IDBIndex,IDBObjectStore])}i(e=>({...e,get:(t,a,n)=>p(t,a)?x:e.get(t,a,n),has:(t,a)=>p(t,a)||e.has(t,a)}));const D=64*Uint8Array.BYTES_PER_ELEMENT,B="p2party";async function S(){return function(e,t,{blocked:a,upgrade:n,blocking:o,terminated:r}={}){const s=indexedDB.open(e,t),i=d(s);return n&&s.addEventListener("upgradeneeded",e=>{n(d(s.result),e.oldVersion,e.newVersion,d(s.transaction),e)}),a&&s.addEventListener("blocked",e=>a(e.oldVersion,e.newVersion,e)),i.then(e=>{r&&e.addEventListener("close",()=>r()),o&&e.addEventListener("versionchange",e=>o(e.oldVersion,e.newVersion,e))}).catch(()=>{}),i}(B,16,{upgrade(e,t,a,n){if(e.objectStoreNames.contains("addressBook")){const e=n.objectStore("addressBook");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("addressBook",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("blacklist")){const e=n.objectStore("blacklist");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("blacklist",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("uniqueRoom")){const e=n.objectStore("uniqueRoom");e.indexNames.contains("roomUrl")||e.createIndex("roomUrl","roomUrl",{unique:!0}),e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!0})}else{const t=e.createObjectStore("uniqueRoom",{keyPath:["roomId"]});t.createIndex("roomUrl","roomUrl",{unique:!0}),t.createIndex("roomId","roomId",{unique:!0})}if(e.objectStoreNames.contains("messageData")){const e=n.objectStore("messageData");e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!0}),e.indexNames.contains("fromPeerId")||e.createIndex("fromPeerId","fromPeerId",{unique:!1})}else{const t=e.createObjectStore("messageData",{keyPath:["timestamp","roomId","merkleRoot"]});t.createIndex("roomId","roomId",{unique:!1}),t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!0}),t.createIndex("fromPeerId","fromPeerId",{unique:!1})}if(e.objectStoreNames.contains("chunks")){const e=n.objectStore("chunks");e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1})}else{const t=e.createObjectStore("chunks",{keyPath:["merkleRoot","chunkIndex"]});t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("hash","hash",{unique:!1})}if(e.objectStoreNames.contains("newChunks")){const e=n.objectStore("newChunks");e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("realChunkHash")||e.createIndex("realChunkHash","realChunkHash",{unique:!0})}else{const t=e.createObjectStore("newChunks",{keyPath:["hash","chunkIndex"]});t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("realChunkHash","realChunkHash",{unique:!0})}if(e.objectStoreNames.contains("sendQueue")){const e=n.objectStore("sendQueue");e.indexNames.contains("labelPeer")||e.createIndex("labelPeer",["label","toPeerId"],{unique:!1})}else{e.createObjectStore("sendQueue",{keyPath:["position","label","toPeerId"]}).createIndex("labelPeer",["label","toPeerId"],{unique:!1})}}})}async function R(){await function(e,{blocked:t}={}){const a=indexedDB.deleteDatabase(e);return t&&a.addEventListener("blocked",e=>t(e.oldVersion,e)),d(a).then(()=>{})}(B,{blocked(){console.error("DB deletion BLOCKED")}})}onmessage=async e=>{const t=e.data,{id:a,method:n}=t;try{let e;switch(n){case"getDBAddressBookEntry":e=await async function(e,t){if(!e&&!t)return;if(e&&e.length<10&&!t)return;if(t&&64!==t.length&&!e)return;const a=await S();try{const n=a.transaction("addressBook","readonly"),o=e?n.objectStore("addressBook").index("peerId"):n.objectStore("addressBook").index("peerPublicKey"),r=e?await o.get(e):await o.get(t);return await n.done,a.close(),r?{username:r.username,peerId:r.peerId,peerPublicKey:r.peerPublicKey}:void 0}catch(e){return void a.close()}}(...t.args);break;case"getAllDBAddressBookEntries":e=await async function(){try{const e=await S(),t=await e.getAll("addressBook");return e.close(),t}catch(e){return[]}}(...t.args);break;case"setDBAddressBookEntry":e=await async function(e,t,a){try{const n=await S(),o=n.transaction(["addressBook"],"readwrite"),r=o.objectStore("addressBook"),s=r.index("peerId"),i=r.index("peerPublicKey"),c=await s.get(t),u=await i.get(a);(!c&&!u||c&&!u||!c&&u)&&await r.put({username:e,peerId:t,peerPublicKey:a,dateAdded:Date.now()}),await o.done,n.close()}catch(e){console.error(e)}}(...t.args);break;case"deleteDBAddressBookEntry":e=await async function(e,t,a){const n=!e||0===e.length,o=!t||t.length<10,r=!a||64!==a.length;if(n&&o&&r)throw new Error("Cannot delete address book with no data");let s=t??"";try{const n=await S(),i=n.transaction("addressBook","readwrite"),c=i.objectStore("addressBook");if(o)if(r){const t=c.index("username"),a=await t.getKey(e);if(a){const n=await t.get(e);s=n?.peerId??"",await c.delete(a)}}else{const e=c.index("peerPublicKey"),t=await e.getKey(a);if(t){const n=await e.get(a);s=n?.peerId??"",await c.delete(t)}}else{const e=c.index("peerId"),a=await e.getKey(t);a&&await c.delete(a)}await i.done,n.close()}catch{}return s}(...t.args);break;case"getDBPeerIsBlacklisted":e=await async function(e,t){if(!e&&!t)return!1;if(e&&e.length<10&&!t)return!1;if(t&&64!==t.length&&!e)return!1;try{const a=await S(),n=a.transaction("blacklist","readonly"),o=e?n.objectStore("blacklist").index("peerId"):n.objectStore("blacklist").index("peerPublicKey"),r=e?await o.get(e):await o.get(t);return await n.done,a.close(),!!r}catch(e){return!1}}(...t.args);break;case"getAllDBBlacklisted":e=await async function(){const e=await S();try{const t=await e.getAll("blacklist");return e.close(),t}catch(t){return e.close(),[]}}(...t.args);break;case"setDBPeerInBlacklist":e=await async function(e,t){try{const a=await S(),n=a.transaction(["blacklist"],"readwrite"),o=n.objectStore("blacklist"),r=o.index("peerId"),s=o.index("peerPublicKey"),i=await r.get(e),c=await s.get(t);(!i&&!c||i&&!c||!i&&c)&&await o.put({peerId:e,peerPublicKey:t,dateAdded:Date.now()}),await n.done,a.close()}catch(e){console.error(e)}}(...t.args);break;case"deleteDBPeerFromBlacklist":e=await async function(e,t){const a=!e||e.length<10,n=!t||64!==t.length;if(a&&n)throw new Error("Cannot delete blacklisted with no data");try{const n=await S(),o=n.transaction("blacklist","readwrite"),r=o.objectStore("blacklist");if(a){const e=r.index("peerPublicKey"),a=await e.getKey(t);a&&await r.delete(a)}else{const t=r.index("peerId"),a=await t.getKey(e);a&&await r.delete(a)}await o.done,n.close()}catch(e){console.error(e)}}(...t.args);break;case"getAllDBUniqueRooms":e=await async function(){const e=await S();try{const t=await e.getAll("uniqueRoom");return e.close(),t}catch(t){return e.close(),[]}}(...t.args);break;case"setDBUniqueRoom":e=await async function(e,t){try{const a=await S(),n=a.transaction(["uniqueRoom"],"readwrite"),o=n.objectStore("uniqueRoom"),r=o.index("roomUrl"),s=o.index("roomId"),i=await r.get(e),c=await s.get(t);if(!i&&!c){const a=Date.now();await o.put({roomId:t,roomUrl:e,messageCount:0,lastMessageMerkleRoot:"",createdAt:a,updatedAt:a})}await n.done,a.close()}catch(e){console.error(e)}}(...t.args);break;case"getDBMessageData":e=await async function(e,t){try{const a=await S(),n=a.transaction(["messageData"],"readonly"),o=n.objectStore("messageData"),r=o.index("merkleRoot"),s=o.index("hash");if(e&&e.length===2*D){const o=await r.get(e);if(o)return await n.done,a.close(),o;if(t&&t.length===2*D){const e=await s.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}if(t&&t.length===2*D){const e=await s.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}catch(e){return void console.error(e)}}(...t.args);break;case"getDBRoomMessageData":e=await async function(e){const t=await S(),a=await t.getAllFromIndex("messageData","roomId",e);t.close();const n=a.length,o=[];for(let t=0;t<n;t++)o.push({roomId:e,merkleRoot:a[t].merkleRoot,hash:a[t].hash,fromPeerId:a[t].fromPeerId,filename:a[t].filename,messageType:a[t].messageType,savedSize:a[t].savedSize,totalSize:a[t].totalSize,channelLabel:a[t].channelLabel,timestamp:a[t].timestamp});return o}(...t.args);break;case"setDBRoomMessageData":e=await async function(e,t,a,n,o,r,s,i,c,u){try{const d=await S(),l=d.transaction(["messageData","uniqueRoom"],"readwrite"),w=l.objectStore("messageData"),h=await w.index("merkleRoot").get(t),m=h?.savedSize??0;try{await w.put({roomId:e,timestamp:u,merkleRoot:t,hash:a,fromPeerId:n,filename:i,messageType:s,savedSize:m!==r?o+m:o,totalSize:r,channelLabel:c})}catch(e){throw await l.done,d.close(),e}const g=l.objectStore("uniqueRoom"),k=await g.index("roomId").get(e);if(k&&k.lastMessageMerkleRoot!==t)try{await g.put({...k,lastMessageMerkleRoot:t,messageCount:k.messageCount+1,updatedAt:Date.now()})}catch(e){throw await l.done,d.close(),e}await l.done,d.close()}catch(e){throw console.error(e),e}}(...t.args);break;case"getDBChunk":e=await async function(e,t){const a=await S(),n=await a.get("chunks",[e,t]);return a.close(),n?.data}(...t.args);break;case"existsDBChunk":e=await async function(e,t){const a=await S(),n=await a.count("chunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBNewChunk":e=await async function(e,t){try{const a=await S(),n=t??-1;if(n>-1){const t=await a.get("newChunks",[e,n]);return a.close(),t}{const t=a.transaction("newChunks"),n=t.objectStore("newChunks").index("realChunkHash"),o=await n.get(e);return await t.done,a.close(),o}}catch(e){return void console.error(e)}}(...t.args);break;case"existsDBNewChunk":e=await async function(e,t){const a=await S(),n=await a.count("newChunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBSendQueue":e=await async function(e,t,a){const n=await S();if(a){const o=await n.get("sendQueue",[a,e,t]);return n.close(),o?[o]:[]}const o=n.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),r=IDBKeyRange.only([e,t]),s=await o.getAll(r);return n.close(),s}(...t.args);break;case"getDBAllChunks":e=await async function(e,t){try{const a=await S(),n=a.transaction("chunks","readonly"),o=n.objectStore("chunks"),r=o.index("hash"),s=o.index("merkleRoot");if(e&&e.length===2*D){const t=await s.getAll(e);return 0===t.length?(await n.done,a.close(),[]):(await n.done,a.close(),t)}if(t&&t.length===2*D){const e=await r.getAll(t);return await n.done,a.close(),e}return await n.done,a.close(),[]}catch(e){return console.error(e),[]}}(...t.args);break;case"getDBAllChunksCount":e=await async function(e,t){try{const a=await S(),n=a.transaction(["chunks"],"readonly"),o=n.objectStore("chunks"),r=o.index("hash"),s=o.index("merkleRoot");if(t&&t.length===2*D){const o=await r.count(t);if(0===o){if(e&&e.length===2*D){const t=await s.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}return await n.done,a.close(),o}if(e&&e.length===2*D){const t=await s.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}catch(e){return 0}}(...t.args);break;case"setDBChunk":e=await async function(e){const t=await S();await t.add("chunks",e),t.close()}(...t.args);break;case"getDBAllNewChunks":e=await async function(e,t){if(!e&&!t)return[];if(e?.length!==2*D&&t?.length!==2*D)return[];const a=await S();if((e?await a.countFromIndex("newChunks","hash",e):await a.countFromIndex("newChunks","merkleRoot",t))>0){const n=e?await a.getAllFromIndex("newChunks","hash",e):await a.getAllFromIndex("newChunks","merkleRoot",t);return a.close(),n}{const n=a.transaction("newChunks","readonly").objectStore("newChunks"),o=e?n.index("hash"):n.index("merkleRoot"),r=e?IDBKeyRange.only(e):IDBKeyRange.only(t),s=await o.getAll(r);return a.close(),s}}(...t.args);break;case"getDBAllNewChunksCount":e=await async function(e){const t=await S(),a=await t.countFromIndex("newChunks","hash",e);return t.close(),a}(...t.args);break;case"setDBNewChunk":e=await async function(e){const t=await S();await t.put("newChunks",e),t.close()}(...t.args);break;case"setDBSendQueue":e=await async function(e){const t=await S();await t.put("sendQueue",e),t.close()}(...t.args);break;case"countDBSendQueue":e=await async function(e,t){const a=await S(),n=a.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),o=IDBKeyRange.only([e,t]),r=await n.count(o);return a.close(),r}(...t.args);break;case"deleteDBChunk":e=await async function(e,t){try{const a=await S(),n=a.transaction("chunks","readwrite"),o=n.objectStore("chunks");if(t){const a=IDBKeyRange.only([e,t]);await o.delete(a)}else{const t=o.index("hash"),a=await t.getAllKeys(e),n=a.length;if(0===n){const t=o.index("merkleRoot"),a=await t.getAllKeys(e),n=a.length;for(let e=0;e<n;e++)await o.delete(a[e])}else for(let e=0;e<n;e++)await o.delete(a[e])}await n.done,a.close()}catch(e){}}(...t.args);break;case"deleteDBNewChunk":e=await async function(e,t,a,n){try{const o=await S(),r=o.transaction("newChunks","readwrite"),s=r.objectStore("newChunks");if(e){const t=s.index("merkleRoot"),a=await t.getAllKeys(e),n=a.length;for(let e=0;e<n;e++)await s.delete(a[e])}else if(a&&n)await s.delete([a,n]);else if(a){const e=s.index("hash"),t=await e.getAllKeys(a),n=t.length;for(let e=0;e<n;e++)await s.delete(t[e])}else if(t){const e=s.index("realChunkHash"),a=await e.getKey(t);a&&await s.delete(a)}await r.done,o.close()}catch(e){console.error(e)}}(...t.args);break;case"deleteDBMessageData":e=await async function(e){try{const t=await S(),a=t.transaction(["messageData","uniqueRoom"],"readwrite"),n=a.objectStore("messageData"),o=a.objectStore("uniqueRoom"),r=n.index("merkleRoot"),s=await r.getAllKeys(e),i=s.length;let c="";for(let e=0;e<i;e++){if(0===e||0===c.length){const t=await n.get(s[e]);c=t?.roomId??""}await n.delete(s[e])}if(c.length>0){const e=o.index("roomId"),t=await e.get(c);if(t){const e=n.index("roomId"),a=await e.getAllKeys(c),r=a.length,s=r>0?await n.get(a[r-1]):void 0;await o.put({...t,messageCount:t.messageCount>0?t.messageCount-1:0,updatedAt:s?.timestamp??Date.now(),lastMessageMerkleRoot:s?.merkleRoot??""})}}await a.done,t.close()}catch(e){}}(...t.args);break;case"deleteDBUniqueRoom":e=await async function(e){try{const t=await S(),a=t.transaction("uniqueRoom","readwrite"),n=a.objectStore("uniqueRoom"),o=n.index("roomId"),r=await o.getKey(e);r&&await n.delete(r),await a.done,t.close()}catch(e){}}(...t.args);break;case"deleteDBSendQueue":e=await async function(e,t,a){try{const n=await S();if(a)await n.delete("sendQueue",[a,e,t]);else{const a=IDBKeyRange.only([e,t]);await n.delete("sendQueue",a)}n.close()}catch(e){}}(...t.args);break;case"deleteDB":e=await R();break;default:return void postMessage({id:a,error:"Method not found"})}postMessage({id:a,result:e})}catch(e){postMessage({id:a,error:String(e)})}};
|
|
2
2
|
//# sourceMappingURL=db.worker.js.map
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { LibCrypto } from "../cryptography/libcrypto";
|
|
2
2
|
import type { Room } from "../reducers/roomSlice";
|
|
3
|
-
export declare const handleReceiveMessage: (data: ArrayBuffer, merkleRoot: Uint8Array,
|
|
3
|
+
export declare const handleReceiveMessage: (data: ArrayBuffer, merkleRoot: Uint8Array, senderPublicKey: Uint8Array, receiverSecretKey: Uint8Array, room: Room, decryptionModule: LibCrypto, merkleModule: LibCrypto) => Promise<{
|
|
4
4
|
date: Date;
|
|
5
5
|
chunkSize: number;
|
|
6
6
|
savedSize: number;
|
|
7
7
|
totalSize: number;
|
|
8
8
|
chunkIndex: number;
|
|
9
9
|
chunkHash: Uint8Array;
|
|
10
|
+
messageHash: Uint8Array;
|
|
10
11
|
receivedFullSize: boolean;
|
|
11
12
|
messageAlreadyExists: boolean;
|
|
12
13
|
chunkAlreadyExists: boolean;
|