This commit is contained in:
rosetta
2026-01-30 05:01:05 +02:00
commit 83f38dc63f
327 changed files with 18725 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
.inner {
display: flex;
justify-content: center;
align-items: center;
padding-top: calc(var(--mantine-spacing-xl));
}
.content {
max-width: 480px;
}
.title {
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
font-family:
Greycliff CF,
var(--mantine-font-family);
font-size: 44px;
line-height: 1.2;
font-weight: 900;
}
.highlight {
position: relative;
background-color: var(--mantine-color-blue-light);
border-radius: var(--mantine-radius-sm);
padding: 4px 12px;
}

View File

@@ -0,0 +1,142 @@
import { Box, Flex, PasswordInput, Text, Transition } from "@mantine/core";
import { useEffect, useState } from "react";
import Lottie from "lottie-react";
import animationData from './lottie.json'
import { useMemory } from "@/app/providers/MemoryProvider/useMemory";
import { mnemonicToSeed } from "web-bip39";
import { useNavigate } from "react-router-dom";
import { modals } from "@mantine/modals";
import { Buffer } from 'buffer'
import { encodeWithPassword, generateHashFromPrivateKey, generateKeyPairFromSeed } from "@/app/crypto/crypto";
import { useAccountProvider } from "@/app/providers/AccountProvider/useAccountProvider";
import { Account } from "@/app/providers/AccountProvider/AccountProvider";
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
import { AnimatedButton } from "@/app/components/AnimatedButton/AnimatedButton";
import { IconChevronRight } from "@tabler/icons-react";
import { SIZE_LOGIN_WIDTH_PX } from "@/app/constants";
export function SetPassword() {
const navigate = useNavigate();
const [password, setPassword] = useState("");
const [confirm, setConfirm] = useState("");
const [phrase, _] = useMemory("seed-phrase", "");
const [mounted, setMounted] = useState(false);
const colors = useRosettaColors();
const { createAccount, loginAccount, selectAccountToLoginDice } = useAccountProvider();
const openInsecurePasswordModal = () => {
modals.openConfirmModal({
title: 'Insecure password',
centered: true,
children: (
<Text size="sm">
Your password is insecure,
such passwords are easy to guess, come up with a new one, or, which is not recommended, leave this one
</Text>
),
withCloseButton: false,
labels: { confirm: 'Continue', cancel: "I'll come up with a new one" },
confirmProps: { color: 'red' },
onConfirm: doneSetup
});
}
useEffect(() => {
if (phrase.trim() == "") {
navigate("/");
}
setTimeout(() => setMounted(true), 100);
}, []);
const doneSetup = async () => {
let seed = await mnemonicToSeed(phrase);
let hex = Buffer.from(seed).toString('hex');
let keypair = await generateKeyPairFromSeed(hex);
const encrypted = await encodeWithPassword(password, keypair.privateKey);
const privateKeyHash = await generateHashFromPrivateKey(keypair.privateKey);
const account: Account = {
publicKey: keypair.publicKey,
privateKey: encrypted,
privatePlain: keypair.privateKey,
privateHash: privateKeyHash,
seedPhraseEncrypted: await encodeWithPassword(password, phrase)
}
createAccount(account);
loginAccount(account);
selectAccountToLoginDice(account);
navigate("/main");
}
const onDone = async () => {
if (!password.match(/[A-Z]+/) || !password.match(/[0-9]+/) || !password.match(/[$@#&!]+/)) {
openInsecurePasswordModal();
return;
}
doneSetup();
}
return (
<Flex h={520} w={385}>
<Flex h={'100%'} w={'100%'}>
<Flex h={'100%'} w={'100%'} pb={'sm'} align={'center'} direction={'column'} justify={'space-between'}>
<Box mt={'xl'}>
<Flex gap={'sm'} w={SIZE_LOGIN_WIDTH_PX} direction={'column'} align={'center'}>
<Lottie animationData={animationData} style={{
width: 100,
height: 100
}} loop={false}></Lottie>
<Flex w={'100%'} gap={'sm'} direction={'column'} mt={'sm'} pl={'sm'} pr={'sm'} align={'center'}>
<Text ta={'center'} fw={500} size={'sm'}>
Protect account
</Text>
<Text c={'dimmed'} ta={'center'} size={'xs'}>
Create a password to protect your account
</Text>
</Flex>
</Flex>
<Transition mounted={mounted} transition="slide-up" duration={400} timingFunction="ease">
{(styles) => (
<Flex w={SIZE_LOGIN_WIDTH_PX} mt={'xl'} pr={'sm'} pl={'sm'} direction={'column'} align={'center'} justify={'center'} gap={'lg'} style={styles}>
<PasswordInput styles={{
input: {
border: '0px solid ' + colors.borderColor,
backgroundColor: colors.mainColor
},
error: {
color: colors.error
}
}} w={'100%'} placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} size="md"></PasswordInput>
<PasswordInput styles={{
input: {
border: '0px solid ' + colors.borderColor,
backgroundColor: colors.mainColor
},
error: {
color: colors.error
}
}} w={'100%'} placeholder="Confirm" value={confirm} onChange={(e) => setConfirm(e.target.value)} size="md"></PasswordInput>
<AnimatedButton disabled={password.length === 0 || confirm.length === 0 || password !== confirm} rightSection={<IconChevronRight size={16}></IconChevronRight>} animated={['#2DA5FF', '#87DBFF']} fullWidth onClick={onDone} size={'md'}>
Start
</AnimatedButton>
</Flex>
)}
</Transition>
</Box>
<Transition mounted={mounted} transition="slide-up" duration={400} timingFunction="ease">
{(styles) => (
<Flex pr={'sm'} pl={'sm'} w={'100%'} align={'center'} justify={'center'} gap={'lg'} style={styles}>
<Text c={'dimmed'} ta={'center'} w={'100%'} size={'xs'}>
Your password <Text c={'blue'} fw={500} span>never leaves</Text> your device and is never stored anywhere.
</Text>
</Flex>
)}
</Transition>
</Flex>
</Flex>
</Flex>)
}

File diff suppressed because one or more lines are too long