update set password flow
This commit is contained in:
@@ -9,15 +9,14 @@ import { Button } from '@shared/button';
|
|||||||
import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||||
|
|
||||||
import { useOnboarding } from '@stores/onboarding';
|
import { useOnboarding } from '@stores/onboarding';
|
||||||
|
import { useStronghold } from '@stores/stronghold';
|
||||||
|
|
||||||
export function CreateStep1Screen() {
|
export function CreateStep1Screen() {
|
||||||
const navigate = useNavigate();
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||||
|
const setPubkey = useOnboarding((state) => state.setPubkey);
|
||||||
|
|
||||||
const [setPubkey, setPrivkey] = useOnboarding((state) => [
|
|
||||||
state.setPubkey,
|
|
||||||
state.setPrivkey,
|
|
||||||
]);
|
|
||||||
const [privkeyInput, setPrivkeyInput] = useState('password');
|
const [privkeyInput, setPrivkeyInput] = useState('password');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,15 @@ const resolver: Resolver<FormValues> = async (values) => {
|
|||||||
|
|
||||||
export function CreateStep2Screen() {
|
export function CreateStep2Screen() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const setPassword = useStronghold((state) => state.setPassword);
|
|
||||||
|
|
||||||
const [pubkey, privkey] = useOnboarding((state) => [state.pubkey, state.privkey]);
|
|
||||||
const [passwordInput, setPasswordInput] = useState('password');
|
const [passwordInput, setPasswordInput] = useState('password');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [privkey, setPassword] = useStronghold((state) => [
|
||||||
|
state.privkey,
|
||||||
|
state.setPassword,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const pubkey = useOnboarding((state) => state.privkey);
|
||||||
|
|
||||||
const { save } = useSecureStorage();
|
const { save } = useSecureStorage();
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ export function CreateStep5Screen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const list = data ? data.profiles.concat(INITIAL_LIST) : [];
|
const list = data ? data.profiles.concat(INITIAL_LIST) : INITIAL_LIST;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-md">
|
<div className="mx-auto w-full max-w-md">
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { createAccount } from '@libs/storage';
|
|||||||
import { LoaderIcon } from '@shared/icons';
|
import { LoaderIcon } from '@shared/icons';
|
||||||
|
|
||||||
import { useOnboarding } from '@stores/onboarding';
|
import { useOnboarding } from '@stores/onboarding';
|
||||||
|
import { useStronghold } from '@stores/stronghold';
|
||||||
|
|
||||||
type FormValues = {
|
type FormValues = {
|
||||||
privkey: string;
|
privkey: string;
|
||||||
@@ -31,11 +32,9 @@ const resolver: Resolver<FormValues> = async (values) => {
|
|||||||
export function ImportStep1Screen() {
|
export function ImportStep1Screen() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||||
|
const setPubkey = useOnboarding((state) => state.setPubkey);
|
||||||
|
|
||||||
const [setPubkey, setPrivkey] = useOnboarding((state) => [
|
|
||||||
state.setPubkey,
|
|
||||||
state.setPrivkey,
|
|
||||||
]);
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const account = useMutation({
|
const account = useMutation({
|
||||||
@@ -74,6 +73,7 @@ export function ImportStep1Screen() {
|
|||||||
|
|
||||||
// use for onboarding process only
|
// use for onboarding process only
|
||||||
setPubkey(pubkey);
|
setPubkey(pubkey);
|
||||||
|
// add stronghold state
|
||||||
setPrivkey(privkey);
|
setPrivkey(privkey);
|
||||||
|
|
||||||
// add account to local database
|
// add account to local database
|
||||||
|
|||||||
@@ -29,11 +29,15 @@ const resolver: Resolver<FormValues> = async (values) => {
|
|||||||
|
|
||||||
export function ImportStep2Screen() {
|
export function ImportStep2Screen() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const setPassword = useStronghold((state) => state.setPassword);
|
|
||||||
|
|
||||||
const [passwordInput, setPasswordInput] = useState('password');
|
const [passwordInput, setPasswordInput] = useState('password');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [pubkey, privkey] = useOnboarding((state) => [state.pubkey, state.privkey]);
|
const [privkey, setPassword] = useStronghold((state) => [
|
||||||
|
state.privkey,
|
||||||
|
state.setPassword,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const pubkey = useOnboarding((state) => state.pubkey);
|
||||||
|
|
||||||
const { save } = useSecureStorage();
|
const { save } = useSecureStorage();
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
|
|
||||||
import { removePrivkey } from '@libs/storage';
|
import { removePrivkey } from '@libs/storage';
|
||||||
|
|
||||||
import { CheckCircleIcon, EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||||
|
|
||||||
import { useStronghold } from '@stores/stronghold';
|
import { useStronghold } from '@stores/stronghold';
|
||||||
|
|
||||||
@@ -35,14 +35,15 @@ export function MigrateScreen() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [passwordInput, setPasswordInput] = useState('password');
|
const [passwordInput, setPasswordInput] = useState('password');
|
||||||
const [passwordStep, setPasswordStep] = useState({ loading: false, done: false });
|
const [loading, setLoading] = useState(false);
|
||||||
const [privkeyStep, setPrivkeyStep] = useState({ loading: false, done: false });
|
const [setPassword, setPrivkey] = useStronghold((state) => [
|
||||||
|
state.setPassword,
|
||||||
|
state.setPrivkey,
|
||||||
|
]);
|
||||||
|
|
||||||
const { account } = useAccount();
|
const { account } = useAccount();
|
||||||
const { save } = useSecureStorage();
|
const { save } = useSecureStorage();
|
||||||
|
|
||||||
const setPassword = useStronghold((state) => state.setPassword);
|
|
||||||
|
|
||||||
// toggle private key
|
// toggle private key
|
||||||
const showPassword = () => {
|
const showPassword = () => {
|
||||||
if (passwordInput === 'password') {
|
if (passwordInput === 'password') {
|
||||||
@@ -52,16 +53,6 @@ export function MigrateScreen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearPrivkey = async () => {
|
|
||||||
setPrivkeyStep((prev) => ({ ...prev, loading: true }));
|
|
||||||
const res = await removePrivkey();
|
|
||||||
if (res) {
|
|
||||||
setPrivkeyStep({ done: true, loading: false });
|
|
||||||
} else {
|
|
||||||
setPrivkeyStep((prev) => ({ ...prev, loading: false }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
setError,
|
setError,
|
||||||
@@ -70,27 +61,32 @@ export function MigrateScreen() {
|
|||||||
} = useForm<FormValues>({ resolver });
|
} = useForm<FormValues>({ resolver });
|
||||||
|
|
||||||
const onSubmit = async (data: { [x: string]: string }) => {
|
const onSubmit = async (data: { [x: string]: string }) => {
|
||||||
setPasswordStep((prev) => ({ ...prev, loading: true }));
|
setLoading(true);
|
||||||
if (data.password.length > 3) {
|
if (data.password.length > 3) {
|
||||||
// add password to local state
|
// add password to local state
|
||||||
setPassword(data.password);
|
setPassword(data.password);
|
||||||
|
|
||||||
// load private in secure storage
|
// load private in secure storage
|
||||||
try {
|
try {
|
||||||
|
// save privkey to secure storage
|
||||||
await save(account.pubkey, account.privkey, data.password);
|
await save(account.pubkey, account.privkey, data.password);
|
||||||
|
// add privkey to state
|
||||||
|
setPrivkey(account.privkey);
|
||||||
|
// remove privkey in db
|
||||||
|
await removePrivkey();
|
||||||
// clear cache
|
// clear cache
|
||||||
await queryClient.invalidateQueries(['currentAccount']);
|
await queryClient.invalidateQueries(['currentAccount']);
|
||||||
// redirect to home
|
// redirect to home
|
||||||
navigate('/', { replace: true });
|
navigate('/', { replace: true });
|
||||||
} catch {
|
} catch {
|
||||||
setPasswordStep((prev) => ({ ...prev, loading: false }));
|
setLoading(false);
|
||||||
setError('password', {
|
setError('password', {
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
message: 'Wrong password',
|
message: 'Wrong password',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setPasswordStep((prev) => ({ ...prev, loading: false }));
|
setLoading(false);
|
||||||
setError('password', {
|
setError('password', {
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
message: 'Password is required and must be greater than 3',
|
message: 'Password is required and must be greater than 3',
|
||||||
@@ -109,53 +105,25 @@ export function MigrateScreen() {
|
|||||||
<div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-3">
|
<div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-3">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-medium text-zinc-200">
|
|
||||||
Remove plaintext privkey store in local database
|
|
||||||
</h3>
|
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
<p className="text-sm text-zinc-400">
|
<p className="text-sm text-zinc-400">
|
||||||
You're using old Lume version which store your private key as
|
You're using old Lume version which store your private key as
|
||||||
plaintext in database, this is huge security risk.
|
plaintext in database, this is huge security risk.
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-2 text-sm text-zinc-400">To secure your private key</p>
|
<p className="mt-2 text-sm text-zinc-400">
|
||||||
<ul className="mt-2 list-outside list-disc pl-5 text-sm text-zinc-400">
|
To secure your private key, please set a password and Lume will put your
|
||||||
<li>Firstly, click button below to remove it from local database</li>
|
private key in secure storage.
|
||||||
<li>
|
</p>
|
||||||
Then set password and Lume will put your private key in secure storage
|
<p className="mt-2 text-sm text-zinc-400">
|
||||||
</li>
|
It is not possible to start the app without applying this step, it is
|
||||||
</ul>
|
easy and fast!
|
||||||
</div>
|
</p>
|
||||||
<div className="mt-3">
|
|
||||||
<div className="relative">
|
|
||||||
<input
|
|
||||||
readOnly
|
|
||||||
value={privkeyStep.done ? 'Nothing to see here' : account.privkey}
|
|
||||||
className="relative w-full rounded-lg bg-zinc-800 px-3 py-3 text-zinc-100 !outline-none placeholder:text-zinc-500"
|
|
||||||
/>
|
|
||||||
<div className="absolute left-0 top-0 flex h-full w-full items-center justify-center rounded-lg bg-black/10 backdrop-blur-sm">
|
|
||||||
{privkeyStep.done ? (
|
|
||||||
privkeyStep.loading ? (
|
|
||||||
<LoaderIcon className="h-4 w-4 animate-spin text-zinc-100" />
|
|
||||||
) : (
|
|
||||||
<CheckCircleIcon className="h-5 w-5 text-green-500" />
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => clearPrivkey()}
|
|
||||||
className="inline-flex w-max items-center justify-center rounded bg-fuchsia-500 px-2.5 py-1.5 text-sm hover:bg-fuchsia-600"
|
|
||||||
>
|
|
||||||
Click to remove
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="mb-0">
|
<form onSubmit={handleSubmit(onSubmit)} className="mb-0">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<span className="font-medium text-zinc-200">
|
<span className="font-medium text-zinc-200">
|
||||||
Set password to protect your key
|
Set a password to protect your key
|
||||||
</span>
|
</span>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
@@ -189,19 +157,17 @@ export function MigrateScreen() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
{privkeyStep.done && (
|
<button
|
||||||
<button
|
type="submit"
|
||||||
type="submit"
|
disabled={!isDirty || !isValid}
|
||||||
disabled={!isDirty || !isValid}
|
className="mt-3 inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50"
|
||||||
className="mt-3 inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50"
|
>
|
||||||
>
|
{loading ? (
|
||||||
{passwordStep.loading ? (
|
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
|
||||||
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
|
) : (
|
||||||
) : (
|
'Continue →'
|
||||||
'Continue →'
|
)}
|
||||||
)}
|
</button>
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user