1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00

Desktop: Allow showing passwords in Master Password dialog

This commit is contained in:
Laurent Cozic 2021-11-15 12:02:59 +00:00
parent 90957e5a34
commit 79d97f2ba7
7 changed files with 85 additions and 16 deletions

View File

@ -534,6 +534,9 @@ packages/app-desktop/gui/NoteToolbar/NoteToolbar.js.map
packages/app-desktop/gui/OneDriveLoginScreen.d.ts
packages/app-desktop/gui/OneDriveLoginScreen.js
packages/app-desktop/gui/OneDriveLoginScreen.js.map
packages/app-desktop/gui/PasswordInput/PasswordInput.d.ts
packages/app-desktop/gui/PasswordInput/PasswordInput.js
packages/app-desktop/gui/PasswordInput/PasswordInput.js.map
packages/app-desktop/gui/ResizableLayout/MoveButtons.d.ts
packages/app-desktop/gui/ResizableLayout/MoveButtons.js
packages/app-desktop/gui/ResizableLayout/MoveButtons.js.map

3
.gitignore vendored
View File

@ -517,6 +517,9 @@ packages/app-desktop/gui/NoteToolbar/NoteToolbar.js.map
packages/app-desktop/gui/OneDriveLoginScreen.d.ts
packages/app-desktop/gui/OneDriveLoginScreen.js
packages/app-desktop/gui/OneDriveLoginScreen.js.map
packages/app-desktop/gui/PasswordInput/PasswordInput.d.ts
packages/app-desktop/gui/PasswordInput/PasswordInput.js
packages/app-desktop/gui/PasswordInput/PasswordInput.js.map
packages/app-desktop/gui/ResizableLayout/MoveButtons.d.ts
packages/app-desktop/gui/ResizableLayout/MoveButtons.js
packages/app-desktop/gui/ResizableLayout/MoveButtons.js.map

View File

@ -5,12 +5,12 @@ import useAsyncEffect, { AsyncEffectEvent } from '@joplin/lib/hooks/useAsyncEffe
import DialogButtonRow, { ClickEvent } from '../DialogButtonRow';
import Dialog from '../Dialog';
import DialogTitle from '../DialogTitle';
import StyledInput from '../style/StyledInput';
import { getMasterPasswordStatus, getMasterPasswordStatusMessage, checkHasMasterPasswordEncryptedData, masterPasswordIsValid, MasterPasswordStatus, resetMasterPassword, updateMasterPassword } from '@joplin/lib/services/e2ee/utils';
import { getMasterPasswordStatus, getMasterPasswordStatusMessage, checkHasMasterPasswordEncryptedData, masterPasswordIsValid, MasterPasswordStatus, resetMasterPassword, updateMasterPassword, getMasterPassword } from '@joplin/lib/services/e2ee/utils';
import { reg } from '@joplin/lib/registry';
import EncryptionService from '@joplin/lib/services/e2ee/EncryptionService';
import KvStore from '@joplin/lib/services/KvStore';
import ShareService from '@joplin/lib/services/share/ShareService';
import { PasswordInput } from '../PasswordInput/PasswordInput';
interface Props {
themeId: number;
@ -41,6 +41,10 @@ export default function(props: Props) {
});
}, [props.dispatch]);
useEffect(() => {
setCurrentPassword(getMasterPassword(false) || '');
}, []);
useAsyncEffect(async (event: AsyncEffectEvent) => {
const newStatus = await getMasterPasswordStatus();
const hasIt = await checkHasMasterPasswordEncryptedData();
@ -122,7 +126,7 @@ export default function(props: Props) {
function renderCurrentPasswordIcon() {
if (!currentPassword || status === MasterPasswordStatus.NotSet) return null;
return currentPasswordIsValid ? <i className="fas fa-check"></i> : <i className="fas fa-times"></i>;
return currentPasswordIsValid ? <i className="fas fa-check password-valid-icon"></i> : <i className="fas fa-times"></i>;
}
function renderPasswordForm() {
@ -130,15 +134,17 @@ export default function(props: Props) {
if (status === MasterPasswordStatus.NotSet) return null;
if (mode === Mode.Reset) return null;
// If the master password is in the keychain we preload it into the
// field and allow displaying it. That way if the user has forgotten
// their password, they have a chance to recover it that way without
// having to reset the password (and lose access to any data that's
// been encrypted with it).
return (
<div className="form-input-group">
<label>{'Current password'}</label>
<div className="current-password-wrapper">
<StyledInput
type="password"
value={currentPassword}
onChange={onCurrentPasswordChange}
/>
<PasswordInput value={currentPassword} onChange={onCurrentPasswordChange}/>
{renderCurrentPasswordIcon()}
</div>
</div>
@ -152,18 +158,20 @@ export default function(props: Props) {
};
if (showPasswordForm) {
const enterPasswordLabel = [MasterPasswordStatus.Loaded, MasterPasswordStatus.Valid].includes(status) ? 'Enter new password' : 'Enter password';
return (
<div>
<div className="form">
{renderCurrentPassword()}
<div className="form-input-group">
<label>{'Enter password'}</label>
<StyledInput type="password" value={password1} onChange={onPasswordChange1}/>
<label>{enterPasswordLabel}</label>
<PasswordInput value={password1} onChange={onPasswordChange1}/>
</div>
{needToRepeatPassword && (
<div className="form-input-group">
<label>{'Re-enter password'}</label>
<StyledInput type="password" value={password2} onChange={onPasswordChange2}/>
<PasswordInput value={password2} onChange={onPasswordChange2}/>
</div>
)}
</div>

View File

@ -0,0 +1,31 @@
import { useState, useCallback } from 'react';
import StyledInput from '../style/StyledInput';
export interface ChangeEvent {
value: string;
}
type ChangeEventHandler = (event: ChangeEvent)=> void;
interface Props {
value: string;
onChange: ChangeEventHandler;
}
export const PasswordInput = (props: Props) => {
const [showPassword, setShowPassword] = useState(false);
const inputType = showPassword ? 'text' : 'password';
const icon = showPassword ? 'far fa-eye-slash' : 'far fa-eye';
const onShowPassword = useCallback(() => {
setShowPassword(current => !current);
}, []);
return (
<div className="password-input">
<StyledInput className="field" type={inputType} value={props.value} onChange={props.onChange}/>
<button onClick={onShowPassword} className="showpasswordbutton"><i className={icon}></i></button>
</div>
);
};

View File

@ -0,0 +1,19 @@
.password-input {
display: flex;
position: relative;
flex: 1;
> .field {
display: flex;
flex: 1;
width: 100%;
}
> .showpasswordbutton {
position: absolute;
right: 5px;
top: 4px;
border: none;
background: none;
}
}

View File

@ -149,7 +149,7 @@ a {
General classes
========================================================================================= */
body {
body, button {
color: var(--joplin-color);
font-size: 16px;
}
@ -238,12 +238,16 @@ Component-specific classes
display: flex;
flex-direction: row;
align-items: center;
> .password-valid-icon {
margin-left: 10px;
}
}
.master-password-dialog .current-password-wrapper input {
flex: 1;
margin-right: 10px;
}
// .master-password-dialog .current-password-wrapper input {
// flex: 1;
// margin-right: 10px;
// }
.master-password-dialog .fa-check {
color: var(--joplin-color-correct);

View File

@ -1,3 +1,4 @@
@use 'main.scss' as main;
@use 'gui/EncryptionConfigScreen/style.scss' as encryption-config-screen;
@use 'gui/PasswordInput/style.scss' as password-input;
@use 'gui/ConfigScreen/style.scss' as config-screen;