@xtr-dev/rondevu-server 0.2.2 → 0.2.3
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/dist/index.js +4 -10
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/src/crypto.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -128,12 +128,6 @@ var invert = (num, md) => {
|
|
|
128
128
|
}
|
|
129
129
|
return b === 1n ? M(x, md) : err("no inverse");
|
|
130
130
|
};
|
|
131
|
-
var callHash = (name) => {
|
|
132
|
-
const fn = hashes[name];
|
|
133
|
-
if (typeof fn !== "function")
|
|
134
|
-
err("hashes." + name + " not set");
|
|
135
|
-
return fn;
|
|
136
|
-
};
|
|
137
131
|
var apoint = (p) => p instanceof Point ? p : err("Point expected");
|
|
138
132
|
var B256 = 2n ** 256n;
|
|
139
133
|
var Point = class _Point {
|
|
@@ -383,8 +377,8 @@ var uvRatio = (u, v) => {
|
|
|
383
377
|
return { isValid: useRoot1 || useRoot2, value: x };
|
|
384
378
|
};
|
|
385
379
|
var modL_LE = (hash) => modN(bytesToNumLE(hash));
|
|
386
|
-
var
|
|
387
|
-
var
|
|
380
|
+
var sha512a = (...m) => hashes.sha512Async(concatBytes(...m));
|
|
381
|
+
var hashFinishA = (res) => sha512a(res.hashable).then(res.finish);
|
|
388
382
|
var defaultVerifyOpts = { zip215: true };
|
|
389
383
|
var _verify = (sig, msg, pub, opts = defaultVerifyOpts) => {
|
|
390
384
|
sig = abytes(sig, L2);
|
|
@@ -415,7 +409,7 @@ var _verify = (sig, msg, pub, opts = defaultVerifyOpts) => {
|
|
|
415
409
|
};
|
|
416
410
|
return { hashable, finish };
|
|
417
411
|
};
|
|
418
|
-
var
|
|
412
|
+
var verifyAsync = async (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishA(_verify(signature, message, publicKey, opts));
|
|
419
413
|
var hashes = {
|
|
420
414
|
sha512Async: async (message) => {
|
|
421
415
|
const s = subtle();
|
|
@@ -630,7 +624,7 @@ async function verifyEd25519Signature(publicKey, signature, message) {
|
|
|
630
624
|
const signatureBytes = base64ToBytes(signature);
|
|
631
625
|
const encoder = new TextEncoder();
|
|
632
626
|
const messageBytes = encoder.encode(message);
|
|
633
|
-
const isValid = await
|
|
627
|
+
const isValid = await verifyAsync(signatureBytes, messageBytes, publicKeyBytes);
|
|
634
628
|
return isValid;
|
|
635
629
|
} catch (err2) {
|
|
636
630
|
console.error("Ed25519 signature verification failed:", err2);
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/app.ts", "../node_modules/@noble/ed25519/index.js", "../src/crypto.ts", "../src/middleware/auth.ts", "../src/config.ts", "../src/storage/sqlite.ts", "../src/storage/hash-id.ts"],
|
|
4
|
-
"sourcesContent": ["import { serve } from '@hono/node-server';\nimport { createApp } from './app.ts';\nimport { loadConfig } from './config.ts';\nimport { SQLiteStorage } from './storage/sqlite.ts';\nimport { Storage } from './storage/types.ts';\n\n/**\n * Main entry point for the standalone Node.js server\n */\nasync function main() {\n const config = loadConfig();\n\n console.log('Starting Rondevu server...');\n console.log('Configuration:', {\n port: config.port,\n storageType: config.storageType,\n storagePath: config.storagePath,\n offerDefaultTtl: `${config.offerDefaultTtl}ms`,\n offerMaxTtl: `${config.offerMaxTtl}ms`,\n offerMinTtl: `${config.offerMinTtl}ms`,\n cleanupInterval: `${config.cleanupInterval}ms`,\n maxOffersPerRequest: config.maxOffersPerRequest,\n maxTopicsPerOffer: config.maxTopicsPerOffer,\n corsOrigins: config.corsOrigins,\n version: config.version,\n });\n\n let storage: Storage;\n\n if (config.storageType === 'sqlite') {\n storage = new SQLiteStorage(config.storagePath);\n console.log('Using SQLite storage');\n } else {\n throw new Error('Unsupported storage type');\n }\n\n // Start periodic cleanup of expired offers\n const cleanupInterval = setInterval(async () => {\n try {\n const now = Date.now();\n const deleted = await storage.deleteExpiredOffers(now);\n if (deleted > 0) {\n console.log(`Cleanup: Deleted ${deleted} expired offer(s)`);\n }\n } catch (err) {\n console.error('Cleanup error:', err);\n }\n }, config.cleanupInterval);\n\n const app = createApp(storage, config);\n\n const server = serve({\n fetch: app.fetch,\n port: config.port,\n });\n\n console.log(`Server running on http://localhost:${config.port}`);\n console.log('Ready to accept connections');\n\n // Graceful shutdown handler\n const shutdown = async () => {\n console.log('\\nShutting down gracefully...');\n clearInterval(cleanupInterval);\n await storage.close();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n", "import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { Storage } from './storage/types.ts';\nimport { Config } from './config.ts';\nimport { createAuthMiddleware, getAuthenticatedPeerId } from './middleware/auth.ts';\nimport { generatePeerId, encryptPeerId, validateUsernameClaim, validateServiceFqn } from './crypto.ts';\nimport type { Context } from 'hono';\n\n/**\n * Creates the Hono application with username and service-based WebRTC signaling\n */\nexport function createApp(storage: Storage, config: Config) {\n const app = new Hono();\n\n // Create auth middleware\n const authMiddleware = createAuthMiddleware(config.authSecret);\n\n // Enable CORS\n app.use('/*', cors({\n origin: (origin) => {\n if (config.corsOrigins.length === 1 && config.corsOrigins[0] === '*') {\n return origin;\n }\n if (config.corsOrigins.includes(origin)) {\n return origin;\n }\n return config.corsOrigins[0];\n },\n allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Origin', 'Authorization'],\n exposeHeaders: ['Content-Type'],\n maxAge: 600,\n credentials: true,\n }));\n\n // ===== General Endpoints =====\n\n /**\n * GET /\n * Returns server information\n */\n app.get('/', (c) => {\n return c.json({\n version: config.version,\n name: 'Rondevu',\n description: 'DNS-like WebRTC signaling with username claiming and service discovery'\n });\n });\n\n /**\n * GET /health\n * Health check endpoint\n */\n app.get('/health', (c) => {\n return c.json({\n status: 'ok',\n timestamp: Date.now(),\n version: config.version\n });\n });\n\n /**\n * POST /register\n * Register a new peer (still needed for peer ID generation)\n */\n app.post('/register', async (c) => {\n try {\n const peerId = generatePeerId();\n const secret = await encryptPeerId(peerId, config.authSecret);\n\n return c.json({\n peerId,\n secret\n }, 200);\n } catch (err) {\n console.error('Error registering peer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Username Management =====\n\n /**\n * POST /usernames/claim\n * Claim a username with cryptographic proof\n */\n app.post('/usernames/claim', async (c) => {\n try {\n const body = await c.req.json();\n const { username, publicKey, signature, message } = body;\n\n if (!username || !publicKey || !signature || !message) {\n return c.json({ error: 'Missing required parameters: username, publicKey, signature, message' }, 400);\n }\n\n // Validate claim\n const validation = await validateUsernameClaim(username, publicKey, signature, message);\n if (!validation.valid) {\n return c.json({ error: validation.error }, 400);\n }\n\n // Attempt to claim username\n try {\n const claimed = await storage.claimUsername({\n username,\n publicKey,\n signature,\n message\n });\n\n return c.json({\n username: claimed.username,\n claimedAt: claimed.claimedAt,\n expiresAt: claimed.expiresAt\n }, 200);\n } catch (err: any) {\n if (err.message?.includes('already claimed')) {\n return c.json({ error: 'Username already claimed by different public key' }, 409);\n }\n throw err;\n }\n } catch (err) {\n console.error('Error claiming username:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /usernames/:username\n * Check if username is available or get claim info\n */\n app.get('/usernames/:username', async (c) => {\n try {\n const username = c.req.param('username');\n\n const claimed = await storage.getUsername(username);\n\n if (!claimed) {\n return c.json({\n username,\n available: true\n }, 200);\n }\n\n return c.json({\n username: claimed.username,\n available: false,\n claimedAt: claimed.claimedAt,\n expiresAt: claimed.expiresAt,\n publicKey: claimed.publicKey\n }, 200);\n } catch (err) {\n console.error('Error checking username:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /usernames/:username/services\n * List services for a username (privacy-preserving)\n */\n app.get('/usernames/:username/services', async (c) => {\n try {\n const username = c.req.param('username');\n\n const services = await storage.listServicesForUsername(username);\n\n return c.json({\n username,\n services\n }, 200);\n } catch (err) {\n console.error('Error listing services:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Service Management =====\n\n /**\n * POST /services\n * Publish a service\n */\n app.post('/services', authMiddleware, async (c) => {\n try {\n const body = await c.req.json();\n const { username, serviceFqn, sdp, ttl, isPublic, metadata, signature, message } = body;\n\n if (!username || !serviceFqn || !sdp) {\n return c.json({ error: 'Missing required parameters: username, serviceFqn, sdp' }, 400);\n }\n\n // Validate service FQN\n const fqnValidation = validateServiceFqn(serviceFqn);\n if (!fqnValidation.valid) {\n return c.json({ error: fqnValidation.error }, 400);\n }\n\n // Verify username ownership (signature required)\n if (!signature || !message) {\n return c.json({ error: 'Missing signature or message for username verification' }, 400);\n }\n\n const usernameRecord = await storage.getUsername(username);\n if (!usernameRecord) {\n return c.json({ error: 'Username not claimed' }, 404);\n }\n\n // Verify signature matches username's public key\n const signatureValidation = await validateUsernameClaim(username, usernameRecord.publicKey, signature, message);\n if (!signatureValidation.valid) {\n return c.json({ error: 'Invalid signature for username' }, 403);\n }\n\n // Validate SDP\n if (typeof sdp !== 'string' || sdp.length === 0) {\n return c.json({ error: 'Invalid SDP' }, 400);\n }\n\n if (sdp.length > 64 * 1024) {\n return c.json({ error: 'SDP too large (max 64KB)' }, 400);\n }\n\n // Calculate expiry\n const peerId = getAuthenticatedPeerId(c);\n const offerTtl = Math.min(\n Math.max(ttl || config.offerDefaultTtl, config.offerMinTtl),\n config.offerMaxTtl\n );\n const expiresAt = Date.now() + offerTtl;\n\n // Create offer first\n const offers = await storage.createOffers([{\n peerId,\n sdp,\n expiresAt\n }]);\n\n if (offers.length === 0) {\n return c.json({ error: 'Failed to create offer' }, 500);\n }\n\n const offer = offers[0];\n\n // Create service\n const result = await storage.createService({\n username,\n serviceFqn,\n offerId: offer.id,\n expiresAt,\n isPublic: isPublic || false,\n metadata: metadata ? JSON.stringify(metadata) : undefined\n });\n\n return c.json({\n serviceId: result.service.id,\n uuid: result.indexUuid,\n offerId: offer.id,\n expiresAt: result.service.expiresAt\n }, 201);\n } catch (err) {\n console.error('Error creating service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /services/:uuid\n * Get service details by index UUID\n */\n app.get('/services/:uuid', async (c) => {\n try {\n const uuid = c.req.param('uuid');\n\n const service = await storage.getServiceByUuid(uuid);\n\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // Get associated offer\n const offer = await storage.getOfferById(service.offerId);\n\n if (!offer) {\n return c.json({ error: 'Associated offer not found' }, 404);\n }\n\n return c.json({\n serviceId: service.id,\n username: service.username,\n serviceFqn: service.serviceFqn,\n offerId: service.offerId,\n sdp: offer.sdp,\n isPublic: service.isPublic,\n metadata: service.metadata ? JSON.parse(service.metadata) : undefined,\n createdAt: service.createdAt,\n expiresAt: service.expiresAt\n }, 200);\n } catch (err) {\n console.error('Error getting service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * DELETE /services/:serviceId\n * Delete a service (requires ownership)\n */\n app.delete('/services/:serviceId', authMiddleware, async (c) => {\n try {\n const serviceId = c.req.param('serviceId');\n const body = await c.req.json();\n const { username } = body;\n\n if (!username) {\n return c.json({ error: 'Missing required parameter: username' }, 400);\n }\n\n const deleted = await storage.deleteService(serviceId, username);\n\n if (!deleted) {\n return c.json({ error: 'Service not found or not owned by this username' }, 404);\n }\n\n return c.json({ success: true }, 200);\n } catch (err) {\n console.error('Error deleting service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * POST /index/:username/query\n * Query service by FQN (returns UUID)\n */\n app.post('/index/:username/query', async (c) => {\n try {\n const username = c.req.param('username');\n const body = await c.req.json();\n const { serviceFqn } = body;\n\n if (!serviceFqn) {\n return c.json({ error: 'Missing required parameter: serviceFqn' }, 400);\n }\n\n const uuid = await storage.queryService(username, serviceFqn);\n\n if (!uuid) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n return c.json({\n uuid,\n allowed: true\n }, 200);\n } catch (err) {\n console.error('Error querying service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Offer Management (Core WebRTC) =====\n\n /**\n * POST /offers\n * Create offers (direct, no service - for testing/advanced users)\n */\n app.post('/offers', authMiddleware, async (c) => {\n try {\n const body = await c.req.json();\n const { offers } = body;\n\n if (!Array.isArray(offers) || offers.length === 0) {\n return c.json({ error: 'Missing or invalid required parameter: offers (must be non-empty array)' }, 400);\n }\n\n if (offers.length > config.maxOffersPerRequest) {\n return c.json({ error: `Too many offers (max ${config.maxOffersPerRequest})` }, 400);\n }\n\n const peerId = getAuthenticatedPeerId(c);\n\n // Validate and prepare offers\n const validated = offers.map((offer: any) => {\n const { sdp, ttl, secret } = offer;\n\n if (typeof sdp !== 'string' || sdp.length === 0) {\n throw new Error('Invalid SDP in offer');\n }\n\n if (sdp.length > 64 * 1024) {\n throw new Error('SDP too large (max 64KB)');\n }\n\n const offerTtl = Math.min(\n Math.max(ttl || config.offerDefaultTtl, config.offerMinTtl),\n config.offerMaxTtl\n );\n\n return {\n peerId,\n sdp,\n expiresAt: Date.now() + offerTtl,\n secret: secret ? String(secret).substring(0, 128) : undefined\n };\n });\n\n const created = await storage.createOffers(validated);\n\n return c.json({\n offers: created.map(offer => ({\n id: offer.id,\n peerId: offer.peerId,\n expiresAt: offer.expiresAt,\n createdAt: offer.createdAt,\n hasSecret: !!offer.secret\n }))\n }, 201);\n } catch (err: any) {\n console.error('Error creating offers:', err);\n return c.json({ error: err.message || 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /offers/mine\n * Get authenticated peer's offers\n */\n app.get('/offers/mine', authMiddleware, async (c) => {\n try {\n const peerId = getAuthenticatedPeerId(c);\n const offers = await storage.getOffersByPeerId(peerId);\n\n return c.json({\n offers: offers.map(offer => ({\n id: offer.id,\n sdp: offer.sdp,\n createdAt: offer.createdAt,\n expiresAt: offer.expiresAt,\n lastSeen: offer.lastSeen,\n hasSecret: !!offer.secret,\n answererPeerId: offer.answererPeerId,\n answered: !!offer.answererPeerId\n }))\n }, 200);\n } catch (err) {\n console.error('Error getting offers:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * DELETE /offers/:offerId\n * Delete an offer\n */\n app.delete('/offers/:offerId', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const peerId = getAuthenticatedPeerId(c);\n\n const deleted = await storage.deleteOffer(offerId, peerId);\n\n if (!deleted) {\n return c.json({ error: 'Offer not found or not owned by this peer' }, 404);\n }\n\n return c.json({ success: true }, 200);\n } catch (err) {\n console.error('Error deleting offer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * POST /offers/:offerId/answer\n * Answer an offer\n */\n app.post('/offers/:offerId/answer', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const body = await c.req.json();\n const { sdp, secret } = body;\n\n if (!sdp) {\n return c.json({ error: 'Missing required parameter: sdp' }, 400);\n }\n\n if (typeof sdp !== 'string' || sdp.length === 0) {\n return c.json({ error: 'Invalid SDP' }, 400);\n }\n\n if (sdp.length > 64 * 1024) {\n return c.json({ error: 'SDP too large (max 64KB)' }, 400);\n }\n\n const answererPeerId = getAuthenticatedPeerId(c);\n\n const result = await storage.answerOffer(offerId, answererPeerId, sdp, secret);\n\n if (!result.success) {\n return c.json({ error: result.error }, 400);\n }\n\n return c.json({ success: true }, 200);\n } catch (err) {\n console.error('Error answering offer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /offers/answers\n * Get answers for authenticated peer's offers\n */\n app.get('/offers/answers', authMiddleware, async (c) => {\n try {\n const peerId = getAuthenticatedPeerId(c);\n const offers = await storage.getAnsweredOffers(peerId);\n\n return c.json({\n answers: offers.map(offer => ({\n offerId: offer.id,\n answererPeerId: offer.answererPeerId,\n answerSdp: offer.answerSdp,\n answeredAt: offer.answeredAt\n }))\n }, 200);\n } catch (err) {\n console.error('Error getting answers:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== ICE Candidate Exchange =====\n\n /**\n * POST /offers/:offerId/ice-candidates\n * Add ICE candidates for an offer\n */\n app.post('/offers/:offerId/ice-candidates', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const body = await c.req.json();\n const { candidates } = body;\n\n if (!Array.isArray(candidates) || candidates.length === 0) {\n return c.json({ error: 'Missing or invalid required parameter: candidates' }, 400);\n }\n\n const peerId = getAuthenticatedPeerId(c);\n\n // Get offer to determine role\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n return c.json({ error: 'Offer not found' }, 404);\n }\n\n // Determine role\n const role = offer.peerId === peerId ? 'offerer' : 'answerer';\n\n const count = await storage.addIceCandidates(offerId, peerId, role, candidates);\n\n return c.json({ count }, 200);\n } catch (err) {\n console.error('Error adding ICE candidates:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /offers/:offerId/ice-candidates\n * Get ICE candidates for an offer\n */\n app.get('/offers/:offerId/ice-candidates', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const since = c.req.query('since');\n const peerId = getAuthenticatedPeerId(c);\n\n // Get offer to determine role\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n return c.json({ error: 'Offer not found' }, 404);\n }\n\n // Get candidates for opposite role\n const targetRole = offer.peerId === peerId ? 'answerer' : 'offerer';\n const sinceTimestamp = since ? parseInt(since, 10) : undefined;\n\n const candidates = await storage.getIceCandidates(offerId, targetRole, sinceTimestamp);\n\n return c.json({\n candidates: candidates.map(c => ({\n candidate: c.candidate,\n createdAt: c.createdAt\n }))\n }, 200);\n } catch (err) {\n console.error('Error getting ICE candidates:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n return app;\n}\n", "/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */\n/**\n * 5KB JS implementation of ed25519 EdDSA signatures.\n * Compliant with RFC8032, FIPS 186-5 & ZIP215.\n * @module\n * @example\n * ```js\nimport * as ed from '@noble/ed25519';\n(async () => {\n const secretKey = ed.utils.randomSecretKey();\n const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);\n const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present\n const signature = await ed.signAsync(message, secretKey);\n const isValid = await ed.verifyAsync(signature, message, pubKey);\n})();\n```\n */\n/**\n * Curve params. ed25519 is twisted edwards curve. Equation is \u2212x\u00B2 + y\u00B2 = -a + dx\u00B2y\u00B2.\n * * P = `2n**255n - 19n` // field over which calculations are done\n * * N = `2n**252n + 27742317777372353535851937790883648493n` // group order, amount of curve points\n * * h = 8 // cofactor\n * * a = `Fp.create(BigInt(-1))` // equation param\n * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param\n * * Gx, Gy are coordinates of Generator / base point\n */\nconst ed25519_CURVE = {\n p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,\n n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,\n h: 8n,\n a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,\n d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,\n Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,\n Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,\n};\nconst { p: P, n: N, Gx, Gy, a: _a, d: _d, h } = ed25519_CURVE;\nconst L = 32; // field / group byte length\nconst L2 = 64;\n// Helpers and Precomputes sections are reused between libraries\n// ## Helpers\n// ----------\nconst captureTrace = (...args) => {\n if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(...args);\n }\n};\nconst err = (message = '') => {\n const e = new Error(message);\n captureTrace(e, err);\n throw e;\n};\nconst isBig = (n) => typeof n === 'bigint'; // is big integer\nconst isStr = (s) => typeof s === 'string'; // is string\nconst isBytes = (a) => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n/** Asserts something is Uint8Array. */\nconst abytes = (value, length, title = '') => {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n err(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n};\n/** create Uint8Array */\nconst u8n = (len) => new Uint8Array(len);\nconst u8fr = (buf) => Uint8Array.from(buf);\nconst padh = (n, pad) => n.toString(16).padStart(pad, '0');\nconst bytesToHex = (b) => Array.from(abytes(b))\n .map((e) => padh(e, 2))\n .join('');\nconst C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters\nconst _ch = (ch) => {\n if (ch >= C._0 && ch <= C._9)\n return ch - C._0; // '2' => 50-48\n if (ch >= C.A && ch <= C.F)\n return ch - (C.A - 10); // 'B' => 66-(65-10)\n if (ch >= C.a && ch <= C.f)\n return ch - (C.a - 10); // 'b' => 98-(97-10)\n return;\n};\nconst hexToBytes = (hex) => {\n const e = 'hex invalid';\n if (!isStr(hex))\n return err(e);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2)\n return err(e);\n const array = u8n(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n // treat each char as ASCII\n const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16\n const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char\n if (n1 === undefined || n2 === undefined)\n return err(e);\n array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9\n }\n return array;\n};\nconst cr = () => globalThis?.crypto; // WebCrypto is available in all modern environments\nconst subtle = () => cr()?.subtle ?? err('crypto.subtle must be defined, consider polyfill');\n// prettier-ignore\nconst concatBytes = (...arrs) => {\n const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0)); // create u8a of summed length\n let pad = 0; // walk through each array,\n arrs.forEach(a => { r.set(a, pad); pad += a.length; }); // ensure they have proper type\n return r;\n};\n/** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */\nconst randomBytes = (len = L) => {\n const c = cr();\n return c.getRandomValues(u8n(len));\n};\nconst big = BigInt;\nconst assertRange = (n, min, max, msg = 'bad number: out of range') => (isBig(n) && min <= n && n < max ? n : err(msg));\n/** modular division */\nconst M = (a, b = P) => {\n const r = a % b;\n return r >= 0n ? r : b + r;\n};\nconst modN = (a) => M(a, N);\n/** Modular inversion using euclidean GCD (non-CT). No negative exponent for now. */\n// prettier-ignore\nconst invert = (num, md) => {\n if (num === 0n || md <= 0n)\n err('no inverse n=' + num + ' mod=' + md);\n let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;\n while (a !== 0n) {\n const q = b / a, r = b % a;\n const m = x - u * q, n = y - v * q;\n b = a, a = r, x = u, y = v, u = m, v = n;\n }\n return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point\n};\nconst callHash = (name) => {\n // @ts-ignore\n const fn = hashes[name];\n if (typeof fn !== 'function')\n err('hashes.' + name + ' not set');\n return fn;\n};\nconst hash = (msg) => callHash('sha512')(msg);\nconst apoint = (p) => (p instanceof Point ? p : err('Point expected'));\n// ## End of Helpers\n// -----------------\nconst B256 = 2n ** 256n;\n/** Point in XYZT extended coordinates. */\nclass Point {\n static BASE;\n static ZERO;\n X;\n Y;\n Z;\n T;\n constructor(X, Y, Z, T) {\n const max = B256;\n this.X = assertRange(X, 0n, max);\n this.Y = assertRange(Y, 0n, max);\n this.Z = assertRange(Z, 1n, max);\n this.T = assertRange(T, 0n, max);\n Object.freeze(this);\n }\n static CURVE() {\n return ed25519_CURVE;\n }\n static fromAffine(p) {\n return new Point(p.x, p.y, 1n, M(p.x * p.y));\n }\n /** RFC8032 5.1.3: Uint8Array to Point. */\n static fromBytes(hex, zip215 = false) {\n const d = _d;\n // Copy array to not mess it up.\n const normed = u8fr(abytes(hex, L));\n // adjust first LE byte = last BE byte\n const lastByte = hex[31];\n normed[31] = lastByte & ~0x80;\n const y = bytesToNumLE(normed);\n // zip215=true: 0 <= y < 2^256\n // zip215=false, RFC8032: 0 <= y < 2^255-19\n const max = zip215 ? B256 : P;\n assertRange(y, 0n, max);\n const y2 = M(y * y); // y\u00B2\n const u = M(y2 - 1n); // u=y\u00B2-1\n const v = M(d * y2 + 1n); // v=dy\u00B2+1\n let { isValid, value: x } = uvRatio(u, v); // (uv\u00B3)(uv\u2077)^(p-5)/8; square root\n if (!isValid)\n err('bad point: y not sqrt'); // not square root: bad point\n const isXOdd = (x & 1n) === 1n; // adjust sign of x coordinate\n const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit\n if (!zip215 && x === 0n && isLastByteOdd)\n err('bad point: x==0, isLastByteOdd'); // x=0, x_0=1\n if (isLastByteOdd !== isXOdd)\n x = M(-x);\n return new Point(x, y, 1n, M(x * y)); // Z=1, T=xy\n }\n static fromHex(hex, zip215) {\n return Point.fromBytes(hexToBytes(hex), zip215);\n }\n get x() {\n return this.toAffine().x;\n }\n get y() {\n return this.toAffine().y;\n }\n /** Checks if the point is valid and on-curve. */\n assertValidity() {\n const a = _a;\n const d = _d;\n const p = this;\n if (p.is0())\n return err('bad point: ZERO'); // TODO: optimize, with vars below?\n // Equation in affine coordinates: ax\u00B2 + y\u00B2 = 1 + dx\u00B2y\u00B2\n // Equation in projective coordinates (X/Z, Y/Z, Z): (aX\u00B2 + Y\u00B2)Z\u00B2 = Z\u2074 + dX\u00B2Y\u00B2\n const { X, Y, Z, T } = p;\n const X2 = M(X * X); // X\u00B2\n const Y2 = M(Y * Y); // Y\u00B2\n const Z2 = M(Z * Z); // Z\u00B2\n const Z4 = M(Z2 * Z2); // Z\u2074\n const aX2 = M(X2 * a); // aX\u00B2\n const left = M(Z2 * M(aX2 + Y2)); // (aX\u00B2 + Y\u00B2)Z\u00B2\n const right = M(Z4 + M(d * M(X2 * Y2))); // Z\u2074 + dX\u00B2Y\u00B2\n if (left !== right)\n return err('bad point: equation left != right (1)');\n // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T\n const XY = M(X * Y);\n const ZT = M(Z * T);\n if (XY !== ZT)\n return err('bad point: equation left != right (2)');\n return this;\n }\n /** Equality check: compare points P&Q. */\n equals(other) {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality\n const X1Z2 = M(X1 * Z2);\n const X2Z1 = M(X2 * Z1);\n const Y1Z2 = M(Y1 * Z2);\n const Y2Z1 = M(Y2 * Z1);\n return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;\n }\n is0() {\n return this.equals(I);\n }\n /** Flip point over y coordinate. */\n negate() {\n return new Point(M(-this.X), this.Y, this.Z, M(-this.T));\n }\n /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */\n double() {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const a = _a;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd\n const A = M(X1 * X1);\n const B = M(Y1 * Y1);\n const C = M(2n * M(Z1 * Z1));\n const D = M(a * A);\n const x1y1 = X1 + Y1;\n const E = M(M(x1y1 * x1y1) - A - B);\n const G = D + B;\n const F = G - C;\n const H = D - B;\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */\n add(other) {\n const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;\n const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve\n const a = _a;\n const d = _d;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3\n const A = M(X1 * X2);\n const B = M(Y1 * Y2);\n const C = M(T1 * d * T2);\n const D = M(Z1 * Z2);\n const E = M((X1 + Y1) * (X2 + Y2) - A - B);\n const F = M(D - C);\n const G = M(D + C);\n const H = M(B - a * A);\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n subtract(other) {\n return this.add(apoint(other).negate());\n }\n /**\n * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.\n * Uses {@link wNAF} for base point.\n * Uses fake point to mitigate side-channel leakage.\n * @param n scalar by which point is multiplied\n * @param safe safe mode guards against timing attacks; unsafe mode is faster\n */\n multiply(n, safe = true) {\n if (!safe && (n === 0n || this.is0()))\n return I;\n assertRange(n, 1n, N);\n if (n === 1n)\n return this;\n if (this.equals(G))\n return wNAF(n).p;\n // init result point & fake point\n let p = I;\n let f = G;\n for (let d = this; n > 0n; d = d.double(), n >>= 1n) {\n // if bit is present, add to point\n // if not present, add to fake, for timing safety\n if (n & 1n)\n p = p.add(d);\n else if (safe)\n f = f.add(d);\n }\n return p;\n }\n multiplyUnsafe(scalar) {\n return this.multiply(scalar, false);\n }\n /** Convert point to 2d xy affine point. (X, Y, Z) \u220B (x=X/Z, y=Y/Z) */\n toAffine() {\n const { X, Y, Z } = this;\n // fast-paths for ZERO point OR Z=1\n if (this.equals(I))\n return { x: 0n, y: 1n };\n const iz = invert(Z, P);\n // (Z * Z^-1) must be 1, otherwise bad math\n if (M(Z * iz) !== 1n)\n err('invalid inverse');\n // x = X*Z^-1; y = Y*Z^-1\n const x = M(X * iz);\n const y = M(Y * iz);\n return { x, y };\n }\n toBytes() {\n const { x, y } = this.assertValidity().toAffine();\n const b = numTo32bLE(y);\n // store sign in first LE byte\n b[31] |= x & 1n ? 0x80 : 0;\n return b;\n }\n toHex() {\n return bytesToHex(this.toBytes());\n }\n clearCofactor() {\n return this.multiply(big(h), false);\n }\n isSmallOrder() {\n return this.clearCofactor().is0();\n }\n isTorsionFree() {\n // Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`\n let p = this.multiply(N / 2n, false).double();\n if (N % 2n)\n p = p.add(this);\n return p.is0();\n }\n}\n/** Generator / base point */\nconst G = new Point(Gx, Gy, 1n, M(Gx * Gy));\n/** Identity / zero point */\nconst I = new Point(0n, 1n, 1n, 0n);\n// Static aliases\nPoint.BASE = G;\nPoint.ZERO = I;\nconst numTo32bLE = (num) => hexToBytes(padh(assertRange(num, 0n, B256), L2)).reverse();\nconst bytesToNumLE = (b) => big('0x' + bytesToHex(u8fr(abytes(b)).reverse()));\nconst pow2 = (x, power) => {\n // pow2(x, 4) == x^(2^4)\n let r = x;\n while (power-- > 0n) {\n r *= r;\n r %= P;\n }\n return r;\n};\n// prettier-ignore\nconst pow_2_252_3 = (x) => {\n const x2 = (x * x) % P; // x^2, bits 1\n const b2 = (x2 * x) % P; // x^3, bits 11\n const b4 = (pow2(b2, 2n) * b2) % P; // x^(2^4-1), bits 1111\n const b5 = (pow2(b4, 1n) * x) % P; // x^(2^5-1), bits 11111\n const b10 = (pow2(b5, 5n) * b5) % P; // x^(2^10)\n const b20 = (pow2(b10, 10n) * b10) % P; // x^(2^20)\n const b40 = (pow2(b20, 20n) * b20) % P; // x^(2^40)\n const b80 = (pow2(b40, 40n) * b40) % P; // x^(2^80)\n const b160 = (pow2(b80, 80n) * b80) % P; // x^(2^160)\n const b240 = (pow2(b160, 80n) * b80) % P; // x^(2^240)\n const b250 = (pow2(b240, 10n) * b10) % P; // x^(2^250)\n const pow_p_5_8 = (pow2(b250, 2n) * x) % P; // < To pow to (p+3)/8, multiply it by x.\n return { pow_p_5_8, b2 };\n};\nconst RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // \u221A-1\n// for sqrt comp\n// prettier-ignore\nconst uvRatio = (u, v) => {\n const v3 = M(v * v * v); // v\u00B3\n const v7 = M(v3 * v3 * v); // v\u2077\n const pow = pow_2_252_3(u * v7).pow_p_5_8; // (uv\u2077)^(p-5)/8\n let x = M(u * v3 * pow); // (uv\u00B3)(uv\u2077)^(p-5)/8\n const vx2 = M(v * x * x); // vx\u00B2\n const root1 = x; // First root candidate\n const root2 = M(x * RM1); // Second root candidate; RM1 is \u221A-1\n const useRoot1 = vx2 === u; // If vx\u00B2 = u (mod p), x is a square root\n const useRoot2 = vx2 === M(-u); // If vx\u00B2 = -u, set x <-- x * 2^((p-1)/4)\n const noRoot = vx2 === M(-u * RM1); // There is no valid root, vx\u00B2 = -u\u221A-1\n if (useRoot1)\n x = root1;\n if (useRoot2 || noRoot)\n x = root2; // We return root2 anyway, for const-time\n if ((M(x) & 1n) === 1n)\n x = M(-x); // edIsNegative\n return { isValid: useRoot1 || useRoot2, value: x };\n};\n// N == L, just weird naming\nconst modL_LE = (hash) => modN(bytesToNumLE(hash)); // modulo L; but little-endian\n/** hashes.sha512 should conform to the interface. */\n// TODO: rename\nconst sha512a = (...m) => hashes.sha512Async(concatBytes(...m)); // Async SHA512\nconst sha512s = (...m) => callHash('sha512')(concatBytes(...m));\n// RFC8032 5.1.5\nconst hash2extK = (hashed) => {\n // slice creates a copy, unlike subarray\n const head = hashed.slice(0, L);\n head[0] &= 248; // Clamp bits: 0b1111_1000\n head[31] &= 127; // 0b0111_1111\n head[31] |= 64; // 0b0100_0000\n const prefix = hashed.slice(L, L2); // secret key \"prefix\"\n const scalar = modL_LE(head); // modular division over curve order\n const point = G.multiply(scalar); // public key point\n const pointBytes = point.toBytes(); // point serialized to Uint8Array\n return { head, prefix, scalar, point, pointBytes };\n};\n// RFC8032 5.1.5; getPublicKey async, sync. Hash priv key and extract point.\nconst getExtendedPublicKeyAsync = (secretKey) => sha512a(abytes(secretKey, L)).then(hash2extK);\nconst getExtendedPublicKey = (secretKey) => hash2extK(sha512s(abytes(secretKey, L)));\n/** Creates 32-byte ed25519 public key from 32-byte secret key. Async. */\nconst getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes);\n/** Creates 32-byte ed25519 public key from 32-byte secret key. To use, set `hashes.sha512` first. */\nconst getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;\nconst hashFinishA = (res) => sha512a(res.hashable).then(res.finish);\nconst hashFinishS = (res) => res.finish(sha512s(res.hashable));\n// Code, shared between sync & async sign\nconst _sign = (e, rBytes, msg) => {\n const { pointBytes: P, scalar: s } = e;\n const r = modL_LE(rBytes); // r was created outside, reduce it modulo L\n const R = G.multiply(r).toBytes(); // R = [r]B\n const hashable = concatBytes(R, P, msg); // dom2(F, C) || R || A || PH(M)\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l\n return abytes(concatBytes(R, numTo32bLE(S)), L2); // 64-byte sig: 32b R.x + 32b LE(S)\n };\n return { hashable, finish };\n};\n/**\n * Signs message using secret key. Async.\n * Follows RFC8032 5.1.6.\n */\nconst signAsync = async (message, secretKey) => {\n const m = abytes(message);\n const e = await getExtendedPublicKeyAsync(secretKey);\n const rBytes = await sha512a(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishA(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\n/**\n * Signs message using secret key. To use, set `hashes.sha512` first.\n * Follows RFC8032 5.1.6.\n */\nconst sign = (message, secretKey) => {\n const m = abytes(message);\n const e = getExtendedPublicKey(secretKey);\n const rBytes = sha512s(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishS(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\nconst defaultVerifyOpts = { zip215: true };\nconst _verify = (sig, msg, pub, opts = defaultVerifyOpts) => {\n sig = abytes(sig, L2); // Signature hex str/Bytes, must be 64 bytes\n msg = abytes(msg); // Message hex str/Bytes\n pub = abytes(pub, L);\n const { zip215 } = opts; // switch between zip215 and rfc8032 verif\n let A;\n let R;\n let s;\n let SB;\n let hashable = Uint8Array.of();\n try {\n A = Point.fromBytes(pub, zip215); // public key A decoded\n R = Point.fromBytes(sig.slice(0, L), zip215); // 0 <= R < 2^256: ZIP215 R can be >= P\n s = bytesToNumLE(sig.slice(L, L2)); // Decode second half as an integer S\n SB = G.multiply(s, false); // in the range 0 <= s < L\n hashable = concatBytes(R.toBytes(), A.toBytes(), msg); // dom2(F, C) || R || A || PH(M)\n }\n catch (error) { }\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n if (SB == null)\n return false; // false if try-catch catched an error\n if (!zip215 && A.isSmallOrder())\n return false; // false for SBS: Strongly Binding Signature\n const k = modL_LE(hashed); // decode in little-endian, modulo L\n const RkA = R.add(A.multiply(k, false)); // [8]R + [8][k]A'\n return RkA.add(SB.negate()).clearCofactor().is0(); // [8][S]B = [8]R + [8][k]A'\n };\n return { hashable, finish };\n};\n/** Verifies signature on message and public key. Async. Follows RFC8032 5.1.7. */\nconst verifyAsync = async (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishA(_verify(signature, message, publicKey, opts));\n/** Verifies signature on message and public key. To use, set `hashes.sha512` first. Follows RFC8032 5.1.7. */\nconst verify = (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishS(_verify(signature, message, publicKey, opts));\n/** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */\nconst etc = {\n bytesToHex: bytesToHex,\n hexToBytes: hexToBytes,\n concatBytes: concatBytes,\n mod: M,\n invert: invert,\n randomBytes: randomBytes,\n};\nconst hashes = {\n sha512Async: async (message) => {\n const s = subtle();\n const m = concatBytes(message);\n return u8n(await s.digest('SHA-512', m.buffer));\n },\n sha512: undefined,\n};\n// FIPS 186 B.4.1 compliant key generation produces private keys\n// with modulo bias being neglible. takes >N+16 bytes, returns (hash mod n-1)+1\nconst randomSecretKey = (seed = randomBytes(L)) => seed;\nconst keygen = (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = getPublicKey(secretKey);\n return { secretKey, publicKey };\n};\nconst keygenAsync = async (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = await getPublicKeyAsync(secretKey);\n return { secretKey, publicKey };\n};\n/** ed25519-specific key utilities. */\nconst utils = {\n getExtendedPublicKeyAsync: getExtendedPublicKeyAsync,\n getExtendedPublicKey: getExtendedPublicKey,\n randomSecretKey: randomSecretKey,\n};\n// ## Precomputes\n// --------------\nconst W = 8; // W is window size\nconst scalarBits = 256;\nconst pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8, NOT 32 - see wNAF loop\nconst pwindowSize = 2 ** (W - 1); // 128 for W=8\nconst precompute = () => {\n const points = [];\n let p = G;\n let b = p;\n for (let w = 0; w < pwindows; w++) {\n b = p;\n points.push(b);\n for (let i = 1; i < pwindowSize; i++) {\n b = b.add(p);\n points.push(b);\n } // i=1, bc we skip 0\n p = b.double();\n }\n return points;\n};\nlet Gpows = undefined; // precomputes for base point G\n// const-time negate\nconst ctneg = (cnd, p) => {\n const n = p.negate();\n return cnd ? n : p;\n};\n/**\n * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by\n * caching multiples of G (base point). Cache is stored in 32MB of RAM.\n * Any time `G.multiply` is done, precomputes are used.\n * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.\n *\n * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,\n * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.\n *\n * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().\n */\nconst wNAF = (n) => {\n const comp = Gpows || (Gpows = precompute());\n let p = I;\n let f = G; // f must be G, or could become I in the end\n const pow_2_w = 2 ** W; // 256 for W=8\n const maxNum = pow_2_w; // 256 for W=8\n const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111\n const shiftBy = big(W); // 8 for W=8\n for (let w = 0; w < pwindows; w++) {\n let wbits = Number(n & mask); // extract W bits.\n n >>= shiftBy; // shift number by W bits.\n // We use negative indexes to reduce size of precomputed table by 2x.\n // Instead of needing precomputes 0..256, we only calculate them for 0..128.\n // If an index > 128 is found, we do (256-index) - where 256 is next window.\n // Naive: index +127 => 127, +224 => 224\n // Optimized: index +127 => 127, +224 => 256-32\n if (wbits > pwindowSize) {\n wbits -= maxNum;\n n += 1n;\n }\n const off = w * pwindowSize;\n const offF = off; // offsets, evaluate both\n const offP = off + Math.abs(wbits) - 1;\n const isEven = w % 2 !== 0; // conditions, evaluate both\n const isNeg = wbits < 0;\n if (wbits === 0) {\n // off == I: can't add it. Adding random offF instead.\n f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point\n }\n else {\n p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point\n }\n }\n if (n !== 0n)\n err('invalid wnaf');\n return { p, f }; // return both real and fake points for JIT\n};\n// !! Remove the export to easily use in REPL / browser console\nexport { etc, getPublicKey, getPublicKeyAsync, hash, hashes, keygen, keygenAsync, Point, sign, signAsync, utils, verify, verifyAsync, };\n", "/**\n * Crypto utilities for stateless peer authentication\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n * Uses @noble/ed25519 for Ed25519 signature verification\n */\n\nimport * as ed25519 from '@noble/ed25519';\n\n// Set SHA-512 hash function for ed25519 (required in @noble/ed25519 v3+)\n// Uses Web Crypto API (compatible with both Node.js and Cloudflare Workers)\ned25519.hashes.sha512Async = async (message: Uint8Array) => {\n return new Uint8Array(await crypto.subtle.digest('SHA-512', message as BufferSource));\n};\n\nconst ALGORITHM = 'AES-GCM';\nconst IV_LENGTH = 12; // 96 bits for GCM\nconst KEY_LENGTH = 32; // 256 bits\n\n// Username validation\nconst USERNAME_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;\nconst USERNAME_MIN_LENGTH = 3;\nconst USERNAME_MAX_LENGTH = 32;\n\n// Timestamp validation (5 minutes tolerance)\nconst TIMESTAMP_TOLERANCE_MS = 5 * 60 * 1000;\n\n/**\n * Generates a random peer ID (16 bytes = 32 hex chars)\n */\nexport function generatePeerId(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generates a random secret key for encryption (32 bytes = 64 hex chars)\n */\nexport function generateSecretKey(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(KEY_LENGTH));\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Convert hex string to Uint8Array\n */\nfunction hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Convert Uint8Array to base64 string\n */\nfunction bytesToBase64(bytes: Uint8Array): string {\n const binString = Array.from(bytes, (byte) =>\n String.fromCodePoint(byte)\n ).join('');\n return btoa(binString);\n}\n\n/**\n * Convert base64 string to Uint8Array\n */\nfunction base64ToBytes(base64: string): Uint8Array {\n const binString = atob(base64);\n return Uint8Array.from(binString, (char) => char.codePointAt(0)!);\n}\n\n/**\n * Encrypts a peer ID using the server secret key\n * Returns base64-encoded encrypted data (IV + ciphertext)\n */\nexport async function encryptPeerId(peerId: string, secretKeyHex: string): Promise<string> {\n const keyBytes = hexToBytes(secretKeyHex);\n\n if (keyBytes.length !== KEY_LENGTH) {\n throw new Error(`Secret key must be ${KEY_LENGTH * 2} hex characters (${KEY_LENGTH} bytes)`);\n }\n\n // Import key\n const key = await crypto.subtle.importKey(\n 'raw',\n keyBytes,\n { name: ALGORITHM, length: 256 },\n false,\n ['encrypt']\n );\n\n // Generate random IV\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n\n // Encrypt peer ID\n const encoder = new TextEncoder();\n const data = encoder.encode(peerId);\n\n const encrypted = await crypto.subtle.encrypt(\n { name: ALGORITHM, iv },\n key,\n data\n );\n\n // Combine IV + ciphertext and encode as base64\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv, 0);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return bytesToBase64(combined);\n}\n\n/**\n * Decrypts an encrypted peer ID secret\n * Returns the plaintext peer ID or throws if decryption fails\n */\nexport async function decryptPeerId(encryptedSecret: string, secretKeyHex: string): Promise<string> {\n try {\n const keyBytes = hexToBytes(secretKeyHex);\n\n if (keyBytes.length !== KEY_LENGTH) {\n throw new Error(`Secret key must be ${KEY_LENGTH * 2} hex characters (${KEY_LENGTH} bytes)`);\n }\n\n // Decode base64\n const combined = base64ToBytes(encryptedSecret);\n\n // Extract IV and ciphertext\n const iv = combined.slice(0, IV_LENGTH);\n const ciphertext = combined.slice(IV_LENGTH);\n\n // Import key\n const key = await crypto.subtle.importKey(\n 'raw',\n keyBytes,\n { name: ALGORITHM, length: 256 },\n false,\n ['decrypt']\n );\n\n // Decrypt\n const decrypted = await crypto.subtle.decrypt(\n { name: ALGORITHM, iv },\n key,\n ciphertext\n );\n\n const decoder = new TextDecoder();\n return decoder.decode(decrypted);\n } catch (err) {\n throw new Error('Failed to decrypt peer ID: invalid secret or secret key');\n }\n}\n\n/**\n * Validates that a peer ID and secret match\n * Returns true if valid, false otherwise\n */\nexport async function validateCredentials(peerId: string, encryptedSecret: string, secretKey: string): Promise<boolean> {\n try {\n const decryptedPeerId = await decryptPeerId(encryptedSecret, secretKey);\n return decryptedPeerId === peerId;\n } catch {\n return false;\n }\n}\n\n// ===== Username and Ed25519 Signature Utilities =====\n\n/**\n * Validates username format\n * Rules: 3-32 chars, lowercase alphanumeric + dash, must start/end with alphanumeric\n */\nexport function validateUsername(username: string): { valid: boolean; error?: string } {\n if (typeof username !== 'string') {\n return { valid: false, error: 'Username must be a string' };\n }\n\n if (username.length < USERNAME_MIN_LENGTH) {\n return { valid: false, error: `Username must be at least ${USERNAME_MIN_LENGTH} characters` };\n }\n\n if (username.length > USERNAME_MAX_LENGTH) {\n return { valid: false, error: `Username must be at most ${USERNAME_MAX_LENGTH} characters` };\n }\n\n if (!USERNAME_REGEX.test(username)) {\n return { valid: false, error: 'Username must be lowercase alphanumeric with optional dashes, and start/end with alphanumeric' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates service FQN format (service-name@version)\n * Service name: reverse domain notation (com.example.service)\n * Version: semantic versioning (1.0.0, 2.1.3-beta, etc.)\n */\nexport function validateServiceFqn(fqn: string): { valid: boolean; error?: string } {\n if (typeof fqn !== 'string') {\n return { valid: false, error: 'Service FQN must be a string' };\n }\n\n // Split into service name and version\n const parts = fqn.split('@');\n if (parts.length !== 2) {\n return { valid: false, error: 'Service FQN must be in format: service-name@version' };\n }\n\n const [serviceName, version] = parts;\n\n // Validate service name (reverse domain notation)\n const serviceNameRegex = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/;\n if (!serviceNameRegex.test(serviceName)) {\n return { valid: false, error: 'Service name must be reverse domain notation (e.g., com.example.service)' };\n }\n\n if (serviceName.length < 3 || serviceName.length > 128) {\n return { valid: false, error: 'Service name must be 3-128 characters' };\n }\n\n // Validate version (semantic versioning)\n const versionRegex = /^[0-9]+\\.[0-9]+\\.[0-9]+(-[a-z0-9.-]+)?$/;\n if (!versionRegex.test(version)) {\n return { valid: false, error: 'Version must be semantic versioning (e.g., 1.0.0, 2.1.3-beta)' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates timestamp is within acceptable range (prevents replay attacks)\n */\nexport function validateTimestamp(timestamp: number): { valid: boolean; error?: string } {\n if (typeof timestamp !== 'number' || !Number.isFinite(timestamp)) {\n return { valid: false, error: 'Timestamp must be a finite number' };\n }\n\n const now = Date.now();\n const diff = Math.abs(now - timestamp);\n\n if (diff > TIMESTAMP_TOLERANCE_MS) {\n return { valid: false, error: `Timestamp too old or too far in future (tolerance: ${TIMESTAMP_TOLERANCE_MS / 1000}s)` };\n }\n\n return { valid: true };\n}\n\n/**\n * Verifies Ed25519 signature\n * @param publicKey Base64-encoded Ed25519 public key (32 bytes)\n * @param signature Base64-encoded Ed25519 signature (64 bytes)\n * @param message Message that was signed (UTF-8 string)\n * @returns true if signature is valid, false otherwise\n */\nexport async function verifyEd25519Signature(\n publicKey: string,\n signature: string,\n message: string\n): Promise<boolean> {\n try {\n // Decode base64 to bytes\n const publicKeyBytes = base64ToBytes(publicKey);\n const signatureBytes = base64ToBytes(signature);\n\n // Encode message as UTF-8\n const encoder = new TextEncoder();\n const messageBytes = encoder.encode(message);\n\n // Verify signature using @noble/ed25519\n const isValid = await ed25519.verify(signatureBytes, messageBytes, publicKeyBytes);\n return isValid;\n } catch (err) {\n console.error('Ed25519 signature verification failed:', err);\n return false;\n }\n}\n\n/**\n * Validates a username claim request\n * Verifies format, timestamp, and signature\n */\nexport async function validateUsernameClaim(\n username: string,\n publicKey: string,\n signature: string,\n message: string\n): Promise<{ valid: boolean; error?: string }> {\n // Validate username format\n const usernameCheck = validateUsername(username);\n if (!usernameCheck.valid) {\n return usernameCheck;\n }\n\n // Parse message format: \"claim:{username}:{timestamp}\"\n const parts = message.split(':');\n if (parts.length !== 3 || parts[0] !== 'claim' || parts[1] !== username) {\n return { valid: false, error: 'Invalid message format (expected: claim:{username}:{timestamp})' };\n }\n\n const timestamp = parseInt(parts[2], 10);\n if (isNaN(timestamp)) {\n return { valid: false, error: 'Invalid timestamp in message' };\n }\n\n // Validate timestamp\n const timestampCheck = validateTimestamp(timestamp);\n if (!timestampCheck.valid) {\n return timestampCheck;\n }\n\n // Verify signature\n const signatureValid = await verifyEd25519Signature(publicKey, signature, message);\n if (!signatureValid) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n return { valid: true };\n}\n", "import { Context, Next } from 'hono';\nimport { validateCredentials } from '../crypto.ts';\n\n/**\n * Authentication middleware for Rondevu\n * Validates Bearer token in format: {peerId}:{encryptedSecret}\n */\nexport function createAuthMiddleware(authSecret: string) {\n return async (c: Context, next: Next) => {\n const authHeader = c.req.header('Authorization');\n\n if (!authHeader) {\n return c.json({ error: 'Missing Authorization header' }, 401);\n }\n\n // Expect format: Bearer {peerId}:{secret}\n const parts = authHeader.split(' ');\n if (parts.length !== 2 || parts[0] !== 'Bearer') {\n return c.json({ error: 'Invalid Authorization header format. Expected: Bearer {peerId}:{secret}' }, 401);\n }\n\n const credentials = parts[1].split(':');\n if (credentials.length !== 2) {\n return c.json({ error: 'Invalid credentials format. Expected: {peerId}:{secret}' }, 401);\n }\n\n const [peerId, encryptedSecret] = credentials;\n\n // Validate credentials (async operation)\n const isValid = await validateCredentials(peerId, encryptedSecret, authSecret);\n if (!isValid) {\n return c.json({ error: 'Invalid credentials' }, 401);\n }\n\n // Attach peer ID to context for use in handlers\n c.set('peerId', peerId);\n\n await next();\n };\n}\n\n/**\n * Helper to get authenticated peer ID from context\n */\nexport function getAuthenticatedPeerId(c: Context): string {\n const peerId = c.get('peerId');\n if (!peerId) {\n throw new Error('No authenticated peer ID in context');\n }\n return peerId;\n}\n", "import { generateSecretKey } from './crypto.ts';\n\n/**\n * Application configuration\n * Reads from environment variables with sensible defaults\n */\nexport interface Config {\n port: number;\n storageType: 'sqlite' | 'memory';\n storagePath: string;\n corsOrigins: string[];\n version: string;\n authSecret: string;\n offerDefaultTtl: number;\n offerMaxTtl: number;\n offerMinTtl: number;\n cleanupInterval: number;\n maxOffersPerRequest: number;\n maxTopicsPerOffer: number;\n}\n\n/**\n * Loads configuration from environment variables\n */\nexport function loadConfig(): Config {\n // Generate or load auth secret\n let authSecret = process.env.AUTH_SECRET;\n if (!authSecret) {\n authSecret = generateSecretKey();\n console.warn('WARNING: No AUTH_SECRET provided. Generated temporary secret:', authSecret);\n console.warn('All peer credentials will be invalidated on server restart.');\n console.warn('Set AUTH_SECRET environment variable to persist credentials across restarts.');\n }\n\n return {\n port: parseInt(process.env.PORT || '3000', 10),\n storageType: (process.env.STORAGE_TYPE || 'sqlite') as 'sqlite' | 'memory',\n storagePath: process.env.STORAGE_PATH || ':memory:',\n corsOrigins: process.env.CORS_ORIGINS\n ? process.env.CORS_ORIGINS.split(',').map(o => o.trim())\n : ['*'],\n version: process.env.VERSION || 'unknown',\n authSecret,\n offerDefaultTtl: parseInt(process.env.OFFER_DEFAULT_TTL || '60000', 10),\n offerMaxTtl: parseInt(process.env.OFFER_MAX_TTL || '86400000', 10),\n offerMinTtl: parseInt(process.env.OFFER_MIN_TTL || '60000', 10),\n cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL || '60000', 10),\n maxOffersPerRequest: parseInt(process.env.MAX_OFFERS_PER_REQUEST || '100', 10),\n maxTopicsPerOffer: parseInt(process.env.MAX_TOPICS_PER_OFFER || '50', 10),\n };\n}\n", "import Database from 'better-sqlite3';\nimport { randomUUID } from 'node:crypto';\nimport {\n Storage,\n Offer,\n IceCandidate,\n CreateOfferRequest,\n Username,\n ClaimUsernameRequest,\n Service,\n CreateServiceRequest,\n ServiceInfo,\n} from './types.ts';\nimport { generateOfferHash } from './hash-id.ts';\n\nconst YEAR_IN_MS = 365 * 24 * 60 * 60 * 1000; // 365 days\n\n/**\n * SQLite storage adapter for rondevu DNS-like system\n * Supports both file-based and in-memory databases\n */\nexport class SQLiteStorage implements Storage {\n private db: Database.Database;\n\n /**\n * Creates a new SQLite storage instance\n * @param path Path to SQLite database file, or ':memory:' for in-memory database\n */\n constructor(path: string = ':memory:') {\n this.db = new Database(path);\n this.initializeDatabase();\n }\n\n /**\n * Initializes database schema with username and service-based structure\n */\n private initializeDatabase(): void {\n this.db.exec(`\n -- Offers table (no topics)\n CREATE TABLE IF NOT EXISTS offers (\n id TEXT PRIMARY KEY,\n peer_id TEXT NOT NULL,\n sdp TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_seen INTEGER NOT NULL,\n secret TEXT,\n answerer_peer_id TEXT,\n answer_sdp TEXT,\n answered_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_offers_peer ON offers(peer_id);\n CREATE INDEX IF NOT EXISTS idx_offers_expires ON offers(expires_at);\n CREATE INDEX IF NOT EXISTS idx_offers_last_seen ON offers(last_seen);\n CREATE INDEX IF NOT EXISTS idx_offers_answerer ON offers(answerer_peer_id);\n\n -- ICE candidates table\n CREATE TABLE IF NOT EXISTS ice_candidates (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n offer_id TEXT NOT NULL,\n peer_id TEXT NOT NULL,\n role TEXT NOT NULL CHECK(role IN ('offerer', 'answerer')),\n candidate TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n FOREIGN KEY (offer_id) REFERENCES offers(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_ice_offer ON ice_candidates(offer_id);\n CREATE INDEX IF NOT EXISTS idx_ice_peer ON ice_candidates(peer_id);\n CREATE INDEX IF NOT EXISTS idx_ice_created ON ice_candidates(created_at);\n\n -- Usernames table\n CREATE TABLE IF NOT EXISTS usernames (\n username TEXT PRIMARY KEY,\n public_key TEXT NOT NULL UNIQUE,\n claimed_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_used INTEGER NOT NULL,\n metadata TEXT,\n CHECK(length(username) >= 3 AND length(username) <= 32)\n );\n\n CREATE INDEX IF NOT EXISTS idx_usernames_expires ON usernames(expires_at);\n CREATE INDEX IF NOT EXISTS idx_usernames_public_key ON usernames(public_key);\n\n -- Services table\n CREATE TABLE IF NOT EXISTS services (\n id TEXT PRIMARY KEY,\n username TEXT NOT NULL,\n service_fqn TEXT NOT NULL,\n offer_id TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n is_public INTEGER NOT NULL DEFAULT 0,\n metadata TEXT,\n FOREIGN KEY (username) REFERENCES usernames(username) ON DELETE CASCADE,\n FOREIGN KEY (offer_id) REFERENCES offers(id) ON DELETE CASCADE,\n UNIQUE(username, service_fqn)\n );\n\n CREATE INDEX IF NOT EXISTS idx_services_username ON services(username);\n CREATE INDEX IF NOT EXISTS idx_services_fqn ON services(service_fqn);\n CREATE INDEX IF NOT EXISTS idx_services_expires ON services(expires_at);\n CREATE INDEX IF NOT EXISTS idx_services_offer ON services(offer_id);\n\n -- Service index table (privacy layer)\n CREATE TABLE IF NOT EXISTS service_index (\n uuid TEXT PRIMARY KEY,\n service_id TEXT NOT NULL,\n username TEXT NOT NULL,\n service_fqn TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_service_index_username ON service_index(username);\n CREATE INDEX IF NOT EXISTS idx_service_index_expires ON service_index(expires_at);\n `);\n\n // Enable foreign keys\n this.db.pragma('foreign_keys = ON');\n }\n\n // ===== Offer Management =====\n\n async createOffers(offers: CreateOfferRequest[]): Promise<Offer[]> {\n const created: Offer[] = [];\n\n // Generate hash-based IDs for all offers first\n const offersWithIds = await Promise.all(\n offers.map(async (offer) => ({\n ...offer,\n id: offer.id || await generateOfferHash(offer.sdp, []),\n }))\n );\n\n // Use transaction for atomic creation\n const transaction = this.db.transaction((offersWithIds: (CreateOfferRequest & { id: string })[]) => {\n const offerStmt = this.db.prepare(`\n INSERT INTO offers (id, peer_id, sdp, created_at, expires_at, last_seen, secret)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const offer of offersWithIds) {\n const now = Date.now();\n\n // Insert offer\n offerStmt.run(\n offer.id,\n offer.peerId,\n offer.sdp,\n now,\n offer.expiresAt,\n now,\n offer.secret || null\n );\n\n created.push({\n id: offer.id,\n peerId: offer.peerId,\n sdp: offer.sdp,\n createdAt: now,\n expiresAt: offer.expiresAt,\n lastSeen: now,\n secret: offer.secret,\n });\n }\n });\n\n transaction(offersWithIds);\n return created;\n }\n\n async getOffersByPeerId(peerId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE peer_id = ? AND expires_at > ?\n ORDER BY last_seen DESC\n `);\n\n const rows = stmt.all(peerId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n async getOfferById(offerId: string): Promise<Offer | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(offerId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToOffer(row);\n }\n\n async deleteOffer(offerId: string, ownerPeerId: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM offers\n WHERE id = ? AND peer_id = ?\n `);\n\n const result = stmt.run(offerId, ownerPeerId);\n return result.changes > 0;\n }\n\n async deleteExpiredOffers(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM offers WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async answerOffer(\n offerId: string,\n answererPeerId: string,\n answerSdp: string,\n secret?: string\n ): Promise<{ success: boolean; error?: string }> {\n // Check if offer exists and is not expired\n const offer = await this.getOfferById(offerId);\n\n if (!offer) {\n return {\n success: false,\n error: 'Offer not found or expired'\n };\n }\n\n // Verify secret if offer is protected\n if (offer.secret && offer.secret !== secret) {\n return {\n success: false,\n error: 'Invalid or missing secret'\n };\n }\n\n // Check if offer already has an answerer\n if (offer.answererPeerId) {\n return {\n success: false,\n error: 'Offer already answered'\n };\n }\n\n // Update offer with answer\n const stmt = this.db.prepare(`\n UPDATE offers\n SET answerer_peer_id = ?, answer_sdp = ?, answered_at = ?\n WHERE id = ? AND answerer_peer_id IS NULL\n `);\n\n const result = stmt.run(answererPeerId, answerSdp, Date.now(), offerId);\n\n if (result.changes === 0) {\n return {\n success: false,\n error: 'Offer already answered (race condition)'\n };\n }\n\n return { success: true };\n }\n\n async getAnsweredOffers(offererPeerId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE peer_id = ? AND answerer_peer_id IS NOT NULL AND expires_at > ?\n ORDER BY answered_at DESC\n `);\n\n const rows = stmt.all(offererPeerId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n // ===== ICE Candidate Management =====\n\n async addIceCandidates(\n offerId: string,\n peerId: string,\n role: 'offerer' | 'answerer',\n candidates: any[]\n ): Promise<number> {\n const stmt = this.db.prepare(`\n INSERT INTO ice_candidates (offer_id, peer_id, role, candidate, created_at)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n const baseTimestamp = Date.now();\n const transaction = this.db.transaction((candidates: any[]) => {\n for (let i = 0; i < candidates.length; i++) {\n stmt.run(\n offerId,\n peerId,\n role,\n JSON.stringify(candidates[i]),\n baseTimestamp + i\n );\n }\n });\n\n transaction(candidates);\n return candidates.length;\n }\n\n async getIceCandidates(\n offerId: string,\n targetRole: 'offerer' | 'answerer',\n since?: number\n ): Promise<IceCandidate[]> {\n let query = `\n SELECT * FROM ice_candidates\n WHERE offer_id = ? AND role = ?\n `;\n\n const params: any[] = [offerId, targetRole];\n\n if (since !== undefined) {\n query += ' AND created_at > ?';\n params.push(since);\n }\n\n query += ' ORDER BY created_at ASC';\n\n const stmt = this.db.prepare(query);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n offerId: row.offer_id,\n peerId: row.peer_id,\n role: row.role,\n candidate: JSON.parse(row.candidate),\n createdAt: row.created_at,\n }));\n }\n\n // ===== Username Management =====\n\n async claimUsername(request: ClaimUsernameRequest): Promise<Username> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n // Try to insert or update\n const stmt = this.db.prepare(`\n INSERT INTO usernames (username, public_key, claimed_at, expires_at, last_used, metadata)\n VALUES (?, ?, ?, ?, ?, NULL)\n ON CONFLICT(username) DO UPDATE SET\n expires_at = ?,\n last_used = ?\n WHERE public_key = ?\n `);\n\n const result = stmt.run(\n request.username,\n request.publicKey,\n now,\n expiresAt,\n now,\n expiresAt,\n now,\n request.publicKey\n );\n\n if (result.changes === 0) {\n throw new Error('Username already claimed by different public key');\n }\n\n return {\n username: request.username,\n publicKey: request.publicKey,\n claimedAt: now,\n expiresAt,\n lastUsed: now,\n };\n }\n\n async getUsername(username: string): Promise<Username | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM usernames\n WHERE username = ? AND expires_at > ?\n `);\n\n const row = stmt.get(username, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return {\n username: row.username,\n publicKey: row.public_key,\n claimedAt: row.claimed_at,\n expiresAt: row.expires_at,\n lastUsed: row.last_used,\n metadata: row.metadata || undefined,\n };\n }\n\n async touchUsername(username: string): Promise<boolean> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n const stmt = this.db.prepare(`\n UPDATE usernames\n SET last_used = ?, expires_at = ?\n WHERE username = ? AND expires_at > ?\n `);\n\n const result = stmt.run(now, expiresAt, username, now);\n return result.changes > 0;\n }\n\n async deleteExpiredUsernames(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM usernames WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n // ===== Service Management =====\n\n async createService(request: CreateServiceRequest): Promise<{\n service: Service;\n indexUuid: string;\n }> {\n const serviceId = randomUUID();\n const indexUuid = randomUUID();\n const now = Date.now();\n\n const transaction = this.db.transaction(() => {\n // Insert service\n const serviceStmt = this.db.prepare(`\n INSERT INTO services (id, username, service_fqn, offer_id, created_at, expires_at, is_public, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n serviceStmt.run(\n serviceId,\n request.username,\n request.serviceFqn,\n request.offerId,\n now,\n request.expiresAt,\n request.isPublic ? 1 : 0,\n request.metadata || null\n );\n\n // Insert service index\n const indexStmt = this.db.prepare(`\n INSERT INTO service_index (uuid, service_id, username, service_fqn, created_at, expires_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n indexStmt.run(\n indexUuid,\n serviceId,\n request.username,\n request.serviceFqn,\n now,\n request.expiresAt\n );\n\n // Touch username to extend expiry\n this.touchUsername(request.username);\n });\n\n transaction();\n\n return {\n service: {\n id: serviceId,\n username: request.username,\n serviceFqn: request.serviceFqn,\n offerId: request.offerId,\n createdAt: now,\n expiresAt: request.expiresAt,\n isPublic: request.isPublic || false,\n metadata: request.metadata,\n },\n indexUuid,\n };\n }\n\n async getServiceById(serviceId: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM services\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(serviceId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async getServiceByUuid(uuid: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT s.* FROM services s\n INNER JOIN service_index si ON s.id = si.service_id\n WHERE si.uuid = ? AND s.expires_at > ?\n `);\n\n const row = stmt.get(uuid, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async listServicesForUsername(username: string): Promise<ServiceInfo[]> {\n const stmt = this.db.prepare(`\n SELECT si.uuid, s.is_public, s.service_fqn, s.metadata\n FROM service_index si\n INNER JOIN services s ON si.service_id = s.id\n WHERE si.username = ? AND si.expires_at > ?\n ORDER BY s.created_at DESC\n `);\n\n const rows = stmt.all(username, Date.now()) as any[];\n\n return rows.map(row => ({\n uuid: row.uuid,\n isPublic: row.is_public === 1,\n serviceFqn: row.is_public === 1 ? row.service_fqn : undefined,\n metadata: row.is_public === 1 ? row.metadata || undefined : undefined,\n }));\n }\n\n async queryService(username: string, serviceFqn: string): Promise<string | null> {\n const stmt = this.db.prepare(`\n SELECT si.uuid FROM service_index si\n INNER JOIN services s ON si.service_id = s.id\n WHERE si.username = ? AND si.service_fqn = ? AND si.expires_at > ?\n `);\n\n const row = stmt.get(username, serviceFqn, Date.now()) as any;\n\n return row ? row.uuid : null;\n }\n\n async deleteService(serviceId: string, username: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM services\n WHERE id = ? AND username = ?\n `);\n\n const result = stmt.run(serviceId, username);\n return result.changes > 0;\n }\n\n async deleteExpiredServices(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM services WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n\n // ===== Helper Methods =====\n\n /**\n * Helper method to convert database row to Offer object\n */\n private rowToOffer(row: any): Offer {\n return {\n id: row.id,\n peerId: row.peer_id,\n sdp: row.sdp,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n lastSeen: row.last_seen,\n secret: row.secret || undefined,\n answererPeerId: row.answerer_peer_id || undefined,\n answerSdp: row.answer_sdp || undefined,\n answeredAt: row.answered_at || undefined,\n };\n }\n\n /**\n * Helper method to convert database row to Service object\n */\n private rowToService(row: any): Service {\n return {\n id: row.id,\n username: row.username,\n serviceFqn: row.service_fqn,\n offerId: row.offer_id,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n isPublic: row.is_public === 1,\n metadata: row.metadata || undefined,\n };\n }\n}\n", "/**\n * Generates a content-based offer ID using SHA-256 hash\n * Creates deterministic IDs based on offer content (sdp, topics)\n * PeerID is not included as it's inferred from authentication\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n *\n * @param sdp - The WebRTC SDP offer\n * @param topics - Array of topic strings\n * @returns SHA-256 hash of the sanitized offer content\n */\nexport async function generateOfferHash(\n sdp: string,\n topics: string[]\n): Promise<string> {\n // Sanitize and normalize the offer content\n // Only include core offer content (not peerId - that's inferred from auth)\n const sanitizedOffer = {\n sdp,\n topics: [...topics].sort(), // Sort topics for consistency\n };\n\n // Create non-prettified JSON string\n const jsonString = JSON.stringify(sanitizedOffer);\n\n // Convert string to Uint8Array for hashing\n const encoder = new TextEncoder();\n const data = encoder.encode(jsonString);\n\n // Generate SHA-256 hash\n const hashBuffer = await crypto.subtle.digest('SHA-256', data);\n\n // Convert hash to hex string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\n\n return hashHex;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { serve } from '@hono/node-server';\nimport { createApp } from './app.ts';\nimport { loadConfig } from './config.ts';\nimport { SQLiteStorage } from './storage/sqlite.ts';\nimport { Storage } from './storage/types.ts';\n\n/**\n * Main entry point for the standalone Node.js server\n */\nasync function main() {\n const config = loadConfig();\n\n console.log('Starting Rondevu server...');\n console.log('Configuration:', {\n port: config.port,\n storageType: config.storageType,\n storagePath: config.storagePath,\n offerDefaultTtl: `${config.offerDefaultTtl}ms`,\n offerMaxTtl: `${config.offerMaxTtl}ms`,\n offerMinTtl: `${config.offerMinTtl}ms`,\n cleanupInterval: `${config.cleanupInterval}ms`,\n maxOffersPerRequest: config.maxOffersPerRequest,\n maxTopicsPerOffer: config.maxTopicsPerOffer,\n corsOrigins: config.corsOrigins,\n version: config.version,\n });\n\n let storage: Storage;\n\n if (config.storageType === 'sqlite') {\n storage = new SQLiteStorage(config.storagePath);\n console.log('Using SQLite storage');\n } else {\n throw new Error('Unsupported storage type');\n }\n\n // Start periodic cleanup of expired offers\n const cleanupInterval = setInterval(async () => {\n try {\n const now = Date.now();\n const deleted = await storage.deleteExpiredOffers(now);\n if (deleted > 0) {\n console.log(`Cleanup: Deleted ${deleted} expired offer(s)`);\n }\n } catch (err) {\n console.error('Cleanup error:', err);\n }\n }, config.cleanupInterval);\n\n const app = createApp(storage, config);\n\n const server = serve({\n fetch: app.fetch,\n port: config.port,\n });\n\n console.log(`Server running on http://localhost:${config.port}`);\n console.log('Ready to accept connections');\n\n // Graceful shutdown handler\n const shutdown = async () => {\n console.log('\\nShutting down gracefully...');\n clearInterval(cleanupInterval);\n await storage.close();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n", "import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { Storage } from './storage/types.ts';\nimport { Config } from './config.ts';\nimport { createAuthMiddleware, getAuthenticatedPeerId } from './middleware/auth.ts';\nimport { generatePeerId, encryptPeerId, validateUsernameClaim, validateServiceFqn } from './crypto.ts';\nimport type { Context } from 'hono';\n\n/**\n * Creates the Hono application with username and service-based WebRTC signaling\n */\nexport function createApp(storage: Storage, config: Config) {\n const app = new Hono();\n\n // Create auth middleware\n const authMiddleware = createAuthMiddleware(config.authSecret);\n\n // Enable CORS\n app.use('/*', cors({\n origin: (origin) => {\n if (config.corsOrigins.length === 1 && config.corsOrigins[0] === '*') {\n return origin;\n }\n if (config.corsOrigins.includes(origin)) {\n return origin;\n }\n return config.corsOrigins[0];\n },\n allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Origin', 'Authorization'],\n exposeHeaders: ['Content-Type'],\n maxAge: 600,\n credentials: true,\n }));\n\n // ===== General Endpoints =====\n\n /**\n * GET /\n * Returns server information\n */\n app.get('/', (c) => {\n return c.json({\n version: config.version,\n name: 'Rondevu',\n description: 'DNS-like WebRTC signaling with username claiming and service discovery'\n });\n });\n\n /**\n * GET /health\n * Health check endpoint\n */\n app.get('/health', (c) => {\n return c.json({\n status: 'ok',\n timestamp: Date.now(),\n version: config.version\n });\n });\n\n /**\n * POST /register\n * Register a new peer (still needed for peer ID generation)\n */\n app.post('/register', async (c) => {\n try {\n const peerId = generatePeerId();\n const secret = await encryptPeerId(peerId, config.authSecret);\n\n return c.json({\n peerId,\n secret\n }, 200);\n } catch (err) {\n console.error('Error registering peer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Username Management =====\n\n /**\n * POST /usernames/claim\n * Claim a username with cryptographic proof\n */\n app.post('/usernames/claim', async (c) => {\n try {\n const body = await c.req.json();\n const { username, publicKey, signature, message } = body;\n\n if (!username || !publicKey || !signature || !message) {\n return c.json({ error: 'Missing required parameters: username, publicKey, signature, message' }, 400);\n }\n\n // Validate claim\n const validation = await validateUsernameClaim(username, publicKey, signature, message);\n if (!validation.valid) {\n return c.json({ error: validation.error }, 400);\n }\n\n // Attempt to claim username\n try {\n const claimed = await storage.claimUsername({\n username,\n publicKey,\n signature,\n message\n });\n\n return c.json({\n username: claimed.username,\n claimedAt: claimed.claimedAt,\n expiresAt: claimed.expiresAt\n }, 200);\n } catch (err: any) {\n if (err.message?.includes('already claimed')) {\n return c.json({ error: 'Username already claimed by different public key' }, 409);\n }\n throw err;\n }\n } catch (err) {\n console.error('Error claiming username:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /usernames/:username\n * Check if username is available or get claim info\n */\n app.get('/usernames/:username', async (c) => {\n try {\n const username = c.req.param('username');\n\n const claimed = await storage.getUsername(username);\n\n if (!claimed) {\n return c.json({\n username,\n available: true\n }, 200);\n }\n\n return c.json({\n username: claimed.username,\n available: false,\n claimedAt: claimed.claimedAt,\n expiresAt: claimed.expiresAt,\n publicKey: claimed.publicKey\n }, 200);\n } catch (err) {\n console.error('Error checking username:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /usernames/:username/services\n * List services for a username (privacy-preserving)\n */\n app.get('/usernames/:username/services', async (c) => {\n try {\n const username = c.req.param('username');\n\n const services = await storage.listServicesForUsername(username);\n\n return c.json({\n username,\n services\n }, 200);\n } catch (err) {\n console.error('Error listing services:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Service Management =====\n\n /**\n * POST /services\n * Publish a service\n */\n app.post('/services', authMiddleware, async (c) => {\n try {\n const body = await c.req.json();\n const { username, serviceFqn, sdp, ttl, isPublic, metadata, signature, message } = body;\n\n if (!username || !serviceFqn || !sdp) {\n return c.json({ error: 'Missing required parameters: username, serviceFqn, sdp' }, 400);\n }\n\n // Validate service FQN\n const fqnValidation = validateServiceFqn(serviceFqn);\n if (!fqnValidation.valid) {\n return c.json({ error: fqnValidation.error }, 400);\n }\n\n // Verify username ownership (signature required)\n if (!signature || !message) {\n return c.json({ error: 'Missing signature or message for username verification' }, 400);\n }\n\n const usernameRecord = await storage.getUsername(username);\n if (!usernameRecord) {\n return c.json({ error: 'Username not claimed' }, 404);\n }\n\n // Verify signature matches username's public key\n const signatureValidation = await validateUsernameClaim(username, usernameRecord.publicKey, signature, message);\n if (!signatureValidation.valid) {\n return c.json({ error: 'Invalid signature for username' }, 403);\n }\n\n // Validate SDP\n if (typeof sdp !== 'string' || sdp.length === 0) {\n return c.json({ error: 'Invalid SDP' }, 400);\n }\n\n if (sdp.length > 64 * 1024) {\n return c.json({ error: 'SDP too large (max 64KB)' }, 400);\n }\n\n // Calculate expiry\n const peerId = getAuthenticatedPeerId(c);\n const offerTtl = Math.min(\n Math.max(ttl || config.offerDefaultTtl, config.offerMinTtl),\n config.offerMaxTtl\n );\n const expiresAt = Date.now() + offerTtl;\n\n // Create offer first\n const offers = await storage.createOffers([{\n peerId,\n sdp,\n expiresAt\n }]);\n\n if (offers.length === 0) {\n return c.json({ error: 'Failed to create offer' }, 500);\n }\n\n const offer = offers[0];\n\n // Create service\n const result = await storage.createService({\n username,\n serviceFqn,\n offerId: offer.id,\n expiresAt,\n isPublic: isPublic || false,\n metadata: metadata ? JSON.stringify(metadata) : undefined\n });\n\n return c.json({\n serviceId: result.service.id,\n uuid: result.indexUuid,\n offerId: offer.id,\n expiresAt: result.service.expiresAt\n }, 201);\n } catch (err) {\n console.error('Error creating service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /services/:uuid\n * Get service details by index UUID\n */\n app.get('/services/:uuid', async (c) => {\n try {\n const uuid = c.req.param('uuid');\n\n const service = await storage.getServiceByUuid(uuid);\n\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // Get associated offer\n const offer = await storage.getOfferById(service.offerId);\n\n if (!offer) {\n return c.json({ error: 'Associated offer not found' }, 404);\n }\n\n return c.json({\n serviceId: service.id,\n username: service.username,\n serviceFqn: service.serviceFqn,\n offerId: service.offerId,\n sdp: offer.sdp,\n isPublic: service.isPublic,\n metadata: service.metadata ? JSON.parse(service.metadata) : undefined,\n createdAt: service.createdAt,\n expiresAt: service.expiresAt\n }, 200);\n } catch (err) {\n console.error('Error getting service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * DELETE /services/:serviceId\n * Delete a service (requires ownership)\n */\n app.delete('/services/:serviceId', authMiddleware, async (c) => {\n try {\n const serviceId = c.req.param('serviceId');\n const body = await c.req.json();\n const { username } = body;\n\n if (!username) {\n return c.json({ error: 'Missing required parameter: username' }, 400);\n }\n\n const deleted = await storage.deleteService(serviceId, username);\n\n if (!deleted) {\n return c.json({ error: 'Service not found or not owned by this username' }, 404);\n }\n\n return c.json({ success: true }, 200);\n } catch (err) {\n console.error('Error deleting service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * POST /index/:username/query\n * Query service by FQN (returns UUID)\n */\n app.post('/index/:username/query', async (c) => {\n try {\n const username = c.req.param('username');\n const body = await c.req.json();\n const { serviceFqn } = body;\n\n if (!serviceFqn) {\n return c.json({ error: 'Missing required parameter: serviceFqn' }, 400);\n }\n\n const uuid = await storage.queryService(username, serviceFqn);\n\n if (!uuid) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n return c.json({\n uuid,\n allowed: true\n }, 200);\n } catch (err) {\n console.error('Error querying service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Offer Management (Core WebRTC) =====\n\n /**\n * POST /offers\n * Create offers (direct, no service - for testing/advanced users)\n */\n app.post('/offers', authMiddleware, async (c) => {\n try {\n const body = await c.req.json();\n const { offers } = body;\n\n if (!Array.isArray(offers) || offers.length === 0) {\n return c.json({ error: 'Missing or invalid required parameter: offers (must be non-empty array)' }, 400);\n }\n\n if (offers.length > config.maxOffersPerRequest) {\n return c.json({ error: `Too many offers (max ${config.maxOffersPerRequest})` }, 400);\n }\n\n const peerId = getAuthenticatedPeerId(c);\n\n // Validate and prepare offers\n const validated = offers.map((offer: any) => {\n const { sdp, ttl, secret } = offer;\n\n if (typeof sdp !== 'string' || sdp.length === 0) {\n throw new Error('Invalid SDP in offer');\n }\n\n if (sdp.length > 64 * 1024) {\n throw new Error('SDP too large (max 64KB)');\n }\n\n const offerTtl = Math.min(\n Math.max(ttl || config.offerDefaultTtl, config.offerMinTtl),\n config.offerMaxTtl\n );\n\n return {\n peerId,\n sdp,\n expiresAt: Date.now() + offerTtl,\n secret: secret ? String(secret).substring(0, 128) : undefined\n };\n });\n\n const created = await storage.createOffers(validated);\n\n return c.json({\n offers: created.map(offer => ({\n id: offer.id,\n peerId: offer.peerId,\n expiresAt: offer.expiresAt,\n createdAt: offer.createdAt,\n hasSecret: !!offer.secret\n }))\n }, 201);\n } catch (err: any) {\n console.error('Error creating offers:', err);\n return c.json({ error: err.message || 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /offers/mine\n * Get authenticated peer's offers\n */\n app.get('/offers/mine', authMiddleware, async (c) => {\n try {\n const peerId = getAuthenticatedPeerId(c);\n const offers = await storage.getOffersByPeerId(peerId);\n\n return c.json({\n offers: offers.map(offer => ({\n id: offer.id,\n sdp: offer.sdp,\n createdAt: offer.createdAt,\n expiresAt: offer.expiresAt,\n lastSeen: offer.lastSeen,\n hasSecret: !!offer.secret,\n answererPeerId: offer.answererPeerId,\n answered: !!offer.answererPeerId\n }))\n }, 200);\n } catch (err) {\n console.error('Error getting offers:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * DELETE /offers/:offerId\n * Delete an offer\n */\n app.delete('/offers/:offerId', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const peerId = getAuthenticatedPeerId(c);\n\n const deleted = await storage.deleteOffer(offerId, peerId);\n\n if (!deleted) {\n return c.json({ error: 'Offer not found or not owned by this peer' }, 404);\n }\n\n return c.json({ success: true }, 200);\n } catch (err) {\n console.error('Error deleting offer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * POST /offers/:offerId/answer\n * Answer an offer\n */\n app.post('/offers/:offerId/answer', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const body = await c.req.json();\n const { sdp, secret } = body;\n\n if (!sdp) {\n return c.json({ error: 'Missing required parameter: sdp' }, 400);\n }\n\n if (typeof sdp !== 'string' || sdp.length === 0) {\n return c.json({ error: 'Invalid SDP' }, 400);\n }\n\n if (sdp.length > 64 * 1024) {\n return c.json({ error: 'SDP too large (max 64KB)' }, 400);\n }\n\n const answererPeerId = getAuthenticatedPeerId(c);\n\n const result = await storage.answerOffer(offerId, answererPeerId, sdp, secret);\n\n if (!result.success) {\n return c.json({ error: result.error }, 400);\n }\n\n return c.json({ success: true }, 200);\n } catch (err) {\n console.error('Error answering offer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /offers/answers\n * Get answers for authenticated peer's offers\n */\n app.get('/offers/answers', authMiddleware, async (c) => {\n try {\n const peerId = getAuthenticatedPeerId(c);\n const offers = await storage.getAnsweredOffers(peerId);\n\n return c.json({\n answers: offers.map(offer => ({\n offerId: offer.id,\n answererPeerId: offer.answererPeerId,\n answerSdp: offer.answerSdp,\n answeredAt: offer.answeredAt\n }))\n }, 200);\n } catch (err) {\n console.error('Error getting answers:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== ICE Candidate Exchange =====\n\n /**\n * POST /offers/:offerId/ice-candidates\n * Add ICE candidates for an offer\n */\n app.post('/offers/:offerId/ice-candidates', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const body = await c.req.json();\n const { candidates } = body;\n\n if (!Array.isArray(candidates) || candidates.length === 0) {\n return c.json({ error: 'Missing or invalid required parameter: candidates' }, 400);\n }\n\n const peerId = getAuthenticatedPeerId(c);\n\n // Get offer to determine role\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n return c.json({ error: 'Offer not found' }, 404);\n }\n\n // Determine role\n const role = offer.peerId === peerId ? 'offerer' : 'answerer';\n\n const count = await storage.addIceCandidates(offerId, peerId, role, candidates);\n\n return c.json({ count }, 200);\n } catch (err) {\n console.error('Error adding ICE candidates:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /offers/:offerId/ice-candidates\n * Get ICE candidates for an offer\n */\n app.get('/offers/:offerId/ice-candidates', authMiddleware, async (c) => {\n try {\n const offerId = c.req.param('offerId');\n const since = c.req.query('since');\n const peerId = getAuthenticatedPeerId(c);\n\n // Get offer to determine role\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n return c.json({ error: 'Offer not found' }, 404);\n }\n\n // Get candidates for opposite role\n const targetRole = offer.peerId === peerId ? 'answerer' : 'offerer';\n const sinceTimestamp = since ? parseInt(since, 10) : undefined;\n\n const candidates = await storage.getIceCandidates(offerId, targetRole, sinceTimestamp);\n\n return c.json({\n candidates: candidates.map(c => ({\n candidate: c.candidate,\n createdAt: c.createdAt\n }))\n }, 200);\n } catch (err) {\n console.error('Error getting ICE candidates:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n return app;\n}\n", "/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */\n/**\n * 5KB JS implementation of ed25519 EdDSA signatures.\n * Compliant with RFC8032, FIPS 186-5 & ZIP215.\n * @module\n * @example\n * ```js\nimport * as ed from '@noble/ed25519';\n(async () => {\n const secretKey = ed.utils.randomSecretKey();\n const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);\n const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present\n const signature = await ed.signAsync(message, secretKey);\n const isValid = await ed.verifyAsync(signature, message, pubKey);\n})();\n```\n */\n/**\n * Curve params. ed25519 is twisted edwards curve. Equation is \u2212x\u00B2 + y\u00B2 = -a + dx\u00B2y\u00B2.\n * * P = `2n**255n - 19n` // field over which calculations are done\n * * N = `2n**252n + 27742317777372353535851937790883648493n` // group order, amount of curve points\n * * h = 8 // cofactor\n * * a = `Fp.create(BigInt(-1))` // equation param\n * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param\n * * Gx, Gy are coordinates of Generator / base point\n */\nconst ed25519_CURVE = {\n p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,\n n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,\n h: 8n,\n a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,\n d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,\n Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,\n Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,\n};\nconst { p: P, n: N, Gx, Gy, a: _a, d: _d, h } = ed25519_CURVE;\nconst L = 32; // field / group byte length\nconst L2 = 64;\n// Helpers and Precomputes sections are reused between libraries\n// ## Helpers\n// ----------\nconst captureTrace = (...args) => {\n if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(...args);\n }\n};\nconst err = (message = '') => {\n const e = new Error(message);\n captureTrace(e, err);\n throw e;\n};\nconst isBig = (n) => typeof n === 'bigint'; // is big integer\nconst isStr = (s) => typeof s === 'string'; // is string\nconst isBytes = (a) => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n/** Asserts something is Uint8Array. */\nconst abytes = (value, length, title = '') => {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n err(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n};\n/** create Uint8Array */\nconst u8n = (len) => new Uint8Array(len);\nconst u8fr = (buf) => Uint8Array.from(buf);\nconst padh = (n, pad) => n.toString(16).padStart(pad, '0');\nconst bytesToHex = (b) => Array.from(abytes(b))\n .map((e) => padh(e, 2))\n .join('');\nconst C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters\nconst _ch = (ch) => {\n if (ch >= C._0 && ch <= C._9)\n return ch - C._0; // '2' => 50-48\n if (ch >= C.A && ch <= C.F)\n return ch - (C.A - 10); // 'B' => 66-(65-10)\n if (ch >= C.a && ch <= C.f)\n return ch - (C.a - 10); // 'b' => 98-(97-10)\n return;\n};\nconst hexToBytes = (hex) => {\n const e = 'hex invalid';\n if (!isStr(hex))\n return err(e);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2)\n return err(e);\n const array = u8n(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n // treat each char as ASCII\n const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16\n const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char\n if (n1 === undefined || n2 === undefined)\n return err(e);\n array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9\n }\n return array;\n};\nconst cr = () => globalThis?.crypto; // WebCrypto is available in all modern environments\nconst subtle = () => cr()?.subtle ?? err('crypto.subtle must be defined, consider polyfill');\n// prettier-ignore\nconst concatBytes = (...arrs) => {\n const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0)); // create u8a of summed length\n let pad = 0; // walk through each array,\n arrs.forEach(a => { r.set(a, pad); pad += a.length; }); // ensure they have proper type\n return r;\n};\n/** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */\nconst randomBytes = (len = L) => {\n const c = cr();\n return c.getRandomValues(u8n(len));\n};\nconst big = BigInt;\nconst assertRange = (n, min, max, msg = 'bad number: out of range') => (isBig(n) && min <= n && n < max ? n : err(msg));\n/** modular division */\nconst M = (a, b = P) => {\n const r = a % b;\n return r >= 0n ? r : b + r;\n};\nconst modN = (a) => M(a, N);\n/** Modular inversion using euclidean GCD (non-CT). No negative exponent for now. */\n// prettier-ignore\nconst invert = (num, md) => {\n if (num === 0n || md <= 0n)\n err('no inverse n=' + num + ' mod=' + md);\n let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;\n while (a !== 0n) {\n const q = b / a, r = b % a;\n const m = x - u * q, n = y - v * q;\n b = a, a = r, x = u, y = v, u = m, v = n;\n }\n return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point\n};\nconst callHash = (name) => {\n // @ts-ignore\n const fn = hashes[name];\n if (typeof fn !== 'function')\n err('hashes.' + name + ' not set');\n return fn;\n};\nconst hash = (msg) => callHash('sha512')(msg);\nconst apoint = (p) => (p instanceof Point ? p : err('Point expected'));\n// ## End of Helpers\n// -----------------\nconst B256 = 2n ** 256n;\n/** Point in XYZT extended coordinates. */\nclass Point {\n static BASE;\n static ZERO;\n X;\n Y;\n Z;\n T;\n constructor(X, Y, Z, T) {\n const max = B256;\n this.X = assertRange(X, 0n, max);\n this.Y = assertRange(Y, 0n, max);\n this.Z = assertRange(Z, 1n, max);\n this.T = assertRange(T, 0n, max);\n Object.freeze(this);\n }\n static CURVE() {\n return ed25519_CURVE;\n }\n static fromAffine(p) {\n return new Point(p.x, p.y, 1n, M(p.x * p.y));\n }\n /** RFC8032 5.1.3: Uint8Array to Point. */\n static fromBytes(hex, zip215 = false) {\n const d = _d;\n // Copy array to not mess it up.\n const normed = u8fr(abytes(hex, L));\n // adjust first LE byte = last BE byte\n const lastByte = hex[31];\n normed[31] = lastByte & ~0x80;\n const y = bytesToNumLE(normed);\n // zip215=true: 0 <= y < 2^256\n // zip215=false, RFC8032: 0 <= y < 2^255-19\n const max = zip215 ? B256 : P;\n assertRange(y, 0n, max);\n const y2 = M(y * y); // y\u00B2\n const u = M(y2 - 1n); // u=y\u00B2-1\n const v = M(d * y2 + 1n); // v=dy\u00B2+1\n let { isValid, value: x } = uvRatio(u, v); // (uv\u00B3)(uv\u2077)^(p-5)/8; square root\n if (!isValid)\n err('bad point: y not sqrt'); // not square root: bad point\n const isXOdd = (x & 1n) === 1n; // adjust sign of x coordinate\n const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit\n if (!zip215 && x === 0n && isLastByteOdd)\n err('bad point: x==0, isLastByteOdd'); // x=0, x_0=1\n if (isLastByteOdd !== isXOdd)\n x = M(-x);\n return new Point(x, y, 1n, M(x * y)); // Z=1, T=xy\n }\n static fromHex(hex, zip215) {\n return Point.fromBytes(hexToBytes(hex), zip215);\n }\n get x() {\n return this.toAffine().x;\n }\n get y() {\n return this.toAffine().y;\n }\n /** Checks if the point is valid and on-curve. */\n assertValidity() {\n const a = _a;\n const d = _d;\n const p = this;\n if (p.is0())\n return err('bad point: ZERO'); // TODO: optimize, with vars below?\n // Equation in affine coordinates: ax\u00B2 + y\u00B2 = 1 + dx\u00B2y\u00B2\n // Equation in projective coordinates (X/Z, Y/Z, Z): (aX\u00B2 + Y\u00B2)Z\u00B2 = Z\u2074 + dX\u00B2Y\u00B2\n const { X, Y, Z, T } = p;\n const X2 = M(X * X); // X\u00B2\n const Y2 = M(Y * Y); // Y\u00B2\n const Z2 = M(Z * Z); // Z\u00B2\n const Z4 = M(Z2 * Z2); // Z\u2074\n const aX2 = M(X2 * a); // aX\u00B2\n const left = M(Z2 * M(aX2 + Y2)); // (aX\u00B2 + Y\u00B2)Z\u00B2\n const right = M(Z4 + M(d * M(X2 * Y2))); // Z\u2074 + dX\u00B2Y\u00B2\n if (left !== right)\n return err('bad point: equation left != right (1)');\n // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T\n const XY = M(X * Y);\n const ZT = M(Z * T);\n if (XY !== ZT)\n return err('bad point: equation left != right (2)');\n return this;\n }\n /** Equality check: compare points P&Q. */\n equals(other) {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality\n const X1Z2 = M(X1 * Z2);\n const X2Z1 = M(X2 * Z1);\n const Y1Z2 = M(Y1 * Z2);\n const Y2Z1 = M(Y2 * Z1);\n return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;\n }\n is0() {\n return this.equals(I);\n }\n /** Flip point over y coordinate. */\n negate() {\n return new Point(M(-this.X), this.Y, this.Z, M(-this.T));\n }\n /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */\n double() {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const a = _a;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd\n const A = M(X1 * X1);\n const B = M(Y1 * Y1);\n const C = M(2n * M(Z1 * Z1));\n const D = M(a * A);\n const x1y1 = X1 + Y1;\n const E = M(M(x1y1 * x1y1) - A - B);\n const G = D + B;\n const F = G - C;\n const H = D - B;\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */\n add(other) {\n const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;\n const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve\n const a = _a;\n const d = _d;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3\n const A = M(X1 * X2);\n const B = M(Y1 * Y2);\n const C = M(T1 * d * T2);\n const D = M(Z1 * Z2);\n const E = M((X1 + Y1) * (X2 + Y2) - A - B);\n const F = M(D - C);\n const G = M(D + C);\n const H = M(B - a * A);\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n subtract(other) {\n return this.add(apoint(other).negate());\n }\n /**\n * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.\n * Uses {@link wNAF} for base point.\n * Uses fake point to mitigate side-channel leakage.\n * @param n scalar by which point is multiplied\n * @param safe safe mode guards against timing attacks; unsafe mode is faster\n */\n multiply(n, safe = true) {\n if (!safe && (n === 0n || this.is0()))\n return I;\n assertRange(n, 1n, N);\n if (n === 1n)\n return this;\n if (this.equals(G))\n return wNAF(n).p;\n // init result point & fake point\n let p = I;\n let f = G;\n for (let d = this; n > 0n; d = d.double(), n >>= 1n) {\n // if bit is present, add to point\n // if not present, add to fake, for timing safety\n if (n & 1n)\n p = p.add(d);\n else if (safe)\n f = f.add(d);\n }\n return p;\n }\n multiplyUnsafe(scalar) {\n return this.multiply(scalar, false);\n }\n /** Convert point to 2d xy affine point. (X, Y, Z) \u220B (x=X/Z, y=Y/Z) */\n toAffine() {\n const { X, Y, Z } = this;\n // fast-paths for ZERO point OR Z=1\n if (this.equals(I))\n return { x: 0n, y: 1n };\n const iz = invert(Z, P);\n // (Z * Z^-1) must be 1, otherwise bad math\n if (M(Z * iz) !== 1n)\n err('invalid inverse');\n // x = X*Z^-1; y = Y*Z^-1\n const x = M(X * iz);\n const y = M(Y * iz);\n return { x, y };\n }\n toBytes() {\n const { x, y } = this.assertValidity().toAffine();\n const b = numTo32bLE(y);\n // store sign in first LE byte\n b[31] |= x & 1n ? 0x80 : 0;\n return b;\n }\n toHex() {\n return bytesToHex(this.toBytes());\n }\n clearCofactor() {\n return this.multiply(big(h), false);\n }\n isSmallOrder() {\n return this.clearCofactor().is0();\n }\n isTorsionFree() {\n // Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`\n let p = this.multiply(N / 2n, false).double();\n if (N % 2n)\n p = p.add(this);\n return p.is0();\n }\n}\n/** Generator / base point */\nconst G = new Point(Gx, Gy, 1n, M(Gx * Gy));\n/** Identity / zero point */\nconst I = new Point(0n, 1n, 1n, 0n);\n// Static aliases\nPoint.BASE = G;\nPoint.ZERO = I;\nconst numTo32bLE = (num) => hexToBytes(padh(assertRange(num, 0n, B256), L2)).reverse();\nconst bytesToNumLE = (b) => big('0x' + bytesToHex(u8fr(abytes(b)).reverse()));\nconst pow2 = (x, power) => {\n // pow2(x, 4) == x^(2^4)\n let r = x;\n while (power-- > 0n) {\n r *= r;\n r %= P;\n }\n return r;\n};\n// prettier-ignore\nconst pow_2_252_3 = (x) => {\n const x2 = (x * x) % P; // x^2, bits 1\n const b2 = (x2 * x) % P; // x^3, bits 11\n const b4 = (pow2(b2, 2n) * b2) % P; // x^(2^4-1), bits 1111\n const b5 = (pow2(b4, 1n) * x) % P; // x^(2^5-1), bits 11111\n const b10 = (pow2(b5, 5n) * b5) % P; // x^(2^10)\n const b20 = (pow2(b10, 10n) * b10) % P; // x^(2^20)\n const b40 = (pow2(b20, 20n) * b20) % P; // x^(2^40)\n const b80 = (pow2(b40, 40n) * b40) % P; // x^(2^80)\n const b160 = (pow2(b80, 80n) * b80) % P; // x^(2^160)\n const b240 = (pow2(b160, 80n) * b80) % P; // x^(2^240)\n const b250 = (pow2(b240, 10n) * b10) % P; // x^(2^250)\n const pow_p_5_8 = (pow2(b250, 2n) * x) % P; // < To pow to (p+3)/8, multiply it by x.\n return { pow_p_5_8, b2 };\n};\nconst RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // \u221A-1\n// for sqrt comp\n// prettier-ignore\nconst uvRatio = (u, v) => {\n const v3 = M(v * v * v); // v\u00B3\n const v7 = M(v3 * v3 * v); // v\u2077\n const pow = pow_2_252_3(u * v7).pow_p_5_8; // (uv\u2077)^(p-5)/8\n let x = M(u * v3 * pow); // (uv\u00B3)(uv\u2077)^(p-5)/8\n const vx2 = M(v * x * x); // vx\u00B2\n const root1 = x; // First root candidate\n const root2 = M(x * RM1); // Second root candidate; RM1 is \u221A-1\n const useRoot1 = vx2 === u; // If vx\u00B2 = u (mod p), x is a square root\n const useRoot2 = vx2 === M(-u); // If vx\u00B2 = -u, set x <-- x * 2^((p-1)/4)\n const noRoot = vx2 === M(-u * RM1); // There is no valid root, vx\u00B2 = -u\u221A-1\n if (useRoot1)\n x = root1;\n if (useRoot2 || noRoot)\n x = root2; // We return root2 anyway, for const-time\n if ((M(x) & 1n) === 1n)\n x = M(-x); // edIsNegative\n return { isValid: useRoot1 || useRoot2, value: x };\n};\n// N == L, just weird naming\nconst modL_LE = (hash) => modN(bytesToNumLE(hash)); // modulo L; but little-endian\n/** hashes.sha512 should conform to the interface. */\n// TODO: rename\nconst sha512a = (...m) => hashes.sha512Async(concatBytes(...m)); // Async SHA512\nconst sha512s = (...m) => callHash('sha512')(concatBytes(...m));\n// RFC8032 5.1.5\nconst hash2extK = (hashed) => {\n // slice creates a copy, unlike subarray\n const head = hashed.slice(0, L);\n head[0] &= 248; // Clamp bits: 0b1111_1000\n head[31] &= 127; // 0b0111_1111\n head[31] |= 64; // 0b0100_0000\n const prefix = hashed.slice(L, L2); // secret key \"prefix\"\n const scalar = modL_LE(head); // modular division over curve order\n const point = G.multiply(scalar); // public key point\n const pointBytes = point.toBytes(); // point serialized to Uint8Array\n return { head, prefix, scalar, point, pointBytes };\n};\n// RFC8032 5.1.5; getPublicKey async, sync. Hash priv key and extract point.\nconst getExtendedPublicKeyAsync = (secretKey) => sha512a(abytes(secretKey, L)).then(hash2extK);\nconst getExtendedPublicKey = (secretKey) => hash2extK(sha512s(abytes(secretKey, L)));\n/** Creates 32-byte ed25519 public key from 32-byte secret key. Async. */\nconst getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes);\n/** Creates 32-byte ed25519 public key from 32-byte secret key. To use, set `hashes.sha512` first. */\nconst getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;\nconst hashFinishA = (res) => sha512a(res.hashable).then(res.finish);\nconst hashFinishS = (res) => res.finish(sha512s(res.hashable));\n// Code, shared between sync & async sign\nconst _sign = (e, rBytes, msg) => {\n const { pointBytes: P, scalar: s } = e;\n const r = modL_LE(rBytes); // r was created outside, reduce it modulo L\n const R = G.multiply(r).toBytes(); // R = [r]B\n const hashable = concatBytes(R, P, msg); // dom2(F, C) || R || A || PH(M)\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l\n return abytes(concatBytes(R, numTo32bLE(S)), L2); // 64-byte sig: 32b R.x + 32b LE(S)\n };\n return { hashable, finish };\n};\n/**\n * Signs message using secret key. Async.\n * Follows RFC8032 5.1.6.\n */\nconst signAsync = async (message, secretKey) => {\n const m = abytes(message);\n const e = await getExtendedPublicKeyAsync(secretKey);\n const rBytes = await sha512a(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishA(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\n/**\n * Signs message using secret key. To use, set `hashes.sha512` first.\n * Follows RFC8032 5.1.6.\n */\nconst sign = (message, secretKey) => {\n const m = abytes(message);\n const e = getExtendedPublicKey(secretKey);\n const rBytes = sha512s(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishS(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\nconst defaultVerifyOpts = { zip215: true };\nconst _verify = (sig, msg, pub, opts = defaultVerifyOpts) => {\n sig = abytes(sig, L2); // Signature hex str/Bytes, must be 64 bytes\n msg = abytes(msg); // Message hex str/Bytes\n pub = abytes(pub, L);\n const { zip215 } = opts; // switch between zip215 and rfc8032 verif\n let A;\n let R;\n let s;\n let SB;\n let hashable = Uint8Array.of();\n try {\n A = Point.fromBytes(pub, zip215); // public key A decoded\n R = Point.fromBytes(sig.slice(0, L), zip215); // 0 <= R < 2^256: ZIP215 R can be >= P\n s = bytesToNumLE(sig.slice(L, L2)); // Decode second half as an integer S\n SB = G.multiply(s, false); // in the range 0 <= s < L\n hashable = concatBytes(R.toBytes(), A.toBytes(), msg); // dom2(F, C) || R || A || PH(M)\n }\n catch (error) { }\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n if (SB == null)\n return false; // false if try-catch catched an error\n if (!zip215 && A.isSmallOrder())\n return false; // false for SBS: Strongly Binding Signature\n const k = modL_LE(hashed); // decode in little-endian, modulo L\n const RkA = R.add(A.multiply(k, false)); // [8]R + [8][k]A'\n return RkA.add(SB.negate()).clearCofactor().is0(); // [8][S]B = [8]R + [8][k]A'\n };\n return { hashable, finish };\n};\n/** Verifies signature on message and public key. Async. Follows RFC8032 5.1.7. */\nconst verifyAsync = async (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishA(_verify(signature, message, publicKey, opts));\n/** Verifies signature on message and public key. To use, set `hashes.sha512` first. Follows RFC8032 5.1.7. */\nconst verify = (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishS(_verify(signature, message, publicKey, opts));\n/** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */\nconst etc = {\n bytesToHex: bytesToHex,\n hexToBytes: hexToBytes,\n concatBytes: concatBytes,\n mod: M,\n invert: invert,\n randomBytes: randomBytes,\n};\nconst hashes = {\n sha512Async: async (message) => {\n const s = subtle();\n const m = concatBytes(message);\n return u8n(await s.digest('SHA-512', m.buffer));\n },\n sha512: undefined,\n};\n// FIPS 186 B.4.1 compliant key generation produces private keys\n// with modulo bias being neglible. takes >N+16 bytes, returns (hash mod n-1)+1\nconst randomSecretKey = (seed = randomBytes(L)) => seed;\nconst keygen = (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = getPublicKey(secretKey);\n return { secretKey, publicKey };\n};\nconst keygenAsync = async (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = await getPublicKeyAsync(secretKey);\n return { secretKey, publicKey };\n};\n/** ed25519-specific key utilities. */\nconst utils = {\n getExtendedPublicKeyAsync: getExtendedPublicKeyAsync,\n getExtendedPublicKey: getExtendedPublicKey,\n randomSecretKey: randomSecretKey,\n};\n// ## Precomputes\n// --------------\nconst W = 8; // W is window size\nconst scalarBits = 256;\nconst pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8, NOT 32 - see wNAF loop\nconst pwindowSize = 2 ** (W - 1); // 128 for W=8\nconst precompute = () => {\n const points = [];\n let p = G;\n let b = p;\n for (let w = 0; w < pwindows; w++) {\n b = p;\n points.push(b);\n for (let i = 1; i < pwindowSize; i++) {\n b = b.add(p);\n points.push(b);\n } // i=1, bc we skip 0\n p = b.double();\n }\n return points;\n};\nlet Gpows = undefined; // precomputes for base point G\n// const-time negate\nconst ctneg = (cnd, p) => {\n const n = p.negate();\n return cnd ? n : p;\n};\n/**\n * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by\n * caching multiples of G (base point). Cache is stored in 32MB of RAM.\n * Any time `G.multiply` is done, precomputes are used.\n * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.\n *\n * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,\n * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.\n *\n * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().\n */\nconst wNAF = (n) => {\n const comp = Gpows || (Gpows = precompute());\n let p = I;\n let f = G; // f must be G, or could become I in the end\n const pow_2_w = 2 ** W; // 256 for W=8\n const maxNum = pow_2_w; // 256 for W=8\n const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111\n const shiftBy = big(W); // 8 for W=8\n for (let w = 0; w < pwindows; w++) {\n let wbits = Number(n & mask); // extract W bits.\n n >>= shiftBy; // shift number by W bits.\n // We use negative indexes to reduce size of precomputed table by 2x.\n // Instead of needing precomputes 0..256, we only calculate them for 0..128.\n // If an index > 128 is found, we do (256-index) - where 256 is next window.\n // Naive: index +127 => 127, +224 => 224\n // Optimized: index +127 => 127, +224 => 256-32\n if (wbits > pwindowSize) {\n wbits -= maxNum;\n n += 1n;\n }\n const off = w * pwindowSize;\n const offF = off; // offsets, evaluate both\n const offP = off + Math.abs(wbits) - 1;\n const isEven = w % 2 !== 0; // conditions, evaluate both\n const isNeg = wbits < 0;\n if (wbits === 0) {\n // off == I: can't add it. Adding random offF instead.\n f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point\n }\n else {\n p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point\n }\n }\n if (n !== 0n)\n err('invalid wnaf');\n return { p, f }; // return both real and fake points for JIT\n};\n// !! Remove the export to easily use in REPL / browser console\nexport { etc, getPublicKey, getPublicKeyAsync, hash, hashes, keygen, keygenAsync, Point, sign, signAsync, utils, verify, verifyAsync, };\n", "/**\n * Crypto utilities for stateless peer authentication\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n * Uses @noble/ed25519 for Ed25519 signature verification\n */\n\nimport * as ed25519 from '@noble/ed25519';\n\n// Set SHA-512 hash function for ed25519 (required in @noble/ed25519 v3+)\n// Uses Web Crypto API (compatible with both Node.js and Cloudflare Workers)\ned25519.hashes.sha512Async = async (message: Uint8Array) => {\n return new Uint8Array(await crypto.subtle.digest('SHA-512', message as BufferSource));\n};\n\nconst ALGORITHM = 'AES-GCM';\nconst IV_LENGTH = 12; // 96 bits for GCM\nconst KEY_LENGTH = 32; // 256 bits\n\n// Username validation\nconst USERNAME_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;\nconst USERNAME_MIN_LENGTH = 3;\nconst USERNAME_MAX_LENGTH = 32;\n\n// Timestamp validation (5 minutes tolerance)\nconst TIMESTAMP_TOLERANCE_MS = 5 * 60 * 1000;\n\n/**\n * Generates a random peer ID (16 bytes = 32 hex chars)\n */\nexport function generatePeerId(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generates a random secret key for encryption (32 bytes = 64 hex chars)\n */\nexport function generateSecretKey(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(KEY_LENGTH));\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Convert hex string to Uint8Array\n */\nfunction hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Convert Uint8Array to base64 string\n */\nfunction bytesToBase64(bytes: Uint8Array): string {\n const binString = Array.from(bytes, (byte) =>\n String.fromCodePoint(byte)\n ).join('');\n return btoa(binString);\n}\n\n/**\n * Convert base64 string to Uint8Array\n */\nfunction base64ToBytes(base64: string): Uint8Array {\n const binString = atob(base64);\n return Uint8Array.from(binString, (char) => char.codePointAt(0)!);\n}\n\n/**\n * Encrypts a peer ID using the server secret key\n * Returns base64-encoded encrypted data (IV + ciphertext)\n */\nexport async function encryptPeerId(peerId: string, secretKeyHex: string): Promise<string> {\n const keyBytes = hexToBytes(secretKeyHex);\n\n if (keyBytes.length !== KEY_LENGTH) {\n throw new Error(`Secret key must be ${KEY_LENGTH * 2} hex characters (${KEY_LENGTH} bytes)`);\n }\n\n // Import key\n const key = await crypto.subtle.importKey(\n 'raw',\n keyBytes,\n { name: ALGORITHM, length: 256 },\n false,\n ['encrypt']\n );\n\n // Generate random IV\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n\n // Encrypt peer ID\n const encoder = new TextEncoder();\n const data = encoder.encode(peerId);\n\n const encrypted = await crypto.subtle.encrypt(\n { name: ALGORITHM, iv },\n key,\n data\n );\n\n // Combine IV + ciphertext and encode as base64\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv, 0);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return bytesToBase64(combined);\n}\n\n/**\n * Decrypts an encrypted peer ID secret\n * Returns the plaintext peer ID or throws if decryption fails\n */\nexport async function decryptPeerId(encryptedSecret: string, secretKeyHex: string): Promise<string> {\n try {\n const keyBytes = hexToBytes(secretKeyHex);\n\n if (keyBytes.length !== KEY_LENGTH) {\n throw new Error(`Secret key must be ${KEY_LENGTH * 2} hex characters (${KEY_LENGTH} bytes)`);\n }\n\n // Decode base64\n const combined = base64ToBytes(encryptedSecret);\n\n // Extract IV and ciphertext\n const iv = combined.slice(0, IV_LENGTH);\n const ciphertext = combined.slice(IV_LENGTH);\n\n // Import key\n const key = await crypto.subtle.importKey(\n 'raw',\n keyBytes,\n { name: ALGORITHM, length: 256 },\n false,\n ['decrypt']\n );\n\n // Decrypt\n const decrypted = await crypto.subtle.decrypt(\n { name: ALGORITHM, iv },\n key,\n ciphertext\n );\n\n const decoder = new TextDecoder();\n return decoder.decode(decrypted);\n } catch (err) {\n throw new Error('Failed to decrypt peer ID: invalid secret or secret key');\n }\n}\n\n/**\n * Validates that a peer ID and secret match\n * Returns true if valid, false otherwise\n */\nexport async function validateCredentials(peerId: string, encryptedSecret: string, secretKey: string): Promise<boolean> {\n try {\n const decryptedPeerId = await decryptPeerId(encryptedSecret, secretKey);\n return decryptedPeerId === peerId;\n } catch {\n return false;\n }\n}\n\n// ===== Username and Ed25519 Signature Utilities =====\n\n/**\n * Validates username format\n * Rules: 3-32 chars, lowercase alphanumeric + dash, must start/end with alphanumeric\n */\nexport function validateUsername(username: string): { valid: boolean; error?: string } {\n if (typeof username !== 'string') {\n return { valid: false, error: 'Username must be a string' };\n }\n\n if (username.length < USERNAME_MIN_LENGTH) {\n return { valid: false, error: `Username must be at least ${USERNAME_MIN_LENGTH} characters` };\n }\n\n if (username.length > USERNAME_MAX_LENGTH) {\n return { valid: false, error: `Username must be at most ${USERNAME_MAX_LENGTH} characters` };\n }\n\n if (!USERNAME_REGEX.test(username)) {\n return { valid: false, error: 'Username must be lowercase alphanumeric with optional dashes, and start/end with alphanumeric' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates service FQN format (service-name@version)\n * Service name: reverse domain notation (com.example.service)\n * Version: semantic versioning (1.0.0, 2.1.3-beta, etc.)\n */\nexport function validateServiceFqn(fqn: string): { valid: boolean; error?: string } {\n if (typeof fqn !== 'string') {\n return { valid: false, error: 'Service FQN must be a string' };\n }\n\n // Split into service name and version\n const parts = fqn.split('@');\n if (parts.length !== 2) {\n return { valid: false, error: 'Service FQN must be in format: service-name@version' };\n }\n\n const [serviceName, version] = parts;\n\n // Validate service name (reverse domain notation)\n const serviceNameRegex = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/;\n if (!serviceNameRegex.test(serviceName)) {\n return { valid: false, error: 'Service name must be reverse domain notation (e.g., com.example.service)' };\n }\n\n if (serviceName.length < 3 || serviceName.length > 128) {\n return { valid: false, error: 'Service name must be 3-128 characters' };\n }\n\n // Validate version (semantic versioning)\n const versionRegex = /^[0-9]+\\.[0-9]+\\.[0-9]+(-[a-z0-9.-]+)?$/;\n if (!versionRegex.test(version)) {\n return { valid: false, error: 'Version must be semantic versioning (e.g., 1.0.0, 2.1.3-beta)' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates timestamp is within acceptable range (prevents replay attacks)\n */\nexport function validateTimestamp(timestamp: number): { valid: boolean; error?: string } {\n if (typeof timestamp !== 'number' || !Number.isFinite(timestamp)) {\n return { valid: false, error: 'Timestamp must be a finite number' };\n }\n\n const now = Date.now();\n const diff = Math.abs(now - timestamp);\n\n if (diff > TIMESTAMP_TOLERANCE_MS) {\n return { valid: false, error: `Timestamp too old or too far in future (tolerance: ${TIMESTAMP_TOLERANCE_MS / 1000}s)` };\n }\n\n return { valid: true };\n}\n\n/**\n * Verifies Ed25519 signature\n * @param publicKey Base64-encoded Ed25519 public key (32 bytes)\n * @param signature Base64-encoded Ed25519 signature (64 bytes)\n * @param message Message that was signed (UTF-8 string)\n * @returns true if signature is valid, false otherwise\n */\nexport async function verifyEd25519Signature(\n publicKey: string,\n signature: string,\n message: string\n): Promise<boolean> {\n try {\n // Decode base64 to bytes\n const publicKeyBytes = base64ToBytes(publicKey);\n const signatureBytes = base64ToBytes(signature);\n\n // Encode message as UTF-8\n const encoder = new TextEncoder();\n const messageBytes = encoder.encode(message);\n\n // Verify signature using @noble/ed25519 (async version)\n const isValid = await ed25519.verifyAsync(signatureBytes, messageBytes, publicKeyBytes);\n return isValid;\n } catch (err) {\n console.error('Ed25519 signature verification failed:', err);\n return false;\n }\n}\n\n/**\n * Validates a username claim request\n * Verifies format, timestamp, and signature\n */\nexport async function validateUsernameClaim(\n username: string,\n publicKey: string,\n signature: string,\n message: string\n): Promise<{ valid: boolean; error?: string }> {\n // Validate username format\n const usernameCheck = validateUsername(username);\n if (!usernameCheck.valid) {\n return usernameCheck;\n }\n\n // Parse message format: \"claim:{username}:{timestamp}\"\n const parts = message.split(':');\n if (parts.length !== 3 || parts[0] !== 'claim' || parts[1] !== username) {\n return { valid: false, error: 'Invalid message format (expected: claim:{username}:{timestamp})' };\n }\n\n const timestamp = parseInt(parts[2], 10);\n if (isNaN(timestamp)) {\n return { valid: false, error: 'Invalid timestamp in message' };\n }\n\n // Validate timestamp\n const timestampCheck = validateTimestamp(timestamp);\n if (!timestampCheck.valid) {\n return timestampCheck;\n }\n\n // Verify signature\n const signatureValid = await verifyEd25519Signature(publicKey, signature, message);\n if (!signatureValid) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n return { valid: true };\n}\n", "import { Context, Next } from 'hono';\nimport { validateCredentials } from '../crypto.ts';\n\n/**\n * Authentication middleware for Rondevu\n * Validates Bearer token in format: {peerId}:{encryptedSecret}\n */\nexport function createAuthMiddleware(authSecret: string) {\n return async (c: Context, next: Next) => {\n const authHeader = c.req.header('Authorization');\n\n if (!authHeader) {\n return c.json({ error: 'Missing Authorization header' }, 401);\n }\n\n // Expect format: Bearer {peerId}:{secret}\n const parts = authHeader.split(' ');\n if (parts.length !== 2 || parts[0] !== 'Bearer') {\n return c.json({ error: 'Invalid Authorization header format. Expected: Bearer {peerId}:{secret}' }, 401);\n }\n\n const credentials = parts[1].split(':');\n if (credentials.length !== 2) {\n return c.json({ error: 'Invalid credentials format. Expected: {peerId}:{secret}' }, 401);\n }\n\n const [peerId, encryptedSecret] = credentials;\n\n // Validate credentials (async operation)\n const isValid = await validateCredentials(peerId, encryptedSecret, authSecret);\n if (!isValid) {\n return c.json({ error: 'Invalid credentials' }, 401);\n }\n\n // Attach peer ID to context for use in handlers\n c.set('peerId', peerId);\n\n await next();\n };\n}\n\n/**\n * Helper to get authenticated peer ID from context\n */\nexport function getAuthenticatedPeerId(c: Context): string {\n const peerId = c.get('peerId');\n if (!peerId) {\n throw new Error('No authenticated peer ID in context');\n }\n return peerId;\n}\n", "import { generateSecretKey } from './crypto.ts';\n\n/**\n * Application configuration\n * Reads from environment variables with sensible defaults\n */\nexport interface Config {\n port: number;\n storageType: 'sqlite' | 'memory';\n storagePath: string;\n corsOrigins: string[];\n version: string;\n authSecret: string;\n offerDefaultTtl: number;\n offerMaxTtl: number;\n offerMinTtl: number;\n cleanupInterval: number;\n maxOffersPerRequest: number;\n maxTopicsPerOffer: number;\n}\n\n/**\n * Loads configuration from environment variables\n */\nexport function loadConfig(): Config {\n // Generate or load auth secret\n let authSecret = process.env.AUTH_SECRET;\n if (!authSecret) {\n authSecret = generateSecretKey();\n console.warn('WARNING: No AUTH_SECRET provided. Generated temporary secret:', authSecret);\n console.warn('All peer credentials will be invalidated on server restart.');\n console.warn('Set AUTH_SECRET environment variable to persist credentials across restarts.');\n }\n\n return {\n port: parseInt(process.env.PORT || '3000', 10),\n storageType: (process.env.STORAGE_TYPE || 'sqlite') as 'sqlite' | 'memory',\n storagePath: process.env.STORAGE_PATH || ':memory:',\n corsOrigins: process.env.CORS_ORIGINS\n ? process.env.CORS_ORIGINS.split(',').map(o => o.trim())\n : ['*'],\n version: process.env.VERSION || 'unknown',\n authSecret,\n offerDefaultTtl: parseInt(process.env.OFFER_DEFAULT_TTL || '60000', 10),\n offerMaxTtl: parseInt(process.env.OFFER_MAX_TTL || '86400000', 10),\n offerMinTtl: parseInt(process.env.OFFER_MIN_TTL || '60000', 10),\n cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL || '60000', 10),\n maxOffersPerRequest: parseInt(process.env.MAX_OFFERS_PER_REQUEST || '100', 10),\n maxTopicsPerOffer: parseInt(process.env.MAX_TOPICS_PER_OFFER || '50', 10),\n };\n}\n", "import Database from 'better-sqlite3';\nimport { randomUUID } from 'node:crypto';\nimport {\n Storage,\n Offer,\n IceCandidate,\n CreateOfferRequest,\n Username,\n ClaimUsernameRequest,\n Service,\n CreateServiceRequest,\n ServiceInfo,\n} from './types.ts';\nimport { generateOfferHash } from './hash-id.ts';\n\nconst YEAR_IN_MS = 365 * 24 * 60 * 60 * 1000; // 365 days\n\n/**\n * SQLite storage adapter for rondevu DNS-like system\n * Supports both file-based and in-memory databases\n */\nexport class SQLiteStorage implements Storage {\n private db: Database.Database;\n\n /**\n * Creates a new SQLite storage instance\n * @param path Path to SQLite database file, or ':memory:' for in-memory database\n */\n constructor(path: string = ':memory:') {\n this.db = new Database(path);\n this.initializeDatabase();\n }\n\n /**\n * Initializes database schema with username and service-based structure\n */\n private initializeDatabase(): void {\n this.db.exec(`\n -- Offers table (no topics)\n CREATE TABLE IF NOT EXISTS offers (\n id TEXT PRIMARY KEY,\n peer_id TEXT NOT NULL,\n sdp TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_seen INTEGER NOT NULL,\n secret TEXT,\n answerer_peer_id TEXT,\n answer_sdp TEXT,\n answered_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_offers_peer ON offers(peer_id);\n CREATE INDEX IF NOT EXISTS idx_offers_expires ON offers(expires_at);\n CREATE INDEX IF NOT EXISTS idx_offers_last_seen ON offers(last_seen);\n CREATE INDEX IF NOT EXISTS idx_offers_answerer ON offers(answerer_peer_id);\n\n -- ICE candidates table\n CREATE TABLE IF NOT EXISTS ice_candidates (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n offer_id TEXT NOT NULL,\n peer_id TEXT NOT NULL,\n role TEXT NOT NULL CHECK(role IN ('offerer', 'answerer')),\n candidate TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n FOREIGN KEY (offer_id) REFERENCES offers(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_ice_offer ON ice_candidates(offer_id);\n CREATE INDEX IF NOT EXISTS idx_ice_peer ON ice_candidates(peer_id);\n CREATE INDEX IF NOT EXISTS idx_ice_created ON ice_candidates(created_at);\n\n -- Usernames table\n CREATE TABLE IF NOT EXISTS usernames (\n username TEXT PRIMARY KEY,\n public_key TEXT NOT NULL UNIQUE,\n claimed_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_used INTEGER NOT NULL,\n metadata TEXT,\n CHECK(length(username) >= 3 AND length(username) <= 32)\n );\n\n CREATE INDEX IF NOT EXISTS idx_usernames_expires ON usernames(expires_at);\n CREATE INDEX IF NOT EXISTS idx_usernames_public_key ON usernames(public_key);\n\n -- Services table\n CREATE TABLE IF NOT EXISTS services (\n id TEXT PRIMARY KEY,\n username TEXT NOT NULL,\n service_fqn TEXT NOT NULL,\n offer_id TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n is_public INTEGER NOT NULL DEFAULT 0,\n metadata TEXT,\n FOREIGN KEY (username) REFERENCES usernames(username) ON DELETE CASCADE,\n FOREIGN KEY (offer_id) REFERENCES offers(id) ON DELETE CASCADE,\n UNIQUE(username, service_fqn)\n );\n\n CREATE INDEX IF NOT EXISTS idx_services_username ON services(username);\n CREATE INDEX IF NOT EXISTS idx_services_fqn ON services(service_fqn);\n CREATE INDEX IF NOT EXISTS idx_services_expires ON services(expires_at);\n CREATE INDEX IF NOT EXISTS idx_services_offer ON services(offer_id);\n\n -- Service index table (privacy layer)\n CREATE TABLE IF NOT EXISTS service_index (\n uuid TEXT PRIMARY KEY,\n service_id TEXT NOT NULL,\n username TEXT NOT NULL,\n service_fqn TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_service_index_username ON service_index(username);\n CREATE INDEX IF NOT EXISTS idx_service_index_expires ON service_index(expires_at);\n `);\n\n // Enable foreign keys\n this.db.pragma('foreign_keys = ON');\n }\n\n // ===== Offer Management =====\n\n async createOffers(offers: CreateOfferRequest[]): Promise<Offer[]> {\n const created: Offer[] = [];\n\n // Generate hash-based IDs for all offers first\n const offersWithIds = await Promise.all(\n offers.map(async (offer) => ({\n ...offer,\n id: offer.id || await generateOfferHash(offer.sdp, []),\n }))\n );\n\n // Use transaction for atomic creation\n const transaction = this.db.transaction((offersWithIds: (CreateOfferRequest & { id: string })[]) => {\n const offerStmt = this.db.prepare(`\n INSERT INTO offers (id, peer_id, sdp, created_at, expires_at, last_seen, secret)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const offer of offersWithIds) {\n const now = Date.now();\n\n // Insert offer\n offerStmt.run(\n offer.id,\n offer.peerId,\n offer.sdp,\n now,\n offer.expiresAt,\n now,\n offer.secret || null\n );\n\n created.push({\n id: offer.id,\n peerId: offer.peerId,\n sdp: offer.sdp,\n createdAt: now,\n expiresAt: offer.expiresAt,\n lastSeen: now,\n secret: offer.secret,\n });\n }\n });\n\n transaction(offersWithIds);\n return created;\n }\n\n async getOffersByPeerId(peerId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE peer_id = ? AND expires_at > ?\n ORDER BY last_seen DESC\n `);\n\n const rows = stmt.all(peerId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n async getOfferById(offerId: string): Promise<Offer | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(offerId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToOffer(row);\n }\n\n async deleteOffer(offerId: string, ownerPeerId: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM offers\n WHERE id = ? AND peer_id = ?\n `);\n\n const result = stmt.run(offerId, ownerPeerId);\n return result.changes > 0;\n }\n\n async deleteExpiredOffers(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM offers WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async answerOffer(\n offerId: string,\n answererPeerId: string,\n answerSdp: string,\n secret?: string\n ): Promise<{ success: boolean; error?: string }> {\n // Check if offer exists and is not expired\n const offer = await this.getOfferById(offerId);\n\n if (!offer) {\n return {\n success: false,\n error: 'Offer not found or expired'\n };\n }\n\n // Verify secret if offer is protected\n if (offer.secret && offer.secret !== secret) {\n return {\n success: false,\n error: 'Invalid or missing secret'\n };\n }\n\n // Check if offer already has an answerer\n if (offer.answererPeerId) {\n return {\n success: false,\n error: 'Offer already answered'\n };\n }\n\n // Update offer with answer\n const stmt = this.db.prepare(`\n UPDATE offers\n SET answerer_peer_id = ?, answer_sdp = ?, answered_at = ?\n WHERE id = ? AND answerer_peer_id IS NULL\n `);\n\n const result = stmt.run(answererPeerId, answerSdp, Date.now(), offerId);\n\n if (result.changes === 0) {\n return {\n success: false,\n error: 'Offer already answered (race condition)'\n };\n }\n\n return { success: true };\n }\n\n async getAnsweredOffers(offererPeerId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE peer_id = ? AND answerer_peer_id IS NOT NULL AND expires_at > ?\n ORDER BY answered_at DESC\n `);\n\n const rows = stmt.all(offererPeerId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n // ===== ICE Candidate Management =====\n\n async addIceCandidates(\n offerId: string,\n peerId: string,\n role: 'offerer' | 'answerer',\n candidates: any[]\n ): Promise<number> {\n const stmt = this.db.prepare(`\n INSERT INTO ice_candidates (offer_id, peer_id, role, candidate, created_at)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n const baseTimestamp = Date.now();\n const transaction = this.db.transaction((candidates: any[]) => {\n for (let i = 0; i < candidates.length; i++) {\n stmt.run(\n offerId,\n peerId,\n role,\n JSON.stringify(candidates[i]),\n baseTimestamp + i\n );\n }\n });\n\n transaction(candidates);\n return candidates.length;\n }\n\n async getIceCandidates(\n offerId: string,\n targetRole: 'offerer' | 'answerer',\n since?: number\n ): Promise<IceCandidate[]> {\n let query = `\n SELECT * FROM ice_candidates\n WHERE offer_id = ? AND role = ?\n `;\n\n const params: any[] = [offerId, targetRole];\n\n if (since !== undefined) {\n query += ' AND created_at > ?';\n params.push(since);\n }\n\n query += ' ORDER BY created_at ASC';\n\n const stmt = this.db.prepare(query);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n offerId: row.offer_id,\n peerId: row.peer_id,\n role: row.role,\n candidate: JSON.parse(row.candidate),\n createdAt: row.created_at,\n }));\n }\n\n // ===== Username Management =====\n\n async claimUsername(request: ClaimUsernameRequest): Promise<Username> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n // Try to insert or update\n const stmt = this.db.prepare(`\n INSERT INTO usernames (username, public_key, claimed_at, expires_at, last_used, metadata)\n VALUES (?, ?, ?, ?, ?, NULL)\n ON CONFLICT(username) DO UPDATE SET\n expires_at = ?,\n last_used = ?\n WHERE public_key = ?\n `);\n\n const result = stmt.run(\n request.username,\n request.publicKey,\n now,\n expiresAt,\n now,\n expiresAt,\n now,\n request.publicKey\n );\n\n if (result.changes === 0) {\n throw new Error('Username already claimed by different public key');\n }\n\n return {\n username: request.username,\n publicKey: request.publicKey,\n claimedAt: now,\n expiresAt,\n lastUsed: now,\n };\n }\n\n async getUsername(username: string): Promise<Username | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM usernames\n WHERE username = ? AND expires_at > ?\n `);\n\n const row = stmt.get(username, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return {\n username: row.username,\n publicKey: row.public_key,\n claimedAt: row.claimed_at,\n expiresAt: row.expires_at,\n lastUsed: row.last_used,\n metadata: row.metadata || undefined,\n };\n }\n\n async touchUsername(username: string): Promise<boolean> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n const stmt = this.db.prepare(`\n UPDATE usernames\n SET last_used = ?, expires_at = ?\n WHERE username = ? AND expires_at > ?\n `);\n\n const result = stmt.run(now, expiresAt, username, now);\n return result.changes > 0;\n }\n\n async deleteExpiredUsernames(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM usernames WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n // ===== Service Management =====\n\n async createService(request: CreateServiceRequest): Promise<{\n service: Service;\n indexUuid: string;\n }> {\n const serviceId = randomUUID();\n const indexUuid = randomUUID();\n const now = Date.now();\n\n const transaction = this.db.transaction(() => {\n // Insert service\n const serviceStmt = this.db.prepare(`\n INSERT INTO services (id, username, service_fqn, offer_id, created_at, expires_at, is_public, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n serviceStmt.run(\n serviceId,\n request.username,\n request.serviceFqn,\n request.offerId,\n now,\n request.expiresAt,\n request.isPublic ? 1 : 0,\n request.metadata || null\n );\n\n // Insert service index\n const indexStmt = this.db.prepare(`\n INSERT INTO service_index (uuid, service_id, username, service_fqn, created_at, expires_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n indexStmt.run(\n indexUuid,\n serviceId,\n request.username,\n request.serviceFqn,\n now,\n request.expiresAt\n );\n\n // Touch username to extend expiry\n this.touchUsername(request.username);\n });\n\n transaction();\n\n return {\n service: {\n id: serviceId,\n username: request.username,\n serviceFqn: request.serviceFqn,\n offerId: request.offerId,\n createdAt: now,\n expiresAt: request.expiresAt,\n isPublic: request.isPublic || false,\n metadata: request.metadata,\n },\n indexUuid,\n };\n }\n\n async getServiceById(serviceId: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM services\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(serviceId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async getServiceByUuid(uuid: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT s.* FROM services s\n INNER JOIN service_index si ON s.id = si.service_id\n WHERE si.uuid = ? AND s.expires_at > ?\n `);\n\n const row = stmt.get(uuid, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async listServicesForUsername(username: string): Promise<ServiceInfo[]> {\n const stmt = this.db.prepare(`\n SELECT si.uuid, s.is_public, s.service_fqn, s.metadata\n FROM service_index si\n INNER JOIN services s ON si.service_id = s.id\n WHERE si.username = ? AND si.expires_at > ?\n ORDER BY s.created_at DESC\n `);\n\n const rows = stmt.all(username, Date.now()) as any[];\n\n return rows.map(row => ({\n uuid: row.uuid,\n isPublic: row.is_public === 1,\n serviceFqn: row.is_public === 1 ? row.service_fqn : undefined,\n metadata: row.is_public === 1 ? row.metadata || undefined : undefined,\n }));\n }\n\n async queryService(username: string, serviceFqn: string): Promise<string | null> {\n const stmt = this.db.prepare(`\n SELECT si.uuid FROM service_index si\n INNER JOIN services s ON si.service_id = s.id\n WHERE si.username = ? AND si.service_fqn = ? AND si.expires_at > ?\n `);\n\n const row = stmt.get(username, serviceFqn, Date.now()) as any;\n\n return row ? row.uuid : null;\n }\n\n async deleteService(serviceId: string, username: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM services\n WHERE id = ? AND username = ?\n `);\n\n const result = stmt.run(serviceId, username);\n return result.changes > 0;\n }\n\n async deleteExpiredServices(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM services WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n\n // ===== Helper Methods =====\n\n /**\n * Helper method to convert database row to Offer object\n */\n private rowToOffer(row: any): Offer {\n return {\n id: row.id,\n peerId: row.peer_id,\n sdp: row.sdp,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n lastSeen: row.last_seen,\n secret: row.secret || undefined,\n answererPeerId: row.answerer_peer_id || undefined,\n answerSdp: row.answer_sdp || undefined,\n answeredAt: row.answered_at || undefined,\n };\n }\n\n /**\n * Helper method to convert database row to Service object\n */\n private rowToService(row: any): Service {\n return {\n id: row.id,\n username: row.username,\n serviceFqn: row.service_fqn,\n offerId: row.offer_id,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n isPublic: row.is_public === 1,\n metadata: row.metadata || undefined,\n };\n }\n}\n", "/**\n * Generates a content-based offer ID using SHA-256 hash\n * Creates deterministic IDs based on offer content (sdp, topics)\n * PeerID is not included as it's inferred from authentication\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n *\n * @param sdp - The WebRTC SDP offer\n * @param topics - Array of topic strings\n * @returns SHA-256 hash of the sanitized offer content\n */\nexport async function generateOfferHash(\n sdp: string,\n topics: string[]\n): Promise<string> {\n // Sanitize and normalize the offer content\n // Only include core offer content (not peerId - that's inferred from auth)\n const sanitizedOffer = {\n sdp,\n topics: [...topics].sort(), // Sort topics for consistency\n };\n\n // Create non-prettified JSON string\n const jsonString = JSON.stringify(sanitizedOffer);\n\n // Convert string to Uint8Array for hashing\n const encoder = new TextEncoder();\n const data = encoder.encode(jsonString);\n\n // Generate SHA-256 hash\n const hashBuffer = await crypto.subtle.digest('SHA-256', data);\n\n // Convert hash to hex string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\n\n return hashHex;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["C", "G", "hexToBytes", "err", "err", "c", "Database", "offersWithIds", "candidates", "err"]
|
|
7
7
|
}
|
package/package.json
CHANGED
package/src/crypto.ts
CHANGED
|
@@ -267,8 +267,8 @@ export async function verifyEd25519Signature(
|
|
|
267
267
|
const encoder = new TextEncoder();
|
|
268
268
|
const messageBytes = encoder.encode(message);
|
|
269
269
|
|
|
270
|
-
// Verify signature using @noble/ed25519
|
|
271
|
-
const isValid = await ed25519.
|
|
270
|
+
// Verify signature using @noble/ed25519 (async version)
|
|
271
|
+
const isValid = await ed25519.verifyAsync(signatureBytes, messageBytes, publicKeyBytes);
|
|
272
272
|
return isValid;
|
|
273
273
|
} catch (err) {
|
|
274
274
|
console.error('Ed25519 signature verification failed:', err);
|