Skip to content

Commit 948a043

Browse files
Merge pull request #14 from mangledbottles/e2ee
End-to-End Encryption (E2EE)
2 parents 0e27789 + 8a25bcf commit 948a043

2 files changed

Lines changed: 75 additions & 30 deletions

File tree

src/Chat.svelte

Lines changed: 69 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,78 +3,117 @@
33
import { Button } from "attractions";
44
import { Autocomplete } from "attractions";
55
6-
76
import {
87
username,
98
receivedScreenshots,
109
selectedScreenshot,
1110
selectedContact,
12-
db
11+
db,
12+
senderKeyPairs,
13+
receiverKeyPairs,
1314
} from "./User";
1415
15-
// on button click, set username
16-
function setUsername() {
17-
console.log({ msg: "updating username", username });
18-
startGun();
19-
}
16+
// Get the senders (logged in user) cryptographically secure public/private key pair
17+
// Contains the public key (pub), the private key (priv), the epub
18+
// (encryption public key) and the epriv (encryption private key)
19+
const senderPair = db.user()._.sea;
20+
senderKeyPairs.set({ ...$senderKeyPairs, ...senderPair });
2021
2122
// Load screenshots received from Gun, listen for incoming
22-
db
23-
.get("screenshots")
23+
db.get("screenshots")
2424
.get($username)
2525
.map()
26-
.once((data, id) => {
27-
console.log({ data, id, message: "screenshots loaded" });
28-
receivedScreenshots.set([...$receivedScreenshots, data]);
26+
.once(async (data, id) => {
27+
if (data.data == null) return;
28+
const { data: encryptedImage, from: fromUser } = data;
29+
30+
const senderEPub = await getUserEPub(fromUser);
31+
32+
// Decrypt the image
33+
const decryptSecret = await SEA.secret(senderEPub, $senderKeyPairs);
34+
const decryptedMessage = await SEA.decrypt(encryptedImage, decryptSecret);
35+
receivedScreenshots.set([...$receivedScreenshots, decryptedMessage]);
2936
});
3037
38+
const getUserEPub = async (alias) => {
39+
// check if alias starts with ~@ (database format for user alias)
40+
if (!alias.startsWith("~@")) alias = `~@${alias}`;
41+
42+
const userAccount = await db.get(alias).once();
43+
if (!userAccount) return;
44+
45+
// Get the receivers public key (pub)
46+
const receiverPubKey = Object.keys(userAccount)[1].substring(1);
47+
// Get the receivers public key for encryption (epub)
48+
const receiverEPub = await db.user(receiverPubKey).get("epub");
49+
50+
return receiverEPub;
51+
};
52+
3153
// Send screenshot to Gun user
32-
function sendMessage() {
54+
const sendMessage = async () => {
3355
console.log("sending message");
3456
const index = new Date().toISOString();
3557
console.log({ username, uusername: $username });
3658
console.log(
3759
`Sending message in 'screenshots' to ${$selectedContact} at index ${index} from ${$username}`
3860
);
3961
40-
// const receivingContact = ($selectedContact).splice(2);
62+
// Encrypt screenshot and message
63+
const encryptSecret = await SEA.secret(
64+
$receiverKeyPairs.epub,
65+
$senderKeyPairs
66+
);
67+
const message = {
68+
image: $selectedScreenshot,
69+
message: `Heres a screenshot from ${$username}`,
70+
};
71+
const encrypted = await SEA.encrypt(message, encryptSecret);
4172
42-
db
43-
.get("screenshots")
73+
db.get("screenshots")
4474
.get($selectedContact)
4575
.get(index)
4676
.put({
47-
image: $selectedScreenshot,
48-
message: `Heres a screenshot from ${$username}`,
77+
data: encrypted,
4978
from: `${$username}`,
5079
});
51-
}
80+
81+
};
5282
5383
// AutoComplete component to search for user contact
5484
let currentChosenContact = [];
5585
async function* getOptions(selectedOption) {
5686
let options = [];
5787
58-
59-
await db.get(`~@${selectedOption}`).once((data, userId) => {
88+
// Find user in database (if it exists)
89+
await db.get(`~@${selectedOption}`).once(async (data, userId) => {
6090
if (!data) return; // if no result, return
6191
62-
console.log({ data, key: userId });
63-
6492
// Set the current chosen contact
65-
// remove first 2 characters of userId
66-
67-
68-
selectedContact.set(userId.substring(2));
69-
console.log({ selectedContact})
70-
console.log({ selectedContact: $selectedContact });
93+
selectedContact.set(userId.substring(2)); // remove the ~@
7194
7295
options.push({
7396
name: userId,
7497
details: `Unique Identifier ${data._}`,
7598
});
7699
77-
console.log({ key: userId });
100+
101+
/**
102+
* End-to-end encryption (E2EE)
103+
*/
104+
105+
// Get the receivers public key for encryption (epub)
106+
const receiverEPub = await getUserEPub(userId);
107+
108+
// Get the senders (logged in user) cryptographically secure public/private key pair
109+
// Contains the public key (pub), the private key (priv), the epub
110+
// (encryption public key) and the epriv (encryption private key)
111+
const senderPair = db.user()._.sea;
112+
113+
// Update state with key pairs
114+
senderKeyPairs.set({ ...$senderKeyPairs, ...senderPair });
115+
receiverKeyPairs.set({ ...$receiverKeyPairs, epub: receiverEPub });
116+
78117
});
79118
80119
yield options;

src/User.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ export const selectedScreenshot = writable('');
2323

2424
// Selected Contact to send Screenshot to
2525
export const selectedContact = writable('');
26+
27+
// Sender: Cryptographically secure public/private key pair
28+
export const senderKeyPairs = writable({});
29+
30+
// Receiver: Cryptographically secure public key pair
31+
export const receiverKeyPairs = writable({});
2632

2733
user.get('alias').on(v => username.set(v))
2834

0 commit comments

Comments
 (0)