mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 03:29:02 +01: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
	 Jin
						Jin