From 8520742bad4de0f9ba4d5f3004a7292d27cf363e Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Thu, 8 Jun 2023 09:24:01 -0700 Subject: [PATCH] feat: add toCID function and tests --- ucan-wasm/Cargo.toml | 1 + ucan-wasm/src/ucan/cid.rs | 43 +++++++++++++++++++++++++++++++ ucan-wasm/src/ucan/mod.rs | 1 + ucan-wasm/tests/browser.test.ts | 12 +++++++-- ucan-wasm/tests/fixtures/cid.json | 13 ++++++++++ ucan-wasm/tests/fixtures/index.ts | 18 +++++++++++++ ucan-wasm/tests/node.test.ts | 18 +++++++++---- ucan-wasm/tests/ucan/cid.test.ts | 37 ++++++++++++++++++++++++++ 8 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 ucan-wasm/src/ucan/cid.rs create mode 100644 ucan-wasm/tests/fixtures/cid.json create mode 100644 ucan-wasm/tests/ucan/cid.test.ts diff --git a/ucan-wasm/Cargo.toml b/ucan-wasm/Cargo.toml index 2f4792f9..08817624 100644 --- a/ucan-wasm/Cargo.toml +++ b/ucan-wasm/Cargo.toml @@ -22,6 +22,7 @@ path = "src/lib.rs" # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for # code size when deploying. base64 = "0.21" +cid = "0.10" console_error_panic_hook = { version = "0.1", optional = true } instant = { version = "0.1", features = ["wasm-bindgen"] } js-sys = { version = "0.3", optional = true } diff --git a/ucan-wasm/src/ucan/cid.rs b/ucan-wasm/src/ucan/cid.rs new file mode 100644 index 00000000..909bbe93 --- /dev/null +++ b/ucan-wasm/src/ucan/cid.rs @@ -0,0 +1,43 @@ +use crate::ucan::JsResult; +use ::ucan::Ucan; +use cid::multihash::Code; +use js_sys::Error; +use wasm_bindgen::prelude::wasm_bindgen; + +/// Compute CID for a UCAN +/// +/// Hashers include SHA2-256, SHA2-512, SHA3-224 +/// SHA3-256, SHA3-384, SHA3-512, Keccak-224, Keccak-256, Keccak-384 +/// Keccak-512, BLAKE2b-256, BLAKE2b-512, BLAKE2s-128, and BLAKE3-256. +/// +/// Defaults to BLAKE3-256 hash function. +/// +#[wasm_bindgen(js_name = "toCID")] +pub async fn to_cid(token: String, hasher: Option) -> JsResult { + let ucan = Ucan::try_from(token).map_err(|e| Error::new(&format!("{e}")))?; + + let hasher_code = get_hasher_code(&hasher.unwrap_or(String::from("BLAKE3-256"))); + let cid = Ucan::to_cid(&ucan, hasher_code).map_err(|e| Error::new(&format!("{e}")))?; + + Ok(cid.into()) +} + +fn get_hasher_code(hasher: &str) -> Code { + match hasher { + "SHA2-256" => Code::Sha2_256, + "SHA2-512" => Code::Sha2_512, + "SHA3-224" => Code::Sha3_224, + "SHA3-256" => Code::Sha3_256, + "SHA3-384" => Code::Sha3_384, + "SHA3-512" => Code::Sha3_512, + "Keccak-224" => Code::Keccak224, + "Keccak-256" => Code::Keccak256, + "Keccak-384" => Code::Keccak384, + "Keccak-512" => Code::Keccak512, + "BLAKE2b-256" => Code::Blake2b256, + "BLAKE2b-512" => Code::Blake2b512, + "BLAKE2s-128" => Code::Blake2s128, + "BLAKE3-256" => Code::Blake3_256, + _ => Code::Blake3_256, + } +} diff --git a/ucan-wasm/src/ucan/mod.rs b/ucan-wasm/src/ucan/mod.rs index 8770866f..e63e2c2a 100644 --- a/ucan-wasm/src/ucan/mod.rs +++ b/ucan-wasm/src/ucan/mod.rs @@ -1,3 +1,4 @@ +pub mod cid; pub mod token; pub mod verify; diff --git a/ucan-wasm/tests/browser.test.ts b/ucan-wasm/tests/browser.test.ts index 11abd640..941bc24f 100644 --- a/ucan-wasm/tests/browser.test.ts +++ b/ucan-wasm/tests/browser.test.ts @@ -1,6 +1,7 @@ -import init, { checkSignature, decode, isExpired, isTooEarly, validate } from '../lib/browser/ucan_wasm.js' -import { runVerifyTests } from "./ucan/verify.test.js" +import init, { checkSignature, decode, isExpired, isTooEarly, toCID, validate } from '../lib/browser/ucan_wasm.js' +import { runCIDTests } from "./ucan/cid.test.js" import { runTokenTests } from "./ucan/token.test.js" +import { runVerifyTests } from "./ucan/verify.test.js" before(async () => { await init() @@ -21,3 +22,10 @@ runTokenTests({ decode } }) + +runCIDTests({ + runner: { describe, it }, + ucan: { + toCID + } +}) diff --git a/ucan-wasm/tests/fixtures/cid.json b/ucan-wasm/tests/fixtures/cid.json new file mode 100644 index 00000000..8c8e0f0b --- /dev/null +++ b/ucan-wasm/tests/fixtures/cid.json @@ -0,0 +1,13 @@ + +[ + { + "hasher": "SHA2-256", + "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsInVjdiI6IjAuOS4wLWNhbmFyeSJ9.eyJhdHQiOlt7ImNhbiI6ImVtYWlsL3NlbmQiLCJuYiI6bnVsbCwid2l0aCI6Im1haWx0bzphbGljZUBlbWFpbC5jb20ifV0sImF1ZCI6ImRpZDprZXk6ejZNa3RhZlpUUkVqSmt2VjVtZkp4Y0xwTkJvVlB3RExoVHVNZzluZzdkWTR6TUFMIiwiZXhwIjo5MjQ2MjExMjAwLCJmY3QiOlt7ImNoYWxsZW5nZSI6ImFiY2RlZiJ9XSwiaXNzIjoiZGlkOmtleTp6Nk1rZmZEWkNrQ1RXcmVnODg2OGZHMUZHRm9nY0pqNVg2UFk5M3BQY1dEbjlib2IiLCJwcmYiOlsiYmFma3I0aWdmM3N6N2tqNWRoeHJkanVmeHZhdmtraW5wazJpNzNpNXBzdXA2Y3h1dmR5bTJqZWN3MmUiXX0.nTJl6kKrEKYzp6D4tTc-xYgNxH4urv8tfGU7so6ZIf5s86yMnb6bLpSPMeRchbOafVIy9vil9vjjYACzY1GvBg", + "cid": "bafkreigzlstpwdjhxgjexfm3njsidz3iusyys3d2way35re3gbcghjzsqa" + }, + { + "hasher": "BLAKE3-256", + "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsInVjdiI6IjAuOS4wLWNhbmFyeSJ9.eyJhdHQiOlt7ImNhbiI6ImVtYWlsL3NlbmQiLCJuYiI6bnVsbCwid2l0aCI6Im1haWx0bzphbGljZUBlbWFpbC5jb20ifV0sImF1ZCI6ImRpZDprZXk6ejZNa3RhZlpUUkVqSmt2VjVtZkp4Y0xwTkJvVlB3RExoVHVNZzluZzdkWTR6TUFMIiwiZXhwIjo5MjQ2MjExMjAwLCJmY3QiOlt7ImNoYWxsZW5nZSI6ImFiY2RlZiJ9XSwiaXNzIjoiZGlkOmtleTp6Nk1rZmZEWkNrQ1RXcmVnODg2OGZHMUZHRm9nY0pqNVg2UFk5M3BQY1dEbjlib2IiLCJwcmYiOlsiYmFma3I0aWdmM3N6N2tqNWRoeHJkanVmeHZhdmtraW5wazJpNzNpNXBzdXA2Y3h1dmR5bTJqZWN3MmUiXX0.nTJl6kKrEKYzp6D4tTc-xYgNxH4urv8tfGU7so6ZIf5s86yMnb6bLpSPMeRchbOafVIy9vil9vjjYACzY1GvBg", + "cid": "bafkr4igg7afrwmgzugre2zxd62t3ycs73hto3pe24bavabroxbjpfam57y" + } +] diff --git a/ucan-wasm/tests/fixtures/index.ts b/ucan-wasm/tests/fixtures/index.ts index f626e11c..c380609d 100644 --- a/ucan-wasm/tests/fixtures/index.ts +++ b/ucan-wasm/tests/fixtures/index.ts @@ -1,6 +1,10 @@ +import cid from './cid.json' import invalid from './invalid.json' import valid from './valid.json' + +// VERIFICATION + type Expectation = 'valid' | 'invalid' type Fixture = { @@ -27,6 +31,7 @@ type Fixture = { }, } + export function getFixture(expectation: Expectation, comment: string): Fixture { let fixture @@ -38,3 +43,16 @@ export function getFixture(expectation: Expectation, comment: string): Fixture { return fixture } + + +// CID + +type CIDFixture = { + hasher: string + token: string + cid: string +} + +export function getCIDFixture(hasher: string): CIDFixture { + return cid.find(f => f.hasher === hasher) +} diff --git a/ucan-wasm/tests/node.test.ts b/ucan-wasm/tests/node.test.ts index 0dcdc176..fab3d904 100644 --- a/ucan-wasm/tests/node.test.ts +++ b/ucan-wasm/tests/node.test.ts @@ -1,16 +1,17 @@ import { describe, it } from 'vitest' -import { checkSignature, decode, isExpired, isTooEarly, validate } from '../lib/node/ucan_wasm.js' +import { checkSignature, decode, isExpired, isTooEarly, toCID, validate } from '../lib/node/ucan_wasm.js' +import { runCIDTests } from "./ucan/cid.test.js" import { runTokenTests } from "./ucan/token.test.js" import { runVerifyTests } from "./ucan/verify.test.js" runVerifyTests({ runner: { describe, it }, ucan: { - isExpired, - isTooEarly, - checkSignature, - validate + isExpired, + isTooEarly, + checkSignature, + validate } }) @@ -20,3 +21,10 @@ runTokenTests({ decode } }) + +runCIDTests({ + runner: { describe, it }, + ucan: { + toCID + } +}) diff --git a/ucan-wasm/tests/ucan/cid.test.ts b/ucan-wasm/tests/ucan/cid.test.ts new file mode 100644 index 00000000..a0b5ab13 --- /dev/null +++ b/ucan-wasm/tests/ucan/cid.test.ts @@ -0,0 +1,37 @@ +import assert from 'assert' +import { getCIDFixture } from '../fixtures/index.js' + +export function runCIDTests( + impl: { + runner?: { describe, it }, + ucan: { + toCID: (token: string, hasher?: string) => Promise + } + }) { + + // Use runner or fallback to implicit mocha implementations + const describe = impl.runner?.describe ?? globalThis.describe + const it = impl.runner?.it ?? globalThis.it + + const { toCID } = impl.ucan + + describe('toCID', async () => { + it('should compute CID for a UCAN using a SHA2-256 hasher', async () => { + const fixture = getCIDFixture('SHA2-256') + const cid = await toCID(fixture.token, 'SHA2-256') + assert.equal(cid, fixture.cid) + }) + + it('should compute CID for a UCAN using a BLAKE3-256 hasher', async () => { + const fixture = getCIDFixture('BLAKE3-256') + const cid = await toCID(fixture.token, 'BLAKE3-256') + assert.equal(cid, fixture.cid) + }) + + it('should compute CID for a UCAN deafulting to the BLAKE3-256 hasher', async () => { + const fixture = getCIDFixture('BLAKE3-256') + const cid = await toCID(fixture.token) + assert.equal(cid, fixture.cid) + }) + }) +}