diff --git a/deno.json b/deno.json index e572fa6..a5dde59 100644 --- a/deno.json +++ b/deno.json @@ -20,5 +20,8 @@ }, "test": { "exclude": ["npm/"] + }, + "lint": { + "exclude": ["npm/"] } } diff --git a/identity/identity.ts b/identity/identity.ts index 387c771..b212bb5 100644 --- a/identity/identity.ts +++ b/identity/identity.ts @@ -1,23 +1,30 @@ import { BlahKeyPair, BlahPublicKey, - BlahSignedPayload, + type BlahSignedPayload, } from "../crypto/mod.ts"; import type { BlahActKeyRecord } from "./actKey.ts"; import { blahIdentityFileSchema } from "./identityFile.ts"; import type { BlahProfile } from "./profile.ts"; -type ActKey = { +type InternalActKey = { raw: BlahSignedPayload; key: BlahPublicKey | BlahKeyPair; expiresAt: Date; sigValid: boolean; }; +type ActKey = { + publicKey: BlahPublicKey; + expiresAt: Date; + sigValid: boolean; + comment: string; +}; + async function constructActKeyFromRaw( raw: BlahSignedPayload, idKey: BlahPublicKey | BlahKeyPair, -): Promise { +): Promise { const publicKey = idKey instanceof BlahKeyPair ? idKey.publicKey : idKey; let sigValid = false; try { @@ -33,27 +40,42 @@ async function constructActKeyFromRaw( } export class BlahIdentity { - idKey: BlahPublicKey | BlahKeyPair; - actKeys: ActKey[]; - rawProfile: BlahSignedPayload; - profileSigValid: boolean; + private internalIdKey: BlahPublicKey | BlahKeyPair; + private internalActKeys: InternalActKey[]; + private rawProfile: BlahSignedPayload; + private internalProfileSigValid: boolean; private constructor( - idKey: BlahPublicKey | BlahKeyPair, - actKeys: ActKey[], + internalIdKey: BlahPublicKey | BlahKeyPair, + internalActKeys: InternalActKey[], rawProfile: BlahSignedPayload, - profileSigValid: boolean, + internalProfileSigValid: boolean, ) { - this.idKey = idKey; - this.actKeys = actKeys; + this.internalIdKey = internalIdKey; + this.internalActKeys = internalActKeys; this.rawProfile = rawProfile; - this.profileSigValid = profileSigValid; + this.internalProfileSigValid = internalProfileSigValid; } get profile(): BlahProfile { return this.rawProfile.signee.payload; } + get idPublicKey(): BlahPublicKey { + return this.internalIdKey instanceof BlahKeyPair + ? this.internalIdKey.publicKey + : this.internalIdKey; + } + + get actKeys(): ActKey[] { + return this.internalActKeys.map(({ key, expiresAt, sigValid, raw }) => ({ + publicKey: key instanceof BlahKeyPair ? key.publicKey : key, + expiresAt, + sigValid, + comment: raw.signee.payload.comment, + })); + } + static async fromIdentityFile( identityFile: unknown, idKeyPair?: BlahKeyPair, @@ -72,13 +94,13 @@ export class BlahIdentity { throw new Error("ID key pair does not match ID key in identity file."); } - const actKeys: ActKey[] = await Promise.all(act_keys.map(async (raw) => { - const actKey = await constructActKeyFromRaw(raw, idKey); - if (actingKeyPair?.id === actKey.key.id) { - actKey.key = actingKeyPair; - } - return actKey; - })); + const actKeys: InternalActKey[] = await Promise.all( + act_keys.map(async (raw) => { + const actKey = await constructActKeyFromRaw(raw, idKey); + if (actingKeyPair?.id === actKey.key.id) actKey.key = actingKeyPair; + return actKey; + }), + ); const rawProfile = profile; const profileSigningKey = await BlahPublicKey.fromID( @@ -97,4 +119,44 @@ export class BlahIdentity { return new BlahIdentity(idKey, actKeys, rawProfile, profileSigValid); } + + static async create( + idKeyPair: BlahKeyPair, + firstActKey: BlahKeyPair, + profile: BlahProfile, + firstActKeyConfig: Partial>, + ): Promise { + const actKey: ActKey = { + publicKey: firstActKey.publicKey, + expiresAt: new Date(Date.now() + 365 * 24 * 3600 * 1000), + sigValid: true, + comment: "", + ...firstActKeyConfig, + }; + + const actKeyRecord: BlahSignedPayload = await idKeyPair + .signPayload({ + typ: "user_act_key", + expire_time: actKey.expiresAt.getTime() / 1000, + comment: actKey.comment, + act_key: actKey.publicKey.id, + }); + + const internalActKey: InternalActKey = { + raw: actKeyRecord, + key: firstActKey, + expiresAt: actKey.expiresAt, + sigValid: true, + }; + + const profileRecord: BlahSignedPayload = await firstActKey + .signPayload(profile); + + return new BlahIdentity( + idKeyPair, + [internalActKey], + profileRecord, + true, + ); + } }