show existing backups and anonymized DBs, #4321

This commit is contained in:
zadam 2023-10-18 23:16:47 +02:00
parent 2132cf3bdc
commit 148bff9f77
8 changed files with 103 additions and 15 deletions

14
package-lock.json generated
View file

@ -79,7 +79,7 @@
},
"devDependencies": {
"cross-env": "7.0.3",
"electron": "25.9.1",
"electron": "25.9.2",
"electron-builder": "24.6.4",
"electron-packager": "17.1.2",
"electron-rebuild": "3.2.9",
@ -4276,9 +4276,9 @@
}
},
"node_modules/electron": {
"version": "25.9.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.1.tgz",
"integrity": "sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ==",
"version": "25.9.2",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.2.tgz",
"integrity": "sha512-hVBN5rsrL99BKNHvzMeYy2PkAmewuIobu4U3o3EzVz4MDoLmMfW4yTH5GZ4RbJrpokoEky5IzGtRR/ggPzL6Fw==",
"hasInstallScript": true,
"dependencies": {
"@electron/get": "^2.0.0",
@ -16633,9 +16633,9 @@
}
},
"electron": {
"version": "25.9.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.1.tgz",
"integrity": "sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ==",
"version": "25.9.2",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.2.tgz",
"integrity": "sha512-hVBN5rsrL99BKNHvzMeYy2PkAmewuIobu4U3o3EzVz4MDoLmMfW4yTH5GZ4RbJrpokoEky5IzGtRR/ggPzL6Fw==",
"requires": {
"@electron/get": "^2.0.0",
"@types/node": "^18.11.18",

View file

@ -97,7 +97,7 @@
},
"devDependencies": {
"cross-env": "7.0.3",
"electron": "25.9.1",
"electron": "25.9.2",
"electron-builder": "24.6.4",
"electron-packager": "17.1.2",
"electron-rebuild": "3.2.9",

View file

@ -20,6 +20,10 @@ const TPL = `
<p>You can decide yourself if you want to provide a fully or lightly anonymized database. Even fully anonymized DB is very useful, however in some cases lightly anonymized database can speed up the process of bug identification and fixing.</p>
<button class="anonymize-light-button btn">Save lightly anonymized database</button>
<h5>Existing anonymized databases</h5>
<ul class="existing-anonymized-databases"></ul>
</div>`;
export default class DatabaseAnonymizationOptions extends OptionsWidget {
@ -38,6 +42,8 @@ export default class DatabaseAnonymizationOptions extends OptionsWidget {
else {
toastService.showMessage(`Created fully anonymized database in ${resp.anonymizedFilePath}`, 10000);
}
this.refresh();
});
this.$anonymizeLightButton.on('click', async () => {
@ -51,6 +57,24 @@ export default class DatabaseAnonymizationOptions extends OptionsWidget {
else {
toastService.showMessage(`Created lightly anonymized database in ${resp.anonymizedFilePath}`, 10000);
}
this.refresh();
});
this.$existingAnonymizedDatabases = this.$widget.find(".existing-anonymized-databases");
}
optionsLoaded(options) {
server.get("database/anonymized-databases").then(anonymizedDatabases => {
this.$existingAnonymizedDatabases.empty();
if (!anonymizedDatabases.length) {
anonymizedDatabases = [{filePath: "no anonymized database yet"}];
}
for (const {filePath} of anonymizedDatabases) {
this.$existingAnonymizedDatabases.append($("<li>").text(filePath));
}
});
}
}

View file

@ -37,6 +37,12 @@ const TPL = `
<button class="backup-database-button btn">Backup database now</button>
</div>
<div class="options-section">
<h4>Existing backups</h4>
<ul class="existing-backup-list"></ul>
</div>
`;
export default class BackupOptions extends OptionsWidget {
@ -49,6 +55,8 @@ export default class BackupOptions extends OptionsWidget {
const {backupFile} = await server.post('database/backup-database');
toastService.showMessage(`Database has been backed up to ${backupFile}`, 10000);
this.refresh();
});
this.$dailyBackupEnabled = this.$widget.find(".daily-backup-enabled");
@ -63,11 +71,25 @@ export default class BackupOptions extends OptionsWidget {
this.$monthlyBackupEnabled.on('change', () =>
this.updateCheckboxOption('monthlyBackupEnabled', this.$monthlyBackupEnabled));
this.$existingBackupList = this.$widget.find(".existing-backup-list");
}
optionsLoaded(options) {
this.setCheckboxState(this.$dailyBackupEnabled, options.dailyBackupEnabled);
this.setCheckboxState(this.$weeklyBackupEnabled, options.weeklyBackupEnabled);
this.setCheckboxState(this.$monthlyBackupEnabled, options.monthlyBackupEnabled);
server.get("database/backups").then(backupFiles => {
this.$existingBackupList.empty();
if (!backupFiles.length) {
backupFiles = [{filePath: "no backup yet"}];
}
for (const {filePath} of backupFiles) {
this.$existingBackupList.append($("<li>").text(filePath));
}
});
}
}

View file

@ -6,8 +6,8 @@ const backupService = require('../../services/backup');
const anonymizationService = require('../../services/anonymization');
const consistencyChecksService = require('../../services/consistency_checks');
async function anonymize(req) {
return await anonymizationService.createAnonymizedCopy(req.params.type);
function getExistingBackups() {
return backupService.getExistingBackups();
}
async function backupDatabase() {
@ -22,6 +22,18 @@ function vacuumDatabase() {
log.info("Database has been vacuumed.");
}
function findAndFixConsistencyIssues() {
consistencyChecksService.runOnDemandChecks(true);
}
function getExistingAnonymizedDatabases() {
return anonymizationService.getExistingAnonymizedDatabases();
}
async function anonymize(req) {
return await anonymizationService.createAnonymizedCopy(req.params.type);
}
function checkIntegrity() {
const results = sql.getRows("PRAGMA integrity_check");
@ -32,14 +44,12 @@ function checkIntegrity() {
};
}
function findAndFixConsistencyIssues() {
consistencyChecksService.runOnDemandChecks(true);
}
module.exports = {
getExistingBackups,
backupDatabase,
vacuumDatabase,
findAndFixConsistencyIssues,
getExistingAnonymizedDatabases,
anonymize,
checkIntegrity
};

View file

@ -289,9 +289,11 @@ function register(app) {
apiRoute(GET, '/api/sql/schema', sqlRoute.getSchema);
apiRoute(PST, '/api/sql/execute/:noteId', sqlRoute.execute);
route(PST, '/api/database/anonymize/:type', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.anonymize, apiResultHandler, false);
apiRoute(GET, '/api/database/anonymized-databases', databaseRoute.getExistingAnonymizedDatabases);
// backup requires execution outside of transaction
route(PST, '/api/database/backup-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.backupDatabase, apiResultHandler, false);
apiRoute(GET, '/api/database/backups', databaseRoute.getExistingBackups);
// VACUUM requires execution outside of transaction
route(PST, '/api/database/vacuum-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.vacuumDatabase, apiResultHandler, false);

View file

@ -4,6 +4,7 @@ const dataDir = require("./data_dir");
const dateUtils = require("./date_utils");
const Database = require("better-sqlite3");
const sql = require("./sql");
const path = require("path");
function getFullAnonymizationScript() {
// we want to delete all non-builtin attributes because they can contain sensitive names and values
@ -70,7 +71,21 @@ async function createAnonymizedCopy(type) {
};
}
function getExistingAnonymizedDatabases() {
if (!fs.existsSync(dataDir.ANONYMIZED_DB_DIR)) {
return [];
}
return fs.readdirSync(dataDir.ANONYMIZED_DB_DIR)
.filter(fileName => fileName.includes("anonymized"))
.map(fileName => ({
fileName: fileName,
filePath: path.resolve(dataDir.ANONYMIZED_DB_DIR, fileName)
}));
}
module.exports = {
getFullAnonymizationScript,
createAnonymizedCopy
createAnonymizedCopy,
getExistingAnonymizedDatabases
}

View file

@ -8,6 +8,20 @@ const log = require('./log');
const syncMutexService = require('./sync_mutex');
const cls = require('./cls');
const sql = require('./sql');
const path = require('path');
function getExistingBackups() {
if (!fs.existsSync(dataDir.BACKUP_DIR)) {
return [];
}
return fs.readdirSync(dataDir.BACKUP_DIR)
.filter(fileName => fileName.includes("backup"))
.map(fileName => ({
fileName: fileName,
filePath: path.resolve(dataDir.BACKUP_DIR, fileName)
}));
}
function regularBackup() {
cls.init(() => {
@ -58,6 +72,7 @@ if (!fs.existsSync(dataDir.BACKUP_DIR)) {
}
module.exports = {
getExistingBackups,
backupNow,
regularBackup
};