From 102a55ceb016b4f0b07b2cdd8d80d965b17f4d33 Mon Sep 17 00:00:00 2001 From: Michael Feher Date: Mon, 15 Apr 2024 18:32:51 -0400 Subject: [PATCH] test: enforce linters and tests - adds tests to the core library - adds ci for pull requests --- .github/workflows/CI.yml | 23 + clients/liquid-auth-client-js/package.json | 3 +- clients/liquid-auth-client-js/src/connect.ts | 10 +- .../__fixtures__/base64url.fixtures.json | 5 + .../tests/connect.spec.js | 2 +- clients/liquid-auth-core/package.json | 2 +- clients/liquid-auth-core/src/encoding.ts | 19 +- clients/liquid-auth-core/src/hi-base32.ts | 354 +- .../encoding.base64url.fixtures.json | 1079 ++++++ .../__fixtures__/wallet.keys.fixtures.json | 2972 +++++++++++++++++ .../liquid-auth-core/tests/encoding.spec.js | 46 + .../tests/generate.fixtures.js | 61 + package.json | 4 +- services/liquid-auth-api-js/.eslintrc.json | 1 + .../src/adapters/redis-io.adapter.ts | 2 +- .../src/algod/algod.service.ts | 1 - .../liquid-auth-api-js/src/app.controller.ts | 4 - services/liquid-auth-api-js/src/app.module.ts | 2 +- .../liquid-auth-api-js/src/app.service.ts | 9 +- .../src/assertion/assertion.controller.ts | 5 +- .../src/attestation/attestation.service.ts | 2 +- .../src/auth/auth.controller.ts | 5 - .../src/connect/connect.controller.ts | 16 +- .../src/signals/signals.gateway.spec.ts | 2 +- services/liquid-auth-api-js/tsconfig.json | 3 +- sites/dapp-ui/src/Contexts.tsx | 12 +- sites/dapp-ui/src/entry-main.tsx | 2 +- sites/dapp-ui/src/hooks/useDataChannel.ts | 4 +- sites/dapp-ui/src/store.ts | 2 +- 29 files changed, 4241 insertions(+), 411 deletions(-) create mode 100644 .github/workflows/CI.yml create mode 100644 clients/liquid-auth-client-js/tests/__fixtures__/base64url.fixtures.json create mode 100644 clients/liquid-auth-core/tests/__fixtures__/encoding.base64url.fixtures.json create mode 100644 clients/liquid-auth-core/tests/__fixtures__/wallet.keys.fixtures.json create mode 100644 clients/liquid-auth-core/tests/encoding.spec.js create mode 100644 clients/liquid-auth-core/tests/generate.fixtures.js diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..e00b40c --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,23 @@ +name: CI +on: [pull_request] +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [ 18.x, 20.x ] + steps: + - name: Checkout + uses: actions/checkout@master + - name: Use Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Install Dependencies + run: npm install + - name: Run Build + run: npm run build + - name: Lint Codebase + run: npm run lint + - name: Unit Tests with Coverage + run: npm run test:cov diff --git a/clients/liquid-auth-client-js/package.json b/clients/liquid-auth-client-js/package.json index d31fe48..ebef85f 100644 --- a/clients/liquid-auth-client-js/package.json +++ b/clients/liquid-auth-client-js/package.json @@ -26,7 +26,8 @@ "dev": "tsc --watch", "build": "tsc", "preinstall": "npm run build", - "test": "tsc && c8 node --test ./tests/connect.test.js" + "test": "tsc && node --test ./tests/connect.spec.js", + "test:cov": "tsc && c8 node --test ./tests/connect.spec.js" }, "author": "", "license": "MIT", diff --git a/clients/liquid-auth-client-js/src/connect.ts b/clients/liquid-auth-client-js/src/connect.ts index b680b21..87b36ac 100644 --- a/clients/liquid-auth-client-js/src/connect.ts +++ b/clients/liquid-auth-client-js/src/connect.ts @@ -1,7 +1,7 @@ import { DEFAULT_FETCH_OPTIONS } from './constants.js'; import type { Account } from 'algosdk'; import type { SignKeyPair } from 'tweetnacl'; -import { sign } from 'tweetnacl'; +import nacl from 'tweetnacl'; import { toBase64URL, encodeAddress } from '@liquid/core/encoding'; export class Message { @@ -58,9 +58,9 @@ export class Message { // Seed or Secret Key if (key instanceof Uint8Array) { if (key.length === 32) { - keyPair = sign.keyPair.fromSeed(key); + keyPair = nacl.sign.keyPair.fromSeed(key); } else if (key.length === 64) { - keyPair = sign.keyPair.fromSecretKey(key); + keyPair = nacl.sign.keyPair.fromSecretKey(key); } else { throw new TypeError('Invalid seed or secret key'); } @@ -71,7 +71,7 @@ export class Message { typeof (key as Account).addr !== 'undefined' && typeof (key as Account).addr === 'string' ) { - keyPair = sign.keyPair.fromSecretKey((key as Account).sk); + keyPair = nacl.sign.keyPair.fromSecretKey((key as Account).sk); } // NACL @@ -86,7 +86,7 @@ export class Message { throw new TypeError('Invalid key'); } this.signature = toBase64URL( - sign.detached(encoder.encode(this.challenge), keyPair.secretKey), + nacl.sign.detached(encoder.encode(this.challenge), keyPair.secretKey), ); this.wallet = encodeAddress(keyPair.publicKey); return this; diff --git a/clients/liquid-auth-client-js/tests/__fixtures__/base64url.fixtures.json b/clients/liquid-auth-client-js/tests/__fixtures__/base64url.fixtures.json new file mode 100644 index 0000000..8c6c516 --- /dev/null +++ b/clients/liquid-auth-client-js/tests/__fixtures__/base64url.fixtures.json @@ -0,0 +1,5 @@ +[ + [ + "" + ] +] diff --git a/clients/liquid-auth-client-js/tests/connect.spec.js b/clients/liquid-auth-client-js/tests/connect.spec.js index 58d6dde..5dbd731 100644 --- a/clients/liquid-auth-client-js/tests/connect.spec.js +++ b/clients/liquid-auth-client-js/tests/connect.spec.js @@ -4,7 +4,7 @@ import algosdk from 'algosdk'; import nacl from "tweetnacl"; import { Message } from '../lib/connect.js'; -import { fromBase64Url } from "../lib/encoding.js"; +import { fromBase64Url } from "@liquid/core"; const encoder = new TextEncoder; test("create instance", async () => { const msg = new Message("hello", "1234", 1234); diff --git a/clients/liquid-auth-core/package.json b/clients/liquid-auth-core/package.json index 4d97a06..a4fb2bc 100644 --- a/clients/liquid-auth-core/package.json +++ b/clients/liquid-auth-core/package.json @@ -26,7 +26,7 @@ "dev": "tsc --watch", "build": "tsc", "preinstall": "npm run build", - "test": "tsc && c8 node --test ./tests/connect.test.js" + "test": "tsc && c8 -r html node --test ./tests/encoding.spec.js" }, "author": "", "license": "MIT", diff --git a/clients/liquid-auth-core/src/encoding.ts b/clients/liquid-auth-core/src/encoding.ts index 72655fa..1aae877 100644 --- a/clients/liquid-auth-core/src/encoding.ts +++ b/clients/liquid-auth-core/src/encoding.ts @@ -1,5 +1,5 @@ import nacl from "tweetnacl"; -import { decodeAsBytes, encode } from "./hi-base32.js"; +import { decodeAsBytes, encodeBytes } from "./hi-base32.js"; import { createMethod } from "./sha512.js"; const sha512_256 = createMethod(256); const chars = @@ -11,6 +11,8 @@ const ALGORAND_ADDRESS_LENGTH = 58; const HASH_BYTES_LENGTH = 32; export const MALFORMED_ADDRESS_ERROR_MSG = "Malformed address"; export const ALGORAND_ADDRESS_BAD_CHECKSUM_ERROR_MSG = "Bad checksum"; +export const INVALID_BASE64URL_INPUT = "Invalid base64url input"; + /** * Bytes to Base64URL * @param {Uint8Array| ArrayBuffer} arr Bytes to convert to URL safe Base64 @@ -19,7 +21,6 @@ export function toBase64URL(arr: Uint8Array | ArrayBuffer): string { const bytes = arr instanceof Uint8Array ? arr : new Uint8Array(arr); const len = bytes.length; let base64 = ""; - for (let i = 0; i < len; i += 3) { base64 += chars[bytes[i] >> 2]; base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; @@ -42,9 +43,10 @@ export function toBase64URL(arr: Uint8Array | ArrayBuffer): string { */ export function fromBase64Url(base64url: string): Uint8Array { if (typeof base64url !== "string") { - throw new TypeError("Must be string!"); + throw new Error(INVALID_BASE64URL_INPUT); } return new Uint8Array( + // TODO: Cross-platform solution since atob is deprecated in Node atob(base64url.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, "")) .split("") .map((c) => c.charCodeAt(0)), @@ -72,7 +74,7 @@ export function encodeAddress(address: Uint8Array) { nacl.sign.publicKeyLength - ALGORAND_CHECKSUM_BYTE_LENGTH, nacl.sign.publicKeyLength, ); - const addr = encode(concatArrays(address, checksum)); + const addr = encodeBytes(concatArrays(address, checksum)); return addr.toString().slice(0, ALGORAND_ADDRESS_LENGTH); // removing the extra '====' } @@ -124,12 +126,3 @@ export function decodeAddress(address: string): Uint8Array { return pk; } - -export function base64ToUint8Array(encoded) { - return new Uint8Array( - // TODO: Cross-platform solution since atob is deprecated in Node - atob(encoded) - .split("") - .map((c) => c.charCodeAt(0)), - ); -} diff --git a/clients/liquid-auth-core/src/hi-base32.ts b/clients/liquid-auth-core/src/hi-base32.ts index 4864374..c6bdc80 100644 --- a/clients/liquid-auth-core/src/hi-base32.ts +++ b/clients/liquid-auth-core/src/hi-base32.ts @@ -42,78 +42,6 @@ const BASE32_DECODE_CHAR: Record = { 7: 31, }; -const blocks = [0, 0, 0, 0, 0, 0, 0, 0]; - -const throwInvalidUtf8 = function (position: number, partial: string) { - if (partial.length > 10) { - partial = "..." + partial.substr(-10); - } - const err: Error & { position?: any } = new Error( - "Decoded data is not valid UTF-8." + - " Maybe try base32.decode.asBytes()?" + - " Partial data after reading " + - position + - " bytes: " + - partial + - " <-", - ); - err.position = position; - throw err; -}; - -const toUtf8String = function (bytes: number[]) { - let str = ""; - const length = bytes.length; - let i = 0; - let followingChars = 0; - let b; - let c; - while (i < length) { - b = bytes[i++]; - if (b <= 0x7f) { - str += String.fromCharCode(b); - continue; - } else if (b > 0xbf && b <= 0xdf) { - c = b & 0x1f; - followingChars = 1; - } else if (b <= 0xef) { - c = b & 0x0f; - followingChars = 2; - } else if (b <= 0xf7) { - c = b & 0x07; - followingChars = 3; - } else { - throwInvalidUtf8(i, str); - } - - if (typeof c === "undefined") throw new Error("c is undefined"); - - for (let j = 0; j < followingChars; ++j) { - b = bytes[i++]; - if (b < 0x80 || b > 0xbf) { - throwInvalidUtf8(i, str); - } - c <<= 6; - c += b & 0x3f; - } - if (c >= 0xd800 && c <= 0xdfff) { - throwInvalidUtf8(i, str); - } - if (c > 0x10ffff) { - throwInvalidUtf8(i, str); - } - - if (c <= 0xffff) { - str += String.fromCharCode(c); - } else { - c -= 0x10000; - str += String.fromCharCode((c >> 10) + 0xd800); - str += String.fromCharCode((c & 0x3ff) + 0xdc00); - } - } - return str; -}; - export const decodeAsBytes = function (base32Str: string): number[] { if (base32Str === "") { return []; @@ -188,188 +116,7 @@ export const decodeAsBytes = function (base32Str: string): number[] { return bytes; }; -const encodeAscii = function (str: string) { - let v1; - let v2; - let v3; - let v4; - let v5; - let base32Str = ""; - const length = str.length; - for ( - var i = 0, count = parseInt((length / 5) as unknown as string) * 5; - i < count; - - ) { - v1 = str.charCodeAt(i++); - v2 = str.charCodeAt(i++); - v3 = str.charCodeAt(i++); - v4 = str.charCodeAt(i++); - v5 = str.charCodeAt(i++); - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[((v2 << 4) | (v3 >>> 4)) & 31] + - BASE32_ENCODE_CHAR[((v3 << 1) | (v4 >>> 7)) & 31] + - BASE32_ENCODE_CHAR[(v4 >>> 2) & 31] + - BASE32_ENCODE_CHAR[((v4 << 3) | (v5 >>> 5)) & 31] + - BASE32_ENCODE_CHAR[v5 & 31]; - } - - // remain char - const remain = length - count; - if (remain === 1) { - v1 = str.charCodeAt(i); - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[(v1 << 2) & 31] + - "======"; - } else if (remain === 2) { - v1 = str.charCodeAt(i++); - v2 = str.charCodeAt(i); - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[(v2 << 4) & 31] + - "===="; - } else if (remain === 3) { - v1 = str.charCodeAt(i++); - v2 = str.charCodeAt(i++); - v3 = str.charCodeAt(i); - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[((v2 << 4) | (v3 >>> 4)) & 31] + - BASE32_ENCODE_CHAR[(v3 << 1) & 31] + - "==="; - } else if (remain === 4) { - v1 = str.charCodeAt(i++); - v2 = str.charCodeAt(i++); - v3 = str.charCodeAt(i++); - v4 = str.charCodeAt(i); - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[((v2 << 4) | (v3 >>> 4)) & 31] + - BASE32_ENCODE_CHAR[((v3 << 1) | (v4 >>> 7)) & 31] + - BASE32_ENCODE_CHAR[(v4 >>> 2) & 31] + - BASE32_ENCODE_CHAR[(v4 << 3) & 31] + - "="; - } - return base32Str; -}; - -const encodeUtf8 = function (str: string) { - let v1; - let v2; - let v3; - let v4; - let v5; - let code; - let end = false; - let base32Str = ""; - let index = 0; - let i; - let start = 0; - let bytes = 0; - const length = str.length; - if (str === "") { - return base32Str; - } - do { - blocks[0] = blocks[5]; - blocks[1] = blocks[6]; - blocks[2] = blocks[7]; - for (i = start; index < length && i < 5; ++index) { - code = str.charCodeAt(index); - if (code < 0x80) { - blocks[i++] = code; - } else if (code < 0x800) { - blocks[i++] = 0xc0 | (code >> 6); - blocks[i++] = 0x80 | (code & 0x3f); - } else if (code < 0xd800 || code >= 0xe000) { - blocks[i++] = 0xe0 | (code >> 12); - blocks[i++] = 0x80 | ((code >> 6) & 0x3f); - blocks[i++] = 0x80 | (code & 0x3f); - } else { - code = - 0x10000 + - (((code & 0x3ff) << 10) | (str.charCodeAt(++index) & 0x3ff)); - blocks[i++] = 0xf0 | (code >> 18); - blocks[i++] = 0x80 | ((code >> 12) & 0x3f); - blocks[i++] = 0x80 | ((code >> 6) & 0x3f); - blocks[i++] = 0x80 | (code & 0x3f); - } - } - bytes += i - start; - start = i - 5; - if (index === length) { - ++index; - } - if (index > length && i < 6) { - end = true; - } - v1 = blocks[0]; - if (i > 4) { - v2 = blocks[1]; - v3 = blocks[2]; - v4 = blocks[3]; - v5 = blocks[4]; - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[((v2 << 4) | (v3 >>> 4)) & 31] + - BASE32_ENCODE_CHAR[((v3 << 1) | (v4 >>> 7)) & 31] + - BASE32_ENCODE_CHAR[(v4 >>> 2) & 31] + - BASE32_ENCODE_CHAR[((v4 << 3) | (v5 >>> 5)) & 31] + - BASE32_ENCODE_CHAR[v5 & 31]; - } else if (i === 1) { - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[(v1 << 2) & 31] + - "======"; - } else if (i === 2) { - v2 = blocks[1]; - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[(v2 << 4) & 31] + - "===="; - } else if (i === 3) { - v2 = blocks[1]; - v3 = blocks[2]; - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[((v2 << 4) | (v3 >>> 4)) & 31] + - BASE32_ENCODE_CHAR[(v3 << 1) & 31] + - "==="; - } else { - v2 = blocks[1]; - v3 = blocks[2]; - v4 = blocks[3]; - base32Str += - BASE32_ENCODE_CHAR[v1 >>> 3] + - BASE32_ENCODE_CHAR[((v1 << 2) | (v2 >>> 6)) & 31] + - BASE32_ENCODE_CHAR[(v2 >>> 1) & 31] + - BASE32_ENCODE_CHAR[((v2 << 4) | (v3 >>> 4)) & 31] + - BASE32_ENCODE_CHAR[((v3 << 1) | (v4 >>> 7)) & 31] + - BASE32_ENCODE_CHAR[(v4 >>> 2) & 31] + - BASE32_ENCODE_CHAR[(v4 << 3) & 31] + - "="; - } - } while (!end); - return base32Str; -}; - -const encodeBytes = function (bytes: Uint8Array) { +export const encodeBytes = function (bytes: Uint8Array) { let v1; let v2; let v3; @@ -443,102 +190,3 @@ const encodeBytes = function (bytes: Uint8Array) { } return base32Str; }; - -export const encode = function ( - input: string | ArrayBuffer | Uint8Array | number[], - asciiOnly?: boolean, -) { - const notString = typeof input !== "string"; - if (notString && input.constructor === ArrayBuffer) { - input = new Uint8Array(input); - } - if (notString) { - return encodeBytes(input as Uint8Array); - } else if (asciiOnly) { - return encodeAscii(input as string); - } else { - return encodeUtf8(input as string); - } -}; - -export const decode = function (base32Str: string, asciiOnly?: boolean) { - if (!asciiOnly) { - return toUtf8String(decodeAsBytes(base32Str)); - } - if (base32Str === "") { - return ""; - } else if (!/^[A-Z2-7=]+$/.test(base32Str)) { - throw new Error("Invalid base32 characters"); - } - let v1; - let v2; - let v3; - let v4; - let v5; - let v6; - let v7; - let v8; - let str = ""; - let length = base32Str.indexOf("="); - if (length === -1) { - length = base32Str.length; - } - - // 8 char to 5 bytes - for (var i = 0, count = (length >> 3) << 3; i < count; ) { - v1 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v2 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v3 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v4 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v5 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v6 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v7 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v8 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - str += - String.fromCharCode(((v1 << 3) | (v2 >>> 2)) & 255) + - String.fromCharCode(((v2 << 6) | (v3 << 1) | (v4 >>> 4)) & 255) + - String.fromCharCode(((v4 << 4) | (v5 >>> 1)) & 255) + - String.fromCharCode(((v5 << 7) | (v6 << 2) | (v7 >>> 3)) & 255) + - String.fromCharCode(((v7 << 5) | v8) & 255); - } - - // remain bytes - const remain = length - count; - if (remain === 2) { - v1 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v2 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - str += String.fromCharCode(((v1 << 3) | (v2 >>> 2)) & 255); - } else if (remain === 4) { - v1 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v2 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v3 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v4 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - str += - String.fromCharCode(((v1 << 3) | (v2 >>> 2)) & 255) + - String.fromCharCode(((v2 << 6) | (v3 << 1) | (v4 >>> 4)) & 255); - } else if (remain === 5) { - v1 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v2 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v3 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v4 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v5 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - str += - String.fromCharCode(((v1 << 3) | (v2 >>> 2)) & 255) + - String.fromCharCode(((v2 << 6) | (v3 << 1) | (v4 >>> 4)) & 255) + - String.fromCharCode(((v4 << 4) | (v5 >>> 1)) & 255); - } else if (remain === 7) { - v1 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v2 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v3 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v4 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v5 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v6 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - v7 = BASE32_DECODE_CHAR[base32Str.charAt(i++)]; - str += - String.fromCharCode(((v1 << 3) | (v2 >>> 2)) & 255) + - String.fromCharCode(((v2 << 6) | (v3 << 1) | (v4 >>> 4)) & 255) + - String.fromCharCode(((v4 << 4) | (v5 >>> 1)) & 255) + - String.fromCharCode(((v5 << 7) | (v6 << 2) | (v7 >>> 3)) & 255); - } - return str; -}; diff --git a/clients/liquid-auth-core/tests/__fixtures__/encoding.base64url.fixtures.json b/clients/liquid-auth-core/tests/__fixtures__/encoding.base64url.fixtures.json new file mode 100644 index 0000000..cf14ba0 --- /dev/null +++ b/clients/liquid-auth-core/tests/__fixtures__/encoding.base64url.fixtures.json @@ -0,0 +1,1079 @@ +[ + { + "origin": "9b1a1b53-0456-4fcd-b10a-4db40352d58a", + "toBase64Url": "OWIxYTFiNTMtMDQ1Ni00ZmNkLWIxMGEtNGRiNDAzNTJkNThh", + "fromBase64Url": [ + 57, + 98, + 49, + 97, + 49, + 98, + 53, + 51, + 45, + 48, + 52, + 53, + 54, + 45, + 52, + 102, + 99, + 100, + 45, + 98, + 49, + 48, + 97, + 45, + 52, + 100, + 98, + 52, + 48, + 51, + 53, + 50, + 100, + 53, + 56, + 97 + ] + }, + { + "origin": "7646809", + "toBase64Url": "NzY0NjgwOQ", + "fromBase64Url": [ + 55, + 54, + 52, + 54, + 56, + 48, + 57 + ] + }, + { + "origin": "b1338059", + "toBase64Url": "YjEzMzgwNTk", + "fromBase64Url": [ + 98, + 49, + 51, + 51, + 56, + 48, + 53, + 57 + ] + }, + { + "origin": "582bd065-f280-4574-b315-3398c75296c5", + "toBase64Url": "NTgyYmQwNjUtZjI4MC00NTc0LWIzMTUtMzM5OGM3NTI5NmM1", + "fromBase64Url": [ + 53, + 56, + 50, + 98, + 100, + 48, + 54, + 53, + 45, + 102, + 50, + 56, + 48, + 45, + 52, + 53, + 55, + 52, + 45, + 98, + 51, + 49, + 53, + 45, + 51, + 51, + 57, + 56, + 99, + 55, + 53, + 50, + 57, + 54, + 99, + 53 + ] + }, + { + "origin": "29572cc5-7c36-4016-9825-abcc9ba51dae", + "toBase64Url": "Mjk1NzJjYzUtN2MzNi00MDE2LTk4MjUtYWJjYzliYTUxZGFl", + "fromBase64Url": [ + 50, + 57, + 53, + 55, + 50, + 99, + 99, + 53, + 45, + 55, + 99, + 51, + 54, + 45, + 52, + 48, + 49, + 54, + 45, + 57, + 56, + 50, + 53, + 45, + 97, + 98, + 99, + 99, + 57, + 98, + 97, + 53, + 49, + 100, + 97, + 101 + ] + }, + { + "origin": "2ce09bdf-69d1-4b08-b93e-3af4ca6a657a", + "toBase64Url": "MmNlMDliZGYtNjlkMS00YjA4LWI5M2UtM2FmNGNhNmE2NTdh", + "fromBase64Url": [ + 50, + 99, + 101, + 48, + 57, + 98, + 100, + 102, + 45, + 54, + 57, + 100, + 49, + 45, + 52, + 98, + 48, + 56, + 45, + 98, + 57, + 51, + 101, + 45, + 51, + 97, + 102, + 52, + 99, + 97, + 54, + 97, + 54, + 53, + 55, + 97 + ] + }, + { + "origin": "15210d8d-308c-4acd-843c-ba6babada62c", + "toBase64Url": "MTUyMTBkOGQtMzA4Yy00YWNkLTg0M2MtYmE2YmFiYWRhNjJj", + "fromBase64Url": [ + 49, + 53, + 50, + 49, + 48, + 100, + 56, + 100, + 45, + 51, + 48, + 56, + 99, + 45, + 52, + 97, + 99, + 100, + 45, + 56, + 52, + 51, + 99, + 45, + 98, + 97, + 54, + 98, + 97, + 98, + 97, + 100, + 97, + 54, + 50, + 99 + ] + }, + { + "origin": "cba26c96-51ad-40c0-b29f-6a46e0d88d43", + "toBase64Url": "Y2JhMjZjOTYtNTFhZC00MGMwLWIyOWYtNmE0NmUwZDg4ZDQz", + "fromBase64Url": [ + 99, + 98, + 97, + 50, + 54, + 99, + 57, + 54, + 45, + 53, + 49, + 97, + 100, + 45, + 52, + 48, + 99, + 48, + 45, + 98, + 50, + 57, + 102, + 45, + 54, + 97, + 52, + 54, + 101, + 48, + 100, + 56, + 56, + 100, + 52, + 51 + ] + }, + { + "origin": "c13cdc12-c7ed-41db-a669-56a664f8127a", + "toBase64Url": "YzEzY2RjMTItYzdlZC00MWRiLWE2NjktNTZhNjY0ZjgxMjdh", + "fromBase64Url": [ + 99, + 49, + 51, + 99, + 100, + 99, + 49, + 50, + 45, + 99, + 55, + 101, + 100, + 45, + 52, + 49, + 100, + 98, + 45, + 97, + 54, + 54, + 57, + 45, + 53, + 54, + 97, + 54, + 54, + 52, + 102, + 56, + 49, + 50, + 55, + 97 + ] + }, + { + "origin": "8507cd12-1a02-4a48-92a5-23fbbe7ad5fe", + "toBase64Url": "ODUwN2NkMTItMWEwMi00YTQ4LTkyYTUtMjNmYmJlN2FkNWZl", + "fromBase64Url": [ + 56, + 53, + 48, + 55, + 99, + 100, + 49, + 50, + 45, + 49, + 97, + 48, + 50, + 45, + 52, + 97, + 52, + 56, + 45, + 57, + 50, + 97, + 53, + 45, + 50, + 51, + 102, + 98, + 98, + 101, + 55, + 97, + 100, + 53, + 102, + 101 + ] + }, + { + "origin": "02b073e9-f33c-4f06-b3aa-d94101a06494", + "toBase64Url": "MDJiMDczZTktZjMzYy00ZjA2LWIzYWEtZDk0MTAxYTA2NDk0", + "fromBase64Url": [ + 48, + 50, + 98, + 48, + 55, + 51, + 101, + 57, + 45, + 102, + 51, + 51, + 99, + 45, + 52, + 102, + 48, + 54, + 45, + 98, + 51, + 97, + 97, + 45, + 100, + 57, + 52, + 49, + 48, + 49, + 97, + 48, + 54, + 52, + 57, + 52 + ] + }, + { + "origin": "064b6627-6dcb-439b-979d-a38c6a4e10f4", + "toBase64Url": "MDY0YjY2MjctNmRjYi00MzliLTk3OWQtYTM4YzZhNGUxMGY0", + "fromBase64Url": [ + 48, + 54, + 52, + 98, + 54, + 54, + 50, + 55, + 45, + 54, + 100, + 99, + 98, + 45, + 52, + 51, + 57, + 98, + 45, + 57, + 55, + 57, + 100, + 45, + 97, + 51, + 56, + 99, + 54, + 97, + 52, + 101, + 49, + 48, + 102, + 52 + ] + }, + { + "origin": "f32a0d44-6d3c-4f68-ba4d-0bc26aed6c7f", + "toBase64Url": "ZjMyYTBkNDQtNmQzYy00ZjY4LWJhNGQtMGJjMjZhZWQ2Yzdm", + "fromBase64Url": [ + 102, + 51, + 50, + 97, + 48, + 100, + 52, + 52, + 45, + 54, + 100, + 51, + 99, + 45, + 52, + 102, + 54, + 56, + 45, + 98, + 97, + 52, + 100, + 45, + 48, + 98, + 99, + 50, + 54, + 97, + 101, + 100, + 54, + 99, + 55, + 102 + ] + }, + { + "origin": "73b68c21-7bab-4608-ad9c-67d2fb954fa2", + "toBase64Url": "NzNiNjhjMjEtN2JhYi00NjA4LWFkOWMtNjdkMmZiOTU0ZmEy", + "fromBase64Url": [ + 55, + 51, + 98, + 54, + 56, + 99, + 50, + 49, + 45, + 55, + 98, + 97, + 98, + 45, + 52, + 54, + 48, + 56, + 45, + 97, + 100, + 57, + 99, + 45, + 54, + 55, + 100, + 50, + 102, + 98, + 57, + 53, + 52, + 102, + 97, + 50 + ] + }, + { + "origin": "d626dd1f-50c5-4438-b920-72b852bb89cd", + "toBase64Url": "ZDYyNmRkMWYtNTBjNS00NDM4LWI5MjAtNzJiODUyYmI4OWNk", + "fromBase64Url": [ + 100, + 54, + 50, + 54, + 100, + 100, + 49, + 102, + 45, + 53, + 48, + 99, + 53, + 45, + 52, + 52, + 51, + 56, + 45, + 98, + 57, + 50, + 48, + 45, + 55, + 50, + 98, + 56, + 53, + 50, + 98, + 98, + 56, + 57, + 99, + 100 + ] + }, + { + "origin": "e598d7e0-282e-4ae9-909b-b18b9710b2b4", + "toBase64Url": "ZTU5OGQ3ZTAtMjgyZS00YWU5LTkwOWItYjE4Yjk3MTBiMmI0", + "fromBase64Url": [ + 101, + 53, + 57, + 56, + 100, + 55, + 101, + 48, + 45, + 50, + 56, + 50, + 101, + 45, + 52, + 97, + 101, + 57, + 45, + 57, + 48, + 57, + 98, + 45, + 98, + 49, + 56, + 98, + 57, + 55, + 49, + 48, + 98, + 50, + 98, + 52 + ] + }, + { + "origin": "84c50a1a-38bb-470b-8347-68d9e323f3d8", + "toBase64Url": "ODRjNTBhMWEtMzhiYi00NzBiLTgzNDctNjhkOWUzMjNmM2Q4", + "fromBase64Url": [ + 56, + 52, + 99, + 53, + 48, + 97, + 49, + 97, + 45, + 51, + 56, + 98, + 98, + 45, + 52, + 55, + 48, + 98, + 45, + 56, + 51, + 52, + 55, + 45, + 54, + 56, + 100, + 57, + 101, + 51, + 50, + 51, + 102, + 51, + 100, + 56 + ] + }, + { + "origin": "53bae0ac-5462-438f-89c4-aa1204146eca", + "toBase64Url": "NTNiYWUwYWMtNTQ2Mi00MzhmLTg5YzQtYWExMjA0MTQ2ZWNh", + "fromBase64Url": [ + 53, + 51, + 98, + 97, + 101, + 48, + 97, + 99, + 45, + 53, + 52, + 54, + 50, + 45, + 52, + 51, + 56, + 102, + 45, + 56, + 57, + 99, + 52, + 45, + 97, + 97, + 49, + 50, + 48, + 52, + 49, + 52, + 54, + 101, + 99, + 97 + ] + }, + { + "origin": "4b487db9-abba-40c5-a0ad-b2250878a332", + "toBase64Url": "NGI0ODdkYjktYWJiYS00MGM1LWEwYWQtYjIyNTA4NzhhMzMy", + "fromBase64Url": [ + 52, + 98, + 52, + 56, + 55, + 100, + 98, + 57, + 45, + 97, + 98, + 98, + 97, + 45, + 52, + 48, + 99, + 53, + 45, + 97, + 48, + 97, + 100, + 45, + 98, + 50, + 50, + 53, + 48, + 56, + 55, + 56, + 97, + 51, + 51, + 50 + ] + }, + { + "origin": "d0941714-eae3-40db-a789-f21aa6401b0d", + "toBase64Url": "ZDA5NDE3MTQtZWFlMy00MGRiLWE3ODktZjIxYWE2NDAxYjBk", + "fromBase64Url": [ + 100, + 48, + 57, + 52, + 49, + 55, + 49, + 52, + 45, + 101, + 97, + 101, + 51, + 45, + 52, + 48, + 100, + 98, + 45, + 97, + 55, + 56, + 57, + 45, + 102, + 50, + 49, + 97, + 97, + 54, + 52, + 48, + 49, + 98, + 48, + 100 + ] + }, + { + "origin": "efb79528-d0bd-433e-be9f-f1020cee08fa", + "toBase64Url": "ZWZiNzk1MjgtZDBiZC00MzNlLWJlOWYtZjEwMjBjZWUwOGZh", + "fromBase64Url": [ + 101, + 102, + 98, + 55, + 57, + 53, + 50, + 56, + 45, + 100, + 48, + 98, + 100, + 45, + 52, + 51, + 51, + 101, + 45, + 98, + 101, + 57, + 102, + 45, + 102, + 49, + 48, + 50, + 48, + 99, + 101, + 101, + 48, + 56, + 102, + 97 + ] + }, + { + "origin": "da2a799b-e1fe-460a-8f3f-0a5f4a124359", + "toBase64Url": "ZGEyYTc5OWItZTFmZS00NjBhLThmM2YtMGE1ZjRhMTI0MzU5", + "fromBase64Url": [ + 100, + 97, + 50, + 97, + 55, + 57, + 57, + 98, + 45, + 101, + 49, + 102, + 101, + 45, + 52, + 54, + 48, + 97, + 45, + 56, + 102, + 51, + 102, + 45, + 48, + 97, + 53, + 102, + 52, + 97, + 49, + 50, + 52, + 51, + 53, + 57 + ] + }, + { + "origin": "822dc1c2-556c-4cee-8c37-411ac530a088", + "toBase64Url": "ODIyZGMxYzItNTU2Yy00Y2VlLThjMzctNDExYWM1MzBhMDg4", + "fromBase64Url": [ + 56, + 50, + 50, + 100, + 99, + 49, + 99, + 50, + 45, + 53, + 53, + 54, + 99, + 45, + 52, + 99, + 101, + 101, + 45, + 56, + 99, + 51, + 55, + 45, + 52, + 49, + 49, + 97, + 99, + 53, + 51, + 48, + 97, + 48, + 56, + 56 + ] + }, + { + "origin": "d035ec77-dd78-4a51-8392-ad28870b0905", + "toBase64Url": "ZDAzNWVjNzctZGQ3OC00YTUxLTgzOTItYWQyODg3MGIwOTA1", + "fromBase64Url": [ + 100, + 48, + 51, + 53, + 101, + 99, + 55, + 55, + 45, + 100, + 100, + 55, + 56, + 45, + 52, + 97, + 53, + 49, + 45, + 56, + 51, + 57, + 50, + 45, + 97, + 100, + 50, + 56, + 56, + 55, + 48, + 98, + 48, + 57, + 48, + 53 + ] + }, + { + "origin": "c934cf59-56a9-45f6-bdbd-7273d2ae86c8", + "toBase64Url": "YzkzNGNmNTktNTZhOS00NWY2LWJkYmQtNzI3M2QyYWU4NmM4", + "fromBase64Url": [ + 99, + 57, + 51, + 52, + 99, + 102, + 53, + 57, + 45, + 53, + 54, + 97, + 57, + 45, + 52, + 53, + 102, + 54, + 45, + 98, + 100, + 98, + 100, + 45, + 55, + 50, + 55, + 51, + 100, + 50, + 97, + 101, + 56, + 54, + 99, + 56 + ] + }, + { + "origin": "b2c572bb-98e1-4d6b-b06c-865a749aacf6", + "toBase64Url": "YjJjNTcyYmItOThlMS00ZDZiLWIwNmMtODY1YTc0OWFhY2Y2", + "fromBase64Url": [ + 98, + 50, + 99, + 53, + 55, + 50, + 98, + 98, + 45, + 57, + 56, + 101, + 49, + 45, + 52, + 100, + 54, + 98, + 45, + 98, + 48, + 54, + 99, + 45, + 56, + 54, + 53, + 97, + 55, + 52, + 57, + 97, + 97, + 99, + 102, + 54 + ] + }, + { + "origin": "5f571217-335c-422e-8c76-0e8b4e1296cf", + "toBase64Url": "NWY1NzEyMTctMzM1Yy00MjJlLThjNzYtMGU4YjRlMTI5NmNm", + "fromBase64Url": [ + 53, + 102, + 53, + 55, + 49, + 50, + 49, + 55, + 45, + 51, + 51, + 53, + 99, + 45, + 52, + 50, + 50, + 101, + 45, + 56, + 99, + 55, + 54, + 45, + 48, + 101, + 56, + 98, + 52, + 101, + 49, + 50, + 57, + 54, + 99, + 102 + ] + } +] \ No newline at end of file diff --git a/clients/liquid-auth-core/tests/__fixtures__/wallet.keys.fixtures.json b/clients/liquid-auth-core/tests/__fixtures__/wallet.keys.fixtures.json new file mode 100644 index 0000000..a3d3614 --- /dev/null +++ b/clients/liquid-auth-core/tests/__fixtures__/wallet.keys.fixtures.json @@ -0,0 +1,2972 @@ +[ + { + "encoded": "65X3KSKFCNX3VUPQDVO3RQUHDZN7BONGBEC6PJWAVKX73DIC356M7M32JM", + "checksum": [ + 207, + 179, + 122, + 75 + ], + "publicKey": [ + 247, + 111, + 181, + 73, + 69, + 19, + 111, + 186, + 209, + 240, + 29, + 93, + 184, + 194, + 135, + 30, + 91, + 240, + 185, + 166, + 9, + 5, + 231, + 166, + 192, + 170, + 175, + 253, + 141, + 2, + 223, + 124 + ], + "privateKey": [ + 236, + 82, + 165, + 230, + 144, + 235, + 251, + 237, + 230, + 241, + 97, + 239, + 230, + 114, + 115, + 205, + 39, + 237, + 91, + 91, + 228, + 34, + 157, + 91, + 55, + 84, + 65, + 60, + 26, + 48, + 169, + 8, + 247, + 111, + 181, + 73, + 69, + 19, + 111, + 186, + 209, + 240, + 29, + 93, + 184, + 194, + 135, + 30, + 91, + 240, + 185, + 166, + 9, + 5, + 231, + 166, + 192, + 170, + 175, + 253, + 141, + 2, + 223, + 124 + ], + "valid": true + }, + { + "encoded": "3DZKAZ2YN5JN5QBGWM75W23O64OTW4MPPQQDDS5AILP3QYMFPKKIEUDTAM", + "checksum": [ + 130, + 80, + 115, + 3 + ], + "publicKey": [ + 216, + 242, + 160, + 103, + 88, + 111, + 82, + 222, + 192, + 38, + 179, + 63, + 219, + 107, + 110, + 247, + 29, + 59, + 113, + 143, + 124, + 32, + 49, + 203, + 160, + 66, + 223, + 184, + 97, + 133, + 122, + 148 + ], + "privateKey": [ + 152, + 114, + 225, + 108, + 240, + 100, + 213, + 212, + 172, + 48, + 32, + 144, + 151, + 231, + 32, + 30, + 173, + 153, + 195, + 20, + 174, + 169, + 232, + 82, + 236, + 159, + 30, + 96, + 252, + 142, + 39, + 13, + 216, + 242, + 160, + 103, + 88, + 111, + 82, + 222, + 192, + 38, + 179, + 63, + 219, + 107, + 110, + 247, + 29, + 59, + 113, + 143, + 124, + 32, + 49, + 203, + 160, + 66, + 223, + 184, + 97, + 133, + 122, + 148 + ], + "valid": true + }, + { + "encoded": "3CA3UDJ7AAWQ7XEBL7LKYBN4IQ4IRJMN3BO2DTAE7LPWMN4UFCFI6ZLXYQ", + "checksum": [ + 143, + 101, + 119, + 196 + ], + "publicKey": [ + 216, + 129, + 186, + 13, + 63, + 0, + 45, + 15, + 220, + 129, + 95, + 214, + 172, + 5, + 188, + 68, + 56, + 136, + 165, + 141, + 216, + 93, + 161, + 204, + 4, + 250, + 223, + 102, + 55, + 148, + 40, + 138 + ], + "privateKey": [ + 60, + 205, + 4, + 66, + 151, + 5, + 167, + 248, + 113, + 97, + 104, + 157, + 84, + 50, + 89, + 30, + 144, + 185, + 44, + 229, + 202, + 201, + 156, + 195, + 39, + 47, + 19, + 233, + 108, + 69, + 129, + 218, + 216, + 129, + 186, + 13, + 63, + 0, + 45, + 15, + 220, + 129, + 95, + 214, + 172, + 5, + 188, + 68, + 56, + 136, + 165, + 141, + 216, + 93, + 161, + 204, + 4, + 250, + 223, + 102, + 55, + 148, + 40, + 138 + ], + "valid": true + }, + { + "encoded": "IFJIXXNSNTAUCDML4QVJ6T3VXSPBRDJCNX2YLZFPRO7I7GTTW5OSXTUSFU", + "checksum": [ + 43, + 206, + 146, + 45 + ], + "publicKey": [ + 65, + 82, + 139, + 221, + 178, + 108, + 193, + 65, + 13, + 139, + 228, + 42, + 159, + 79, + 117, + 188, + 158, + 24, + 141, + 34, + 109, + 245, + 133, + 228, + 175, + 139, + 190, + 143, + 154, + 115, + 183, + 93 + ], + "privateKey": [ + 47, + 32, + 137, + 143, + 141, + 169, + 18, + 201, + 164, + 162, + 151, + 241, + 159, + 238, + 30, + 215, + 92, + 41, + 79, + 3, + 253, + 206, + 123, + 30, + 160, + 207, + 39, + 194, + 23, + 77, + 25, + 87, + 65, + 82, + 139, + 221, + 178, + 108, + 193, + 65, + 13, + 139, + 228, + 42, + 159, + 79, + 117, + 188, + 158, + 24, + 141, + 34, + 109, + 245, + 133, + 228, + 175, + 139, + 190, + 143, + 154, + 115, + 183, + 93 + ], + "valid": true + }, + { + "encoded": "DEVJC5CGWY5HW4MWAR7B2LJ27UGN6FIBDZSZHOXPYFBEOQ4CAKHOIGBAFU", + "checksum": [ + 228, + 24, + 32, + 45 + ], + "publicKey": [ + 25, + 42, + 145, + 116, + 70, + 182, + 58, + 123, + 113, + 150, + 4, + 126, + 29, + 45, + 58, + 253, + 12, + 223, + 21, + 1, + 30, + 101, + 147, + 186, + 239, + 193, + 66, + 71, + 67, + 130, + 2, + 142 + ], + "privateKey": [ + 59, + 135, + 230, + 131, + 153, + 70, + 197, + 206, + 114, + 168, + 168, + 48, + 224, + 98, + 88, + 6, + 152, + 206, + 54, + 215, + 145, + 201, + 19, + 105, + 141, + 2, + 12, + 119, + 104, + 49, + 67, + 173, + 25, + 42, + 145, + 116, + 70, + 182, + 58, + 123, + 113, + 150, + 4, + 126, + 29, + 45, + 58, + 253, + 12, + 223, + 21, + 1, + 30, + 101, + 147, + 186, + 239, + 193, + 66, + 71, + 67, + 130, + 2, + 142 + ], + "valid": true + }, + { + "encoded": "7F55SDXF6MAB4CPZDRJEJOPLAXUVC2K4UKCOFE2XZBUWM3PUZHHDAPBB6Y", + "checksum": [ + 48, + 60, + 33, + 246 + ], + "publicKey": [ + 249, + 123, + 217, + 14, + 229, + 243, + 0, + 30, + 9, + 249, + 28, + 82, + 68, + 185, + 235, + 5, + 233, + 81, + 105, + 92, + 162, + 132, + 226, + 147, + 87, + 200, + 105, + 102, + 109, + 244, + 201, + 206 + ], + "privateKey": [ + 170, + 229, + 17, + 238, + 54, + 123, + 122, + 60, + 139, + 221, + 182, + 156, + 180, + 215, + 174, + 87, + 99, + 138, + 60, + 38, + 232, + 75, + 134, + 182, + 181, + 152, + 248, + 252, + 182, + 132, + 218, + 142, + 249, + 123, + 217, + 14, + 229, + 243, + 0, + 30, + 9, + 249, + 28, + 82, + 68, + 185, + 235, + 5, + 233, + 81, + 105, + 92, + 162, + 132, + 226, + 147, + 87, + 200, + 105, + 102, + 109, + 244, + 201, + 206 + ], + "valid": true + }, + { + "encoded": "YZILV5REF7QEWU4AXWB47IPPV6NZIX3GLI5OW77DY7COHNA2Q6ZOZJEEIA", + "checksum": [ + 236, + 164, + 132, + 64 + ], + "publicKey": [ + 198, + 80, + 186, + 246, + 36, + 47, + 224, + 75, + 83, + 128, + 189, + 131, + 207, + 161, + 239, + 175, + 155, + 148, + 95, + 102, + 90, + 58, + 235, + 127, + 227, + 199, + 196, + 227, + 180, + 26, + 135, + 178 + ], + "privateKey": [ + 200, + 107, + 43, + 245, + 88, + 254, + 51, + 104, + 17, + 85, + 250, + 110, + 170, + 119, + 20, + 131, + 124, + 31, + 32, + 95, + 201, + 69, + 210, + 175, + 142, + 53, + 183, + 156, + 82, + 146, + 148, + 71, + 198, + 80, + 186, + 246, + 36, + 47, + 224, + 75, + 83, + 128, + 189, + 131, + 207, + 161, + 239, + 175, + 155, + 148, + 95, + 102, + 90, + 58, + 235, + 127, + 227, + 199, + 196, + 227, + 180, + 26, + 135, + 178 + ], + "valid": true + }, + { + "encoded": "7KQHLEGZYRASKPLX56Y2HX7IXHFKA7HQ73SNUHOGJJVAR7HG4FGN5KPJOY", + "checksum": [ + 222, + 169, + 233, + 118 + ], + "publicKey": [ + 250, + 160, + 117, + 144, + 217, + 196, + 65, + 37, + 61, + 119, + 239, + 177, + 163, + 223, + 232, + 185, + 202, + 160, + 124, + 240, + 254, + 228, + 218, + 29, + 198, + 74, + 106, + 8, + 252, + 230, + 225, + 76 + ], + "privateKey": [ + 149, + 127, + 178, + 220, + 65, + 150, + 96, + 238, + 72, + 215, + 215, + 107, + 116, + 136, + 188, + 151, + 101, + 82, + 161, + 17, + 189, + 41, + 17, + 232, + 22, + 57, + 183, + 130, + 167, + 68, + 79, + 49, + 250, + 160, + 117, + 144, + 217, + 196, + 65, + 37, + 61, + 119, + 239, + 177, + 163, + 223, + 232, + 185, + 202, + 160, + 124, + 240, + 254, + 228, + 218, + 29, + 198, + 74, + 106, + 8, + 252, + 230, + 225, + 76 + ], + "valid": true + }, + { + "encoded": "LIC5K5IW6K2GE5Q5GA3E6OZA7FQUCI4XR5A3GE3SLOF6U3LXAT2J7RIRKE", + "checksum": [ + 159, + 197, + 17, + 81 + ], + "publicKey": [ + 90, + 5, + 213, + 117, + 22, + 242, + 180, + 98, + 118, + 29, + 48, + 54, + 79, + 59, + 32, + 249, + 97, + 65, + 35, + 151, + 143, + 65, + 179, + 19, + 114, + 91, + 139, + 234, + 109, + 119, + 4, + 244 + ], + "privateKey": [ + 255, + 188, + 242, + 10, + 174, + 222, + 130, + 43, + 72, + 183, + 35, + 151, + 13, + 4, + 71, + 139, + 206, + 175, + 235, + 38, + 37, + 247, + 101, + 193, + 96, + 125, + 1, + 207, + 69, + 48, + 47, + 158, + 90, + 5, + 213, + 117, + 22, + 242, + 180, + 98, + 118, + 29, + 48, + 54, + 79, + 59, + 32, + 249, + 97, + 65, + 35, + 151, + 143, + 65, + 179, + 19, + 114, + 91, + 139, + 234, + 109, + 119, + 4, + 244 + ], + "valid": true + }, + { + "encoded": "ABRYPE4VTV7Y25NJPYA3ENHUCIZHD4AD3L57QFM6GMUFSPPH5NZNLINR2U", + "checksum": [ + 213, + 161, + 177, + 213 + ], + "publicKey": [ + 0, + 99, + 135, + 147, + 149, + 157, + 127, + 141, + 117, + 169, + 126, + 1, + 178, + 52, + 244, + 18, + 50, + 113, + 240, + 3, + 218, + 251, + 248, + 21, + 158, + 51, + 40, + 89, + 61, + 231, + 235, + 114 + ], + "privateKey": [ + 26, + 185, + 149, + 114, + 143, + 48, + 38, + 79, + 77, + 45, + 9, + 217, + 48, + 239, + 132, + 182, + 220, + 33, + 72, + 101, + 28, + 194, + 32, + 9, + 211, + 57, + 219, + 51, + 225, + 157, + 235, + 68, + 0, + 99, + 135, + 147, + 149, + 157, + 127, + 141, + 117, + 169, + 126, + 1, + 178, + 52, + 244, + 18, + 50, + 113, + 240, + 3, + 218, + 251, + 248, + 21, + 158, + 51, + 40, + 89, + 61, + 231, + 235, + 114 + ], + "valid": true + }, + { + "encoded": "TLRWCVZN22GRXQQEDWCMP64UD63DDKX5RU2KLG2SROOSHMRCW2TYBX6IPA", + "checksum": [ + 128, + 223, + 200, + 120 + ], + "publicKey": [ + 154, + 227, + 97, + 87, + 45, + 214, + 141, + 27, + 194, + 4, + 29, + 132, + 199, + 251, + 148, + 31, + 182, + 49, + 170, + 253, + 141, + 52, + 165, + 155, + 82, + 139, + 157, + 35, + 178, + 34, + 182, + 167 + ], + "privateKey": [ + 142, + 247, + 46, + 26, + 245, + 91, + 2, + 250, + 59, + 32, + 77, + 184, + 143, + 20, + 252, + 20, + 230, + 81, + 31, + 99, + 78, + 174, + 62, + 132, + 203, + 79, + 112, + 39, + 10, + 243, + 45, + 58, + 154, + 227, + 97, + 87, + 45, + 214, + 141, + 27, + 194, + 4, + 29, + 132, + 199, + 251, + 148, + 31, + 182, + 49, + 170, + 253, + 141, + 52, + 165, + 155, + 82, + 139, + 157, + 35, + 178, + 34, + 182, + 167 + ], + "valid": true + }, + { + "encoded": "RPM3AIUUYIZHZ53MTWQV57SIEMCWLLAWBZU5V2PGGCAD4LNAGYAKPTLK7M", + "checksum": [ + 167, + 205, + 106, + 251 + ], + "publicKey": [ + 139, + 217, + 176, + 34, + 148, + 194, + 50, + 124, + 247, + 108, + 157, + 161, + 94, + 254, + 72, + 35, + 5, + 101, + 172, + 22, + 14, + 105, + 218, + 233, + 230, + 48, + 128, + 62, + 45, + 160, + 54, + 0 + ], + "privateKey": [ + 83, + 91, + 204, + 156, + 166, + 183, + 152, + 183, + 89, + 116, + 168, + 194, + 158, + 207, + 200, + 225, + 5, + 217, + 96, + 232, + 204, + 119, + 171, + 68, + 149, + 88, + 0, + 69, + 226, + 124, + 156, + 40, + 139, + 217, + 176, + 34, + 148, + 194, + 50, + 124, + 247, + 108, + 157, + 161, + 94, + 254, + 72, + 35, + 5, + 101, + 172, + 22, + 14, + 105, + 218, + 233, + 230, + 48, + 128, + 62, + 45, + 160, + 54, + 0 + ], + "valid": true + }, + { + "encoded": "Y5BMK2M4RCTM4P4NI4KITKG6RDVIAFTHAWZOFQRZ3DY6LQANC47G67AQDA", + "checksum": [ + 111, + 124, + 16, + 24 + ], + "publicKey": [ + 199, + 66, + 197, + 105, + 156, + 136, + 166, + 206, + 63, + 141, + 71, + 20, + 137, + 168, + 222, + 136, + 234, + 128, + 22, + 103, + 5, + 178, + 226, + 194, + 57, + 216, + 241, + 229, + 192, + 13, + 23, + 62 + ], + "privateKey": [ + 231, + 105, + 81, + 0, + 19, + 201, + 132, + 39, + 165, + 197, + 52, + 54, + 182, + 11, + 163, + 210, + 58, + 56, + 146, + 198, + 100, + 44, + 94, + 5, + 152, + 250, + 79, + 193, + 233, + 34, + 104, + 157, + 199, + 66, + 197, + 105, + 156, + 136, + 166, + 206, + 63, + 141, + 71, + 20, + 137, + 168, + 222, + 136, + 234, + 128, + 22, + 103, + 5, + 178, + 226, + 194, + 57, + 216, + 241, + 229, + 192, + 13, + 23, + 62 + ], + "valid": true + }, + { + "encoded": "UM4F2PWJDTUT6JGMC6EHTEQH3ZYDSWIITY7LJX5WKWSMGLS3BOEREE64AI", + "checksum": [ + 18, + 19, + 220, + 2 + ], + "publicKey": [ + 163, + 56, + 93, + 62, + 201, + 28, + 233, + 63, + 36, + 204, + 23, + 136, + 121, + 146, + 7, + 222, + 112, + 57, + 89, + 8, + 158, + 62, + 180, + 223, + 182, + 85, + 164, + 195, + 46, + 91, + 11, + 137 + ], + "privateKey": [ + 248, + 82, + 21, + 209, + 157, + 247, + 81, + 107, + 89, + 168, + 80, + 67, + 122, + 44, + 171, + 169, + 41, + 181, + 9, + 192, + 166, + 134, + 137, + 128, + 149, + 201, + 214, + 31, + 117, + 193, + 190, + 80, + 163, + 56, + 93, + 62, + 201, + 28, + 233, + 63, + 36, + 204, + 23, + 136, + 121, + 146, + 7, + 222, + 112, + 57, + 89, + 8, + 158, + 62, + 180, + 223, + 182, + 85, + 164, + 195, + 46, + 91, + 11, + 137 + ], + "valid": true + }, + { + "encoded": "Z4EZILHIAVL22WSXYQ4YNOXDVZAYJCXOROQ3RV2ZPFORWXITDIGJYPT7AE", + "checksum": [ + 156, + 62, + 127, + 1 + ], + "publicKey": [ + 207, + 9, + 148, + 44, + 232, + 5, + 87, + 173, + 90, + 87, + 196, + 57, + 134, + 186, + 227, + 174, + 65, + 132, + 138, + 238, + 139, + 161, + 184, + 215, + 89, + 121, + 93, + 27, + 93, + 19, + 26, + 12 + ], + "privateKey": [ + 78, + 155, + 21, + 250, + 204, + 122, + 133, + 236, + 164, + 137, + 234, + 124, + 161, + 0, + 99, + 3, + 89, + 135, + 152, + 128, + 153, + 85, + 240, + 227, + 187, + 140, + 181, + 128, + 145, + 122, + 22, + 76, + 207, + 9, + 148, + 44, + 232, + 5, + 87, + 173, + 90, + 87, + 196, + 57, + 134, + 186, + 227, + 174, + 65, + 132, + 138, + 238, + 139, + 161, + 184, + 215, + 89, + 121, + 93, + 27, + 93, + 19, + 26, + 12 + ], + "valid": true + }, + { + "encoded": "W67VZ3BUOIHYKQTRQMRST3D3DH3GZQ43SLDPUN2UUQRQG7QV24BXZORLZ4", + "checksum": [ + 124, + 186, + 43, + 207 + ], + "publicKey": [ + 183, + 191, + 92, + 236, + 52, + 114, + 15, + 133, + 66, + 113, + 131, + 35, + 41, + 236, + 123, + 25, + 246, + 108, + 195, + 155, + 146, + 198, + 250, + 55, + 84, + 164, + 35, + 3, + 126, + 21, + 215, + 3 + ], + "privateKey": [ + 197, + 54, + 178, + 164, + 214, + 232, + 186, + 145, + 212, + 210, + 240, + 179, + 30, + 138, + 155, + 165, + 11, + 180, + 13, + 241, + 10, + 181, + 210, + 72, + 125, + 124, + 199, + 142, + 49, + 219, + 155, + 163, + 183, + 191, + 92, + 236, + 52, + 114, + 15, + 133, + 66, + 113, + 131, + 35, + 41, + 236, + 123, + 25, + 246, + 108, + 195, + 155, + 146, + 198, + 250, + 55, + 84, + 164, + 35, + 3, + 126, + 21, + 215, + 3 + ], + "valid": true + }, + { + "encoded": "5QZA22GPL44PLHHE5VQLMI7N6GTHCJIUARS4VMLF5UTV5WCWAH5N2C7IYQ", + "checksum": [ + 221, + 11, + 232, + 196 + ], + "publicKey": [ + 236, + 50, + 13, + 104, + 207, + 95, + 56, + 245, + 156, + 228, + 237, + 96, + 182, + 35, + 237, + 241, + 166, + 113, + 37, + 20, + 4, + 101, + 202, + 177, + 101, + 237, + 39, + 94, + 216, + 86, + 1, + 250 + ], + "privateKey": [ + 215, + 168, + 230, + 6, + 122, + 132, + 10, + 131, + 105, + 210, + 33, + 72, + 199, + 63, + 234, + 0, + 154, + 126, + 34, + 243, + 70, + 241, + 217, + 197, + 237, + 62, + 218, + 56, + 111, + 209, + 77, + 249, + 236, + 50, + 13, + 104, + 207, + 95, + 56, + 245, + 156, + 228, + 237, + 96, + 182, + 35, + 237, + 241, + 166, + 113, + 37, + 20, + 4, + 101, + 202, + 177, + 101, + 237, + 39, + 94, + 216, + 86, + 1, + 250 + ], + "valid": true + }, + { + "encoded": "ZA44DPMGYEPONVXWHUTBQ66SKCB5PX7BPWHIMFKAOEV5MRBJKL7ADHXGQY", + "checksum": [ + 1, + 158, + 230, + 134 + ], + "publicKey": [ + 200, + 57, + 193, + 189, + 134, + 193, + 30, + 230, + 214, + 246, + 61, + 38, + 24, + 123, + 210, + 80, + 131, + 215, + 223, + 225, + 125, + 142, + 134, + 21, + 64, + 113, + 43, + 214, + 68, + 41, + 82, + 254 + ], + "privateKey": [ + 243, + 190, + 156, + 61, + 249, + 117, + 242, + 42, + 26, + 52, + 88, + 164, + 80, + 66, + 196, + 99, + 223, + 96, + 56, + 108, + 69, + 43, + 210, + 52, + 235, + 177, + 145, + 183, + 130, + 32, + 133, + 104, + 200, + 57, + 193, + 189, + 134, + 193, + 30, + 230, + 214, + 246, + 61, + 38, + 24, + 123, + 210, + 80, + 131, + 215, + 223, + 225, + 125, + 142, + 134, + 21, + 64, + 113, + 43, + 214, + 68, + 41, + 82, + 254 + ], + "valid": true + }, + { + "encoded": "MQ3AVNCM7P7BD7NHDD3HFEMJKTAZUTHI7FVLZTV2UJBW4TDBYCANNXF2PU", + "checksum": [ + 214, + 220, + 186, + 125 + ], + "publicKey": [ + 100, + 54, + 10, + 180, + 76, + 251, + 254, + 17, + 253, + 167, + 24, + 246, + 114, + 145, + 137, + 84, + 193, + 154, + 76, + 232, + 249, + 106, + 188, + 206, + 186, + 162, + 67, + 110, + 76, + 97, + 192, + 128 + ], + "privateKey": [ + 70, + 121, + 167, + 29, + 7, + 192, + 110, + 199, + 56, + 217, + 37, + 76, + 62, + 142, + 87, + 172, + 204, + 86, + 250, + 151, + 149, + 166, + 125, + 44, + 67, + 86, + 190, + 106, + 52, + 67, + 74, + 76, + 100, + 54, + 10, + 180, + 76, + 251, + 254, + 17, + 253, + 167, + 24, + 246, + 114, + 145, + 137, + 84, + 193, + 154, + 76, + 232, + 249, + 106, + 188, + 206, + 186, + 162, + 67, + 110, + 76, + 97, + 192, + 128 + ], + "valid": true + }, + { + "encoded": "RHY76D66VAWH7CAS3TCDN4TVUKRFT6SRIBAHSIQLX65BT6ZUXHEOXFM4IU", + "checksum": [ + 235, + 149, + 156, + 69 + ], + "publicKey": [ + 137, + 241, + 255, + 15, + 222, + 168, + 44, + 127, + 136, + 18, + 220, + 196, + 54, + 242, + 117, + 162, + 162, + 89, + 250, + 81, + 64, + 64, + 121, + 34, + 11, + 191, + 186, + 25, + 251, + 52, + 185, + 200 + ], + "privateKey": [ + 121, + 22, + 228, + 11, + 197, + 95, + 122, + 61, + 187, + 147, + 228, + 14, + 156, + 6, + 128, + 96, + 111, + 111, + 242, + 234, + 197, + 159, + 147, + 121, + 109, + 154, + 155, + 40, + 78, + 35, + 74, + 226, + 137, + 241, + 255, + 15, + 222, + 168, + 44, + 127, + 136, + 18, + 220, + 196, + 54, + 242, + 117, + 162, + 162, + 89, + 250, + 81, + 64, + 64, + 121, + 34, + 11, + 191, + 186, + 25, + 251, + 52, + 185, + 200 + ], + "valid": true + }, + { + "encoded": "KDHPRHISHU25PJO5OG36NS5MMPPRMLITDWRHZKSKYVMH4YUCAGRYTHDYCY", + "checksum": [ + 137, + 156, + 120, + 22 + ], + "publicKey": [ + 80, + 206, + 248, + 157, + 18, + 61, + 53, + 215, + 165, + 221, + 113, + 183, + 230, + 203, + 172, + 99, + 223, + 22, + 45, + 19, + 29, + 162, + 124, + 170, + 74, + 197, + 88, + 126, + 98, + 130, + 1, + 163 + ], + "privateKey": [ + 194, + 133, + 62, + 0, + 75, + 220, + 24, + 137, + 21, + 68, + 233, + 242, + 236, + 145, + 44, + 49, + 218, + 158, + 249, + 177, + 236, + 11, + 85, + 94, + 224, + 98, + 236, + 28, + 172, + 204, + 26, + 140, + 80, + 206, + 248, + 157, + 18, + 61, + 53, + 215, + 165, + 221, + 113, + 183, + 230, + 203, + 172, + 99, + 223, + 22, + 45, + 19, + 29, + 162, + 124, + 170, + 74, + 197, + 88, + 126, + 98, + 130, + 1, + 163 + ], + "valid": true + }, + { + "encoded": "RXVJINFGGMBCNU7NOFKTAOFIFJ5R3A4EWHKAWCW6KNXTRDQCFCRGV3BF4M", + "checksum": [ + 106, + 236, + 37, + 227 + ], + "publicKey": [ + 141, + 234, + 148, + 52, + 166, + 51, + 2, + 38, + 211, + 237, + 113, + 85, + 48, + 56, + 168, + 42, + 123, + 29, + 131, + 132, + 177, + 212, + 11, + 10, + 222, + 83, + 111, + 56, + 142, + 2, + 40, + 162 + ], + "privateKey": [ + 174, + 110, + 127, + 107, + 13, + 238, + 168, + 163, + 107, + 207, + 64, + 140, + 144, + 65, + 3, + 179, + 50, + 248, + 133, + 145, + 228, + 201, + 13, + 149, + 94, + 80, + 9, + 24, + 89, + 183, + 48, + 177, + 141, + 234, + 148, + 52, + 166, + 51, + 2, + 38, + 211, + 237, + 113, + 85, + 48, + 56, + 168, + 42, + 123, + 29, + 131, + 132, + 177, + 212, + 11, + 10, + 222, + 83, + 111, + 56, + 142, + 2, + 40, + 162 + ], + "valid": true + }, + { + "encoded": "GSBE3TORJTLULQ5TLJWYUN4TGL2ZPDWDIJPSNZJD5UZRCUBWAKDF53OUC4", + "checksum": [ + 94, + 237, + 212, + 23 + ], + "publicKey": [ + 52, + 130, + 77, + 205, + 209, + 76, + 215, + 69, + 195, + 179, + 90, + 109, + 138, + 55, + 147, + 50, + 245, + 151, + 142, + 195, + 66, + 95, + 38, + 229, + 35, + 237, + 51, + 17, + 80, + 54, + 2, + 134 + ], + "privateKey": [ + 252, + 63, + 28, + 247, + 87, + 146, + 55, + 131, + 127, + 151, + 3, + 238, + 74, + 46, + 69, + 50, + 102, + 89, + 155, + 217, + 159, + 41, + 186, + 73, + 137, + 198, + 147, + 32, + 37, + 208, + 185, + 152, + 52, + 130, + 77, + 205, + 209, + 76, + 215, + 69, + 195, + 179, + 90, + 109, + 138, + 55, + 147, + 50, + 245, + 151, + 142, + 195, + 66, + 95, + 38, + 229, + 35, + 237, + 51, + 17, + 80, + 54, + 2, + 134 + ], + "valid": true + }, + { + "encoded": "D2L64V5Z66TLNWU5ZM54A336MTMS5AZKR5OPSMBLR4XD7VBYKETNCSAY64", + "checksum": [ + 209, + 72, + 24, + 247 + ], + "publicKey": [ + 30, + 151, + 238, + 87, + 185, + 247, + 166, + 182, + 218, + 157, + 203, + 59, + 192, + 111, + 126, + 100, + 217, + 46, + 131, + 42, + 143, + 92, + 249, + 48, + 43, + 143, + 46, + 63, + 212, + 56, + 81, + 38 + ], + "privateKey": [ + 34, + 81, + 159, + 199, + 84, + 137, + 16, + 242, + 193, + 192, + 215, + 222, + 202, + 69, + 41, + 115, + 205, + 0, + 162, + 254, + 53, + 75, + 16, + 141, + 76, + 23, + 120, + 227, + 103, + 13, + 222, + 254, + 30, + 151, + 238, + 87, + 185, + 247, + 166, + 182, + 218, + 157, + 203, + 59, + 192, + 111, + 126, + 100, + 217, + 46, + 131, + 42, + 143, + 92, + 249, + 48, + 43, + 143, + 46, + 63, + 212, + 56, + 81, + 38 + ], + "valid": true + }, + { + "encoded": "4YC7UGVCQTXTN6O4JU6NRR6II47JSMMBQFB5KQLAQOJQPPWMZBWPEYMEGU", + "checksum": [ + 242, + 97, + 132, + 53 + ], + "publicKey": [ + 230, + 5, + 250, + 26, + 162, + 132, + 239, + 54, + 249, + 220, + 77, + 60, + 216, + 199, + 200, + 71, + 62, + 153, + 49, + 129, + 129, + 67, + 213, + 65, + 96, + 131, + 147, + 7, + 190, + 204, + 200, + 108 + ], + "privateKey": [ + 235, + 119, + 55, + 43, + 251, + 155, + 99, + 84, + 236, + 172, + 40, + 207, + 137, + 142, + 14, + 1, + 219, + 100, + 11, + 11, + 173, + 130, + 192, + 235, + 137, + 60, + 202, + 202, + 98, + 211, + 15, + 223, + 230, + 5, + 250, + 26, + 162, + 132, + 239, + 54, + 249, + 220, + 77, + 60, + 216, + 199, + 200, + 71, + 62, + 153, + 49, + 129, + 129, + 67, + 213, + 65, + 96, + 131, + 147, + 7, + 190, + 204, + 200, + 108 + ], + "valid": true + }, + { + "encoded": "4ZRBSTR35CQI4HYQPF3TNTRD4UMC2JBU5HOOMXYKQT6XK73VZ7T4D727QI", + "checksum": [ + 193, + 255, + 95, + 130 + ], + "publicKey": [ + 230, + 98, + 25, + 78, + 59, + 232, + 160, + 142, + 31, + 16, + 121, + 119, + 54, + 206, + 35, + 229, + 24, + 45, + 36, + 52, + 233, + 220, + 230, + 95, + 10, + 132, + 253, + 117, + 127, + 117, + 207, + 231 + ], + "privateKey": [ + 99, + 201, + 58, + 96, + 244, + 72, + 243, + 128, + 178, + 220, + 187, + 212, + 171, + 203, + 31, + 200, + 165, + 250, + 188, + 110, + 159, + 111, + 54, + 31, + 78, + 111, + 233, + 41, + 210, + 215, + 230, + 237, + 230, + 98, + 25, + 78, + 59, + 232, + 160, + 142, + 31, + 16, + 121, + 119, + 54, + 206, + 35, + 229, + 24, + 45, + 36, + 52, + 233, + 220, + 230, + 95, + 10, + 132, + 253, + 117, + 127, + 117, + 207, + 231 + ], + "valid": true + }, + { + "encoded": "CDJO6P5IBFG2QXOPK7MAWNC5FDITMKYSE2T7RC5WERIBT2JRLINNGJBIBE", + "checksum": [ + 211, + 36, + 40, + 9 + ], + "publicKey": [ + 16, + 210, + 239, + 63, + 168, + 9, + 77, + 168, + 93, + 207, + 87, + 216, + 11, + 52, + 93, + 40, + 209, + 54, + 43, + 18, + 38, + 167, + 248, + 139, + 182, + 36, + 80, + 25, + 233, + 49, + 90, + 26 + ], + "privateKey": [ + 34, + 196, + 2, + 58, + 182, + 159, + 66, + 30, + 196, + 172, + 242, + 106, + 199, + 35, + 215, + 3, + 234, + 190, + 151, + 60, + 238, + 168, + 33, + 126, + 80, + 71, + 85, + 240, + 172, + 240, + 175, + 238, + 16, + 210, + 239, + 63, + 168, + 9, + 77, + 168, + 93, + 207, + 87, + 216, + 11, + 52, + 93, + 40, + 209, + 54, + 43, + 18, + 38, + 167, + 248, + 139, + 182, + 36, + 80, + 25, + 233, + 49, + 90, + 26 + ], + "valid": true + } +] \ No newline at end of file diff --git a/clients/liquid-auth-core/tests/encoding.spec.js b/clients/liquid-auth-core/tests/encoding.spec.js new file mode 100644 index 0000000..7115f46 --- /dev/null +++ b/clients/liquid-auth-core/tests/encoding.spec.js @@ -0,0 +1,46 @@ +import test from 'node:test'; +import assert from 'node:assert'; + +import * as encoding from '../lib/encoding.js'; +import base64UrlFixtures from './__fixtures__/encoding.base64url.fixtures.json' assert {type: 'json'}; +import walletKeysFixtures from './__fixtures__/wallet.keys.fixtures.json' assert {type: 'json'}; + + +// Invalid Inputs +test(`fromBase64URL(*) throws ${encoding.INVALID_BASE64URL_INPUT}`, function(){ + assert.throws(()=>encoding.fromBase64Url(12345), new Error(encoding.INVALID_BASE64URL_INPUT)); +}) +base64UrlFixtures.forEach((fixture, i)=>{ + const encoder = new TextEncoder(); + + test(`toBase64URL(${fixture.origin})`, () => { + assert.equal(fixture.toBase64Url, encoding.toBase64URL(i % 2 ? encoder.encode(fixture.origin) : fixture.fromBase64Url)); + }) + test(`fromBase64URL(${fixture.origin})`, () => { + assert.deepEqual(new Uint8Array(fixture.fromBase64Url), encoding.fromBase64Url(fixture.toBase64Url)); + }); +}) + + + + +// Test Basic Inputs +test(`decodeAddress(*) throws ${encoding.MALFORMED_ADDRESS_ERROR_MSG}`, function(){ + assert.throws(()=>encoding.decodeAddress(12345), new Error(encoding.MALFORMED_ADDRESS_ERROR_MSG)); +}) +// Algorand Address Tests +walletKeysFixtures.forEach(function (fixture){ + test(`decodeAddress(${fixture.encoded})`, function(){ + const decoded = encoding.decodeAddress(fixture.encoded); + assert.deepEqual(new Uint8Array(fixture.publicKey), decoded); + }) + test(`encodeAddress(${fixture.encoded})`, function() { + const address = encoding.encodeAddress(new Uint8Array(fixture.publicKey)); + assert.equal(fixture.encoded, address); + }) + + test(`decodeAddress(${fixture.encoded.slice(0, -4) + "===="}) throws ${encoding.ALGORAND_ADDRESS_BAD_CHECKSUM_ERROR_MSG}`, function(){ + assert.throws(()=>encoding.decodeAddress(fixture.encoded.slice(0, -4) + "===="), new Error(encoding.ALGORAND_ADDRESS_BAD_CHECKSUM_ERROR_MSG)) + }) + +}) diff --git a/clients/liquid-auth-core/tests/generate.fixtures.js b/clients/liquid-auth-core/tests/generate.fixtures.js new file mode 100644 index 0000000..cc97449 --- /dev/null +++ b/clients/liquid-auth-core/tests/generate.fixtures.js @@ -0,0 +1,61 @@ +import {toBase64URL, } from "../lib/index.js"; +import * as fs from "node:fs"; +import algosdk from 'algosdk' + +const data = [ + "9b1a1b53-0456-4fcd-b10a-4db40352d58a", //OWIxYTFiNTMtMDQ1Ni00ZmNkLWIxMGEtNGRiNDAzNTJkNThh - Validated + "7646809", // Catch 7 Bits + "b1338059", // Catch 8 Bits + "582bd065-f280-4574-b315-3398c75296c5", + "29572cc5-7c36-4016-9825-abcc9ba51dae", + "2ce09bdf-69d1-4b08-b93e-3af4ca6a657a", + "15210d8d-308c-4acd-843c-ba6babada62c", + "cba26c96-51ad-40c0-b29f-6a46e0d88d43", + "c13cdc12-c7ed-41db-a669-56a664f8127a", + "8507cd12-1a02-4a48-92a5-23fbbe7ad5fe", + "02b073e9-f33c-4f06-b3aa-d94101a06494", + "064b6627-6dcb-439b-979d-a38c6a4e10f4", + "f32a0d44-6d3c-4f68-ba4d-0bc26aed6c7f", + "73b68c21-7bab-4608-ad9c-67d2fb954fa2", + "d626dd1f-50c5-4438-b920-72b852bb89cd", + "e598d7e0-282e-4ae9-909b-b18b9710b2b4", + "84c50a1a-38bb-470b-8347-68d9e323f3d8", + "53bae0ac-5462-438f-89c4-aa1204146eca", + "4b487db9-abba-40c5-a0ad-b2250878a332", + "d0941714-eae3-40db-a789-f21aa6401b0d", + "efb79528-d0bd-433e-be9f-f1020cee08fa", + "da2a799b-e1fe-460a-8f3f-0a5f4a124359", + "822dc1c2-556c-4cee-8c37-411ac530a088", + "d035ec77-dd78-4a51-8392-ad28870b0905", + "c934cf59-56a9-45f6-bdbd-7273d2ae86c8", + "b2c572bb-98e1-4d6b-b06c-865a749aacf6", + "5f571217-335c-422e-8c76-0e8b4e1296cf" +] + +const walletKeys = data.map(()=>{ + const address = algosdk.generateAccount() + return { + encoded: address.addr, + checksum: new Array(...algosdk.decodeAddress(address.addr).checksum), + publicKey: new Array(...algosdk.decodeAddress(address.addr).publicKey), + privateKey: new Array(...address.sk), + valid: true + } +}) + + +fs.writeFileSync('./tests/__fixtures__/wallet.keys.fixtures.json', JSON.stringify(walletKeys, null, 2)) + + +const encodingBase64URL = data.map((d)=>{ + const encoder = new TextEncoder() + return { + origin: d, + toBase64Url: toBase64URL(encoder.encode(d)), + fromBase64Url: new Array(...encoder.encode(d)), + } +}) + +fs.writeFileSync('./tests/__fixtures__/encoding.base64url.fixtures.json', JSON.stringify(encodingBase64URL, null, 2)) + +console.log(Buffer.from('hello', 'base32')) diff --git a/package.json b/package.json index 82baed9..79fb660 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,10 @@ "dev:core": "npm run dev --if-present --workspace @liquid/core", "dev:sdk": "npm run dev --if-present --workspace @liquid/auth-client", "dev:ui": "npm run dev --if-present --workspace dapp-ui", - "build": "npm run build --workspace @liquid/auth-client && npm run build --workspace @liquid/auth-api && npm run build --workspace dapp-ui", + "build": "npm run build --workspace @liquid/core && npm run build --workspace @liquid/auth-client && npm run build --workspace @liquid/auth-api && npm run build --workspace dapp-ui", "lint": "npm run lint --if-present --ws", + "test": "npm run test --if-present --ws", + "test:cov": "npm run test:cov --if-present --ws", "start": "npm run start:prod --workspace @liquid/auth-api" }, "workspaces": [ diff --git a/services/liquid-auth-api-js/.eslintrc.json b/services/liquid-auth-api-js/.eslintrc.json index 8277ad8..8cd93a2 100644 --- a/services/liquid-auth-api-js/.eslintrc.json +++ b/services/liquid-auth-api-js/.eslintrc.json @@ -21,6 +21,7 @@ "dist/**" ], "rules": { + "@typescript-eslint/ban-ts-comment": "warn", "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-module-boundary-types": "off", diff --git a/services/liquid-auth-api-js/src/adapters/redis-io.adapter.ts b/services/liquid-auth-api-js/src/adapters/redis-io.adapter.ts index 21e84f9..27a1307 100644 --- a/services/liquid-auth-api-js/src/adapters/redis-io.adapter.ts +++ b/services/liquid-auth-api-js/src/adapters/redis-io.adapter.ts @@ -1,5 +1,5 @@ import { IoAdapter } from '@nestjs/platform-socket.io'; -import { ServerOptions, Socket } from 'socket.io'; +import { ServerOptions } from 'socket.io'; import { createAdapter } from '@socket.io/redis-adapter'; import { Redis } from 'ioredis'; import { NestExpressApplication } from '@nestjs/platform-express'; diff --git a/services/liquid-auth-api-js/src/algod/algod.service.ts b/services/liquid-auth-api-js/src/algod/algod.service.ts index 34922e7..5678325 100644 --- a/services/liquid-auth-api-js/src/algod/algod.service.ts +++ b/services/liquid-auth-api-js/src/algod/algod.service.ts @@ -11,4 +11,3 @@ export class AlgodService extends algosdk.Algodv2 { super(token, server, port); } } - diff --git a/services/liquid-auth-api-js/src/app.controller.ts b/services/liquid-auth-api-js/src/app.controller.ts index 22d9f55..866b9cd 100644 --- a/services/liquid-auth-api-js/src/app.controller.ts +++ b/services/liquid-auth-api-js/src/app.controller.ts @@ -1,10 +1,6 @@ import { Controller, Get, Logger, Req, Res, Session } from '@nestjs/common'; import type { Response } from 'express'; -// ignore due to jest -// @ts-ignore -import assetLinks from '../assetlinks.json' with { type: 'json' }; - @Controller() export class AppController { private readonly logger = new Logger(AppController.name); diff --git a/services/liquid-auth-api-js/src/app.module.ts b/services/liquid-auth-api-js/src/app.module.ts index 3f498d1..d21f66c 100644 --- a/services/liquid-auth-api-js/src/app.module.ts +++ b/services/liquid-auth-api-js/src/app.module.ts @@ -16,7 +16,7 @@ import { AuthModule } from './auth/auth.module.js'; // Connect/Signals import { ConnectModule } from './connect/connect.module.js'; import { SignalsModule } from './signals/signals.module.js'; -import { AppController } from "./app.controller.js"; +import { AppController } from './app.controller.js'; @Module({ imports: [ diff --git a/services/liquid-auth-api-js/src/app.service.ts b/services/liquid-auth-api-js/src/app.service.ts index 9149c85..dc1526f 100644 --- a/services/liquid-auth-api-js/src/app.service.ts +++ b/services/liquid-auth-api-js/src/app.service.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import UAParser from 'ua-parser-js'; -import { toBase64URL } from "@liquid/core"; +import { toBase64URL } from '@liquid/core'; //@ts-ignore, required for jest import assetLinks from '../assetlinks.json' assert { type: 'json' }; @@ -18,13 +18,14 @@ export class AppService { parser.getOS().name.includes('Android') && typeof parser.getBrowser().name !== 'string' ) { - const pkgName = ua.split('/')[0] - console.log(pkgName) + const pkgName = ua.split('/')[0]; + console.log(pkgName); const statement = assetLinks.filter( (al) => al?.target?.package_name === pkgName, ); // TODO: better lookup for fingerprints using Headers - const octArray: number[] = statement[0].target.sha256_cert_fingerprints[0].split(':') + const octArray: number[] = statement[0].target.sha256_cert_fingerprints[0] + .split(':') .map((h) => parseInt(h, 16)); const androidHash = toBase64URL(new Uint8Array(octArray)); origin = `android:apk-key-hash:${androidHash}`; diff --git a/services/liquid-auth-api-js/src/assertion/assertion.controller.ts b/services/liquid-auth-api-js/src/assertion/assertion.controller.ts index ab24433..584c81a 100644 --- a/services/liquid-auth-api-js/src/assertion/assertion.controller.ts +++ b/services/liquid-auth-api-js/src/assertion/assertion.controller.ts @@ -1,7 +1,8 @@ import { Body, Controller, - Get, Inject, + Get, + Inject, Logger, Post, Req, @@ -148,7 +149,7 @@ export class AssertionController { await this.authService.update(user); const credential = await this.authService.findCredential(body.id); - console.log(credential) + console.log(credential); delete session.challenge; session.wallet = user.wallet; diff --git a/services/liquid-auth-api-js/src/attestation/attestation.service.ts b/services/liquid-auth-api-js/src/attestation/attestation.service.ts index 328daa5..8191bc5 100644 --- a/services/liquid-auth-api-js/src/attestation/attestation.service.ts +++ b/services/liquid-auth-api-js/src/attestation/attestation.service.ts @@ -63,7 +63,7 @@ export class AttestationService { credential: AttestationCredentialJSON & { device?: string }, ) { const expectedOrigin = this.appService.getOrigin(ua); - console.log(expectedOrigin) + console.log(expectedOrigin); const expectedRPID = this.configService.get('hostname'); const verifiedAttestation = await fido2.verifyAttestationResponse({ credential, diff --git a/services/liquid-auth-api-js/src/auth/auth.controller.ts b/services/liquid-auth-api-js/src/auth/auth.controller.ts index bd82d26..96ac704 100644 --- a/services/liquid-auth-api-js/src/auth/auth.controller.ts +++ b/services/liquid-auth-api-js/src/auth/auth.controller.ts @@ -1,9 +1,7 @@ import { - Body, Controller, Delete, Get, - Post, Req, Res, Session, @@ -13,9 +11,6 @@ import type { Request, Response } from 'express'; import { AuthService } from './auth.service.js'; import { AuthGuard } from './auth.guard.js'; -type LoginRequestDTO = { - wallet: string; -}; @Controller('auth') export class AuthController { constructor(private authService: AuthService) {} diff --git a/services/liquid-auth-api-js/src/connect/connect.controller.ts b/services/liquid-auth-api-js/src/connect/connect.controller.ts index 72b0b11..2625fd3 100644 --- a/services/liquid-auth-api-js/src/connect/connect.controller.ts +++ b/services/liquid-auth-api-js/src/connect/connect.controller.ts @@ -12,7 +12,7 @@ import { ClientProxy } from '@nestjs/microservices'; import { AuthService } from '../auth/auth.service.js'; import { AlgodService } from '../algod/algod.service.js'; import nacl from 'tweetnacl'; -import { decodeAddress, base64ToUint8Array } from '@liquid/core/encoding'; +import { decodeAddress, fromBase64Url } from '@liquid/core/encoding'; type LinkResponseDTO = { credId?: string; @@ -47,16 +47,14 @@ export class ConnectController { @Body() { requestId, wallet, challenge, signature, credId }: LinkResponseDTO, ) { - this.logger.log( - `POST /connect/response for RequestId: ${requestId} Session: ${session.id} with Wallet: ${wallet}`, - ); - // Decode Address - const publicKey = decodeAddress(wallet); + this.logger.log( + `POST /connect/response for RequestId: ${requestId} Session: ${session.id} with Wallet: ${wallet}`, + ); + // Decode Address + const publicKey = decodeAddress(wallet); // Decode signature - const uint8Signature = base64ToUint8Array( - signature.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, ''), - ); + const uint8Signature = fromBase64Url(signature); // Validate Signature const encoder = new TextEncoder(); diff --git a/services/liquid-auth-api-js/src/signals/signals.gateway.spec.ts b/services/liquid-auth-api-js/src/signals/signals.gateway.spec.ts index ab99c46..c8bf861 100644 --- a/services/liquid-auth-api-js/src/signals/signals.gateway.spec.ts +++ b/services/liquid-auth-api-js/src/signals/signals.gateway.spec.ts @@ -1,6 +1,6 @@ import { Test, TestingModule } from '@nestjs/testing'; import { SignalsGateway } from './signals.gateway.js'; -import { Server, Socket } from "socket.io"; +import { Server, Socket } from 'socket.io'; // eslint-disable-next-line @typescript-eslint/no-var-requires const candidateFixture = require('./__fixtures__/candidate.fixture.json'); diff --git a/services/liquid-auth-api-js/tsconfig.json b/services/liquid-auth-api-js/tsconfig.json index e3e741b..e8f4d91 100644 --- a/services/liquid-auth-api-js/tsconfig.json +++ b/services/liquid-auth-api-js/tsconfig.json @@ -5,7 +5,7 @@ "removeComments": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "allowSyntheticDefaultImports": false, + "allowSyntheticDefaultImports": true, "target": "ESNext", "moduleResolution": "NodeNext", "sourceMap": true, @@ -22,6 +22,7 @@ "inlineSources": true, "resolveJsonModule": true, "allowJs": true, + "esModuleInterop": true, // Set `sourceRoot` to "/" to strip the build path prefix // from generated source code references. // This improves issue grouping in Sentry. diff --git a/sites/dapp-ui/src/Contexts.tsx b/sites/dapp-ui/src/Contexts.tsx index 27973eb..bf06ac3 100644 --- a/sites/dapp-ui/src/Contexts.tsx +++ b/sites/dapp-ui/src/Contexts.tsx @@ -4,14 +4,20 @@ export const ColorModeContext = createContext({ toggle: () => {} }); export const StateContext = createContext({ state: 'debug', - setState: (_: string) => {}, + setState: (_: string) => { + console.log(_); + }, }); export const SnackbarContext = createContext({ open: false, - setOpen: (_: boolean) => {}, + setOpen: (_: boolean) => { + console.log(_); + }, message: '', - setMessage: (_: string) => {}, + setMessage: (_: string) => { + console.log(_); + }, }); export { DataChannelContext } from './hooks/useDataChannel.ts'; diff --git a/sites/dapp-ui/src/entry-main.tsx b/sites/dapp-ui/src/entry-main.tsx index 0565258..f6db3f5 100644 --- a/sites/dapp-ui/src/entry-main.tsx +++ b/sites/dapp-ui/src/entry-main.tsx @@ -1,6 +1,6 @@ import './index.css'; import * as ReactDOM from 'react-dom/client'; -import { StrictMode } from 'react'; +// import { StrictMode } from 'react'; import App from './App.tsx'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/sites/dapp-ui/src/hooks/useDataChannel.ts b/sites/dapp-ui/src/hooks/useDataChannel.ts index 41e15e0..bf27f29 100644 --- a/sites/dapp-ui/src/hooks/useDataChannel.ts +++ b/sites/dapp-ui/src/hooks/useDataChannel.ts @@ -6,7 +6,9 @@ type DataChannelState = { }; export const DataChannelContext = createContext({ dataChannel: null, - setDataChannel: (_: RTCDataChannel) => {}, + setDataChannel: (_: RTCDataChannel) => { + console.log(_); + }, } as DataChannelState); /** diff --git a/sites/dapp-ui/src/store.ts b/sites/dapp-ui/src/store.ts index 3a486a6..2f742e5 100644 --- a/sites/dapp-ui/src/store.ts +++ b/sites/dapp-ui/src/store.ts @@ -60,7 +60,7 @@ export const usePeerStore = create((set) => ({ })); export type Message = { - data: any; + data: unknown; type: 'local' | 'remote'; timestamp: number; };