Skip to content

Commit

Permalink
feat: vaults (#927)
Browse files Browse the repository at this point in the history
* feat: vaults
  • Loading branch information
moughxyz authored Mar 21, 2022
1 parent 9f032f1 commit 57469d6
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 32 deletions.
130 changes: 128 additions & 2 deletions app/assets/javascripts/components/AccountMenu/AdvancedOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { WebApplication } from '@/ui_models/application';
import { AppState } from '@/ui_models/app_state';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { useState } from 'preact/hooks';
import { useEffect, useState } from 'preact/hooks';
import { Checkbox } from '../Checkbox';
import { Icon } from '../Icon';
import { InputWithIcon } from '../InputWithIcon';
Expand All @@ -11,14 +11,70 @@ type Props = {
application: WebApplication;
appState: AppState;
disabled?: boolean;
onVaultChange?: (isVault: boolean, vaultedEmail?: string) => void;
onStrictSignInChange?: (isStrictSignIn: boolean) => void;
};

export const AdvancedOptions: FunctionComponent<Props> = observer(
({ appState, application, disabled = false, children }) => {
({
appState,
application,
disabled = false,
onVaultChange,
onStrictSignInChange,
children,
}) => {
const { server, setServer, enableServerOption, setEnableServerOption } =
appState.accountMenu;
const [showAdvanced, setShowAdvanced] = useState(false);

const [isVault, setIsVault] = useState(false);
const [vaultName, setVaultName] = useState('');
const [vaultUserphrase, setVaultUserphrase] = useState('');

const [isStrictSignin, setIsStrictSignin] = useState(false);

useEffect(() => {
const recomputeVaultedEmail = async () => {
const vaultedEmail = await application.vaultToEmail(
vaultName,
vaultUserphrase
);

if (!vaultedEmail) {
if (vaultName?.length > 0 && vaultUserphrase?.length > 0) {
application.alertService.alert('Unable to compute vault name.');
}
return;
}
onVaultChange?.(true, vaultedEmail);
};

if (vaultName && vaultUserphrase) {
recomputeVaultedEmail();
}
}, [vaultName, vaultUserphrase, application, onVaultChange]);

useEffect(() => {
onVaultChange?.(isVault);
}, [isVault, onVaultChange]);

const handleIsVaultChange = () => {
setIsVault(!isVault);
};

const handleVaultNameChange = (e: Event) => {
if (e.target instanceof HTMLInputElement) {
setVaultName(e.target.value);
}
};

const handleVaultUserphraseChange = (e: Event) => {
if (e.target instanceof HTMLInputElement) {
setVaultUserphrase(e.target.value);
}
};

const handleServerOptionChange = (e: Event) => {
if (e.target instanceof HTMLInputElement) {
setEnableServerOption(e.target.checked);
Expand All @@ -32,6 +88,12 @@ export const AdvancedOptions: FunctionComponent<Props> = observer(
}
};

const handleStrictSigninChange = () => {
const newValue = !isStrictSignin;
setIsStrictSignin(newValue);
onStrictSignInChange?.(newValue);
};

const toggleShowAdvanced = () => {
setShowAdvanced(!showAdvanced);
};
Expand All @@ -50,6 +112,70 @@ export const AdvancedOptions: FunctionComponent<Props> = observer(
{showAdvanced ? (
<div className="px-3 my-2">
{children}

{appState.enableUnfinishedFeatures && (
<div className="flex justify-between items-center mb-1">
<Checkbox
name="vault-mode"
label="Vault Mode"
checked={isVault}
disabled={disabled}
onChange={handleIsVaultChange}
/>
<a
href="https://standardnotes.com/help/80"
target="_blank"
rel="noopener noreferrer"
title="Learn more"
>
<Icon type="info" className="color-neutral" />
</a>
</div>
)}

{appState.enableUnfinishedFeatures && isVault && (
<>
<InputWithIcon
className={`mb-2`}
icon="folder"
inputType="text"
placeholder="Vault name"
value={vaultName}
onChange={handleVaultNameChange}
disabled={disabled}
/>
<InputWithIcon
className={`mb-2 `}
icon="server"
inputType={'text'}
placeholder="Vault userphrase"
value={vaultUserphrase}
onChange={handleVaultUserphraseChange}
disabled={disabled}
/>
</>
)}

{onStrictSignInChange && (
<div className="flex justify-between items-center mb-1">
<Checkbox
name="use-strict-signin"
label="Use strict sign-in"
checked={isStrictSignin}
disabled={disabled}
onChange={handleStrictSigninChange}
/>
<a
href="https://standardnotes.com/help/security"
target="_blank"
rel="noopener noreferrer"
title="Learn more"
>
<Icon type="info" className="color-neutral" />
</a>
</div>
)}

<Checkbox
name="custom-sync-server"
label="Custom sync server"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,6 @@ export const ConfirmPassword: FunctionComponent<Props> = observer(
/>
) : null}
</form>
<div className="h-1px my-2 bg-border"></div>
<AdvancedOptions
appState={appState}
application={application}
disabled={isRegistering}
/>
</>
);
}
Expand Down
15 changes: 14 additions & 1 deletion app/assets/javascripts/components/AccountMenu/CreateAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const CreateAccount: FunctionComponent<Props> = observer(

const emailInputRef = useRef<HTMLInputElement>(null);
const passwordInputRef = useRef<HTMLInputElement>(null);
const [isVault, setIsVault] = useState(false);

useEffect(() => {
if (emailInputRef.current) {
Expand Down Expand Up @@ -82,6 +83,13 @@ export const CreateAccount: FunctionComponent<Props> = observer(
setPassword('');
};

const onVaultChange = (isVault: boolean, vaultedEmail?: string) => {
setIsVault(isVault);
if (isVault && vaultedEmail) {
setEmail(vaultedEmail);
}
};

return (
<>
<div className="flex items-center px-3 mt-1 mb-3">
Expand All @@ -101,6 +109,7 @@ export const CreateAccount: FunctionComponent<Props> = observer(
inputType="email"
placeholder="Email"
value={email}
disabled={isVault}
onChange={handleEmailChange}
onKeyDown={handleKeyDown}
ref={emailInputRef}
Expand Down Expand Up @@ -130,7 +139,11 @@ export const CreateAccount: FunctionComponent<Props> = observer(
/>
</form>
<div className="h-1px my-2 bg-border"></div>
<AdvancedOptions application={application} appState={appState} />
<AdvancedOptions
application={application}
appState={appState}
onVaultChange={onVaultChange}
/>
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const GeneralAccountMenu: FunctionComponent<Props> = observer(
<>
<div className="px-3 mb-3 color-foreground text-sm">
<div>You're signed in as:</div>
<div className="my-0.5 font-bold">{user.email}</div>
<div className="my-0.5 font-bold wrap">{user.email}</div>
<span className="color-neutral">{application.getHost()}</span>
</div>
<div className="flex items-start justify-between px-3 mb-2">
Expand Down
38 changes: 17 additions & 21 deletions app/assets/javascripts/components/AccountMenu/SignIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AppState } from '@/ui_models/app_state';
import { isDev } from '@/utils';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { useEffect, useRef, useState } from 'preact/hooks';
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { AccountMenuPane } from '.';
import { Button } from '../Button';
import { Checkbox } from '../Checkbox';
Expand All @@ -25,10 +25,12 @@ export const SignInPane: FunctionComponent<Props> = observer(
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [isEphemeral, setIsEphemeral] = useState(false);

const [isStrictSignin, setIsStrictSignin] = useState(false);
const [isSigningIn, setIsSigningIn] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const [shouldMergeLocal, setShouldMergeLocal] = useState(true);
const [isVault, setIsVault] = useState(false);

const emailInputRef = useRef<HTMLInputElement>(null);
const passwordInputRef = useRef<HTMLInputElement>(null);
Expand Down Expand Up @@ -106,6 +108,16 @@ export const SignInPane: FunctionComponent<Props> = observer(
}
};

const onVaultChange = useCallback(
(newIsVault: boolean, vaultedEmail?: string) => {
setIsVault(newIsVault);
if (newIsVault && vaultedEmail) {
setEmail(vaultedEmail);
}
},
[setEmail]
);

const handleSignInFormSubmit = (e: Event) => {
e.preventDefault();

Expand Down Expand Up @@ -145,7 +157,7 @@ export const SignInPane: FunctionComponent<Props> = observer(
onChange={handleEmailChange}
onFocus={resetInvalid}
onKeyDown={handleKeyDown}
disabled={isSigningIn}
disabled={isSigningIn || isVault}
ref={emailInputRef}
/>
<InputWithIcon
Expand Down Expand Up @@ -197,25 +209,9 @@ export const SignInPane: FunctionComponent<Props> = observer(
appState={appState}
application={application}
disabled={isSigningIn}
>
<div className="flex justify-between items-center mb-1">
<Checkbox
name="use-strict-signin"
label="Use strict sign-in"
checked={isStrictSignin}
disabled={isSigningIn}
onChange={handleStrictSigninChange}
/>
<a
href="https://standardnotes.com/help/security"
target="_blank"
rel="noopener noreferrer"
title="Learn more"
>
<Icon type="info" className="color-neutral" />
</a>
</div>
</AdvancedOptions>
onVaultChange={onVaultChange}
onStrictSignInChange={handleStrictSigninChange}
/>
</>
);
}
Expand Down
4 changes: 4 additions & 0 deletions app/assets/javascripts/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
EmailIcon,
EyeIcon,
EyeOffIcon,
FileIcon,
FolderIcon,
FileDocIcon,
FileImageIcon,
FileMovIcon,
Expand Down Expand Up @@ -139,6 +141,8 @@ export const ICONS = {
editor: EditorIcon,
email: EmailIcon,
eye: EyeIcon,
file: FileIcon,
folder: FolderIcon,
hashtag: HashtagIcon,
help: HelpIcon,
history: HistoryIcon,
Expand Down
1 change: 1 addition & 0 deletions app/assets/javascripts/components/InputWithIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const InputWithIcon: FunctionComponent<Props> = forwardRef(
className={`pr-2 w-full border-0 focus:shadow-none ${
disabled ? DISABLED_CLASSNAME : ''
}`}
spellcheck={false}
disabled={disabled}
placeholder={placeholder}
ref={ref}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export const Credentials: FunctionComponent<Props> = observer(
<Title>Credentials</Title>
<Subtitle>Email</Subtitle>
<Text>
You're signed in as <span className="font-bold">{user?.email}</span>
You're signed in as{' '}
<span className="font-bold wrap">{user?.email}</span>
</Text>
<Button
className="min-w-20 mt-3"
Expand Down

0 comments on commit 57469d6

Please sign in to comment.