From e34bd84b0cbf2d465cd9b2afd5b13ce917644238 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 14 May 2024 12:56:59 -1000 Subject: [PATCH] docs(federation): :memo: Update READMEs and some docstrings --- federation/README.md | 70 ++++++++++++++++++++++++--- federation/cryptography/index.test.ts | 4 +- federation/cryptography/index.ts | 12 +++-- 3 files changed, 73 insertions(+), 13 deletions(-) diff --git a/federation/README.md b/federation/README.md index 89816f5..395e20f 100644 --- a/federation/README.md +++ b/federation/README.md @@ -16,12 +16,6 @@ Compilation (bundling/minifying) time is a few seconds, almost all of which is s ### Federation -#### Roadmap - -- [x] Validation -- [ ] Signing code -- [ ] Advanced validator - #### Validation [**Zod**](https://zod.dev) is used to validate and parse the objects. All Lysand objects are already written for you. @@ -54,10 +48,70 @@ const validNote = await validator.Note(validNoteObject); // validNote is still the same as noteObject ``` -For more information about Note's methods, see the [**Zod documentation**](https://zod.dev/docs/). - Your editor's IntelliSense should provide you with every method and property available, which all match the [**Lysand**](https://lysand.org) specification names. +#### Cryptography + +The cryptography module provides two main classes: [`SignatureConstructor`](federation/cryptography/index.ts) and [`SignatureValidator`](federation/cryptography/index.ts). These classes are used to construct and validate signatures for requests, respectively. + +##### SignatureConstructor + +The [`SignatureConstructor`](federation/cryptography/index.ts) class is used to construct a signature for a request. It can be instantiated with a private key and a key ID: + +```ts +const privateKey = // CryptoKey +const keyId = "https://example.com/users/6a18f2c3-120e-4949-bda4-2aa4c8264d51"; +const constructor = new SignatureConstructor(privateKey, keyId); +``` + +Alternatively, you can create a `SignatureConstructor` instance from a base64-encoded private key: + +```ts +const privateKey = "base64PrivateKey"; +const keyId = "https://example.com/users/6a18f2c3-120e-4949-bda4-2aa4c8264d51"; +const constructor = await SignatureConstructor.fromStringKey(privateKey, keyId); +``` + +The `sign` method is used to sign a request: + +```ts +const request = new Request(); +// Returns a Request object with Signature and Date set +const signature = await constructor.sign(request); +// Alternatively +// Returns a Header object with Signature and Date set +const signature = await constructor.sign(date, method, url, body); +``` + +##### SignatureValidator + +The [`SignatureValidator`](federation/cryptography/index.ts) class is used to validate the signature of a request. It can be instantiated with a public key: + +```ts +const publicKey = // CryptoKey +const validator = new SignatureValidator(publicKey); +``` + +Alternatively, you can create a `SignatureValidator` instance from a base64-encoded public key: + +```ts +const publicKey = "base64PublicKey"; +const validator = await SignatureValidator.fromStringKey(publicKey); +``` + +The `validate` method is used to validate a request or signature: + +```ts +const request = new Request(); +// Returns boolean or TypeError if data is invalid +const isValid = await validator.validate(request); +// Alternatively +// Returns boolean or TypeError if data is invalid +const isValid = await validator.validate(signature, date, method, url, body); +``` + +Please note that these classes require the WebCrypto API and Ed25519 support in the environment. WebCrypto support is automatically checked, but Ed25519 cannot be as far as I know. + ## Getting Started ### Prerequisites diff --git a/federation/cryptography/index.test.ts b/federation/cryptography/index.test.ts index 8ca7a70..3bf5fbc 100644 --- a/federation/cryptography/index.test.ts +++ b/federation/cryptography/index.test.ts @@ -1,5 +1,5 @@ -import { describe, beforeAll, test, expect, beforeEach } from "bun:test"; -import { SignatureValidator, SignatureConstructor } from "./index"; +import { beforeAll, beforeEach, describe, expect, test } from "bun:test"; +import { SignatureConstructor, SignatureValidator } from "./index"; describe("SignatureValidator", () => { let validator: SignatureValidator; diff --git a/federation/cryptography/index.ts b/federation/cryptography/index.ts index 276d35d..11f9095 100644 --- a/federation/cryptography/index.ts +++ b/federation/cryptography/index.ts @@ -189,6 +189,11 @@ export class SignatureConstructor { /** * Creates a new instance of SignatureConstructor. * @param privateKey The private key used for signature generation. + * @param keyId The key ID used for the Signature header. + * @example + * const privateKey = // CryptoKey + * const keyId = "https://example.com/users/6a18f2c3-120e-4949-bda4-2aa4c8264d51"; + * const constructor = new SignatureConstructor(privateKey, keyId); */ constructor( private privateKey: CryptoKey, @@ -200,10 +205,12 @@ export class SignatureConstructor { /** * Creates a SignatureConstructor instance from a base64-encoded private key. * @param base64PrivateKey The base64-encoded private key. + * @param keyId The key ID used for the Signature header. * @returns A Promise that resolves to a SignatureConstructor instance. * @example * const privateKey = "base64PrivateKey"; - * const constructor = await SignatureConstructor.fromStringKey(privateKey); + * const keyId = "https://example.com/users/6a18f2c3-120e-4949-bda4-2aa4c8264d51"; + * const constructor = await SignatureConstructor.fromStringKey(privateKey, keyId); */ static async fromStringKey( base64PrivateKey: string, @@ -243,8 +250,7 @@ export class SignatureConstructor { * const method = "GET"; * const url = new URL("https://example.com"); * const body = "request body"; - * const headers = new Headers(); - * const signedHeaders = await constructor.sign(method, url, body, headers); + * const signedHeaders = await constructor.sign(method, url, body); */ async sign( method: HttpVerb,