Skip to content

Commit

Permalink
Merge pull request #1255 from buttercup/fix/password_prompt
Browse files Browse the repository at this point in the history
Password prompt rebuild
  • Loading branch information
perry-mitchell authored Nov 26, 2023
2 parents 8b000f9 + 1a8c329 commit 8e5533e
Show file tree
Hide file tree
Showing 19 changed files with 375 additions and 302 deletions.
3 changes: 2 additions & 1 deletion source/main/services/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { applyCurrentTheme } from "./theme";
import { updateTrayIcon } from "../actions/tray";
import { updateAppMenu } from "../actions/appMenu";
import { getConfigValue, initialise as initialiseConfig } from "./config";
import { getConfigPath, getVaultStoragePath } from "./storage";
import { getConfigPath, getVaultSettingsPath, getVaultStoragePath } from "./storage";
import { getOSLocale } from "./locale";
import { startFileHost } from "./fileHost";
import { isPortable } from "../library/portability";
Expand All @@ -28,6 +28,7 @@ export async function initialise() {
logInfo(`Logs location: ${getLogPath()}`);
logInfo(`Config location: ${getConfigPath()}`);
logInfo(`Vault config storage location: ${getVaultStoragePath()}`);
logInfo(`Vault-specific settings path: ${getVaultSettingsPath("<ID>")}`);
await initialiseConfig();
const preferences = await getConfigValue("preferences");
const locale = await getOSLocale();
Expand Down
6 changes: 3 additions & 3 deletions source/renderer/actions/facade.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ipcRenderer } from "electron";
import { VaultFacade, VaultSourceID } from "buttercup";
import { setCurrentVault, setCurrentVaultSupportsAttachments } from "../state/vaults";
import { VAULTS_STATE } from "../state/vaults";
import { setCurrentFacade } from "../services/facade";

export async function fetchUpdatedFacade(sourceID: VaultSourceID) {
Expand All @@ -9,8 +9,8 @@ export async function fetchUpdatedFacade(sourceID: VaultSourceID) {
sourceID
);
const facade: VaultFacade = JSON.parse(rawFacade);
setCurrentVaultSupportsAttachments(attachments);
setCurrentVault(sourceID);
VAULTS_STATE.currentVaultAttachments = !!attachments;
VAULTS_STATE.currentVault = sourceID;
if (!facade) {
setCurrentFacade(null);
return;
Expand Down
22 changes: 13 additions & 9 deletions source/renderer/actions/password.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import { VaultSourceID } from "buttercup";
import { getPasswordEmitter } from "../services/password";
import { sourceHasBiometricAvailability } from "../services/biometrics";
import { setBiometricSourceID, showPasswordPrompt } from "../state/password";
import { PASSWORD_STATE } from "../state/password";

export async function getPrimaryPassword(sourceID?: VaultSourceID): Promise<string | null> {
export async function getPrimaryPassword(
sourceID?: VaultSourceID
): Promise<[password: string | null, biometricsEnabled: boolean, usedBiometrics: boolean]> {
let biometricsEnabled: boolean = false;
if (sourceID) {
const supportsBiometrics = await sourceHasBiometricAvailability(sourceID);
if (supportsBiometrics) {
setBiometricSourceID(sourceID);
PASSWORD_STATE.passwordViaBiometricSource = sourceID;
biometricsEnabled = true;
}
}
showPasswordPrompt(true);
PASSWORD_STATE.showPrompt = true;
const emitter = getPasswordEmitter();
const password = await new Promise<string | null>((resolve) => {
const callback = (password: string | null) => {
resolve(password);
const [password, usedBiometrics] = await new Promise<[string | null, boolean]>((resolve) => {
const callback = (password: string | null, usedBiometrics: boolean) => {
resolve([password, usedBiometrics]);
emitter.removeListener("password", callback);
};
emitter.once("password", callback);
});
setBiometricSourceID(null);
return password;
PASSWORD_STATE.passwordViaBiometricSource = null;
return [password, biometricsEnabled, usedBiometrics];
}
6 changes: 3 additions & 3 deletions source/renderer/actions/removeVault.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ipcRenderer } from "electron";
import { VaultSourceID } from "buttercup";
import { getCurrentSourceID, setCurrentVault } from "../state/vaults";
import { VAULTS_STATE } from "../state/vaults";

export async function removeVaultSource(sourceID: VaultSourceID) {
if (sourceID === getCurrentSourceID()) {
setCurrentVault(null);
if (sourceID === VAULTS_STATE.currentVault) {
VAULTS_STATE.currentVault = null;
}
ipcRenderer.send(
"remove-source",
Expand Down
44 changes: 43 additions & 1 deletion source/renderer/actions/unlockVault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { getPrimaryPassword } from "./password";
import { setBusy } from "../state/app";
import { showError } from "../services/notifications";
import { logInfo } from "../library/log";
import { getVaultSettings, saveVaultSettings } from "../services/vaultSettings";
import { t } from "../../shared/i18n/trans";

export async function unlockVaultSource(sourceID: VaultSourceID): Promise<boolean> {
const password = await getPrimaryPassword(sourceID);
const [password, biometricsEnabled, usedBiometrics] = await getPrimaryPassword(sourceID);
if (!password) return false;
setBusy(true);
logInfo(`Unlocking source: ${sourceID}`);
Expand All @@ -23,6 +24,47 @@ export async function unlockVaultSource(sourceID: VaultSourceID): Promise<boolea
return await unlockVaultSource(sourceID);
}
setBusy(false);
// Update config
if (biometricsEnabled) {
const vaultSettings = await getVaultSettings(sourceID);
const { biometricForcePasswordMaxInterval, biometricForcePasswordCount } = vaultSettings;
const maxPasswordCount = parseInt(biometricForcePasswordCount, 10);
const maxInterval = parseInt(biometricForcePasswordMaxInterval, 10);
if (!isNaN(maxPasswordCount) && maxPasswordCount > 0 && usedBiometrics) {
// Max password count enabled, increment count
vaultSettings.biometricUnlockCount += 1;
logInfo(`biometric unlock count increased: ${vaultSettings.biometricUnlockCount}`);
} else {
// Not enabled, ensure 0
vaultSettings.biometricUnlockCount = 0;
}
if (!isNaN(maxInterval) && maxInterval > 0 && usedBiometrics) {
// Interval enabled, set to now
if (
typeof vaultSettings.biometricLastManualUnlock === "number" &&
vaultSettings.biometricLastManualUnlock > 0
) {
logInfo(
`biometric unlock date ignored as already set: ${vaultSettings.biometricLastManualUnlock}`
);
} else {
vaultSettings.biometricLastManualUnlock = Date.now();
logInfo(`biometric unlock date set: ${vaultSettings.biometricLastManualUnlock}`);
}
} else if (
typeof vaultSettings.biometricLastManualUnlock === "number" &&
vaultSettings.biometricLastManualUnlock > 0
) {
// Exceeded: new date
vaultSettings.biometricLastManualUnlock = Date.now();
logInfo(`biometric unlock date reset: ${vaultSettings.biometricLastManualUnlock}`);
} else {
// Not enabled: back to null
vaultSettings.biometricLastManualUnlock = null;
}
await saveVaultSettings(sourceID, vaultSettings);
}
// Return result
logInfo(`Unlocked source: ${sourceID}`);
return true;
}
Loading

0 comments on commit 8e5533e

Please sign in to comment.