From f0ac7b541f2b15579bb873c81e2aa2ecbd7ee9af Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 30 May 2023 10:10:09 +0200 Subject: [PATCH 01/10] expose the private key to the writeHomeCommunity function --- dht-node/src/dht_node/index.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index 6e48806d8..4e9b83107 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -24,6 +24,8 @@ export type CommunityApi = { url: string } +type KeyPair = { publicKey: Buffer; secretKey: Buffer } + export const startDHT = async (topic: string): Promise => { try { const TOPIC = DHT.hash(Buffer.from(topic)) @@ -31,11 +33,11 @@ export const startDHT = async (topic: string): Promise => { CONFIG.FEDERATION_DHT_SEED ? Buffer.alloc(KEY_SECRET_SEEDBYTES, CONFIG.FEDERATION_DHT_SEED) : null, - ) + ) as KeyPair const pubKeyString = keyPair.publicKey.toString('hex') logger.info(`keyPairDHT: publicKey=${pubKeyString}`) logger.debug(`keyPairDHT: secretKey=${keyPair.secretKey.toString('hex')}`) - await writeHomeCommunityEntry(pubKeyString) + await writeHomeCommunityEntry(keyPair) const ownApiVersions = await writeFederatedHomeCommunityEntries(pubKeyString) logger.info(`ApiList: ${JSON.stringify(ownApiVersions)}`) @@ -211,13 +213,13 @@ async function writeFederatedHomeCommunityEntries(pubKey: string): Promise { +async function writeHomeCommunityEntry(keyPair: KeyPair): Promise { try { // check for existing homeCommunity entry let homeCom = await DbCommunity.findOne({ foreign: false }) if (homeCom) { // simply update the existing entry, but it MUST keep the ID and UUID because of possible relations - homeCom.publicKey = Buffer.from(pubKey) + homeCom.publicKey = Buffer.from(keyPair.publicKey) homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/' homeCom.name = CONFIG.COMMUNITY_NAME homeCom.description = CONFIG.COMMUNITY_DESCRIPTION @@ -227,7 +229,7 @@ async function writeHomeCommunityEntry(pubKey: string): Promise { // insert a new homecommunity entry including a new ID and a new but ensured unique UUID homeCom = new DbCommunity() homeCom.foreign = false - homeCom.publicKey = Buffer.from(pubKey) + homeCom.publicKey = Buffer.from(keyPair.publicKey) homeCom.communityUuid = await newCommunityUuid() homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/' homeCom.name = CONFIG.COMMUNITY_NAME From 9256439cf9bd93acc585d292ebd0aa511052fd76 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 30 May 2023 10:36:19 +0200 Subject: [PATCH 02/10] remove obsolete Buffer.from --- dht-node/src/dht_node/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index 4e9b83107..adef0fc52 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -219,7 +219,7 @@ async function writeHomeCommunityEntry(keyPair: KeyPair): Promise { let homeCom = await DbCommunity.findOne({ foreign: false }) if (homeCom) { // simply update the existing entry, but it MUST keep the ID and UUID because of possible relations - homeCom.publicKey = Buffer.from(keyPair.publicKey) + homeCom.publicKey = keyPair.publicKey homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/' homeCom.name = CONFIG.COMMUNITY_NAME homeCom.description = CONFIG.COMMUNITY_DESCRIPTION @@ -229,7 +229,7 @@ async function writeHomeCommunityEntry(keyPair: KeyPair): Promise { // insert a new homecommunity entry including a new ID and a new but ensured unique UUID homeCom = new DbCommunity() homeCom.foreign = false - homeCom.publicKey = Buffer.from(keyPair.publicKey) + homeCom.publicKey = keyPair.publicKey homeCom.communityUuid = await newCommunityUuid() homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/' homeCom.name = CONFIG.COMMUNITY_NAME From e408497ee058e2b8398bbfaafd9b18323da4ec21 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 6 Jun 2023 12:07:30 +0200 Subject: [PATCH 03/10] sodium native types --- backend/@types/sodium-native/index.d.ts | 8 ++++++++ backend/package.json | 1 + backend/yarn.lock | 9 ++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 backend/@types/sodium-native/index.d.ts diff --git a/backend/@types/sodium-native/index.d.ts b/backend/@types/sodium-native/index.d.ts new file mode 100644 index 000000000..773d85ee5 --- /dev/null +++ b/backend/@types/sodium-native/index.d.ts @@ -0,0 +1,8 @@ +// eslint-disable-next-line import/no-unresolved +export * from '@/node_modules/@types/sodium-native' + +declare module 'sodium-native' { + export function crypto_hash_sha512_init(state: Buffer, key?: Buffer, outlen?: Buffer): void + export function crypto_hash_sha512_update(state: Buffer, input: Buffer): void + export function crypto_hash_sha512_final(state: Buffer, out: Buffer): void +} diff --git a/backend/package.json b/backend/package.json index 68ec89ec0..10d58f8ed 100644 --- a/backend/package.json +++ b/backend/package.json @@ -55,6 +55,7 @@ "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^16.10.3", "@types/nodemailer": "^6.4.4", + "@types/sodium-native": "^2.3.5", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.57.1", "@typescript-eslint/parser": "^5.57.1", diff --git a/backend/yarn.lock b/backend/yarn.lock index 4d070934b..24537fc57 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1181,6 +1181,13 @@ "@types/mime" "^1" "@types/node" "*" +"@types/sodium-native@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@types/sodium-native/-/sodium-native-2.3.5.tgz#5d2681e7b6b67bcbdc63cfb133e303ec9e942e43" + integrity sha512-a3DAIpW8+36XAY8aIR36JBQQsfOabxHuJwx11DL/PTvnbwEWPAXW66b8QbMi0r2vUnkOfREsketxdvjBmQxqDQ== + dependencies: + "@types/node" "*" + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -3645,7 +3652,7 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== "gradido-database@file:../database": - version "1.20.0" + version "1.21.0" dependencies: "@types/uuid" "^8.3.4" cross-env "^7.0.3" From 6160492e152c4d7ed7d2090b5f5f0b7ec2df4ea0 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 6 Jun 2023 12:21:47 +0200 Subject: [PATCH 04/10] ignore CamelCase for sodium-native, ignore sodium-native import false positives --- backend/.eslintrc.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 78ac9e41e..d49637dec 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -25,10 +25,12 @@ module.exports = { }, node: true, }, + // the parser cannot handle the split sodium import + 'import/ignore': ['sodium-native'], }, rules: { 'no-console': 'error', - camelcase: ['error', { allow: ['FederationClient_*'] }], + camelcase: ['error', { allow: ['FederationClient_*', 'crypto_*', 'randombytes_random'] }], 'no-debugger': 'error', 'prettier/prettier': [ 'error', From 39ead9375525cb0bce30543780735dfb7d002ff5 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 6 Jun 2023 12:22:09 +0200 Subject: [PATCH 05/10] sodium native imports with types --- backend/src/graphql/resolver/UserResolver.ts | 7 ++-- backend/src/password/EncryptorUtils.ts | 42 +++++++++++++------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index cbfd9b5c5..461c44388 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -70,6 +70,9 @@ import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' import { getTimeDurationObject, printTimeDuration } from '@/util/time' +// eslint-disable-next-line import/no-relative-parent-imports +import { randombytes_random } from 'sodium-native' + import { FULL_CREATION_AVAILABLE } from './const/const' import { getUserCreations } from './util/creations' import { findUserByIdentifier } from './util/findUserByIdentifier' @@ -77,8 +80,6 @@ import { validateAlias } from './util/validateAlias' // eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs const random = require('random-bigint') -// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs -const sodium = require('sodium-native') const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl'] const DEFAULT_LANGUAGE = 'de' @@ -237,7 +238,7 @@ export class UserResolver { // TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent. const user = new User(communityDbUser) - user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in? + user.id = randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in? user.gradidoID = uuidv4() user.firstName = firstName user.lastName = lastName diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts index 827fc9547..92035c2d7 100644 --- a/backend/src/password/EncryptorUtils.ts +++ b/backend/src/password/EncryptorUtils.ts @@ -10,8 +10,20 @@ import { CONFIG } from '@/config' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs -const sodium = require('sodium-native') +import { + crypto_shorthash_KEYBYTES, + crypto_box_SEEDBYTES, + crypto_hash_sha512_init, + crypto_hash_sha512_update, + crypto_hash_sha512_final, + crypto_hash_sha512_BYTES, + crypto_hash_sha512_STATEBYTES, + crypto_shorthash_BYTES, + crypto_pwhash_SALTBYTES, + crypto_pwhash, + crypto_shorthash, + // eslint-disable-next-line import/no-relative-parent-imports +} from 'sodium-native' // We will reuse this for changePassword export const isValidPassword = (password: string): boolean => { @@ -22,36 +34,36 @@ export const SecretKeyCryptographyCreateKey = (salt: string, password: string): logger.trace('SecretKeyCryptographyCreateKey...') const configLoginAppSecret = Buffer.from(CONFIG.LOGIN_APP_SECRET, 'hex') const configLoginServerKey = Buffer.from(CONFIG.LOGIN_SERVER_KEY, 'hex') - if (configLoginServerKey.length !== sodium.crypto_shorthash_KEYBYTES) { + if (configLoginServerKey.length !== crypto_shorthash_KEYBYTES) { throw new LogError( 'ServerKey has an invalid size', configLoginServerKey.length, - sodium.crypto_shorthash_KEYBYTES, + crypto_shorthash_KEYBYTES, ) } - const state = Buffer.alloc(sodium.crypto_hash_sha512_STATEBYTES) - sodium.crypto_hash_sha512_init(state) - sodium.crypto_hash_sha512_update(state, Buffer.from(salt)) - sodium.crypto_hash_sha512_update(state, configLoginAppSecret) - const hash = Buffer.alloc(sodium.crypto_hash_sha512_BYTES) - sodium.crypto_hash_sha512_final(state, hash) + const state = Buffer.alloc(crypto_hash_sha512_STATEBYTES) + crypto_hash_sha512_init(state) + crypto_hash_sha512_update(state, Buffer.from(salt)) + crypto_hash_sha512_update(state, configLoginAppSecret) + const hash = Buffer.alloc(crypto_hash_sha512_BYTES) + crypto_hash_sha512_final(state, hash) - const encryptionKey = Buffer.alloc(sodium.crypto_box_SEEDBYTES) + const encryptionKey = Buffer.alloc(crypto_box_SEEDBYTES) const opsLimit = 10 const memLimit = 33554432 const algo = 2 - sodium.crypto_pwhash( + crypto_pwhash( encryptionKey, Buffer.from(password), - hash.slice(0, sodium.crypto_pwhash_SALTBYTES), + hash.slice(0, crypto_pwhash_SALTBYTES), opsLimit, memLimit, algo, ) - const encryptionKeyHash = Buffer.alloc(sodium.crypto_shorthash_BYTES) - sodium.crypto_shorthash(encryptionKeyHash, encryptionKey, configLoginServerKey) + const encryptionKeyHash = Buffer.alloc(crypto_shorthash_BYTES) + crypto_shorthash(encryptionKeyHash, encryptionKey, configLoginServerKey) return [encryptionKeyHash, encryptionKey] } From 6ca68ce19d362c3c69eb945dc42f0cd2d12aab5c Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 6 Jun 2023 12:52:10 +0200 Subject: [PATCH 06/10] sodium native ignored for relative-inport --- backend/.eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index d49637dec..96460d193 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -60,7 +60,7 @@ module.exports = { 'import/no-dynamic-require': 'error', 'import/no-internal-modules': 'off', 'import/no-relative-packages': 'error', - 'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }], + 'import/no-relative-parent-imports': ['error', { ignore: ['@/*', 'sodium-native'] }], 'import/no-self-import': 'error', 'import/no-unresolved': 'error', 'import/no-useless-path-segments': 'error', From 6d4e9ffb33c1b75e177b7319ffc3a642b265ba68 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 6 Jun 2023 12:52:24 +0200 Subject: [PATCH 07/10] remove obsolte lint disable --- backend/src/graphql/resolver/UserResolver.ts | 1 - backend/src/password/EncryptorUtils.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 461c44388..db7c93b6d 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -70,7 +70,6 @@ import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' import { getTimeDurationObject, printTimeDuration } from '@/util/time' -// eslint-disable-next-line import/no-relative-parent-imports import { randombytes_random } from 'sodium-native' import { FULL_CREATION_AVAILABLE } from './const/const' diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts index 92035c2d7..64dcb2289 100644 --- a/backend/src/password/EncryptorUtils.ts +++ b/backend/src/password/EncryptorUtils.ts @@ -22,7 +22,6 @@ import { crypto_pwhash_SALTBYTES, crypto_pwhash, crypto_shorthash, - // eslint-disable-next-line import/no-relative-parent-imports } from 'sodium-native' // We will reuse this for changePassword From 5119ea1f301c1e310fc410862a6b4eeeceed49f0 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 7 Jun 2023 13:01:52 +0200 Subject: [PATCH 08/10] enable most eslint-plugin-n rules --- database/.eslintrc.js | 68 ++++++++++++++++++------------------ database/package.json | 3 ++ database/src/config/index.ts | 2 +- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/database/.eslintrc.js b/database/.eslintrc.js index 587506ecc..896a7ed68 100644 --- a/database/.eslintrc.js +++ b/database/.eslintrc.js @@ -101,43 +101,43 @@ module.exports = { // ], // 'import/prefer-default-export': 'off', // n - // 'n/handle-callback-err': 'error', - // 'n/no-callback-literal': 'error', - // 'n/no-exports-assign': 'error', + 'n/handle-callback-err': 'error', + 'n/no-callback-literal': 'error', + 'n/no-exports-assign': 'error', // 'n/no-extraneous-import': 'error', - // 'n/no-extraneous-require': 'error', - // 'n/no-hide-core-modules': 'error', - // 'n/no-missing-import': 'off', // not compatible with typescript - // 'n/no-missing-require': 'error', - // 'n/no-new-require': 'error', - // 'n/no-path-concat': 'error', + 'n/no-extraneous-require': 'error', + 'n/no-hide-core-modules': 'error', + 'n/no-missing-import': 'off', // not compatible with typescript + 'n/no-missing-require': 'error', + 'n/no-new-require': 'error', + 'n/no-path-concat': 'error', // 'n/no-process-exit': 'error', - // 'n/no-unpublished-bin': 'error', - // 'n/no-unpublished-import': 'off', // TODO need to exclude seeds - // 'n/no-unpublished-require': 'error', - // 'n/no-unsupported-features': ['error', { ignores: ['modules'] }], - // 'n/no-unsupported-features/es-builtins': 'error', - // 'n/no-unsupported-features/es-syntax': 'error', - // 'n/no-unsupported-features/node-builtins': 'error', - // 'n/process-exit-as-throw': 'error', - // 'n/shebang': 'error', - // 'n/callback-return': 'error', - // 'n/exports-style': 'error', - // 'n/file-extension-in-import': 'off', - // 'n/global-require': 'error', - // 'n/no-mixed-requires': 'error', - // 'n/no-process-env': 'error', - // 'n/no-restricted-import': 'error', - // 'n/no-restricted-require': 'error', + 'n/no-unpublished-bin': 'error', + 'n/no-unpublished-import': 'off', // TODO need to exclude seeds + 'n/no-unpublished-require': 'error', + 'n/no-unsupported-features': ['error', { ignores: ['modules'] }], + 'n/no-unsupported-features/es-builtins': 'error', + 'n/no-unsupported-features/es-syntax': 'error', + 'n/no-unsupported-features/node-builtins': 'error', + 'n/process-exit-as-throw': 'error', + 'n/shebang': 'error', + 'n/callback-return': 'error', + 'n/exports-style': 'error', + 'n/file-extension-in-import': 'off', + 'n/global-require': 'error', + 'n/no-mixed-requires': 'error', + 'n/no-process-env': 'error', + 'n/no-restricted-import': 'error', + 'n/no-restricted-require': 'error', // 'n/no-sync': 'error', - // 'n/prefer-global/buffer': 'error', - // 'n/prefer-global/console': 'error', - // 'n/prefer-global/process': 'error', - // 'n/prefer-global/text-decoder': 'error', - // 'n/prefer-global/text-encoder': 'error', - // 'n/prefer-global/url': 'error', - // 'n/prefer-global/url-search-params': 'error', - // 'n/prefer-promises/dns': 'error', + 'n/prefer-global/buffer': 'error', + 'n/prefer-global/console': 'error', + 'n/prefer-global/process': 'error', + 'n/prefer-global/text-decoder': 'error', + 'n/prefer-global/text-encoder': 'error', + 'n/prefer-global/url': 'error', + 'n/prefer-global/url-search-params': 'error', + 'n/prefer-promises/dns': 'error', // 'n/prefer-promises/fs': 'error', // promise // 'promise/catch-or-return': 'error', diff --git a/database/package.json b/database/package.json index 65b76ca14..abc69d21d 100644 --- a/database/package.json +++ b/database/package.json @@ -48,5 +48,8 @@ "ts-mysql-migrate": "^1.0.2", "typeorm": "^0.2.38", "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14" } } diff --git a/database/src/config/index.ts b/database/src/config/index.ts index ba41f11d4..2da46f777 100644 --- a/database/src/config/index.ts +++ b/database/src/config/index.ts @@ -1,4 +1,4 @@ -// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env) +/* eslint-disable n/no-process-env */ import dotenv from 'dotenv' dotenv.config() From 1545cf772a4959d526e49d09a4634e4524568812 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Thu, 8 Jun 2023 14:54:59 +0200 Subject: [PATCH 09/10] lint fix --- backend/.eslintrc.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 1916e1ea2..e853c8bf6 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -60,7 +60,10 @@ module.exports = { 'import/no-dynamic-require': 'error', 'import/no-internal-modules': 'off', 'import/no-relative-packages': 'error', - 'import/no-relative-parent-imports': ['error', { ignore: ['@/*', 'random-bigint', 'sodium-native'] }], + 'import/no-relative-parent-imports': [ + 'error', + { ignore: ['@/*', 'random-bigint', 'sodium-native'] }, + ], 'import/no-self-import': 'error', 'import/no-unresolved': 'error', 'import/no-useless-path-segments': 'error', From d536a4b689251b89fdd312430eaf86f894e17daa Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 9 Jun 2023 13:09:07 +0200 Subject: [PATCH 10/10] lint fixes --- backend/src/graphql/resolver/UserResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 38e61248f..a61bbfd32 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -70,8 +70,8 @@ import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' import { getTimeDurationObject, printTimeDuration } from '@/util/time' -import { randombytes_random } from 'sodium-native' import random from 'random-bigint' +import { randombytes_random } from 'sodium-native' import { FULL_CREATION_AVAILABLE } from './const/const' import { getUserCreations } from './util/creations'