Add RSA key to actors, use LRU cache
This commit is contained in:
parent
e5082ed805
commit
f8674ed053
|
@ -1,7 +1,32 @@
|
||||||
|
import { nip19, secp } from '@/deps.ts';
|
||||||
|
|
||||||
/** Application-wide configuration. */
|
/** Application-wide configuration. */
|
||||||
const Conf = {
|
const Conf = {
|
||||||
get nsec() {
|
get nsec() {
|
||||||
return Deno.env.get('DITTO_NSEC');
|
const value = Deno.env.get('DITTO_NSEC');
|
||||||
|
if (!value) {
|
||||||
|
throw new Error('Missing DITTO_NSEC');
|
||||||
|
}
|
||||||
|
if (!value.startsWith('nsec1')) {
|
||||||
|
throw new Error('Invalid DITTO_NSEC');
|
||||||
|
}
|
||||||
|
return value as `nsec1${string}`;
|
||||||
|
},
|
||||||
|
get seckey() {
|
||||||
|
const result = nip19.decode(Conf.nsec);
|
||||||
|
if (result.type !== 'nsec') {
|
||||||
|
throw new Error('Invalid DITTO_NSEC');
|
||||||
|
}
|
||||||
|
return result.data;
|
||||||
|
},
|
||||||
|
get cryptoKey() {
|
||||||
|
return crypto.subtle.importKey(
|
||||||
|
'raw',
|
||||||
|
secp.utils.hexToBytes(Conf.seckey),
|
||||||
|
{ name: 'HMAC', hash: 'SHA-256' },
|
||||||
|
false,
|
||||||
|
['sign', 'verify'],
|
||||||
|
);
|
||||||
},
|
},
|
||||||
get relay() {
|
get relay() {
|
||||||
return Deno.env.get('DITTO_RELAY');
|
return Deno.env.get('DITTO_RELAY');
|
||||||
|
|
12
src/deps.ts
12
src/deps.ts
|
@ -21,7 +21,7 @@ export {
|
||||||
nip19,
|
nip19,
|
||||||
nip21,
|
nip21,
|
||||||
verifySignature,
|
verifySignature,
|
||||||
} from 'npm:nostr-tools@^1.11.2';
|
} from 'npm:nostr-tools@^1.12.1';
|
||||||
export { findReplyTag } from 'https://gitlab.com/soapbox-pub/mostr/-/raw/c67064aee5ade5e01597c6d23e22e53c628ef0e2/src/nostr/tags.ts';
|
export { findReplyTag } from 'https://gitlab.com/soapbox-pub/mostr/-/raw/c67064aee5ade5e01597c6d23e22e53c628ef0e2/src/nostr/tags.ts';
|
||||||
export { parseFormData } from 'npm:formdata-helper@^0.3.0';
|
export { parseFormData } from 'npm:formdata-helper@^0.3.0';
|
||||||
// @deno-types="npm:@types/lodash@4.14.194"
|
// @deno-types="npm:@types/lodash@4.14.194"
|
||||||
|
@ -39,3 +39,13 @@ export { default as sanitizeHtml } from 'npm:sanitize-html@^2.10.0';
|
||||||
export { default as ISO6391 } from 'npm:iso-639-1@2.1.15';
|
export { default as ISO6391 } from 'npm:iso-639-1@2.1.15';
|
||||||
export { Dongoose } from 'https://raw.githubusercontent.com/alexgleason/dongoose/68b7ad9dd7b6ec0615e246a9f1603123c1709793/mod.ts';
|
export { Dongoose } from 'https://raw.githubusercontent.com/alexgleason/dongoose/68b7ad9dd7b6ec0615e246a9f1603123c1709793/mod.ts';
|
||||||
export { createPentagon } from 'https://deno.land/x/pentagon@v0.1.1/mod.ts';
|
export { createPentagon } from 'https://deno.land/x/pentagon@v0.1.1/mod.ts';
|
||||||
|
export {
|
||||||
|
type ParsedSignature,
|
||||||
|
pemToPublicKey,
|
||||||
|
publicKeyToPem,
|
||||||
|
signRequest,
|
||||||
|
verifyRequest,
|
||||||
|
} from 'https://gitlab.com/soapbox-pub/fedisign/-/raw/v0.2.1/mod.ts';
|
||||||
|
export { generateSeededRsa } from 'https://gitlab.com/soapbox-pub/seeded-rsa/-/raw/v1.0.0/mod.ts';
|
||||||
|
export * as secp from 'npm:@noble/secp256k1@^1.7.1';
|
||||||
|
export { LRUCache } from 'npm:lru-cache@^10.0.0';
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Conf } from '@/config.ts';
|
import { Conf } from '@/config.ts';
|
||||||
import { parseMetaContent } from '@/schema.ts';
|
import { parseMetaContent } from '@/schema.ts';
|
||||||
|
import { getPublicKeyPem } from '@/utils/rsa.ts';
|
||||||
|
|
||||||
import type { Event } from '@/event.ts';
|
import type { Event } from '@/event.ts';
|
||||||
import type { Actor } from '@/schemas/activitypub.ts';
|
import type { Actor } from '@/schemas/activitypub.ts';
|
||||||
|
@ -32,6 +33,11 @@ async function toActor(event: Event<0>, username: string): Promise<Actor> {
|
||||||
summary: content.about ?? '',
|
summary: content.about ?? '',
|
||||||
attachment: [],
|
attachment: [],
|
||||||
tag: [],
|
tag: [],
|
||||||
|
publicKey: {
|
||||||
|
id: Conf.local(`/users/${username}#main-key`),
|
||||||
|
owner: Conf.local(`/users/${username}`),
|
||||||
|
publicKeyPem: await getPublicKeyPem(event.pubkey),
|
||||||
|
},
|
||||||
endpoints: {
|
endpoints: {
|
||||||
sharedInbox: Conf.local('/inbox'),
|
sharedInbox: Conf.local('/inbox'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Conf } from '@/config.ts';
|
||||||
|
import { generateSeededRsa, LRUCache, publicKeyToPem, secp } from '@/deps.ts';
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
bits: 1024,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rsaCache = new LRUCache<string, Promise<string>>({ max: 1000 });
|
||||||
|
|
||||||
|
async function buildSeed(pubkey: string): Promise<string> {
|
||||||
|
const key = await Conf.cryptoKey;
|
||||||
|
const data = new TextEncoder().encode(pubkey);
|
||||||
|
const signature = await window.crypto.subtle.sign('HMAC', key, data);
|
||||||
|
return secp.utils.bytesToHex(new Uint8Array(signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPublicKeyPem(pubkey: string): Promise<string> {
|
||||||
|
const cached = await rsaCache.get(pubkey);
|
||||||
|
if (cached) return cached;
|
||||||
|
|
||||||
|
const seed = await buildSeed(pubkey);
|
||||||
|
const { publicKey } = await generateSeededRsa(seed, opts);
|
||||||
|
const promise = publicKeyToPem(publicKey);
|
||||||
|
|
||||||
|
rsaCache.set(pubkey, promise);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getPublicKeyPem };
|
Loading…
Reference in New Issue