Skip to content

Commit a937134

Browse files
authored
Merge pull request #8 from CryptCollab/feature/documentJoining
Feature/document joining
2 parents 2e4e23c + e6c51f7 commit a937134

20 files changed

Lines changed: 1034 additions & 346 deletions

package-lock.json

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
"bootstrap": "^5.2.3",
3030
"buffer": "^6.0.3",
3131
"html-react-parser": "^3.0.15",
32+
"easy-web-crypto": "^1.3.1",
33+
"idb-keyval": "^6.2.0",
3234
"js-base64": "^3.7.5",
3335
"localforage": "^1.10.0",
3436
"match-sorter": "^6.3.1",

src/components/TypeAhead.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const TypeAhead: React.FC<TypeAheadProps> = ({ selectedUserList, setSelectedUser
4747
renderMenuItemChildren={(option: any) => (
4848
<>
4949
<span>{option.userName}{option.email}</span>
50+
{/* <Button variant = "secondary" >Invite</Button> */}
5051
</>
5152
)}
5253
/>

src/components/UserInviteModal.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React, { useState } from "react";
2+
import { Modal, Button } from "react-bootstrap";
3+
import TypeAhead, { TypeAheadProps } from "./TypeAhead";
4+
5+
interface UserInvitieModalProps extends TypeAheadProps {
6+
isModalOpen: boolean;
7+
setIsModalOpen: React.Dispatch<React.SetStateAction<boolean>>;
8+
handleInvite: () => void;
9+
}
10+
11+
const UserInviteModal: React.FC<UserInvitieModalProps> = ({
12+
isModalOpen,
13+
setIsModalOpen,
14+
selectedUserList,
15+
setSelectedUserList,
16+
handleInvite,
17+
}) => {
18+
const closeModal = () => {
19+
setIsModalOpen(false);
20+
};
21+
return (
22+
<Modal show={isModalOpen}>
23+
<Modal.Header>
24+
<Modal.Title>Invite paticipants</Modal.Title>
25+
</Modal.Header>
26+
<Modal.Body>
27+
<TypeAhead
28+
selectedUserList={selectedUserList}
29+
setSelectedUserList={setSelectedUserList}
30+
/>
31+
</Modal.Body>
32+
<Modal.Footer>
33+
<Button variant="primary" onClick={handleInvite}>
34+
Invite
35+
</Button>
36+
<Button variant="secondary" onClick={closeModal}>
37+
Close
38+
</Button>
39+
</Modal.Footer>
40+
</Modal>
41+
);
42+
};
43+
export default UserInviteModal;

src/components/UserInvitieModal.tsx

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/cryptolib/lib/persistence.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from "sodium-plus";
99
import { Keypair, wipe } from "./util";
1010
import { Buffer } from "buffer";
11-
import { Store } from "secure-webstore";
11+
import { Store } from "../secureIDBStorage";
1212

1313

1414
export type IdentityKeyPair = { identitySecret: Ed25519SecretKey, identityPublic: Ed25519PublicKey | any };
@@ -26,7 +26,7 @@ export interface IdentityKeyManagerInterface {
2626
Promise<IdentityKeyPair>;
2727
getMyIdentityString():
2828
Promise<string>;
29-
getPreKeypair():
29+
getPreKeypair(keyStore: Store):
3030
Promise<PreKeyPair>;
3131
persistOneTimeKeys(bundle: Keypair[]):
3232
Promise<void>;
@@ -37,7 +37,11 @@ export interface IdentityKeyManagerInterface {
3737
persistPrekeyPair(prekeyPair: PreKeyPair):
3838
Promise<void>
3939
saveIdentityKeypair(identitykeypair: IdentityKeyPair, keyStore: Store):
40-
Promise<void>
40+
Promise<void>
41+
savePreKeyPair(prekeyPair: PreKeyPair, keyStore: Store):
42+
Promise<void>
43+
44+
4145
}
4246

4347
export interface SessionKeyManagerInterface {
@@ -159,10 +163,12 @@ export class DefaultSessionKeyManager implements SessionKeyManagerInterface {
159163
if (recipient) {
160164
const keys = await this.symmetricRatchet(this.sessions[id].receiving);
161165
this.sessions[id].receiving = keys[0];
166+
//console.log(this.sessions[id]);
162167
return keys[1];
163168
} else {
164169
const keys = await this.symmetricRatchet(this.sessions[id].sending);
165170
this.sessions[id].sending = keys[0];
171+
//console.log(this.sessions[id]);
166172
return keys[1];
167173
}
168174
}
@@ -323,8 +329,8 @@ export class DefaultIdentityKeyManager implements IdentityKeyManagerInterface {
323329
*
324330
* This only returns the X25519 keys. It doesn't include the Ed25519 signature.
325331
*/
326-
async getPreKeypair(): Promise<PreKeyPair> {
327-
const sodium = await this.getSodium();
332+
async getPreKeypair(keyStore: Store): Promise<PreKeyPair> {
333+
this.preKey = await this.loadPreKeypair(keyStore);
328334
if (this.preKey == undefined) {
329335
this.preKey = await this.generatePreKeypair();
330336
}
@@ -349,6 +355,19 @@ export class DefaultIdentityKeyManager implements IdentityKeyManagerInterface {
349355
return { identitySecret: sk, identityPublic: pk };
350356
}
351357

358+
359+
async loadPreKeypair(keyStore: Store): Promise<PreKeyPair> {
360+
const sodium = await this.getSodium();
361+
await keyStore.init();
362+
const sk = new X25519SecretKey(
363+
await sodium.sodium_hex2bin(await keyStore.get("preKeySecret"))
364+
);
365+
const pk = new X25519PublicKey(
366+
await sodium.sodium_hex2bin(await keyStore.get("preKeyPublic"))
367+
);
368+
return { preKeySecret: sk, preKeyPublic: pk };
369+
}
370+
352371
/**
353372
* Store one-time keys in memory.
354373
*
@@ -378,6 +397,17 @@ export class DefaultIdentityKeyManager implements IdentityKeyManagerInterface {
378397
}
379398

380399

400+
async savePreKeyPair(preKeyPair: PreKeyPair, keyStore: Store): Promise<void> {
401+
const sodium = await this.getSodium();
402+
if (!keyStore) {
403+
console.log("No key store provided, not saving prekey pair.");
404+
}
405+
await keyStore.init();
406+
await keyStore.set("preKeyPublic", await sodium.sodium_bin2hex(preKeyPair.preKeyPublic.getBuffer()));
407+
await keyStore.set("preKeySecret", await sodium.sodium_bin2hex(preKeyPair.preKeySecret.getBuffer()));
408+
}
409+
410+
381411
/**
382412
* Saves the prekey pair to memory
383413
* @param {X25519PublicKey} preKeyPublic

src/cryptolib/lib/store.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
class Store {
2+
storeName: string
3+
private _dbName: string
4+
private _storeName: string
5+
private _dbp?: IDBDatabase
6+
7+
constructor (dbName = 'keyval-store', storeName = 'keyval') {
8+
this.storeName = storeName
9+
this._dbName = dbName
10+
this._storeName = storeName
11+
this._init()
12+
}
13+
14+
async _withIDBStore <T>(type: IDBTransactionMode, callback: (store: IDBObjectStore) => T): Promise<T> {
15+
const db = await this._init()
16+
17+
let ret: T | undefined
18+
await new Promise<void>((resolve, reject) => {
19+
const transaction = db.transaction(this.storeName, type)
20+
transaction.oncomplete = () => resolve()
21+
transaction.onabort = transaction.onerror = () => reject(transaction.error)
22+
ret = callback(transaction.objectStore(this.storeName))
23+
});
24+
return ret!;
25+
}
26+
27+
async _init () {
28+
if (this._dbp) {
29+
return this._dbp
30+
}
31+
this._dbp = await new Promise<IDBDatabase>((resolve, reject) => {
32+
const openreq = window.indexedDB.open(this._dbName, 1)
33+
openreq.onerror = () => reject(openreq.error)
34+
openreq.onsuccess = () => resolve(openreq.result)
35+
// First time setup: create an empty object store
36+
openreq.onupgradeneeded = () => {
37+
openreq.result.createObjectStore(this._storeName)
38+
}
39+
});
40+
this._dbp.onclose = () => {
41+
this._dbp = undefined
42+
}
43+
this._dbp.onversionchange = (e) => {
44+
if (e.newVersion === null) { // an attempt is made to delete the db
45+
console.log('Got delete request for db')
46+
this._dbp?.close() // force close our connection to the db
47+
}
48+
}
49+
return this._dbp
50+
}
51+
52+
_close () {
53+
this._dbp?.close()
54+
}
55+
}
56+
57+
let store: Store | undefined
58+
59+
function getDefaultStore () {
60+
if (!store) {
61+
store = new Store()
62+
}
63+
return store
64+
}
65+
66+
async function get (key: IDBValidKey | IDBKeyRange, store = getDefaultStore()) {
67+
const request = await store._withIDBStore('readonly', store =>
68+
store.get(key)
69+
)
70+
return request.result;
71+
}
72+
73+
function set (key: IDBValidKey, value: any, store = getDefaultStore()) {
74+
return store._withIDBStore('readwrite', store => {
75+
store.put(value, key)
76+
})
77+
}
78+
79+
function del (key: IDBValidKey | IDBKeyRange, store = getDefaultStore()) {
80+
return store._withIDBStore('readwrite', store => {
81+
store.delete(key)
82+
})
83+
}
84+
85+
function clear (store = getDefaultStore()) {
86+
return store._withIDBStore('readwrite', store => {
87+
store.clear()
88+
})
89+
}
90+
91+
function keys (store = getDefaultStore()): Promise<IDBValidKey[]> {
92+
return store._withIDBStore('readonly', store => {
93+
// This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
94+
// And openKeyCursor isn't supported by Safari.
95+
const keys: IDBValidKey[] = [];
96+
(store.openKeyCursor || store.openCursor).call(store).onsuccess = function () {
97+
if (!this.result) {
98+
return
99+
}
100+
keys.push(this.result.key)
101+
this.result.continue()
102+
}
103+
return keys
104+
})
105+
}
106+
107+
function close (store = getDefaultStore()) {
108+
return store._close()
109+
}
110+
111+
export { Store, get, set, del, clear, keys, close }

src/cryptolib/lib/symmetric.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export async function decryptData(
144144
// console.log(aad)
145145
const storedCommitment = await sodium.sodium_hex2bin(encrypted.slice(50, 114));
146146
const { encKey, commitment } = await deriveKeys(key, nonce);
147+
//console.log(encKey,commitment)
147148
if (!(await sodium.sodium_memcmp(storedCommitment, commitment))) {
148149
// console.log(commitment)
149150
// console.log(storedCommitment)

0 commit comments

Comments
 (0)