mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
port dump-db and other tools to TS
This commit is contained in:
parent
2cc34efbde
commit
b83c6023c4
@ -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());
|
@ -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
|
||||
|
||||
|
@ -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, {
|
@ -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
|
||||
};
|
@ -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
|
||||
};
|
@ -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
|
||||
};
|
@ -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
|
||||
};
|
@ -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
18
dump-db/inc/sql.ts
Normal 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
1513
dump-db/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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
10
dump-db/tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES6",
|
||||
"strict": true
|
||||
}
|
||||
}
|
1
package-lock.json
generated
1
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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}`);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -14,7 +14,7 @@
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.js",
|
||||
"./src/**/*.ts",
|
||||
"./src/**/*.ts",
|
||||
"./*.ts",
|
||||
"./spec/**/*.ts",
|
||||
"./spec-es6/**/*.ts"
|
||||
|
Loading…
x
Reference in New Issue
Block a user