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 88% rename from .github/workflows/main.yml rename to .github/workflows/main.yaml index 7ee4bde..0266908 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: @@ -32,6 +35,8 @@ jobs: node-version: [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/CHANGELOG.md b/CHANGELOG.md index e662e45..43f3a44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # bedrock-tokenization ChangeLog +## 23.3.0 - 2026-06-dd + +### Changed +- Expect node >= 22. +- 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/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/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/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/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 bc53add..30b10f2 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", @@ -26,15 +26,14 @@ "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": { @@ -45,15 +44,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' } }]; 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,