68 lines
2.5 KiB
TypeScript
68 lines
2.5 KiB
TypeScript
|
|
import { ShadeSessionManager } from '../../packages/shade-core/src/index.js';
|
||
|
|
import { SubtleCryptoProvider, MemoryStorage } from '../../packages/shade-crypto-web/src/index.js';
|
||
|
|
|
||
|
|
const crypto = new SubtleCryptoProvider();
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
console.log('=== Shade Basic Conversation ===\n');
|
||
|
|
|
||
|
|
// Set up Alice and Bob with separate storage
|
||
|
|
const alice = new ShadeSessionManager(crypto, new MemoryStorage());
|
||
|
|
const bob = new ShadeSessionManager(crypto, new MemoryStorage());
|
||
|
|
|
||
|
|
await alice.initialize();
|
||
|
|
await bob.initialize();
|
||
|
|
|
||
|
|
// Show fingerprints (safety numbers for verification)
|
||
|
|
console.log('Alice fingerprint:', await alice.getIdentityFingerprint());
|
||
|
|
console.log('Bob fingerprint: ', await bob.getIdentityFingerprint());
|
||
|
|
console.log();
|
||
|
|
|
||
|
|
// Bob generates one-time prekeys (would be uploaded to a prekey server)
|
||
|
|
const bobOTPKs = await bob.generateOneTimePreKeys(5);
|
||
|
|
const bobBundle = await bob.createPreKeyBundle();
|
||
|
|
bobBundle.oneTimePreKey = {
|
||
|
|
keyId: bobOTPKs[0].keyId,
|
||
|
|
publicKey: bobOTPKs[0].keyPair.publicKey,
|
||
|
|
};
|
||
|
|
|
||
|
|
// Alice fetches Bob's bundle (here: directly) and starts a session
|
||
|
|
await alice.initSessionFromBundle('bob', bobBundle);
|
||
|
|
|
||
|
|
// Alice → Bob
|
||
|
|
console.log('→ Alice encrypts: "Hello Bob!"');
|
||
|
|
const msg1 = await alice.encrypt('bob', 'Hello Bob!');
|
||
|
|
const plain1 = await bob.decrypt('alice', msg1);
|
||
|
|
console.log(`← Bob decrypts: "${plain1}"`);
|
||
|
|
|
||
|
|
// Bob → Alice (triggers DH ratchet step)
|
||
|
|
console.log('\n→ Bob encrypts: "Hi Alice, got your message"');
|
||
|
|
const msg2 = await bob.encrypt('alice', 'Hi Alice, got your message');
|
||
|
|
const plain2 = await alice.decrypt('bob', msg2);
|
||
|
|
console.log(`← Alice decrypts: "${plain2}"`);
|
||
|
|
|
||
|
|
// Several more turns
|
||
|
|
console.log('\n=== Continued conversation (each message has a unique key) ===');
|
||
|
|
const conversation = [
|
||
|
|
['alice', 'How are you?'],
|
||
|
|
['bob', 'Doing well!'],
|
||
|
|
['alice', 'Want to grab coffee?'],
|
||
|
|
['bob', 'Sure, when?'],
|
||
|
|
] as const;
|
||
|
|
|
||
|
|
for (const [from, text] of conversation) {
|
||
|
|
const sender = from === 'alice' ? alice : bob;
|
||
|
|
const receiver = from === 'alice' ? bob : alice;
|
||
|
|
const recvAddr = from === 'alice' ? 'alice' : 'bob';
|
||
|
|
const sendAddr = from === 'alice' ? 'bob' : 'alice';
|
||
|
|
|
||
|
|
const env = await sender.encrypt(sendAddr, text);
|
||
|
|
const plain = await receiver.decrypt(recvAddr, env);
|
||
|
|
console.log(`${from === 'alice' ? 'Alice' : 'Bob '}: "${plain}"`);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n=== Done. Every message used a unique key. ===');
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch(console.error);
|