mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
Continued integrating TOTP.
This commit is contained in:
parent
baca395c0a
commit
fad51409a9
2
package-lock.json
generated
2
package-lock.json
generated
@ -7855,7 +7855,7 @@
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ie/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||
},
|
||||
"node_modules/isobject": {
|
||||
|
@ -39,7 +39,7 @@ const TPL = `
|
||||
<h4> Generate TOTP Secret </h4>
|
||||
<span class="totp-secret" > </span>
|
||||
<br>
|
||||
<button class="regenerate-totp"> Regenerate TOTP Secret </button>
|
||||
<button class="regenerate-totp" disabled="true"> Regenerate TOTP Secret </button>
|
||||
</div>`;
|
||||
|
||||
export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
@ -56,9 +56,6 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
this.$mfaHeadding.text("Multi-Factor Authentication");
|
||||
this.generateKey();
|
||||
|
||||
// var gen = require("speakeasy");
|
||||
// toastService.showMessage("***REMOVED***");
|
||||
|
||||
this.$totpEnabled.on("change", async () => {
|
||||
this.updateCheckboxOption("totpEnabled", this.$totpEnabled);
|
||||
});
|
||||
@ -67,6 +64,10 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
this.generateKey();
|
||||
});
|
||||
|
||||
this.$saveTotpButton.on("click", async () => {
|
||||
this.save();
|
||||
});
|
||||
|
||||
this.$protectedSessionTimeout = this.$widget.find(
|
||||
".protected-session-timeout-in-seconds"
|
||||
);
|
||||
@ -100,49 +101,30 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
// }
|
||||
|
||||
optionsLoaded(options) {
|
||||
// I need to make sure that this is actually pinging the server and that this information is being pulled
|
||||
// because it is telling me "totpEnabled is not allowed to be changed" in a toast every time I check the box
|
||||
server.get("totp/enabled").then((result) => {
|
||||
if (result.success) {
|
||||
console.log("Result message: " + typeof result.message);
|
||||
console.log("Result message: " + result.message);
|
||||
this.setCheckboxState(this.$totpEnabled, result.message);
|
||||
|
||||
console.log("TOTP Status: " + typeof result.message);
|
||||
|
||||
if (result.message) {
|
||||
this.$totpSecretInput.prop("disabled", false);
|
||||
this.$saveTotpButton.prop("disabled", false);
|
||||
} else {
|
||||
this.$totpSecretInput.prop("disabled", true);
|
||||
this.$saveTotpButton.prop("disabled", true);
|
||||
}
|
||||
this.$totpEnabled.prop("checked", result.message);
|
||||
this.$totpSecretInput.prop("disabled", !result.message);
|
||||
this.$saveTotpButton.prop("disabled", !result.message);
|
||||
this.$totpSecret.prop("disapbled", !result.message);
|
||||
} else {
|
||||
toastService.showError(result.message);
|
||||
}
|
||||
});
|
||||
|
||||
server.get("totp/get").then((result) => {
|
||||
this.$totpSecretInput.text(result.secret);
|
||||
});
|
||||
|
||||
this.$protectedSessionTimeout.val(options.protectedSessionTimeout);
|
||||
}
|
||||
|
||||
save() {
|
||||
const oldPassword = this.$oldPassword.val();
|
||||
const newPassword1 = this.$newPassword1.val();
|
||||
const newPassword2 = this.$newPassword2.val();
|
||||
|
||||
this.$oldPassword.val("");
|
||||
this.$newPassword1.val("");
|
||||
this.$newPassword2.val("");
|
||||
|
||||
if (newPassword1 !== newPassword2) {
|
||||
toastService.showError("New passwords are not the same.");
|
||||
return false;
|
||||
}
|
||||
// TODO: CHECK VALIDITY OF SECRET
|
||||
|
||||
server
|
||||
.post("password/change", {
|
||||
current_password: oldPassword,
|
||||
new_password: newPassword1,
|
||||
.post("totp/set", {
|
||||
secret: this.$totpSecretInput.val(),
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
|
@ -1,145 +1,152 @@
|
||||
"use strict";
|
||||
|
||||
import optionService = require('../../services/options');
|
||||
import log = require('../../services/log');
|
||||
import searchService = require('../../services/search/services/search');
|
||||
import ValidationError = require('../../errors/validation_error');
|
||||
import { Request } from 'express';
|
||||
import optionService = require("../../services/options");
|
||||
import log = require("../../services/log");
|
||||
import searchService = require("../../services/search/services/search");
|
||||
import ValidationError = require("../../errors/validation_error");
|
||||
import { Request } from "express";
|
||||
|
||||
// options allowed to be updated directly in the Options dialog
|
||||
const ALLOWED_OPTIONS = new Set([
|
||||
'eraseEntitiesAfterTimeInSeconds',
|
||||
'protectedSessionTimeout',
|
||||
'revisionSnapshotTimeInterval',
|
||||
'zoomFactor',
|
||||
'theme',
|
||||
'syncServerHost',
|
||||
'syncServerTimeout',
|
||||
'syncProxy',
|
||||
'hoistedNoteId',
|
||||
'mainFontSize',
|
||||
'mainFontFamily',
|
||||
'treeFontSize',
|
||||
'treeFontFamily',
|
||||
'detailFontSize',
|
||||
'detailFontFamily',
|
||||
'monospaceFontSize',
|
||||
'monospaceFontFamily',
|
||||
'openNoteContexts',
|
||||
'vimKeymapEnabled',
|
||||
'codeLineWrapEnabled',
|
||||
'codeNotesMimeTypes',
|
||||
'spellCheckEnabled',
|
||||
'spellCheckLanguageCode',
|
||||
'imageMaxWidthHeight',
|
||||
'imageJpegQuality',
|
||||
'leftPaneWidth',
|
||||
'rightPaneWidth',
|
||||
'leftPaneVisible',
|
||||
'rightPaneVisible',
|
||||
'nativeTitleBarVisible',
|
||||
'headingStyle',
|
||||
'autoCollapseNoteTree',
|
||||
'autoReadonlySizeText',
|
||||
'autoReadonlySizeCode',
|
||||
'overrideThemeFonts',
|
||||
'dailyBackupEnabled',
|
||||
'weeklyBackupEnabled',
|
||||
'monthlyBackupEnabled',
|
||||
'maxContentWidth',
|
||||
'compressImages',
|
||||
'downloadImagesAutomatically',
|
||||
'minTocHeadings',
|
||||
'highlightsList',
|
||||
'checkForUpdates',
|
||||
'disableTray',
|
||||
'eraseUnusedAttachmentsAfterSeconds',
|
||||
'disableTray',
|
||||
'customSearchEngineName',
|
||||
'customSearchEngineUrl',
|
||||
'promotedAttributesOpenInRibbon',
|
||||
'editedNotesOpenInRibbon'
|
||||
"eraseEntitiesAfterTimeInSeconds",
|
||||
"protectedSessionTimeout",
|
||||
"revisionSnapshotTimeInterval",
|
||||
"zoomFactor",
|
||||
"theme",
|
||||
"syncServerHost",
|
||||
"syncServerTimeout",
|
||||
"syncProxy",
|
||||
"hoistedNoteId",
|
||||
"mainFontSize",
|
||||
"mainFontFamily",
|
||||
"treeFontSize",
|
||||
"treeFontFamily",
|
||||
"detailFontSize",
|
||||
"detailFontFamily",
|
||||
"monospaceFontSize",
|
||||
"monospaceFontFamily",
|
||||
"openNoteContexts",
|
||||
"vimKeymapEnabled",
|
||||
"codeLineWrapEnabled",
|
||||
"codeNotesMimeTypes",
|
||||
"spellCheckEnabled",
|
||||
"spellCheckLanguageCode",
|
||||
"imageMaxWidthHeight",
|
||||
"imageJpegQuality",
|
||||
"leftPaneWidth",
|
||||
"rightPaneWidth",
|
||||
"leftPaneVisible",
|
||||
"rightPaneVisible",
|
||||
"nativeTitleBarVisible",
|
||||
"headingStyle",
|
||||
"autoCollapseNoteTree",
|
||||
"autoReadonlySizeText",
|
||||
"autoReadonlySizeCode",
|
||||
"overrideThemeFonts",
|
||||
"dailyBackupEnabled",
|
||||
"weeklyBackupEnabled",
|
||||
"monthlyBackupEnabled",
|
||||
"maxContentWidth",
|
||||
"compressImages",
|
||||
"downloadImagesAutomatically",
|
||||
"minTocHeadings",
|
||||
"highlightsList",
|
||||
"checkForUpdates",
|
||||
"disableTray",
|
||||
"eraseUnusedAttachmentsAfterSeconds",
|
||||
"disableTray",
|
||||
"customSearchEngineName",
|
||||
"customSearchEngineUrl",
|
||||
"promotedAttributesOpenInRibbon",
|
||||
"editedNotesOpenInRibbon",
|
||||
"totpEnabled",
|
||||
]);
|
||||
|
||||
function getOptions() {
|
||||
const optionMap = optionService.getOptionMap();
|
||||
const resultMap: Record<string, string> = {};
|
||||
const optionMap = optionService.getOptionMap();
|
||||
const resultMap: Record<string, string> = {};
|
||||
|
||||
for (const optionName in optionMap) {
|
||||
if (isAllowed(optionName)) {
|
||||
resultMap[optionName] = optionMap[optionName];
|
||||
}
|
||||
for (const optionName in optionMap) {
|
||||
if (isAllowed(optionName)) {
|
||||
resultMap[optionName] = optionMap[optionName];
|
||||
}
|
||||
}
|
||||
|
||||
resultMap['isPasswordSet'] = optionMap['passwordVerificationHash'] ? 'true' : 'false';
|
||||
resultMap["isPasswordSet"] = optionMap["passwordVerificationHash"]
|
||||
? "true"
|
||||
: "false";
|
||||
|
||||
return resultMap;
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
function updateOption(req: Request) {
|
||||
const {name, value} = req.params;
|
||||
const { name, value } = req.params;
|
||||
|
||||
if (!update(name, value)) {
|
||||
throw new ValidationError("not allowed option to change");
|
||||
}
|
||||
if (!update(name, value)) {
|
||||
throw new ValidationError("not allowed option to change");
|
||||
}
|
||||
}
|
||||
|
||||
function updateOptions(req: Request) {
|
||||
for (const optionName in req.body) {
|
||||
console.log( optionName )
|
||||
if (!update(optionName, req.body[optionName])) {
|
||||
// this should be improved
|
||||
// it should return 400 instead of current 500, but at least it now rollbacks transaction
|
||||
throw new Error(`Option '${optionName}' is not allowed to be changed`);
|
||||
}
|
||||
for (const optionName in req.body) {
|
||||
console.log(optionName);
|
||||
if (!update(optionName, req.body[optionName])) {
|
||||
// this should be improved
|
||||
// it should return 400 instead of current 500, but at least it now rollbacks transaction
|
||||
throw new Error(`Option '${optionName}' is not allowed to be changed`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function update(name: string, value: string) {
|
||||
if (!isAllowed(name)) {
|
||||
return false;
|
||||
}
|
||||
if (!isAllowed(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name !== 'openNoteContexts') {
|
||||
log.info(`Updating option '${name}' to '${value}'`);
|
||||
}
|
||||
if (name !== "openNoteContexts") {
|
||||
log.info(`Updating option '${name}' to '${value}'`);
|
||||
}
|
||||
|
||||
optionService.setOption(name, value);
|
||||
optionService.setOption(name, value);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function getUserThemes() {
|
||||
const notes = searchService.searchNotes("#appTheme", {ignoreHoistedNote: true});
|
||||
const ret = [];
|
||||
const notes = searchService.searchNotes("#appTheme", {
|
||||
ignoreHoistedNote: true,
|
||||
});
|
||||
const ret = [];
|
||||
|
||||
for (const note of notes) {
|
||||
let value = note.getOwnedLabelValue('appTheme');
|
||||
for (const note of notes) {
|
||||
let value = note.getOwnedLabelValue("appTheme");
|
||||
|
||||
if (!value) {
|
||||
value = note.title.toLowerCase().replace(/[^a-z0-9]/gi, '-');
|
||||
}
|
||||
|
||||
ret.push({
|
||||
val: value,
|
||||
title: note.title,
|
||||
noteId: note.noteId
|
||||
});
|
||||
if (!value) {
|
||||
value = note.title.toLowerCase().replace(/[^a-z0-9]/gi, "-");
|
||||
}
|
||||
|
||||
return ret;
|
||||
ret.push({
|
||||
val: value,
|
||||
title: note.title,
|
||||
noteId: note.noteId,
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function isAllowed(name: string) {
|
||||
return ALLOWED_OPTIONS.has(name)
|
||||
|| name.startsWith("keyboardShortcuts")
|
||||
|| name.endsWith("Collapsed")
|
||||
|| name.startsWith("hideArchivedNotes");
|
||||
return (
|
||||
ALLOWED_OPTIONS.has(name) ||
|
||||
name.startsWith("keyboardShortcuts") ||
|
||||
name.endsWith("Collapsed") ||
|
||||
name.startsWith("hideArchivedNotes")
|
||||
);
|
||||
}
|
||||
|
||||
export = {
|
||||
getOptions,
|
||||
updateOption,
|
||||
updateOptions,
|
||||
getUserThemes
|
||||
getOptions,
|
||||
updateOption,
|
||||
updateOptions,
|
||||
getUserThemes,
|
||||
};
|
||||
|
@ -1,4 +1,6 @@
|
||||
import options = require("../../services/options");
|
||||
import totp_secret = require("../../services/encryption/totp_secret");
|
||||
import { Request } from "express";
|
||||
const speakeasy = require("speakeasy");
|
||||
|
||||
function verifyOTPToken(guessedToken: any) {
|
||||
@ -20,24 +22,35 @@ function generateSecret() {
|
||||
}
|
||||
|
||||
function checkForTOTP() {
|
||||
const totpEnabled = options.getOptionBool("totpEnabled")
|
||||
const totpEnabled = options.getOptionBool("totpEnabled");
|
||||
return { success: "true", message: totpEnabled };
|
||||
}
|
||||
|
||||
function enableTOTP() {
|
||||
options.setOption("totpEnabled", true)
|
||||
options.setOption("totpEnab| voidled", true);
|
||||
return { success: "true" };
|
||||
}
|
||||
|
||||
function disableTOTP() {
|
||||
options.setOption("totpEnabled", false)
|
||||
options.setOption("totpEnabled", false);
|
||||
return { success: "true" };
|
||||
}
|
||||
|
||||
function setTotpSecret(req: Request) {
|
||||
console.log("TODO: Save Secret");
|
||||
// totp_secret.setTotpSecret(req.body.secret);
|
||||
}
|
||||
|
||||
function getSecret() {
|
||||
return "TODO: Get Secret";
|
||||
}
|
||||
|
||||
export = {
|
||||
verifyOTPToken,
|
||||
generateSecret,
|
||||
checkForTOTP,
|
||||
enableTOTP,
|
||||
disableTOTP
|
||||
disableTOTP,
|
||||
setTotpSecret,
|
||||
getSecret,
|
||||
};
|
||||
|
@ -157,8 +157,10 @@ function register(app: express.Application) {
|
||||
|
||||
apiRoute(GET, "/api/totp/generate", totp.generateSecret);
|
||||
apiRoute(GET, "/api/totp/enabled", totp.checkForTOTP);
|
||||
apiRoute(GET, "/api/totp/enable", totp.enableTOTP);
|
||||
apiRoute(GET, "/api/totp/disable", totp.disableTOTP);
|
||||
apiRoute(PST, "/api/totp/enable", totp.enableTOTP);
|
||||
apiRoute(PST, "/api/totp/disable", totp.disableTOTP);
|
||||
apiRoute(PST, "/api/totp/set", totp.setTotpSecret);
|
||||
apiRoute(GET, "/api/totp/get", totp.getSecret);
|
||||
|
||||
apiRoute(GET, "/api/tree", treeApiRoute.getTree);
|
||||
apiRoute(PST, "/api/tree/load", treeApiRoute.load);
|
||||
@ -185,7 +187,7 @@ function register(app: express.Application) {
|
||||
apiRoute(PUT, "/api/notes/:noteId/title", notesApiRoute.changeTitle);
|
||||
apiRoute(
|
||||
PST,
|
||||
"/api/notes/:noteId/duplicate/:parentNoteId",
|
||||
"/api/notes/:noteId/duplicPOSTate/:parentNoteId",
|
||||
notesApiRoute.duplicateSubtree
|
||||
);
|
||||
apiRoute(
|
||||
|
Loading…
x
Reference in New Issue
Block a user