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:
parent
90957e5a34
commit
79d97f2ba7
@ -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
3
.gitignore
vendored
@ -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
|
||||
|
@ -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>
|
||||
|
31
packages/app-desktop/gui/PasswordInput/PasswordInput.tsx
Normal file
31
packages/app-desktop/gui/PasswordInput/PasswordInput.tsx
Normal 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>
|
||||
);
|
||||
};
|
19
packages/app-desktop/gui/PasswordInput/style.scss
Normal file
19
packages/app-desktop/gui/PasswordInput/style.scss
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
Loading…
Reference in New Issue
Block a user