From cd9db6319029efe8d7bf35e5b5f2094de4e5aec1 Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Sun, 21 Jun 2026 17:40:22 -0400 Subject: [PATCH 1/5] Update linting. --- .eslintrc.cjs | 15 --------- .github/workflows/{main.yml => main.yaml} | 16 +++++++--- eslint.config.js | 16 ++++++++++ lib/batchVersions.js | 4 +-- lib/tokens/aeskw.js | 4 +-- lib/tokens/format.js | 8 ++--- package.json | 10 +++--- test/.eslintrc.cjs | 9 ------ test/mocha/10-documents.js | 2 +- test/mocha/20-tokens.js | 38 ++++++++++------------- test/mocha/mock.data.js | 4 +-- 11 files changed, 59 insertions(+), 67 deletions(-) delete mode 100644 .eslintrc.cjs rename .github/workflows/{main.yml => main.yaml} (86%) create mode 100644 eslint.config.js delete mode 100644 test/.eslintrc.cjs diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index a941733..0000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - root: true, - env: { - node: true - }, - extends: [ - 'digitalbazaar', - 'digitalbazaar/jsdoc', - 'digitalbazaar/module' - ], - ignorePatterns: ['node_modules/'], - rules: { - 'unicorn/prefer-node-protocol': 'error' - } -}; diff --git a/.github/workflows/main.yml b/.github/workflows/main.yaml similarity index 86% rename from .github/workflows/main.yml rename to .github/workflows/main.yaml index 7ee4bde..666cde7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yaml @@ -1,7 +1,9 @@ -name: Bedrock Node.js CI +name: Main CI on: [push] +permissions: {} + jobs: lint: runs-on: ubuntu-latest @@ -11,6 +13,8 @@ jobs: node-version: [24.x] steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: @@ -19,7 +23,6 @@ jobs: - name: Run eslint run: npm run lint test-node: - needs: [lint] runs-on: ubuntu-latest timeout-minutes: 10 services: @@ -29,9 +32,11 @@ jobs: - 27017:27017 strategy: matrix: - node-version: [22.x, 24.x] + node-version: [20.x, 22.x, 24.x] steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: @@ -45,7 +50,6 @@ jobs: cd test npm test coverage: - needs: [test-node] runs-on: ubuntu-latest timeout-minutes: 10 services: @@ -58,6 +62,8 @@ jobs: node-version: [24.x] steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: @@ -73,6 +79,6 @@ jobs: - name: Upload coverage to Codecov uses: codecov/codecov-action@v6 with: - file: ./test/coverage/lcov.info + files: ./test/coverage/lcov.info fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..1ea616b --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,16 @@ +import config from '@digitalbazaar/eslint-config/node-recommended'; + +export default [ + ...config, + { + files: [ + 'test/mocha/**/*.js' + ], + languageOptions: { + globals: { + // @bedrock/test global + assertNoError: true + } + } + } +]; diff --git a/lib/batchVersions.js b/lib/batchVersions.js index 4cb0ce2..91ca503 100644 --- a/lib/batchVersions.js +++ b/lib/batchVersions.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2020-2025 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2026 Digital Bazaar, Inc. */ import * as bedrock from '@bedrock/core'; import * as database from '@bedrock/mongodb'; @@ -14,7 +14,7 @@ const {util: {BedrockError}} = bedrock; const CACHE = new LRU({ max: 100, // 24 hour ttl - ttl: 1000 * 60 * 60 * 24, + ttl: 1000 * 60 * 60 * 24 }); // a special ID, the literal string "NEXT_OPTIONS", is used to identify the diff --git a/lib/tokens/aeskw.js b/lib/tokens/aeskw.js index 4c577f6..b177f9f 100644 --- a/lib/tokens/aeskw.js +++ b/lib/tokens/aeskw.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2020-2022 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2026 Digital Bazaar, Inc. */ import crypto from 'node:crypto'; @@ -41,7 +41,7 @@ class Kek { try { const cipher = crypto.createDecipheriv('id-aes256-wrap', kek, AES_KW_IV); return Buffer.concat([cipher.update(wrappedKey), cipher.final()]); - } catch(e) { + } catch { // decryption failed return null; } diff --git a/lib/tokens/format.js b/lib/tokens/format.js index 7ca5e16..8fe5e9e 100644 --- a/lib/tokens/format.js +++ b/lib/tokens/format.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2020-2025 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2026 Digital Bazaar, Inc. */ import * as base58 from 'base58-universal'; import * as batchVersions from '../batchVersions.js'; @@ -77,7 +77,7 @@ export async function create({ // salt payload.set(salt, offset += 2); // wrapped - payload.set(wrapped, offset += salt.length); + payload.set(wrapped, offset + salt.length); // ConcealedIdToken "meta" is "attributes" @@ -88,7 +88,7 @@ export async function create({ '@context': CIT_CONTEXT_URL, type: 'ConcealedIdToken', meta: `z${base58.encode(attributes)}`, - payload: `z${base58.encode(payload)}`, + payload: `z${base58.encode(payload)}` }; const token = await cborldEncode({ jsonldDocument, @@ -183,7 +183,7 @@ export async function parse({token}) { let offset = payload.byteOffset + VERSION_SIZE; const salt = new Uint8Array(payload.buffer, offset, batchSaltSize); const wrapped = new Uint8Array( - payload.buffer, offset += batchSaltSize, wrappedSize); + payload.buffer, offset + batchSaltSize, wrappedSize); // get tokenizer associated with version const tokenizer = await tokenizers.get({id: batchVersion.tokenizerId}); diff --git a/package.json b/package.json index bc53add..716b6e4 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Bedrock Tokenization Engine", "main": "./lib/index.js", "scripts": { - "lint": "eslint ." + "lint": "eslint" }, "repository": { "type": "git", @@ -45,15 +45,13 @@ "@bedrock/tokenizer": "^11.0.0" }, "devDependencies": { - "eslint": "^8.57.1", - "eslint-config-digitalbazaar": "^5.2.0", - "eslint-plugin-jsdoc": "^50.6.8", - "eslint-plugin-unicorn": "^56.0.1" + "@digitalbazaar/eslint-config": "^9.0.0", + "eslint": "^10.5.0" }, "directories": { "lib": "./lib" }, "engines": { - "node": ">=18" + "node": ">=22" } } diff --git a/test/.eslintrc.cjs b/test/.eslintrc.cjs deleted file mode 100644 index 4d36201..0000000 --- a/test/.eslintrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - globals: { - should: true, - assertNoError: true - }, - env: { - mocha: true - } -}; diff --git a/test/mocha/10-documents.js b/test/mocha/10-documents.js index a8c1c25..6a8bfb8 100644 --- a/test/mocha/10-documents.js +++ b/test/mocha/10-documents.js @@ -80,7 +80,7 @@ describe('Documents', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#' + 'z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } }]; const result = await documents.register({ diff --git a/test/mocha/20-tokens.js b/test/mocha/20-tokens.js index ef952a3..6b7420c 100644 --- a/test/mocha/20-tokens.js +++ b/test/mocha/20-tokens.js @@ -90,7 +90,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -133,7 +133,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -229,7 +229,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -647,9 +647,9 @@ describe('Tokens', function() { const {tokens: tks} = await tokens.create( {internalId, attributes, tokenCount}); - let token = tks[0]; - // change type of token to string - token = ''; + tks.length.should.equal(tokenCount); + // set type of token to string + const token = ''; try { result = await tokens.resolve({requester, token}); } catch(e) { @@ -658,8 +658,8 @@ describe('Tokens', function() { should.exist(err); should.not.exist(result); err.name.should.equal('TypeError'); - err.message.should.equal('"token" must be a Uint8Array that is 2 bytes or' + - ' more in size.'); + err.message.should.equal( + '"token" must be a Uint8Array that is 2 bytes or more in size.'); }); it('should throw error if token length is less than minimumSize', async function() { @@ -700,12 +700,11 @@ describe('Tokens', function() { // upsert mock entity the token is for await entities._upsert({internalId, ttl: 60000}); - let token; const {tokens: tks} = await tokens.create( {internalId, attributes, tokenCount}); - token = tks[0]; + tks.length.should.equal(tokenCount); // change length of token to be greater than 58 - token = new Uint8Array([ + const token = new Uint8Array([ 0, 0, 129, 160, 29, 189, 3, 64, 185, 31, 158, 32, 154, 159, 45, 235, 20, 205, 64, 222, 9, 66, 192, 79, 183, 54, 204, 169, 197, 19, 52, @@ -841,7 +840,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -883,7 +882,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -925,7 +924,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -1012,7 +1011,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -1053,7 +1052,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -1100,7 +1099,7 @@ describe('Tokens', function() { header: { kid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoA' + 'nwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc', - alg: 'ECDH-ES+A256KW', + alg: 'ECDH-ES+A256KW' } } ]; @@ -1270,6 +1269,7 @@ describe('Tokens', function() { // create tokens const tks = await tokens.create( {internalId, attributes, tokenCount, minAssuranceForResolution: -1}); + areTokens(tks); ({entity} = await entities.get({internalId})); // now an attempt to `setMinAssuranceForResolution` should fail because @@ -1277,7 +1277,6 @@ describe('Tokens', function() { result = await entities.setMinAssuranceForResolution( {entity, minAssuranceForResolution: 2}); result.should.equal(false); - result = undefined; // now resolve a token with an assurance failure let err; @@ -1307,7 +1306,6 @@ describe('Tokens', function() { result = await entities.setMinAssuranceForResolution( {entity, minAssuranceForResolution: 2}); result.should.equal(false); - result = undefined; delete entity.lastBatchInvalidationDate; // now a simulated attempt to `setMinAssuranceForResolution` should @@ -1317,7 +1315,6 @@ describe('Tokens', function() { result = await entities.setMinAssuranceForResolution( {entity, minAssuranceForResolution: 2}); result.should.equal(false); - result = undefined; entity.batchInvalidationCount--; // invalidate tokens (and do not update `entity` afterwards before next @@ -1331,7 +1328,6 @@ describe('Tokens', function() { result = await entities.setMinAssuranceForResolution( {entity, minAssuranceForResolution: 2}); result.should.equal(false); - result = undefined; // now an attempt to `setMinAssuranceForResolution` should *still* fail // because of a new `batchInvalidationCount` in the database, even diff --git a/test/mocha/mock.data.js b/test/mocha/mock.data.js index f717556..084840e 100644 --- a/test/mocha/mock.data.js +++ b/test/mocha/mock.data.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2021-2022 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2021-2026 Digital Bazaar, Inc. */ export const mockData = {}; @@ -13,7 +13,7 @@ const products = [{ service: { // default dev `id` configured in `bedrock-kms-http` id: 'did:key:z6MkwZ7AXrDpuVi5duY2qvVSx1tBkGmVnmRjDvvwzoVnAzC4', - type: 'webkms', + type: 'webkms' } }]; From d2f97a02aeab8a40a6f67a709129e4905024c6be Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Sun, 21 Jun 2026 17:41:08 -0400 Subject: [PATCH 2/5] Update test deps. --- test/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/package.json b/test/package.json index c38a7f8..1f28b16 100644 --- a/test/package.json +++ b/test/package.json @@ -18,7 +18,7 @@ "@bedrock/https-agent": "^4.1.0", "@bedrock/jsonld-document-loader": "^5.2.0", "@bedrock/kms": "^16.0.0", - "@bedrock/kms-http": "^22.0.0", + "@bedrock/kms-http": "^23.2.0", "@bedrock/ledger-context": "^25.0.0", "@bedrock/meter": "^6.0.0", "@bedrock/meter-http": "^14.0.0", @@ -38,10 +38,10 @@ "@digitalbazaar/x25519-key-agreement-key-2020": "^3.0.1", "base58-universal": "^2.0.0", "bnid": "^3.0.0", - "c8": "^10.1.3", - "canonicalize": "^2.1.0", - "cross-env": "^7.0.3", - "sinon": "^19.0.2" + "c8": "^11.0.0", + "canonicalize": "^3.0.0", + "cross-env": "^10.1.0", + "sinon": "^22.0.0" }, "c8": { "excludeNodeModules": false, From c133e3e143af878195ca09e03be8f67a5a63b161 Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Sun, 21 Jun 2026 17:43:32 -0400 Subject: [PATCH 3/5] Update dependencies. --- CHANGELOG.md | 9 +++++++++ package.json | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e662e45..918d734 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # bedrock-tokenization ChangeLog +## 23.3.0 - 2026-06-dd + +### Changed +- Update dependencies: + - `canonicalize@3` + - `@digitalbazaar/cborld@8.1` + - `@digitalbazaar/minimal-cipher@6.1.1` + - `lru-cache@11.5.1`. + ## 23.2.0 - 2026-06-21 ### Added diff --git a/package.json b/package.json index 716b6e4..24e24d5 100644 --- a/package.json +++ b/package.json @@ -26,15 +26,15 @@ "homepage": "https://github.com/digitalbazaar/bedrock-tokenization", "dependencies": { "@digitalbazaar/bitstring": "^3.1.0", - "@digitalbazaar/cborld": "^8.0.0", - "@digitalbazaar/minimal-cipher": "^6.0.0", + "@digitalbazaar/cborld": "^8.1.0", + "@digitalbazaar/minimal-cipher": "^6.1.1", "assert-plus": "^1.0.0", "base58-universal": "^2.0.0", "base64url-universal": "^2.0.0", "bnid": "^3.0.0", - "canonicalize": "^2.1.0", + "canonicalize": "^3.0.0", "cit-context": "^2.0.1", - "lru-cache": "^11.1.0", + "lru-cache": "^11.5.1", "p-limit": "^6.2.0" }, "peerDependencies": { From 959f970b2346a0517e58dc35ce4e9c05680aac60 Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Sun, 21 Jun 2026 17:46:23 -0400 Subject: [PATCH 4/5] Replace `base64url-universal` dependency w/native base64url. --- CHANGELOG.md | 1 + lib/tokens/batches.js | 5 ++--- lib/tokens/resolve.js | 5 ++--- package.json | 1 - 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 918d734..43f3a44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 23.3.0 - 2026-06-dd ### Changed +- Expect node >= 22. - Update dependencies: - `canonicalize@3` - `@digitalbazaar/cborld@8.1` diff --git a/lib/tokens/batches.js b/lib/tokens/batches.js index 25908a5..713ea5a 100644 --- a/lib/tokens/batches.js +++ b/lib/tokens/batches.js @@ -1,7 +1,6 @@ /*! - * Copyright (c) 2020-2025 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2026 Digital Bazaar, Inc. */ -import * as base64url from 'base64url-universal'; import * as batchVersions from '../batchVersions.js'; import * as bedrock from '@bedrock/core'; import * as database from '@bedrock/mongodb'; @@ -23,7 +22,7 @@ only 100, so it fits within this parameter. The config for this module has comments that indicate that the max configurable token batch size is 256 and this is because of this implementation detail. */ const EMPTY_RESOLVED_LIST_FOR_MAX_BATCH_SIZE_256 = Buffer.from( - base64url.decode('H4sIAAAAAAAAA2NgwA8ArVUKGSAAAAA')); + 'H4sIAAAAAAAAA2NgwA8ArVUKGSAAAAA', 'base64url'); const INTERNAL_ID_SIZE = 16; const MAX_TOKEN_COUNT = 100; diff --git a/lib/tokens/resolve.js b/lib/tokens/resolve.js index 956c2db..28f9778 100644 --- a/lib/tokens/resolve.js +++ b/lib/tokens/resolve.js @@ -1,7 +1,6 @@ /*! - * Copyright (c) 2020-2025 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2026 Digital Bazaar, Inc. */ -import * as base64url from 'base64url-universal'; import * as bedrock from '@bedrock/core'; import * as entities from '../entities.js'; import { @@ -95,7 +94,7 @@ export async function resolve({ }); // find resolution list for `requester` - const encodedRequester = base64url.encode(requester); + const encodedRequester = Buffer.from(requester).toString('base64url'); const requesterList = resolution[encodedRequester]; // see if token is already resolved diff --git a/package.json b/package.json index 24e24d5..30b10f2 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@digitalbazaar/minimal-cipher": "^6.1.1", "assert-plus": "^1.0.0", "base58-universal": "^2.0.0", - "base64url-universal": "^2.0.0", "bnid": "^3.0.0", "canonicalize": "^3.0.0", "cit-context": "^2.0.1", From e158b731225f8dff719bc2fc5fe3023ce71e4ffd Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Sun, 21 Jun 2026 17:47:41 -0400 Subject: [PATCH 5/5] Remove node 20 from test matrix. --- .github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 666cde7..0266908 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -32,7 +32,7 @@ jobs: - 27017:27017 strategy: matrix: - node-version: [20.x, 22.x, 24.x] + node-version: [22.x, 24.x] steps: - uses: actions/checkout@v6 with: