mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
Started integrating totp into startup sequance
This commit is contained in:
parent
3fb4d95fd7
commit
baca395c0a
@ -17,6 +17,26 @@ const TPL = `
|
||||
Use TOTP (Time-based One-Time Password) to safeguard your data in this application because it adds an additional layer of security by generating unique passcodes that expire quickly, making it harder for unauthorized access. TOTP also reduces the risk of account compromise through common threats like phishing attacks or password breaches.
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h4>TOTP Settings</h4>
|
||||
<div>
|
||||
<label>
|
||||
Enable TOTP
|
||||
</label>
|
||||
<input type="checkbox" class="totp-enabled" />
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="options-section">
|
||||
<label>
|
||||
TOTP Secret
|
||||
</label>
|
||||
<input class="totp-secret-input form-control" disabled="true" type="text">
|
||||
<button class="save-totp" disabled="true"> Save TOTP Secret </button>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h4> Generate TOTP Secret </h4>
|
||||
<span class="totp-secret" > </span>
|
||||
<br>
|
||||
<button class="regenerate-totp"> Regenerate TOTP Secret </button>
|
||||
@ -28,7 +48,10 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
|
||||
this.$mfaHeadding = this.$widget.find(".mfa-heading");
|
||||
this.$regenerateTotpButton = this.$widget.find(".regenerate-totp");
|
||||
this.$totpEnabled = this.$widget.find(".totp-enabled");
|
||||
this.$totpSecret = this.$widget.find(".totp-secret");
|
||||
this.$totpSecretInput = this.$widget.find(".totp-secret-input");
|
||||
this.$saveTotpButton = this.$widget.find(".save-totp");
|
||||
|
||||
this.$mfaHeadding.text("Multi-Factor Authentication");
|
||||
this.generateKey();
|
||||
@ -36,6 +59,10 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
// var gen = require("speakeasy");
|
||||
// toastService.showMessage("***REMOVED***");
|
||||
|
||||
this.$totpEnabled.on("change", async () => {
|
||||
this.updateCheckboxOption("totpEnabled", this.$totpEnabled);
|
||||
});
|
||||
|
||||
this.$regenerateTotpButton.on("click", async () => {
|
||||
this.generateKey();
|
||||
});
|
||||
@ -54,7 +81,6 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
async generateKey() {
|
||||
server.get("totp/generate").then((result) => {
|
||||
if (result.success) {
|
||||
// password changed so current protected session is invalid and needs to be cleared
|
||||
this.$totpSecret.text(result.message);
|
||||
} else {
|
||||
toastService.showError(result.message);
|
||||
@ -62,13 +88,40 @@ export default class MultiFactorAuthenticationOptions extends OptionsWidget {
|
||||
});
|
||||
}
|
||||
|
||||
optionsLoaded(options) {
|
||||
const isPasswordSet = options.isPasswordSet === "true";
|
||||
// async toggleTOTP() {
|
||||
// if (this.$totpEnabled)
|
||||
// server.post("totp/enable").then((result) => {
|
||||
// if (!result.success) toastService.showError(result.message);
|
||||
// });
|
||||
// else
|
||||
// server.post("totp/disable").then((result) => {
|
||||
// if (!result.success) toastService.showError(result.message);
|
||||
// });
|
||||
// }
|
||||
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
toastService.showError(result.message);
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.find(".old-password-form-group").toggle(isPasswordSet);
|
||||
this.$savePasswordButton.text(
|
||||
isPasswordSet ? "Change fff Password" : "Set Password"
|
||||
);
|
||||
this.$protectedSessionTimeout.val(options.protectedSessionTimeout);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ export default class OptionsWidget extends NoteContextAwareWidget {
|
||||
}
|
||||
|
||||
async updateMultipleOptions(opts) {
|
||||
await server.put('options', opts);
|
||||
await server.put("options", opts);
|
||||
|
||||
this.showUpdateNotification();
|
||||
}
|
||||
@ -27,24 +27,24 @@ export default class OptionsWidget extends NoteContextAwareWidget {
|
||||
title: "Options status",
|
||||
message: "Options change have been saved.",
|
||||
icon: "slider",
|
||||
closeAfter: 2000
|
||||
closeAfter: 2000,
|
||||
});
|
||||
}
|
||||
|
||||
async updateCheckboxOption(name, $checkbox) {
|
||||
const isChecked = $checkbox.prop("checked");
|
||||
|
||||
return await this.updateOption(name, isChecked ? 'true' : 'false');
|
||||
return await this.updateOption(name, isChecked ? "true" : "false");
|
||||
}
|
||||
|
||||
setCheckboxState($checkbox, optionValue) {
|
||||
$checkbox.prop('checked', optionValue === 'true');
|
||||
$checkbox.prop("checked", optionValue === "true");
|
||||
}
|
||||
|
||||
optionsLoaded(options) {}
|
||||
|
||||
async refreshWithNote(note) {
|
||||
const options = await server.get('options');
|
||||
const options = await server.get("options");
|
||||
|
||||
this.optionsLoaded(options);
|
||||
}
|
||||
|
@ -86,6 +86,7 @@ function updateOption(req: Request) {
|
||||
|
||||
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
|
||||
|
@ -1,3 +1,4 @@
|
||||
import options = require("../../services/options");
|
||||
const speakeasy = require("speakeasy");
|
||||
|
||||
function verifyOTPToken(guessedToken: any) {
|
||||
@ -18,7 +19,25 @@ function generateSecret() {
|
||||
return { success: "true", message: speakeasy.generateSecret().base32 };
|
||||
}
|
||||
|
||||
function checkForTOTP() {
|
||||
const totpEnabled = options.getOptionBool("totpEnabled")
|
||||
return { success: "true", message: totpEnabled };
|
||||
}
|
||||
|
||||
function enableTOTP() {
|
||||
options.setOption("totpEnabled", true)
|
||||
return { success: "true" };
|
||||
}
|
||||
|
||||
function disableTOTP() {
|
||||
options.setOption("totpEnabled", false)
|
||||
return { success: "true" };
|
||||
}
|
||||
|
||||
export = {
|
||||
verifyOTPToken,
|
||||
generateSecret,
|
||||
checkForTOTP,
|
||||
enableTOTP,
|
||||
disableTOTP
|
||||
};
|
||||
|
@ -14,6 +14,8 @@ import { AppRequest } from './route-interface';
|
||||
function loginPage(req: Request, res: Response) {
|
||||
res.render('login', {
|
||||
failedAuth: false,
|
||||
// totpEnabled: optionService.getOption("hasOTPEnabled"),
|
||||
totpEnabled: false,
|
||||
assetPath: assetPath,
|
||||
appPath: appPath
|
||||
});
|
||||
@ -59,6 +61,7 @@ function setPassword(req: Request, res: Response) {
|
||||
|
||||
function login(req: AppRequest, res: Response) {
|
||||
const guessedPassword = req.body.password;
|
||||
const guessedTotp = req.body.token;
|
||||
|
||||
if (verifyPassword(guessedPassword)) {
|
||||
const rememberMe = req.body.rememberMe;
|
||||
|
@ -156,6 +156,9 @@ function register(app: express.Application) {
|
||||
route(GET, "/setup", [], setupRoute.setupPage);
|
||||
|
||||
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(GET, "/api/tree", treeApiRoute.getTree);
|
||||
apiRoute(PST, "/api/tree/load", treeApiRoute.load);
|
||||
|
@ -96,7 +96,8 @@ const defaultOptions = [
|
||||
{ name: 'customSearchEngineName', value: 'DuckDuckGo', isSynced: true },
|
||||
{ name: 'customSearchEngineUrl', value: 'https://duckduckgo.com/?q={keyword}', isSynced: true },
|
||||
{ name: 'promotedAttributesOpenInRibbon', value: 'true', isSynced: true },
|
||||
{ name: 'editedNotesOpenInRibbon', value: 'true', isSynced: true }
|
||||
{ name: 'editedNotesOpenInRibbon', value: 'true', isSynced: true },
|
||||
// { name: 'totpEnabled', value: 'false', isSynced: false }
|
||||
];
|
||||
|
||||
function initStartupOptions() {
|
||||
|
@ -41,6 +41,21 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<% if( totpEnabled ) { %>
|
||||
<div class="form-group">
|
||||
<label for="otp-token">OTP Token</label>
|
||||
<div class="controls">
|
||||
<input
|
||||
id="token"
|
||||
name="token"
|
||||
placeholder=""
|
||||
class="form-control"
|
||||
type="number"
|
||||
maxlength="6"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<% } %>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
|
Loading…
x
Reference in New Issue
Block a user