Files
Shade/examples/01-basic-conversation/main.ts
Sterister 75008b623a
Some checks failed
Test / test (push) Has been cancelled
docs: M-Hard 9-11 — README, examples, CI, benchmarks, migration guide
M-Hard 9: Documentation + examples
- README.md, SECURITY.md, THREAT-MODEL.md
- 5 runnable examples: basic conversation, prekey server,
  WebSocket tunnel, identity verification, Dokploy deployment

M-Hard 10: CI + publishing + benchmarks
- GitHub Actions: test workflow with PostgreSQL service container
- GitHub Actions: publish workflow for npm releases on git tags
- Benchmark suite (bench/run.ts) with markdown output
- LICENSE (MIT), CHANGELOG.md, CONTRIBUTING.md

M-Hard 11: Migration guide
- MIGRATION.md with three-phase rollout strategy
- Concrete examples for replacing static AES tunnels
- Concrete examples for per-device push notification migration
- Sections for Orchestrator and Nova migrations

Benchmark highlights:
- AES-256-GCM: ~100K ops/sec
- Encrypt+decrypt roundtrip: ~17K ops/sec
- X3DH handshake: ~165 ops/sec (hardware acceleration limited)
- Compute fingerprint: ~76K ops/sec

All 11 M-Hard milestones complete. 193 tests passing, 0 failures.
Shade is production-ready.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:58:30 +02:00

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);