server-ts: services/encryption/*.js -> ts

This commit is contained in:
Elian Doran 2024-02-16 23:03:19 +02:00
parent dc359b2a74
commit c20d2273e6
No known key found for this signature in database
6 changed files with 42 additions and 43 deletions

View File

@ -1,9 +1,9 @@
"use strict"; "use strict";
const crypto = require('crypto'); import crypto = require('crypto');
const log = require('../log'); import log = require('../log');
function arraysIdentical(a, b) { function arraysIdentical(a: Buffer, b: Buffer) {
let i = a.length; let i = a.length;
if (i !== b.length) return false; if (i !== b.length) return false;
while (i--) { while (i--) {
@ -12,12 +12,12 @@ function arraysIdentical(a, b) {
return true; return true;
} }
function shaArray(content) { function shaArray(content: crypto.BinaryLike) {
// we use this as a simple checksum and don't rely on its security, so SHA-1 is good enough // we use this as a simple checksum and don't rely on its security, so SHA-1 is good enough
return crypto.createHash('sha1').update(content).digest(); return crypto.createHash('sha1').update(content).digest();
} }
function pad(data) { function pad(data: Buffer): Buffer {
if (data.length > 16) { if (data.length > 16) {
data = data.slice(0, 16); data = data.slice(0, 16);
} }
@ -30,7 +30,7 @@ function pad(data) {
return Buffer.from(data); return Buffer.from(data);
} }
function encrypt(key, plainText) { function encrypt(key: Buffer, plainText: Buffer | string) {
if (!key) { if (!key) {
throw new Error("No data key!"); throw new Error("No data key!");
} }
@ -51,10 +51,7 @@ function encrypt(key, plainText) {
return encryptedDataWithIv.toString('base64'); return encryptedDataWithIv.toString('base64');
} }
/** function decrypt(key: Buffer, cipherText: string | Buffer): Buffer | false | null {
* @returns {Buffer|false|null}
*/
function decrypt(key, cipherText) {
if (cipherText === null) { if (cipherText === null) {
return null; return null;
} }
@ -88,12 +85,12 @@ function decrypt(key, cipherText) {
return payload; return payload;
} }
catch (e) { catch (e: any) {
// recovery from https://github.com/zadam/trilium/issues/510 // recovery from https://github.com/zadam/trilium/issues/510
if (e.message?.includes("WRONG_FINAL_BLOCK_LENGTH") || e.message?.includes("wrong final block length")) { if (e.message?.includes("WRONG_FINAL_BLOCK_LENGTH") || e.message?.includes("wrong final block length")) {
log.info("Caught WRONG_FINAL_BLOCK_LENGTH, returning cipherText instead"); log.info("Caught WRONG_FINAL_BLOCK_LENGTH, returning cipherText instead");
return cipherText; return Buffer.from(cipherText);
} }
else { else {
throw e; throw e;
@ -101,7 +98,7 @@ function decrypt(key, cipherText) {
} }
} }
function decryptString(dataKey, cipherText) { function decryptString(dataKey: Buffer, cipherText: string) {
const buffer = decrypt(dataKey, cipherText); const buffer = decrypt(dataKey, cipherText);
if (buffer === null) { if (buffer === null) {
@ -115,7 +112,7 @@ function decryptString(dataKey, cipherText) {
return buffer.toString('utf-8'); return buffer.toString('utf-8');
} }
module.exports = { export = {
encrypt, encrypt,
decrypt, decrypt,
decryptString decryptString

View File

@ -1,28 +1,28 @@
"use strict"; "use strict";
const optionService = require('../options.js'); import optionService = require('../options.js');
const crypto = require('crypto'); import crypto = require('crypto');
function getVerificationHash(password) { function getVerificationHash(password: crypto.BinaryLike) {
const salt = optionService.getOption('passwordVerificationSalt'); const salt = optionService.getOption('passwordVerificationSalt');
return getScryptHash(password, salt); return getScryptHash(password, salt);
} }
function getPasswordDerivedKey(password) { function getPasswordDerivedKey(password: crypto.BinaryLike) {
const salt = optionService.getOption('passwordDerivedKeySalt'); const salt = optionService.getOption('passwordDerivedKeySalt');
return getScryptHash(password, salt); return getScryptHash(password, salt);
} }
function getScryptHash(password, salt) { function getScryptHash(password: crypto.BinaryLike, salt: crypto.BinaryLike) {
const hashed = crypto.scryptSync(password, salt, 32, const hashed = crypto.scryptSync(password, salt, 32,
{N: 16384, r:8, p:1}); {N: 16384, r:8, p:1});
return hashed; return hashed;
} }
module.exports = { export = {
getVerificationHash, getVerificationHash,
getPasswordDerivedKey getPasswordDerivedKey
}; };

View File

@ -1,16 +1,16 @@
"use strict"; "use strict";
const sql = require('../sql'); import sql = require('../sql');
const optionService = require('../options.js'); import optionService = require('../options.js');
const myScryptService = require('./my_scrypt.js'); import myScryptService = require('./my_scrypt.js');
const utils = require('../utils'); import utils = require('../utils');
const passwordEncryptionService = require('./password_encryption.js'); import passwordEncryptionService = require('./password_encryption.js');
function isPasswordSet() { function isPasswordSet() {
return !!sql.getValue("SELECT value FROM options WHERE name = 'passwordVerificationHash'"); return !!sql.getValue("SELECT value FROM options WHERE name = 'passwordVerificationHash'");
} }
function changePassword(currentPassword, newPassword) { function changePassword(currentPassword: string, newPassword: string) {
if (!isPasswordSet()) { if (!isPasswordSet()) {
throw new Error("Password has not been set yet, so it cannot be changed. Use 'setPassword' instead."); throw new Error("Password has not been set yet, so it cannot be changed. Use 'setPassword' instead.");
} }
@ -29,8 +29,11 @@ function changePassword(currentPassword, newPassword) {
optionService.setOption('passwordDerivedKeySalt', utils.randomSecureToken(32)); optionService.setOption('passwordDerivedKeySalt', utils.randomSecureToken(32));
const newPasswordVerificationKey = utils.toBase64(myScryptService.getVerificationHash(newPassword)); const newPasswordVerificationKey = utils.toBase64(myScryptService.getVerificationHash(newPassword));
passwordEncryptionService.setDataKey(newPassword, decryptedDataKey); if (decryptedDataKey) {
// FIXME: what should happen if the decrypted data key is null?
passwordEncryptionService.setDataKey(newPassword, decryptedDataKey);
}
optionService.setOption('passwordVerificationHash', newPasswordVerificationKey); optionService.setOption('passwordVerificationHash', newPasswordVerificationKey);
}); });
@ -40,7 +43,7 @@ function changePassword(currentPassword, newPassword) {
}; };
} }
function setPassword(password) { function setPassword(password: string) {
if (isPasswordSet()) { if (isPasswordSet()) {
throw new Error("Password is set already. Either change it or perform 'reset password' first."); throw new Error("Password is set already. Either change it or perform 'reset password' first.");
} }
@ -48,13 +51,13 @@ function setPassword(password) {
optionService.createOption('passwordVerificationSalt', utils.randomSecureToken(32), true); optionService.createOption('passwordVerificationSalt', utils.randomSecureToken(32), true);
optionService.createOption('passwordDerivedKeySalt', utils.randomSecureToken(32), true); optionService.createOption('passwordDerivedKeySalt', utils.randomSecureToken(32), true);
const passwordVerificationKey = utils.toBase64(myScryptService.getVerificationHash(password), true); const passwordVerificationKey = utils.toBase64(myScryptService.getVerificationHash(password));
optionService.createOption('passwordVerificationHash', passwordVerificationKey, true); optionService.createOption('passwordVerificationHash', passwordVerificationKey, true);
// passwordEncryptionService expects these options to already exist // passwordEncryptionService expects these options to already exist
optionService.createOption('encryptedDataKey', '', true); optionService.createOption('encryptedDataKey', '', true);
passwordEncryptionService.setDataKey(password, utils.randomSecureToken(16), true); passwordEncryptionService.setDataKey(password, utils.randomSecureToken(16));
return { return {
success: true success: true

View File

@ -1,9 +1,9 @@
const optionService = require('../options.js'); import optionService = require('../options.js');
const myScryptService = require('./my_scrypt.js'); import myScryptService = require('./my_scrypt.js');
const utils = require('../utils'); import utils = require('../utils');
const dataEncryptionService = require('./data_encryption.js'); import dataEncryptionService = require('./data_encryption.js');
function verifyPassword(password) { function verifyPassword(password: string) {
const givenPasswordHash = utils.toBase64(myScryptService.getVerificationHash(password)); const givenPasswordHash = utils.toBase64(myScryptService.getVerificationHash(password));
const dbPasswordHash = optionService.getOptionOrNull('passwordVerificationHash'); const dbPasswordHash = optionService.getOptionOrNull('passwordVerificationHash');
@ -15,7 +15,7 @@ function verifyPassword(password) {
return givenPasswordHash === dbPasswordHash; return givenPasswordHash === dbPasswordHash;
} }
function setDataKey(password, plainTextDataKey) { function setDataKey(password: string, plainTextDataKey: string | Buffer) {
const passwordDerivedKey = myScryptService.getPasswordDerivedKey(password); const passwordDerivedKey = myScryptService.getPasswordDerivedKey(password);
const newEncryptedDataKey = dataEncryptionService.encrypt(passwordDerivedKey, plainTextDataKey); const newEncryptedDataKey = dataEncryptionService.encrypt(passwordDerivedKey, plainTextDataKey);
@ -23,8 +23,7 @@ function setDataKey(password, plainTextDataKey) {
optionService.setOption('encryptedDataKey', newEncryptedDataKey); optionService.setOption('encryptedDataKey', newEncryptedDataKey);
} }
/** @return {Buffer} */ function getDataKey(password: string) {
function getDataKey(password) {
const passwordDerivedKey = myScryptService.getPasswordDerivedKey(password); const passwordDerivedKey = myScryptService.getPasswordDerivedKey(password);
const encryptedDataKey = optionService.getOption('encryptedDataKey'); const encryptedDataKey = optionService.getOption('encryptedDataKey');
@ -34,7 +33,7 @@ function getDataKey(password) {
return decryptedDataKey; return decryptedDataKey;
} }
module.exports = { export = {
verifyPassword, verifyPassword,
getDataKey, getDataKey,
setDataKey setDataKey

View File

@ -313,7 +313,7 @@ function disableSlowQueryLogging<T>(cb: () => T) {
} }
} }
module.exports = { export = {
dbConnection, dbConnection,
insert, insert,
replace, replace,

View File

@ -41,7 +41,7 @@ function hashedBlobId(content: string) {
return kindaBase62Hash.substr(0, 20); return kindaBase62Hash.substr(0, 20);
} }
function toBase64(plainText: string) { function toBase64(plainText: string | Buffer) {
return Buffer.from(plainText).toString('base64'); return Buffer.from(plainText).toString('base64');
} }
@ -311,7 +311,7 @@ function isString(x: any) {
return Object.prototype.toString.call(x) === "[object String]"; return Object.prototype.toString.call(x) === "[object String]";
} }
module.exports = { export = {
randomSecureToken, randomSecureToken,
randomString, randomString,
md5, md5,