From a06673ed06e6c982c8c765427af32d157f967ab8 Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Tue, 28 Nov 2023 02:13:24 +1300 Subject: [PATCH 1/4] wip typings --- js/secret-channel/package.json | 12 +++- js/secret-channel/src/crypto-javascript.js | 25 +++++++- js/secret-channel/src/crypto-native.js | 24 ++++++++ js/secret-channel/src/protocol.js | 68 ++++++++++++++++++++-- js/secret-channel/src/types.ts | 13 +++++ js/secret-channel/tsconfig.json | 16 +++++ package.json | 6 +- 7 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 js/secret-channel/src/types.ts create mode 100644 js/secret-channel/tsconfig.json diff --git a/js/secret-channel/package.json b/js/secret-channel/package.json index 10527d5..8657180 100644 --- a/js/secret-channel/package.json +++ b/js/secret-channel/package.json @@ -2,12 +2,22 @@ "name": "secret-channel", "version": "1.0.0", "description": "Streaming authenticated encryption using ChaCha20-Poly1305", + "type": "commonjs", "main": "./src/index.js", + "exports": { + ".": "./src/index.js", + "./javascript": "./src/javascript.js" + }, "browser": { "./src/index.js": "./src/javascript.js" }, + "files": [ + "src/**/*" + ], "scripts": { - "test": "node --test" + "build": "npm run test:types && tsc --build", + "test": "npm run clean-check && node --test", + "test:types": "tsc --build --clean" }, "repository": { "type": "git", diff --git a/js/secret-channel/src/crypto-javascript.js b/js/secret-channel/src/crypto-javascript.js index e00cf47..e0edd7f 100644 --- a/js/secret-channel/src/crypto-javascript.js +++ b/js/secret-channel/src/crypto-javascript.js @@ -1,8 +1,11 @@ -const b4a = require('b4a') const { chacha20poly1305 } = require('@noble/ciphers/chacha') const debug = require('./debug') +/** + * @typedef {import('./types').B4A} B4A + */ + module.exports = { encrypt, decrypt, @@ -10,6 +13,12 @@ module.exports = { isZero, } +/** + * @param {B4A} keyArg + * @param {B4A} nonceArg + * @param {B4A} plaintextArg + * @returns {B4A} + */ function encrypt(keyArg, nonceArg, plaintextArg) { // ensure args are Uint8Array's, even in Node.js const key = Uint8Array.from(keyArg) @@ -21,10 +30,20 @@ function encrypt(keyArg, nonceArg, plaintextArg) { return ciphertext } +/** + * @param {B4A} key + * @param {B4A} nonce + * @param {B4A} ciphertext + * @returns {B4A} + */ function decrypt(key, nonce, ciphertext) { return chacha20poly1305(key, nonce).encrypt(ciphertext) } +/** + * @param {B4A} buf + * @returns {void} + */ function increment(buf) { const len = buf.length let c = 1 @@ -35,6 +54,10 @@ function increment(buf) { } } +/** + * @param {B4A} buf + * @returns {boolean} + */ function isZero(buf) { const len = buf.length let d = 0 diff --git a/js/secret-channel/src/crypto-native.js b/js/secret-channel/src/crypto-native.js index b52d730..e3865ce 100644 --- a/js/secret-channel/src/crypto-native.js +++ b/js/secret-channel/src/crypto-native.js @@ -9,6 +9,10 @@ const { const debug = require('./debug') +/** + * @typedef {import('./types').B4A} B4A + */ + module.exports = { encrypt, decrypt, @@ -16,6 +20,12 @@ module.exports = { isZero, } +/** + * @param {B4A} key + * @param {B4A} nonce + * @param {B4A} plaintext + * @returns {B4A} + */ function encrypt(key, nonce, plaintext) { debug('encrypt( %h , %h , %h )', key.slice(0, 2), nonce, plaintext) const ciphertext = b4a.allocUnsafe(plaintext.length + ABYTES) @@ -24,16 +34,30 @@ function encrypt(key, nonce, plaintext) { return ciphertext } +/** + * @param {B4A} key + * @param {B4A} nonce + * @param {B4A} ciphertext + * @returns {B4A} + */ function decrypt(key, nonce, ciphertext) { const plaintext = b4a.allocUnsafe(ciphertext.length - ABYTES) sodiumDecrypt(plaintext, null, ciphertext, null, nonce, key) return plaintext } +/** + * @param {B4A} buffer + * @returns {void} + */ function increment(buffer) { sodiumIncrement(buffer) } +/** + * @param {B4A} buffer + * @returns {boolean} + */ function isZero(buffer) { return sodiumIsZero(buffer) } diff --git a/js/secret-channel/src/protocol.js b/js/secret-channel/src/protocol.js index 7814ce5..0c65796 100644 --- a/js/secret-channel/src/protocol.js +++ b/js/secret-channel/src/protocol.js @@ -1,5 +1,10 @@ const b4a = require('b4a') +/** + * @typedef {import("./types").B4A} B4A + * @typedef {import("./types").Crypt} Crypt + */ + const { KEY_SIZE, NONCE_SIZE, @@ -8,10 +13,26 @@ const { } = require('./constants') class Encrypter { + /** + * @type {Crypt} + */ #crypto + + /** + * @type {B4A | null} + */ #key + + /** + * @type {B4A} + */ #nonce + /** + * @param {Crypt} crypto + * @param {B4A} key + * @param {B4A} nonce + */ constructor(crypto, key, nonce) { this.#crypto = crypto @@ -34,25 +55,30 @@ class Encrypter { b4a.copy(nonce, this.#nonce) } + /** + * @param {B4A} plaintext + * @returns {[B4A, B4A]} + */ next(plaintext) { - if (this.#key === null) { - throw new Error('secret-channel/Encrypter: stream has already ended') - } const plaintextBuffer = b4a.from(plaintext) const length = this.#chunkLength(plaintextBuffer.length) const content = this.#chunkContent(plaintextBuffer) return [length, content] } + /** + * @returns {B4A} + */ end() { - if (this.#key === null) { - throw new Error('secret-channel/Encrypter: stream has already ended') - } const eos = this.#chunkEndOfStream() this.#key = null return eos } + /** + * @param {number} length + * @returns {B4A} + */ #chunkLength(length) { const lengthData = b4a.allocUnsafe(LENGTH_OR_END_PLAINTEXT) const lengthDataView = new DataView(lengthData.buffer, lengthData.byteOffset, lengthData.length) @@ -60,16 +86,30 @@ class Encrypter { return this.#encrypt(lengthData) } + /** + * @param {B4A} content + * @returns {B4A} + */ #chunkContent(content) { return this.#encrypt(content) } + /** + * @return {B4A} + */ #chunkEndOfStream() { const eos = b4a.alloc(LENGTH_OR_END_PLAINTEXT, 0) return this.#encrypt(eos) } + /** + * @param {B4A} bytes + * @returns {B4A} + */ #encrypt(bytes) { + if (this.#key === null) { + throw new Error('secret-channel/Encrypter: stream has already ended') + } const ciphertext = this.#crypto.encrypt(this.#key, this.#nonce, bytes) this.#crypto.increment(this.#nonce) return ciphertext @@ -77,10 +117,26 @@ class Encrypter { } class Decrypter { + /** + * @type {Crypt} + */ #crypto + + /** + * @type {B4A} + */ #key + + /** + * @type {B4A} + */ #nonce + /** + * @param {Crypt} crypto + * @param {B4A} key + * @param {B4A} nonce + */ constructor(crypto, key, nonce) { this.#crypto = crypto diff --git a/js/secret-channel/src/types.ts b/js/secret-channel/src/types.ts new file mode 100644 index 0000000..4b5f238 --- /dev/null +++ b/js/secret-channel/src/types.ts @@ -0,0 +1,13 @@ +export type B4A = Buffer | Uint8Array + +export type Encrypt = (key: B4A, nonce: B4A, plaintext: B4A) => B4A +export type Decrypt = (key: B4A, nonce: B4A, ciphertext: B4A) => B4A +export type Increment = (buf: B4A) => void +export type IsZero = (buf: B4A) => boolean + +export type Crypt = { + encrypt: Encrypt + decrypt: Decrypt + increment: Increment + isZero: IsZero +} diff --git a/js/secret-channel/tsconfig.json b/js/secret-channel/tsconfig.json new file mode 100644 index 0000000..c65b2ce --- /dev/null +++ b/js/secret-channel/tsconfig.json @@ -0,0 +1,16 @@ +{ + "include": ["src/**/*.js"], + "exclude": ["node_modules/", "test/"], + "compilerOptions": { + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + "lib": ["es2022", "dom"], + "module": "node16", + "skipLibCheck": true, + "strict": true, + "target": "es2021" + } +} diff --git a/package.json b/package.json index 281dc91..f824f48 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ "./js/*" ], "devDependencies": { - "prettier": "^3.1.0" + "@types/b4a": "^1.6.4", + "@types/debug": "^4.1.12", + "@types/node": "^20.10.0", + "prettier": "^3.1.0", + "typescript": "^5.3.2" } } From de59e9aa0f730eb6befcdbd83436718165bd03c7 Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Thu, 7 Dec 2023 01:43:09 +1300 Subject: [PATCH 2/4] finish secret-channel typings --- .gitignore | 1 + js/secret-channel/package.json | 4 ++- js/secret-channel/src/crypto-native.js | 12 +++++--- js/secret-channel/src/protocol.js | 40 ++++++++++++++++++++------ js/secret-channel/tsconfig.json | 2 +- package.json | 1 + 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index ff72a70..4271312 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules npm-debug.log* package-lock.json +*.d.ts diff --git a/js/secret-channel/package.json b/js/secret-channel/package.json index 8657180..5b54261 100644 --- a/js/secret-channel/package.json +++ b/js/secret-channel/package.json @@ -4,6 +4,7 @@ "description": "Streaming authenticated encryption using ChaCha20-Poly1305", "type": "commonjs", "main": "./src/index.js", + "types": "./src/index.d.ts", "exports": { ".": "./src/index.js", "./javascript": "./src/javascript.js" @@ -16,7 +17,7 @@ ], "scripts": { "build": "npm run test:types && tsc --build", - "test": "npm run clean-check && node --test", + "test": "npm run test:types && node --test", "test:types": "tsc --build --clean" }, "repository": { @@ -42,6 +43,7 @@ "homepage": "https://github.com/ahdinosaur/secret-channel#readme", "dependencies": { "@noble/ciphers": "^0.4.0", + "@types/sodium-native": "^2.3.9", "b4a": "^1.6.4", "debug": "^4.3.4", "sodium-native": "^4.0.4" diff --git a/js/secret-channel/src/crypto-native.js b/js/secret-channel/src/crypto-native.js index e3865ce..46d4be1 100644 --- a/js/secret-channel/src/crypto-native.js +++ b/js/secret-channel/src/crypto-native.js @@ -1,7 +1,9 @@ -const b4a = require('b4a') const { + // @ts-ignore crypto_aead_chacha20poly1305_ietf_encrypt: sodiumEncrypt, + // @ts-ignore crypto_aead_chacha20poly1305_ietf_decrypt: sodiumDecrypt, + // @ts-ignore crypto_aead_chacha20poly1305_ietf_ABYTES: ABYTES, sodium_increment: sodiumIncrement, sodium_is_zero: sodiumIsZero, @@ -28,7 +30,7 @@ module.exports = { */ function encrypt(key, nonce, plaintext) { debug('encrypt( %h , %h , %h )', key.slice(0, 2), nonce, plaintext) - const ciphertext = b4a.allocUnsafe(plaintext.length + ABYTES) + const ciphertext = Buffer.allocUnsafe(plaintext.length + ABYTES) sodiumEncrypt(ciphertext, plaintext, null, null, nonce, key) debug('encrypt -> %h', ciphertext) return ciphertext @@ -41,7 +43,7 @@ function encrypt(key, nonce, plaintext) { * @returns {B4A} */ function decrypt(key, nonce, ciphertext) { - const plaintext = b4a.allocUnsafe(ciphertext.length - ABYTES) + const plaintext = Buffer.allocUnsafe(ciphertext.length - ABYTES) sodiumDecrypt(plaintext, null, ciphertext, null, nonce, key) return plaintext } @@ -51,6 +53,7 @@ function decrypt(key, nonce, ciphertext) { * @returns {void} */ function increment(buffer) { + // @ts-ignore sodiumIncrement(buffer) } @@ -59,5 +62,6 @@ function increment(buffer) { * @returns {boolean} */ function isZero(buffer) { - return sodiumIsZero(buffer) + // @ts-ignore + return sodiumIsZero(buffer, buffer.length) } diff --git a/js/secret-channel/src/protocol.js b/js/secret-channel/src/protocol.js index 0c65796..c2b1b56 100644 --- a/js/secret-channel/src/protocol.js +++ b/js/secret-channel/src/protocol.js @@ -116,6 +116,15 @@ class Encrypter { } } +/** + * @typedef {{ + * type: 'length' + * length: number + * } | { + * type: 'end-of-stream' + * }} LengthOrEnd + */ + class Decrypter { /** * @type {Crypt} @@ -123,7 +132,7 @@ class Decrypter { #crypto /** - * @type {B4A} + * @type {B4A | null} */ #key @@ -159,11 +168,11 @@ class Decrypter { b4a.copy(nonce, this.#nonce) } + /** + * @param {B4A} ciphertext + * @returns {LengthOrEnd} + */ lengthOrEnd(ciphertext) { - if (this.#key === null) { - throw new Error('secret-channel/Decrypter: stream has already ended') - } - if (ciphertext.length !== LENGTH_OR_END_CIPHERTEXT) { throw new Error( `secret-channel/Decrypter: length / end ciphertext must be ${LENGTH_OR_END_CIPHERTEXT} bytes`, @@ -189,20 +198,35 @@ class Decrypter { } } + /** + * @param {B4A} ciphertext + * @returns {B4A} + */ content(ciphertext) { - if (this.#key === null) { - throw new Error('secret-channel/Decrypter: stream has already ended') - } return this.#decrypt(ciphertext) } + /** + * @param {B4A} bytes + * @returns {B4A} + */ #decrypt(bytes) { + if (this.#key === null) { + throw new Error('secret-channel/Decrypter: stream has already ended') + } const plaintext = this.#crypto.decrypt(this.#key, this.#nonce, bytes) this.#crypto.increment(this.#nonce) return plaintext } } +/** + * @param {Crypt} crypto + * @returns {{ + * createEncrypter: (key: B4A, nonce: B4A) => Encrypter + * createDecrypter: (key: B4A, nonce: B4A) => Decrypter + * }} + */ function protocol(crypto) { return { createEncrypter(key, nonce) { diff --git a/js/secret-channel/tsconfig.json b/js/secret-channel/tsconfig.json index c65b2ce..f92428e 100644 --- a/js/secret-channel/tsconfig.json +++ b/js/secret-channel/tsconfig.json @@ -8,7 +8,7 @@ "exactOptionalPropertyTypes": true, "forceConsistentCasingInFileNames": true, "lib": ["es2022", "dom"], - "module": "node16", + "module": "NodeNext", "skipLibCheck": true, "strict": true, "target": "es2021" diff --git a/package.json b/package.json index f824f48..7e7f654 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "secret-channel-project", "scripts": { + "build": "npm run build --workspaces --if-present", "test": "npm run test --workspaces --if-present", "lint": "prettier --check \"./js/*/(src|test|bench)/**/*.js\"", "format": "prettier --write \"./js/*/(src|test|bench)/**/*.js\"" From 4e5b0706dcb4f98bbe3c42b16fd853f37d66beca Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Thu, 7 Dec 2023 02:04:54 +1300 Subject: [PATCH 3/4] more types --- js/pull-secret-channel/package.json | 16 +++- js/pull-secret-channel/src/index.js | 122 +++++++++++++++++++-------- js/pull-secret-channel/tsconfig.json | 16 ++++ 3 files changed, 118 insertions(+), 36 deletions(-) create mode 100644 js/pull-secret-channel/tsconfig.json diff --git a/js/pull-secret-channel/package.json b/js/pull-secret-channel/package.json index dae16a9..42c8ea7 100644 --- a/js/pull-secret-channel/package.json +++ b/js/pull-secret-channel/package.json @@ -2,9 +2,23 @@ "name": "pull-secret-channel", "version": "1.0.0", "description": "Pull stream of authenticated encryption ChaCha20-Poly1305", + "type": "commonjs", "main": "./src/index.js", + "types": "./src/index.d.ts", + "exports": { + ".": "./src/index.js", + "./javascript": "./src/javascript.js" + }, + "browser": { + "./src/index.js": "./src/javascript.js" + }, + "files": [ + "src/**/*" + ], "scripts": { - "test": "node --test" + "build": "npm run test:types && tsc --build", + "test": "npm run test:types && node --test", + "test:types": "tsc --build --clean" }, "repository": { "type": "git", diff --git a/js/pull-secret-channel/src/index.js b/js/pull-secret-channel/src/index.js index 9da35e5..984b0c2 100644 --- a/js/pull-secret-channel/src/index.js +++ b/js/pull-secret-channel/src/index.js @@ -1,4 +1,6 @@ +// @ts-ignore const pullThrough = require('pull-through') +// @ts-ignore const pullReader = require('pull-reader') const { createEncrypter, @@ -17,16 +19,36 @@ module.exports = { TAG_SIZE, } +/** + @typedef {Buffer | Uint8Array} B4A + @typedef {null | true | Error} End + @typedef {(end: End, cb: (end: End, data?: any) => void) => void} Source + @typedef {{ + queue: (buf: B4A | null) => void + }} PullThroughThis +*/ + +/** + * @param {B4A} key + * @param {B4A} nonce + */ function pullEncrypter(key, nonce) { const encrypter = createEncrypter(key, nonce) return pullThrough( + /** + * @this {PullThroughThis} + * @param {B4A} contentPlaintext + */ function pullEncrypterData(contentPlaintext) { const [lengthCiphertext, contentCiphertext] = encrypter.next(contentPlaintext) this.queue(lengthCiphertext) this.queue(contentCiphertext) }, + /** + * @this {PullThroughThis} + */ function pullEncrypterEnd() { const endCiphertext = encrypter.end() this.queue(endCiphertext) @@ -35,67 +57,97 @@ function pullEncrypter(key, nonce) { ) } +/** + * @param {B4A} key + * @param {B4A} nonce + */ function pullDecrypter(key, nonce) { const decrypter = createDecrypter(key, nonce) + /** @type {End} */ let ending = null const reader = pullReader() + /** + * @param {Source} read + */ return function pullDecrypterThrough(read) { reader(read) + /** + * @param {End} end + * @param {(end: End, data?: B4A) => void} cb + */ return function pullDecrypterSource(end, cb) { if (end) return reader.abort(end, cb) if (ending) return cb(ending) - reader.read(LENGTH_OR_END_CIPHERTEXT, function (err, lengthOrEndCiphertext) { - if (err) { - if (err === true) { - ending = new Error( - 'pull-secret-channel/decrypter: stream ended before end-of-stream message', - ) - } else { - ending = err - } - return cb(ending) - } - - let lengthOrEnd - try { - lengthOrEnd = decrypter.lengthOrEnd(lengthOrEndCiphertext) - } catch (err) { - ending = err - // TODO attach error context - return abort(err) - } - - if (lengthOrEnd.type === 'end-of-stream') { - ending = true - return cb(ending) - } - - const { length } = lengthOrEnd - reader.read(length + TAG_SIZE, function (err, contentCiphertext) { + reader.read( + LENGTH_OR_END_CIPHERTEXT, + + /** + * @param {End} err + * @param {B4A} lengthOrEndCiphertext + */ + function (err, lengthOrEndCiphertext) { if (err) { - ending = err + if (err === true) { + ending = new Error( + 'pull-secret-channel/decrypter: stream ended before end-of-stream message', + ) + } else { + ending = err + } return cb(ending) } - let contentPlaintext + let lengthOrEnd try { - contentPlaintext = decrypter.content(contentCiphertext) - } catch (err) { + lengthOrEnd = decrypter.lengthOrEnd(lengthOrEndCiphertext) + } catch (/** @type any */ err) { ending = err // TODO attach error context return abort(err) } - cb(null, contentPlaintext) - }) - }) + if (lengthOrEnd.type === 'end-of-stream') { + ending = true + return cb(ending) + } + + const { length } = lengthOrEnd + reader.read( + length + TAG_SIZE, + /** + * @param {End} err + * @param {B4A} contentCiphertext + */ + function (err, contentCiphertext) { + if (err) { + ending = err + return cb(ending) + } + + let contentPlaintext + try { + contentPlaintext = decrypter.content(contentCiphertext) + } catch (/** @type any */ err) { + ending = err + // TODO attach error context + return abort(err) + } + + cb(null, contentPlaintext) + }, + ) + }, + ) // use abort when the input was invalid, // but the source hasn't actually ended yet. + /** + * @param {End} err + */ function abort(err) { ending = err || true reader.abort(ending, cb) diff --git a/js/pull-secret-channel/tsconfig.json b/js/pull-secret-channel/tsconfig.json new file mode 100644 index 0000000..f92428e --- /dev/null +++ b/js/pull-secret-channel/tsconfig.json @@ -0,0 +1,16 @@ +{ + "include": ["src/**/*.js"], + "exclude": ["node_modules/", "test/"], + "compilerOptions": { + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + "lib": ["es2022", "dom"], + "module": "NodeNext", + "skipLibCheck": true, + "strict": true, + "target": "es2021" + } +} From 8811870f4cdf0341e1d790da2249375f6bf3f2bb Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Thu, 7 Dec 2023 22:14:03 +1300 Subject: [PATCH 4/4] configure ts better --- js/pull-secret-channel/package.json | 1 + js/pull-secret-channel/tsconfig.json | 15 ++--------- js/secret-channel/package.json | 1 + js/secret-channel/src/crypto-javascript.js | 6 +++-- js/secret-channel/tsconfig.json | 15 ++--------- tsconfig.json | 29 ++++++++++++++++++++++ 6 files changed, 39 insertions(+), 28 deletions(-) create mode 100644 tsconfig.json diff --git a/js/pull-secret-channel/package.json b/js/pull-secret-channel/package.json index 42c8ea7..4e2dbbd 100644 --- a/js/pull-secret-channel/package.json +++ b/js/pull-secret-channel/package.json @@ -16,6 +16,7 @@ "src/**/*" ], "scripts": { + "prepublishOnly": "npm run build", "build": "npm run test:types && tsc --build", "test": "npm run test:types && node --test", "test:types": "tsc --build --clean" diff --git a/js/pull-secret-channel/tsconfig.json b/js/pull-secret-channel/tsconfig.json index f92428e..4b6a738 100644 --- a/js/pull-secret-channel/tsconfig.json +++ b/js/pull-secret-channel/tsconfig.json @@ -1,16 +1,5 @@ { + "extends": "../../tsconfig.json", "include": ["src/**/*.js"], - "exclude": ["node_modules/", "test/"], - "compilerOptions": { - "checkJs": true, - "declaration": true, - "emitDeclarationOnly": true, - "exactOptionalPropertyTypes": true, - "forceConsistentCasingInFileNames": true, - "lib": ["es2022", "dom"], - "module": "NodeNext", - "skipLibCheck": true, - "strict": true, - "target": "es2021" - } + "exclude": ["node_modules/", "test/"] } diff --git a/js/secret-channel/package.json b/js/secret-channel/package.json index 5b54261..688dcf7 100644 --- a/js/secret-channel/package.json +++ b/js/secret-channel/package.json @@ -16,6 +16,7 @@ "src/**/*" ], "scripts": { + "prepublishOnly": "npm run build", "build": "npm run test:types && tsc --build", "test": "npm run test:types && node --test", "test:types": "tsc --build --clean" diff --git a/js/secret-channel/src/crypto-javascript.js b/js/secret-channel/src/crypto-javascript.js index e0edd7f..2bfca2e 100644 --- a/js/secret-channel/src/crypto-javascript.js +++ b/js/secret-channel/src/crypto-javascript.js @@ -48,7 +48,7 @@ function increment(buf) { const len = buf.length let c = 1 for (let i = 0; i < len; i++) { - c += buf[i] + c += /** @type number */ (buf[i]) buf[i] = c c >>= 8 } @@ -61,6 +61,8 @@ function increment(buf) { function isZero(buf) { const len = buf.length let d = 0 - for (let i = 0; i < len; i++) d |= buf[i] + for (let i = 0; i < len; i++) { + d |= /** @type number */ (buf[i]) + } return d === 0 } diff --git a/js/secret-channel/tsconfig.json b/js/secret-channel/tsconfig.json index f92428e..4b6a738 100644 --- a/js/secret-channel/tsconfig.json +++ b/js/secret-channel/tsconfig.json @@ -1,16 +1,5 @@ { + "extends": "../../tsconfig.json", "include": ["src/**/*.js"], - "exclude": ["node_modules/", "test/"], - "compilerOptions": { - "checkJs": true, - "declaration": true, - "emitDeclarationOnly": true, - "exactOptionalPropertyTypes": true, - "forceConsistentCasingInFileNames": true, - "lib": ["es2022", "dom"], - "module": "NodeNext", - "skipLibCheck": true, - "strict": true, - "target": "es2021" - } + "exclude": ["node_modules/", "test/"] } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e2ab460 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "resolveJsonModule": true, + "strict": true, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + "useDefineForClassFields": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "noUncheckedIndexedAccess": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "target": "ES2022" + } +}