diff --git a/packages/codecs/LICENSE b/packages/codecs/LICENSE new file mode 100644 index 000000000..eeec9a94b --- /dev/null +++ b/packages/codecs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 idOS Network + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/codecs/README.md b/packages/codecs/README.md new file mode 100644 index 000000000..7de8ffdcb --- /dev/null +++ b/packages/codecs/README.md @@ -0,0 +1,3 @@ +# idOS codecs + +A collection of codecs used by the idOS SDK. diff --git a/packages/codecs/index.ts b/packages/codecs/index.ts new file mode 100644 index 000000000..dbca852d8 --- /dev/null +++ b/packages/codecs/index.ts @@ -0,0 +1,10 @@ +export { decode as base64Decode } from "@stablelib/base64"; +export { encode as base64Encode } from "@stablelib/base64"; +export { writeUint16BE as binaryWriteUint16BE } from "@stablelib/binary"; +export { concat as bytesConcat } from "@stablelib/bytes"; +export { decode as hexDecode } from "@stablelib/hex"; +export { encode as hexEncode } from "@stablelib/hex"; +export { hash as sha256Hash } from "@stablelib/sha256"; +export { decode as utf8Decode } from "@stablelib/utf8"; +export { encode as utf8Encode } from "@stablelib/utf8"; +export { serialize as borshSerialize } from "borsh"; diff --git a/packages/codecs/package.json b/packages/codecs/package.json new file mode 100644 index 000000000..d028c217e --- /dev/null +++ b/packages/codecs/package.json @@ -0,0 +1,19 @@ +{ + "name": "@idos-network/codecs", + "version": "0.0.1", + "description": "A collection of codecs used by the idOS SDK.", + "homepage": "https://idos.network", + "repository": "https://github.com/idos-network/idos-sdk-js", + "license": "MIT", + "type": "module", + "main": "index.ts", + "dependencies": { + "@stablelib/base64": "^1.0.1", + "@stablelib/binary": "^1.0.1", + "@stablelib/bytes": "^1.0.1", + "@stablelib/hex": "^2.0.0", + "@stablelib/sha256": "^1.0.1", + "@stablelib/utf8": "^1.0.1", + "borsh": "^1.0.0" + } +} diff --git a/packages/codecs/tsconfig.json b/packages/codecs/tsconfig.json new file mode 100644 index 000000000..b2612cd29 --- /dev/null +++ b/packages/codecs/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "composite": true, + "lib": ["ESNext"], + "module": "ESNext", + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": "." + }, + "include": ["./src/**/*.ts"] +} diff --git a/packages/idos-sdk-js/package.json b/packages/idos-sdk-js/package.json index 1fb9e1930..e7ec16bad 100644 --- a/packages/idos-sdk-js/package.json +++ b/packages/idos-sdk-js/package.json @@ -58,15 +58,9 @@ "dependencies": { "@digitalbazaar/ed25519-signature-2020": "^5.2.0", "@digitalbazaar/ed25519-verification-key-2020": "^4.1.0", + "@idos-network/codecs": "workspace:*", "@digitalbazaar/vc": "^6.0.2", "@kwilteam/kwil-js": "0.7.1", - "@stablelib/base64": "^1.0.1", - "@stablelib/binary": "^1.0.1", - "@stablelib/bytes": "^1.0.1", - "@stablelib/hex": "^2.0.0", - "@stablelib/sha256": "^1.0.1", - "@stablelib/utf8": "^1.0.1", - "borsh": "^1.0.0", "es-toolkit": "^1.23.0", "bs58": "^6.0.0", "jsonld": "^8.3.1", diff --git a/packages/idos-sdk-js/src/lib/auth.ts b/packages/idos-sdk-js/src/lib/auth.ts index 8d7fbc5f9..1f804f2bb 100644 --- a/packages/idos-sdk-js/src/lib/auth.ts +++ b/packages/idos-sdk-js/src/lib/auth.ts @@ -1,12 +1,14 @@ +import { + base64Decode, + binaryWriteUint16BE, + borshSerialize, + bytesConcat, + utf8Decode, +} from "@idos-network/codecs"; +import type { EthSigner } from "@kwilteam/kwil-js/dist/core/builders"; import type { SignMessageParams, SignedMessage, Wallet } from "@near-wallet-selector/core"; -import * as Base64Codec from "@stablelib/base64"; -import * as BinaryCodec from "@stablelib/binary"; -import * as BytesCodec from "@stablelib/bytes"; -import * as Utf8Codec from "@stablelib/utf8"; -import * as BorshCodec from "borsh"; import type { Signer } from "ethers"; -import type { EthSigner } from "@kwilteam/kwil-js/dist/core/builders"; import type { Store } from "../../../idos-store"; import type { KwilWrapper } from "./kwil-wrapper"; import { Nonce } from "./nonce"; @@ -149,7 +151,7 @@ export class Auth { const signer = async (message: string | Uint8Array): Promise => { // biome-ignore lint/style/noParameterAssign: we're narrowing the type on purpose. - if (typeof message !== "string") message = Utf8Codec.decode(message); + if (typeof message !== "string") message = utf8Decode(message); if (!wallet.signMessage) throw new Error("Only wallets with signMessage are supported."); const nonceSuggestion = Buffer.from(new Nonce(32).bytes); @@ -188,12 +190,12 @@ export class Auth { callbackUrl, }; - const nep413BorshPayload = BorshCodec.serialize(nep413BorschSchema, nep413BorshParams); + const nep413BorshPayload = borshSerialize(nep413BorschSchema, nep413BorshParams); - return BytesCodec.concat( - BinaryCodec.writeUint16BE(nep413BorshPayload.length), + return bytesConcat( + binaryWriteUint16BE(nep413BorshPayload.length), nep413BorshPayload, - Base64Codec.decode(signature), + base64Decode(signature), ); }; diff --git a/packages/idos-sdk-js/src/lib/data.ts b/packages/idos-sdk-js/src/lib/data.ts index 6d80ae390..14c1b46e0 100644 --- a/packages/idos-sdk-js/src/lib/data.ts +++ b/packages/idos-sdk-js/src/lib/data.ts @@ -1,7 +1,5 @@ +import { base64Decode, base64Encode, hexEncode, utf8Encode } from "@idos-network/codecs"; import type { idOSCredential } from "@idos-network/idos-sdk-types"; -import * as Base64Codec from "@stablelib/base64"; -import * as HexCodec from "@stablelib/hex"; -import * as Utf8Codec from "@stablelib/utf8"; import nacl from "tweetnacl"; import type { Enclave } from "./enclave"; import type { KwilWrapper } from "./kwil-wrapper"; @@ -81,7 +79,7 @@ export class Data { let receiverPublicKey: string | undefined; if (tableName === "credentials") { - receiverPublicKey = receiverPublicKey ?? Base64Codec.encode(await this.enclave.ready()); + receiverPublicKey = receiverPublicKey ?? base64Encode(await this.enclave.ready()); for (const record of records) { Object.assign( record, @@ -131,7 +129,7 @@ export class Data { } if (tableName === "credentials") { - receiverPublicKey ??= Base64Codec.encode(await this.enclave.ready()); + receiverPublicKey ??= base64Encode(await this.enclave.ready()); Object.assign( record, await this.#buildInsertableIDOSCredential( @@ -266,7 +264,7 @@ export class Data { const record: any = recordLike; if (tableName === "credentials") { - receiverPublicKey ??= Base64Codec.encode(await this.enclave.ready()); + receiverPublicKey ??= base64Encode(await this.enclave.ready()); Object.assign( record, await this.#buildInsertableIDOSCredential( @@ -371,7 +369,7 @@ export class Data { receiverEncryptionPublicKey, ); const publicNotesSignature = nacl.sign.detached( - Utf8Codec.encode(publicNotes), + utf8Encode(publicNotes), issuerAuthenticationKeyPair.secretKey, ); @@ -380,16 +378,16 @@ export class Data { content, public_notes: publicNotes, - public_notes_signature: Base64Codec.encode(publicNotesSignature), + public_notes_signature: base64Encode(publicNotesSignature), - broader_signature: Base64Codec.encode( + broader_signature: base64Encode( nacl.sign.detached( - Uint8Array.from([...publicNotesSignature, ...Base64Codec.decode(content)]), + Uint8Array.from([...publicNotesSignature, ...base64Decode(content)]), issuerAuthenticationKeyPair.secretKey, ), ), - issuer_auth_public_key: HexCodec.encode(issuerAuthenticationKeyPair.publicKey, true), + issuer_auth_public_key: hexEncode(issuerAuthenticationKeyPair.publicKey, true), encryption_public_key: isPresent(encryptorPublicKey), }; } diff --git a/packages/idos-sdk-js/src/lib/enclave-providers/iframe-enclave.ts b/packages/idos-sdk-js/src/lib/enclave-providers/iframe-enclave.ts index 8d8c08ecd..63420c536 100644 --- a/packages/idos-sdk-js/src/lib/enclave-providers/iframe-enclave.ts +++ b/packages/idos-sdk-js/src/lib/enclave-providers/iframe-enclave.ts @@ -1,5 +1,6 @@ +import { base64Encode } from "@idos-network/codecs"; import type { idOSCredential } from "@idos-network/idos-sdk-types"; -import * as Base64Codec from "@stablelib/base64"; + import type { BackupPasswordInfo } from "../types"; import type { DiscoverEncryptionKeyResponse, @@ -246,7 +247,7 @@ export class IframeEnclave implements EnclaveProvider { return { humanId, - encryptionPublicKey: Base64Codec.encode(encryptionPublicKey), + encryptionPublicKey: base64Encode(encryptionPublicKey), }; } } diff --git a/packages/idos-sdk-js/src/lib/enclave.ts b/packages/idos-sdk-js/src/lib/enclave.ts index 9dbf8c0a8..530123e2b 100644 --- a/packages/idos-sdk-js/src/lib/enclave.ts +++ b/packages/idos-sdk-js/src/lib/enclave.ts @@ -1,6 +1,5 @@ +import { base64Decode, base64Encode, utf8Decode, utf8Encode } from "@idos-network/codecs"; import type { idOSCredential } from "@idos-network/idos-sdk-types"; -import * as Base64Codec from "@stablelib/base64"; -import * as Utf8Codec from "@stablelib/utf8"; import type { Auth } from "./auth"; import type { EnclaveProvider } from "./enclave-providers/types"; import type { BackupPasswordInfo } from "./types"; @@ -47,23 +46,23 @@ export class Enclave { if (!this.encryptionPublicKey) await this.ready(); const { content, encryptorPublicKey } = await this.provider.encrypt( - Utf8Codec.encode(message), - receiverPublicKey === undefined ? undefined : Base64Codec.decode(receiverPublicKey), + utf8Encode(message), + receiverPublicKey === undefined ? undefined : base64Decode(receiverPublicKey), ); return { - content: Base64Codec.encode(content), - encryptorPublicKey: Base64Codec.encode(encryptorPublicKey), + content: base64Encode(content), + encryptorPublicKey: base64Encode(encryptorPublicKey), }; } async decrypt(message: string, senderPublicKey?: string): Promise { if (!this.encryptionPublicKey) await this.ready(); - return Utf8Codec.decode( + return utf8Decode( await this.provider.decrypt( - Base64Codec.decode(message), - senderPublicKey === undefined ? undefined : Base64Codec.decode(senderPublicKey), + base64Decode(message), + senderPublicKey === undefined ? undefined : base64Decode(senderPublicKey), ), ); } diff --git a/packages/idos-sdk-js/src/lib/grants/near.ts b/packages/idos-sdk-js/src/lib/grants/near.ts index 33426e229..8181edb2e 100644 --- a/packages/idos-sdk-js/src/lib/grants/near.ts +++ b/packages/idos-sdk-js/src/lib/grants/near.ts @@ -1,5 +1,5 @@ +import { base64Decode } from "@idos-network/codecs"; import type { SignMessageParams, SignedMessage, Wallet } from "@near-wallet-selector/core"; -import * as Base64Codec from "@stablelib/base64"; import type { Contract, connect, keyStores, providers } from "near-api-js"; import { Nonce } from "../nonce"; import Grant from "./grant"; @@ -135,7 +135,7 @@ export class NearGrants implements GrantChild { if (!nonce) throw new Error("signMessage is expected to return a nonce, but it didn't"); return { - signature: Base64Codec.decode(b64Signature), + signature: base64Decode(b64Signature), nonce, }; } diff --git a/packages/idos-sdk-js/src/lib/utils.ts b/packages/idos-sdk-js/src/lib/utils.ts index 369270440..c7e7f8b70 100644 --- a/packages/idos-sdk-js/src/lib/utils.ts +++ b/packages/idos-sdk-js/src/lib/utils.ts @@ -1,5 +1,5 @@ +import { hexEncode } from "@idos-network/codecs"; import type { AccessKeyList } from "@near-js/types"; -import { encode as encodeHex } from "@stablelib/hex"; import bs58 from "bs58"; import type { connect as connectT } from "near-api-js"; @@ -36,7 +36,7 @@ export async function getNearFullAccessPublicKeys( export function implicitAddressFromPublicKey(publicKey: string) { const key_without_prefix = publicKey.replace(/^ed25519:/, ""); - const implicitAddress = encodeHex(bs58.decode(key_without_prefix)); + const implicitAddress = hexEncode(bs58.decode(key_without_prefix)); return implicitAddress; } diff --git a/packages/issuer-sdk-js/package.json b/packages/issuer-sdk-js/package.json index 92b3ded0a..5b9fd1a97 100644 --- a/packages/issuer-sdk-js/package.json +++ b/packages/issuer-sdk-js/package.json @@ -58,10 +58,8 @@ "vitest": "^0.31.4" }, "dependencies": { + "@idos-network/codecs": "workspace:*", "@kwilteam/kwil-js": "0.7.1", - "@stablelib/base64": "^1.0.1", - "@stablelib/hex": "^2.0.0", - "@stablelib/utf8": "^1.0.1", "es-toolkit": "^1.23.0", "tiny-invariant": "^1.3.3", "tweetnacl": "^1.0.3" diff --git a/packages/issuer-sdk-js/src/credentials.ts b/packages/issuer-sdk-js/src/credentials.ts index a0be5c301..5fa57b244 100644 --- a/packages/issuer-sdk-js/src/credentials.ts +++ b/packages/issuer-sdk-js/src/credentials.ts @@ -1,7 +1,5 @@ +import { base64Decode, base64Encode, hexEncode, utf8Encode } from "@idos-network/codecs"; import type { idOSCredential } from "@idos-network/idos-sdk-types"; -import * as Base64Codec from "@stablelib/base64"; -import * as HexCodec from "@stablelib/hex"; -import * as Utf8Codec from "@stablelib/utf8"; import { omit } from "es-toolkit"; import nacl from "tweetnacl"; import type { IssuerConfig } from "./create-issuer-config"; @@ -15,13 +13,13 @@ const buildUpdateablePublicNotes = ( { publicNotes }: UpdateablePublicNotes, ) => { const publicNotesSignature = nacl.sign.detached( - Utf8Codec.encode(publicNotes), + utf8Encode(publicNotes), issuerConfig.signingKeyPair.secretKey, ); return { public_notes: publicNotes, - public_notes_signature: Base64Codec.encode(publicNotesSignature), + public_notes_signature: base64Encode(publicNotesSignature), }; }; @@ -45,7 +43,7 @@ const buildInsertableIDOSCredential = ( }, ): InsertableIDOSCredential => { const ephemeralKeyPair = nacl.box.keyPair(); - const content = Base64Codec.decode( + const content = base64Decode( encryptContent(plaintextContent, receiverEncryptionPublicKey, ephemeralKeyPair.secretKey), ); @@ -55,20 +53,20 @@ const buildInsertableIDOSCredential = ( return { human_id: humanId, - content: Base64Codec.encode(content), + content: base64Encode(content), public_notes, public_notes_signature, - broader_signature: Base64Codec.encode( + broader_signature: base64Encode( nacl.sign.detached( - Uint8Array.from([...Base64Codec.decode(public_notes_signature), ...content]), + Uint8Array.from([...base64Decode(public_notes_signature), ...content]), issuerConfig.signingKeyPair.secretKey, ), ), - issuer_auth_public_key: HexCodec.encode(issuerConfig.signingKeyPair.publicKey, true), - encryption_public_key: Base64Codec.encode(ephemeralKeyPair.publicKey), + issuer_auth_public_key: hexEncode(issuerConfig.signingKeyPair.publicKey, true), + encryption_public_key: base64Encode(ephemeralKeyPair.publicKey), }; }; diff --git a/packages/issuer-sdk-js/src/internal.ts b/packages/issuer-sdk-js/src/internal.ts index a537235d9..5dba9e3d9 100644 --- a/packages/issuer-sdk-js/src/internal.ts +++ b/packages/issuer-sdk-js/src/internal.ts @@ -1,5 +1,5 @@ +import { base64Encode } from "@idos-network/codecs"; import { Utils } from "@kwilteam/kwil-js"; -import * as Base64Codec from "@stablelib/base64"; import nacl from "tweetnacl"; export function ensureEntityId(entity: T): { id: string } & T { @@ -29,9 +29,9 @@ export function encryptContent( throw Error( `Couldn't encrypt. ${JSON.stringify( { - message: Base64Codec.encode(message), - nonce: Base64Codec.encode(nonce), - receiverPublicKey: Base64Codec.encode(receiverPublicKey), + message: base64Encode(message), + nonce: base64Encode(nonce), + receiverPublicKey: base64Encode(receiverPublicKey), }, null, 2, @@ -42,5 +42,5 @@ export function encryptContent( fullMessage.set(nonce, 0); fullMessage.set(encrypted, nonce.length); - return Base64Codec.encode(fullMessage); + return base64Encode(fullMessage); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15a8cdda5..b81a42ebf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -380,7 +380,7 @@ importers: version: 8.7.0(near-api-js@3.0.4(encoding@0.1.13)) axios: specifier: ^1.6.8 - version: 1.7.2(debug@4.3.5) + version: 1.7.2 ethers: specifier: ^6.13 version: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -522,20 +522,8 @@ importers: specifier: ^5.0.2 version: 5.0.10 - packages/idos-sdk-js: + packages/codecs: dependencies: - '@digitalbazaar/ed25519-signature-2020': - specifier: ^5.2.0 - version: 5.2.0(web-streams-polyfill@3.2.1) - '@digitalbazaar/ed25519-verification-key-2020': - specifier: ^4.1.0 - version: 4.1.0 - '@digitalbazaar/vc': - specifier: ^6.0.2 - version: 6.0.2(web-streams-polyfill@3.2.1) - '@kwilteam/kwil-js': - specifier: 0.7.1 - version: 0.7.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@stablelib/base64': specifier: ^1.0.1 version: 1.0.1 @@ -557,6 +545,24 @@ importers: borsh: specifier: ^1.0.0 version: 1.0.0 + + packages/idos-sdk-js: + dependencies: + '@digitalbazaar/ed25519-signature-2020': + specifier: ^5.2.0 + version: 5.2.0(web-streams-polyfill@3.2.1) + '@digitalbazaar/ed25519-verification-key-2020': + specifier: ^4.1.0 + version: 4.1.0 + '@digitalbazaar/vc': + specifier: ^6.0.2 + version: 6.0.2(web-streams-polyfill@3.2.1) + '@idos-network/codecs': + specifier: workspace:* + version: link:../codecs + '@kwilteam/kwil-js': + specifier: 0.7.1 + version: 0.7.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) bs58: specifier: ^6.0.0 version: 6.0.0 @@ -708,18 +714,12 @@ importers: packages/issuer-sdk-js: dependencies: + '@idos-network/codecs': + specifier: workspace:* + version: link:../codecs '@kwilteam/kwil-js': specifier: 0.7.1 version: 0.7.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@stablelib/base64': - specifier: ^1.0.1 - version: 1.0.1 - '@stablelib/hex': - specifier: ^2.0.0 - version: 2.0.0 - '@stablelib/utf8': - specifier: ^1.0.1 - version: 1.0.1 es-toolkit: specifier: ^1.23.0 version: 1.23.0 @@ -17343,8 +17343,8 @@ snapshots: dependencies: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.1.0 - '@noble/hashes': 1.5.0 - '@scure/base': 1.1.9 + '@noble/hashes': 1.6.1 + '@scure/base': 1.2.1 '@types/debug': 4.1.12 debug: 4.3.5(supports-color@8.1.1) pony-cause: 2.1.11 @@ -17357,8 +17357,8 @@ snapshots: dependencies: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.1.0 - '@noble/hashes': 1.5.0 - '@scure/base': 1.1.9 + '@noble/hashes': 1.6.1 + '@scure/base': 1.2.1 '@types/debug': 4.1.12 debug: 4.3.5(supports-color@8.1.1) pony-cause: 2.1.11 @@ -23962,14 +23962,14 @@ snapshots: axios@0.27.2: dependencies: - follow-redirects: 1.15.6(debug@4.3.5) + follow-redirects: 1.15.6(debug@4.3.4) form-data: 4.0.0 transitivePeerDependencies: - debug axios@1.6.7: dependencies: - follow-redirects: 1.15.6(debug@4.3.5) + follow-redirects: 1.15.6(debug@4.3.4) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -23983,6 +23983,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.7.2: + dependencies: + follow-redirects: 1.15.6(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axios@1.7.2(debug@4.3.5): dependencies: follow-redirects: 1.15.6(debug@4.3.5) @@ -26322,7 +26330,7 @@ snapshots: http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.6(debug@4.3.5) + follow-redirects: 1.15.6(debug@4.3.4) requires-port: 1.0.0 transitivePeerDependencies: - debug