port dump-db and other tools to TS

This commit is contained in:
Jin 2024-08-10 18:23:49 +02:00
parent 2cc34efbde
commit b83c6023c4
18 changed files with 1197 additions and 518 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/env node
const anonymizationService = require('../src/services/anonymization');
const fs = require('fs');
const path = require('path');
import anonymizationService from '../src/services/anonymization.js';
import fs from 'fs';
import path from 'path';
fs.writeFileSync(path.resolve(__dirname, 'tpl', 'anonymize-database.sql'), anonymizationService.getFullAnonymizationScript());

View File

@ -14,10 +14,10 @@ npm install
## Running
See output of `node dump-db.js --help`:
See output of `npx esrun dump.ts --help`:
```
dump-db.js <path_to_document> <target_directory>
dump-db.ts <path_to_document> <target_directory>
dump the contents of document.db into the target directory

View File

@ -1,14 +1,14 @@
#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const dumpService = require('./inc/dump.js');
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import dumpService from './inc/dump.js';
yargs(hideBin(process.argv))
.command('$0 <path_to_document> <target_directory>', 'dump the contents of document.db into the target directory', (yargs) => {
return yargs
.positional('path_to_document', { describe: 'path to the document.db' })
.positional('target_directory', { describe: 'path of the directory into which the notes should be dumped' })
.option('path_to_document', { alias: 'p', describe: 'path to the document.db', type: 'string', demandOption: true })
.option('target_directory', { alias: 't', describe: 'path of the directory into which the notes should be dumped', type: 'string', demandOption: true });
}, (argv) => {
try {
dumpService.dumpDocument(argv.path_to_document, argv.target_directory, {

View File

@ -1,8 +1,8 @@
const crypto = require("crypto");
const sql = require('./sql');
const decryptService = require('./decrypt.js');
import crypto from 'crypto';
import sql from './sql.js';
import decryptService from './decrypt.js';
function getDataKey(password) {
function getDataKey(password: any) {
if (!password) {
return null;
}
@ -16,28 +16,28 @@ function getDataKey(password) {
return decryptedDataKey;
}
catch (e) {
catch (e: any) {
throw new Error(`Cannot read data key, the entered password might be wrong. The underlying error: '${e.message}', stack:\n${e.stack}`);
}
}
function getPasswordDerivedKey(password) {
function getPasswordDerivedKey(password: any) {
const salt = getOption('passwordDerivedKeySalt');
return getScryptHash(password, salt);
}
function getScryptHash(password, salt) {
function getScryptHash(password: any, salt: any) {
const hashed = crypto.scryptSync(password, salt, 32,
{N: 16384, r:8, p:1});
{ N: 16384, r: 8, p: 1 });
return hashed;
}
function getOption(name) {
function getOption(name: string) {
return sql.getValue("SELECT value FROM options WHERE name = ?", [name]);
}
module.exports = {
export default {
getDataKey
};

View File

@ -1,6 +1,6 @@
const crypto = require("crypto");
import crypto from 'crypto';
function decryptString(dataKey, cipherText) {
function decryptString(dataKey: any, cipherText: any) {
const buffer = decrypt(dataKey, cipherText);
if (buffer === null) {
@ -16,7 +16,7 @@ function decryptString(dataKey, cipherText) {
return str;
}
function decrypt(key, cipherText, ivLength = 13) {
function decrypt(key: any, cipherText: any, ivLength = 13) {
if (cipherText === null) {
return null;
}
@ -46,11 +46,10 @@ function decrypt(key, cipherText, ivLength = 13) {
return payload;
}
catch (e) {
catch (e: any) {
// recovery from https://github.com/zadam/trilium/issues/510
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");
console.log("Caught WRONG_FINAL_BLOCK_LENGTH, returning cipherText instead");
return cipherText;
}
else {
@ -59,7 +58,7 @@ function decrypt(key, cipherText, ivLength = 13) {
}
}
function pad(data) {
function pad(data: any) {
if (data.length > 16) {
data = data.slice(0, 16);
}
@ -72,7 +71,7 @@ function pad(data) {
return Buffer.from(data);
}
function arraysIdentical(a, b) {
function arraysIdentical(a: any, b: any) {
let i = a.length;
if (i !== b.length) return false;
while (i--) {
@ -81,12 +80,12 @@ function arraysIdentical(a, b) {
return true;
}
function shaArray(content) {
function shaArray(content: any) {
// we use this as simple checksum and don't rely on its security so SHA-1 is good enough
return crypto.createHash('sha1').update(content).digest();
}
module.exports = {
export default {
decrypt,
decryptString
};

View File

@ -1,11 +1,11 @@
const fs = require("fs");
const sanitize = require("sanitize-filename");
const sql = require('./sql.js');
const decryptService = require('./decrypt.js');
const dataKeyService = require('./data_key.js');
const extensionService = require('./extension.js');
import fs from 'fs';
import sanitize from 'sanitize-filename';
import sql from './sql.js';
import decryptService from './decrypt.js';
import dataKeyService from './data_key.js';
import extensionService from './extension.js';
function dumpDocument(documentPath, targetPath, options) {
function dumpDocument(documentPath: string, targetPath: string, options: { password: any; includeDeleted: any; }) {
const stats = {
succeeded: 0,
failed: 0,
@ -19,14 +19,14 @@ function dumpDocument(documentPath, targetPath, options) {
const dataKey = dataKeyService.getDataKey(options.password);
const existingPaths = {};
const noteIdToPath = {};
const existingPaths: Record<string, any> = {};
const noteIdToPath: Record<string, any> = {};
dumpNote(targetPath, 'root');
printDumpResults(stats, options);
function dumpNote(targetPath, noteId) {
function dumpNote(targetPath: any, noteId: any) {
console.log(`Reading note '${noteId}'`);
let childTargetPath, noteRow, fileNameWithPath;
@ -94,7 +94,7 @@ function dumpDocument(documentPath, targetPath, options) {
noteIdToPath[noteId] = childTargetPath;
}
catch (e) {
catch (e: any) {
console.error(`DUMPERROR: Writing '${noteId}' failed with error '${e.message}':\n${e.stack}`);
stats.failed++;
@ -108,9 +108,9 @@ function dumpDocument(documentPath, targetPath, options) {
}
try {
fs.mkdirSync(childTargetPath, { recursive: true });
fs.mkdirSync(childTargetPath as string, { recursive: true });
}
catch (e) {
catch (e: any) {
console.error(`DUMPERROR: Creating directory ${childTargetPath} failed with error '${e.message}'`);
}
@ -121,7 +121,7 @@ function dumpDocument(documentPath, targetPath, options) {
}
}
function printDumpResults(stats, options) {
function printDumpResults(stats: any, options: any) {
console.log('\n----------------------- STATS -----------------------');
console.log('Successfully dumpted notes: ', stats.succeeded.toString().padStart(5, ' '));
console.log('Protected notes: ', stats.protected.toString().padStart(5, ' '), options.password ? '' : '(skipped)');
@ -134,7 +134,7 @@ function printDumpResults(stats, options) {
}
}
function isContentEmpty(content) {
function isContentEmpty(content: any) {
if (!content) {
return true;
}
@ -150,7 +150,7 @@ function isContentEmpty(content) {
}
}
function validatePaths(documentPath, targetPath) {
function validatePaths(documentPath: string, targetPath: string) {
if (!fs.existsSync(documentPath)) {
console.error(`Path to document '${documentPath}' has not been found. Run with --help to see usage.`);
process.exit(1);
@ -166,6 +166,6 @@ function validatePaths(documentPath, targetPath) {
}
}
module.exports = {
export default {
dumpDocument
};

View File

@ -1,7 +1,7 @@
const path = require("path");
const mimeTypes = require("mime-types");
import path from "path";
import mimeTypes from "mime-types";
function getFileName(note, childTargetPath, safeTitle) {
function getFileName(note: any, childTargetPath: string, safeTitle: string) {
let existingExtension = path.extname(safeTitle).toLowerCase();
let newExtension;
@ -29,6 +29,6 @@ function getFileName(note, childTargetPath, safeTitle) {
return fileNameWithPath;
}
module.exports = {
export default {
getFileName
};

View File

@ -1,17 +0,0 @@
const Database = require("better-sqlite3");
let dbConnection;
const openDatabase = (documentPath) => { dbConnection = new Database(documentPath, { readonly: true }) };
const getRow = (query, params = []) => dbConnection.prepare(query).get(params);
const getRows = (query, params = []) => dbConnection.prepare(query).all(params);
const getValue = (query, params = []) => dbConnection.prepare(query).pluck().get(params);
const getColumn = (query, params = []) => dbConnection.prepare(query).pluck().all(params);
module.exports = {
openDatabase,
getRow,
getRows,
getValue,
getColumn
};

18
dump-db/inc/sql.ts Normal file
View File

@ -0,0 +1,18 @@
import Database, { Database as DatabaseType } from "better-sqlite3";
let dbConnection: DatabaseType;
const openDatabase = (documentPath: string) => { dbConnection = new Database(documentPath, { readonly: true }) };
const getRow = (query: string, params: string[] = []): Record<string, any> => dbConnection.prepare(query).get(params) as Record<string, any>;
const getRows = (query: string, params = []) => dbConnection.prepare(query).all(params);
const getValue = (query: string, params: string[] = []) => dbConnection.prepare(query).pluck().get(params);
const getColumn = (query: string, params: string[] = []) => dbConnection.prepare(query).pluck().all(params);
export default {
openDatabase,
getRow,
getRows,
getValue,
getColumn
};

1513
dump-db/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,24 +2,30 @@
"name": "dump-db",
"version": "1.0.0",
"description": "Standalone tool to dump contents of Trilium document.db file into a directory tree of notes",
"main": "dump-db.js",
"main": "dump-db.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/zadam/trilium.git"
"url": "git+https://github.com/TriliumNext/Notes.git"
},
"author": "zadam",
"author": "TriliumNext",
"license": "ISC",
"bugs": {
"url": "https://github.com/zadam/trilium/issues"
"url": "https://github.com/TriliumNext/Notes/issues"
},
"homepage": "https://github.com/zadam/trilium/dump-db#readme",
"homepage": "https://github.com/TriliumNext/Notes/blob/master/dump-db/README.md",
"dependencies": {
"better-sqlite3": "7.5.0",
"mime-types": "2.1.34",
"sanitize-filename": "1.6.3",
"yargs": "17.3.1"
"better-sqlite3": "^11.1.2",
"esrun": "^3.2.26",
"mime-types": "^2.1.34",
"sanitize-filename": "^1.6.3",
"yargs": "^17.3.1"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.11",
"@types/mime-types": "^2.1.4",
"@types/yargs": "^17.0.33"
}
}

10
dump-db/tsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "ES6",
"strict": true
}
}

1
package-lock.json generated
View File

@ -15866,6 +15866,7 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",

View File

@ -44,7 +44,8 @@
"update-build-info": "tsx bin/update-build-info.ts",
"errors": "tsc --watch --noEmit",
"integration-edit-db": "cross-env TRILIUM_INTEGRATION_TEST=edit TRILIUM_PORT=8081 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/www.ts",
"integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/www.ts"
"integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/www.ts",
"generate-document": "cross-env nodemon src/tools/generate_document.ts 1000"
},
"dependencies": {
"@braintree/sanitize-url": "^7.1.0",

View File

@ -107,7 +107,7 @@ function getNewNoteTitle(parentNote: BNote) {
// - now
// - parentNote
title = eval(`\`${titleTemplate}\``);
title = (0, eval)(`\`${titleTemplate}\``);
} catch (e: any) {
log.error(`Title template of note '${parentNote.noteId}' failed with: ${e.message}`);
}

View File

@ -99,7 +99,7 @@ function executeScript(script: string, params: ScriptParams, startNoteId: string
}
function execute(ctx: ScriptContext, script: string) {
return function () { return eval(`const apiContext = this;\r\n(${script}\r\n)()`); }.call(ctx);
return function () { return (0, eval)(`const apiContext = this;\r\n(${script}\r\n)()`); }.call(ctx);
}
function getParams(params?: ScriptParams) {

View File

@ -3,13 +3,13 @@
* will create 1000 new notes and some clones into the current document.db
*/
require('../becca/entity_constructor');
const sqlInit = require('../services/sql_init');
const noteService = require('../services/notes');
const attributeService = require('../services/attributes');
const cls = require('../services/cls');
const cloningService = require('../services/cloning');
const loremIpsum = require('lorem-ipsum').loremIpsum;
import sqlInit from '../services/sql_init.js';
import noteService from '../services/notes.js';
import attributeService from '../services/attributes.js';
import cls from '../services/cls.js';
import cloningService from '../services/cloning.js';
import loremIpsum from 'lorem-ipsum';
import '../becca/entity_constructor.js';
const noteCount = parseInt(process.argv[2]);
@ -28,7 +28,7 @@ function getRandomNoteId() {
async function start() {
for (let i = 0; i < noteCount; i++) {
const title = loremIpsum({
const title = loremIpsum.loremIpsum({
count: 1,
units: 'sentences',
sentenceLowerBound: 1,
@ -36,7 +36,7 @@ async function start() {
});
const paragraphCount = Math.floor(Math.random() * Math.random() * 100);
const content = loremIpsum({
const content = loremIpsum.loremIpsum({
count: paragraphCount,
units: 'paragraphs',
sentenceLowerBound: 1,
@ -46,7 +46,7 @@ async function start() {
format: 'html'
});
const {note} = noteService.createNewNote({
const { note } = noteService.createNewNote({
parentNoteId: getRandomNoteId(),
title,
content,
@ -58,7 +58,7 @@ async function start() {
if (Math.random() < 0.04) {
const noteIdToClone = note.noteId;
const parentNoteId = getRandomNoteId();
const prefix = Math.random() > 0.8 ? "prefix" : null;
const prefix = Math.random() > 0.8 ? "prefix" : '';
const result = await cloningService.cloneNoteToBranch(noteIdToClone, parentNoteId, prefix);

View File

@ -14,7 +14,7 @@
},
"include": [
"./src/**/*.js",
"./src/**/*.ts",
"./src/**/*.ts",
"./*.ts",
"./spec/**/*.ts",
"./spec-es6/**/*.ts"