diff --git a/CHANGELOG.md b/CHANGELOG.md index 186f2e2..7d3727e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.0.1-alpha.182](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.181...v0.0.1-alpha.182) (2024-10-31) + + +### Features + +* add base64 getters to udi class ([637c613](https://github.com/DIG-Network/dig-chia-sdk/commit/637c613bc5695967829349978915ffc9a7d60b1a)) +* add base64 getters to udi class ([2b111d2](https://github.com/DIG-Network/dig-chia-sdk/commit/2b111d2263ee58b1376db65db8edcf5ad947991e)) + ### [0.0.1-alpha.181](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.180...v0.0.1-alpha.181) (2024-10-31) diff --git a/package-lock.json b/package-lock.json index 3388818..26cde2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dignetwork/dig-sdk", - "version": "0.0.1-alpha.181", + "version": "0.0.1-alpha.182", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@dignetwork/dig-sdk", - "version": "0.0.1-alpha.181", + "version": "0.0.1-alpha.182", "license": "ISC", "dependencies": { "@dignetwork/datalayer-driver": "^0.1.29", diff --git a/package.json b/package.json index 3891a96..28cb44c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dignetwork/dig-sdk", - "version": "0.0.1-alpha.181", + "version": "0.0.1-alpha.182", "description": "", "type": "commonjs", "main": "./dist/index.js", diff --git a/src/utils/Udi.ts b/src/utils/Udi.ts index f6d4aae..00abae6 100644 --- a/src/utils/Udi.ts +++ b/src/utils/Udi.ts @@ -36,12 +36,15 @@ class Udi { if (Udi.isBase32(input)) { const paddedInput = Udi.addBase32Padding(input.toUpperCase()); - return Buffer.from(base32Decode(paddedInput, false)); // Decode as UTF-8 + return Buffer.from(base32Decode(paddedInput, false)); } - throw new Error( - "Invalid input encoding. Must be 32-byte hex or Base32 string." - ); + if (Udi.isBase64Safe(input)) { + const standardBase64 = Udi.addBase64Padding(Udi.toStandardBase64(input)); + return Buffer.from(standardBase64, "base64"); + } + + throw new Error("Invalid input encoding. Must be 32-byte hex, Base32, or Base64 URL-safe string."); } static isHex(input: string): boolean { @@ -52,12 +55,28 @@ class Udi { return /^[a-z2-7]{52}$/.test(input.toLowerCase()); } + static isBase64Safe(input: string): boolean { + return /^[A-Za-z0-9\-_]+$/.test(input); + } + static addBase32Padding(input: string): string { - // Calculate required padding const paddingNeeded = (8 - (input.length % 8)) % 8; return input + "=".repeat(paddingNeeded); } + static toStandardBase64(base64Safe: string): string { + return base64Safe.replace(/-/g, "+").replace(/_/g, "/"); + } + + static toBase64Safe(base64Standard: string): string { + return base64Standard.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); + } + + static addBase64Padding(base64: string): string { + const paddingNeeded = (4 - (base64.length % 4)) % 4; + return base64 + "=".repeat(paddingNeeded); + } + withRootHash(rootHash: string | Buffer | null): Udi { return new Udi(this.chainName, this._storeId, rootHash, this.resourceKey); } @@ -69,7 +88,7 @@ class Udi { static fromUrn(urn: string): Udi { const parsedUrn = urns.parseURN(urn); if (parsedUrn.nid.toLowerCase() !== Udi.nid) { - throw new Error(`Invalid nid: ${parsedUrn.nid}`); + throw new Error(`Invalid UDI: ${parsedUrn.nid}`); } const parts = parsedUrn.nss.split(":"); @@ -94,7 +113,7 @@ class Udi { return new Udi(chainName, storeId, rootHash, resourceKey); } - toUrn(encoding: "hex" | "base32" = "hex"): string { + toUrn(encoding: "hex" | "base32" | "base64" = "hex"): string { const storeIdStr = this.bufferToString(this._storeId, encoding); let urn = `${Udi.namespace}:${this.chainName}:${storeIdStr}`; @@ -110,10 +129,15 @@ class Udi { return urn; } - bufferToString(buffer: Buffer, encoding: "hex" | "base32"): string { - return encoding === "hex" - ? buffer.toString("hex") - : base32Encode(buffer).toLowerCase().replace(/=+$/, ""); + bufferToString(buffer: Buffer, encoding: "hex" | "base32" | "base64"): string { + if (encoding === "hex") { + return buffer.toString("hex"); + } else if (encoding === "base32") { + return base32Encode(buffer).toLowerCase().replace(/=+$/, ""); + } else if (encoding === "base64") { + return Udi.toBase64Safe(buffer.toString("base64")); + } + throw new Error("Unsupported encoding type"); } equals(other: Udi): boolean { @@ -132,12 +156,7 @@ class Udi { } clone(): Udi { - return new Udi( - this.chainName, - this._storeId, - this._rootHash, - this.resourceKey - ); + return new Udi(this.chainName, this._storeId, this._rootHash, this.resourceKey); } hashCode(): string { @@ -159,9 +178,15 @@ class Udi { } get rootHashBase32(): string | null { - return this._rootHash - ? this.bufferToString(this._rootHash, "base32") - : null; + return this._rootHash ? this.bufferToString(this._rootHash, "base32") : null; + } + + get storeIdBase64(): string { + return this.bufferToString(this._storeId, "base64"); + } + + get rootHashBase64(): string | null { + return this._rootHash ? this.bufferToString(this._rootHash, "base64") : null; } }