update stronghold

This commit is contained in:
Ren Amamiya 2023-07-20 08:57:58 +07:00
parent a80477b40e
commit bbfdb139c6
16 changed files with 74 additions and 127 deletions

View File

@ -28,7 +28,7 @@
"cheerio": "1.0.0-rc.12",
"dayjs": "^1.11.9",
"destr": "^1.2.2",
"framer-motion": "^10.12.22",
"framer-motion": "^10.13.0",
"get-urls": "^11.0.0",
"immer": "^10.0.2",
"light-bolt11-decoder": "^3.0.0",

View File

@ -38,8 +38,8 @@ dependencies:
specifier: ^1.2.2
version: 1.2.2
framer-motion:
specifier: ^10.12.22
version: 10.12.22(react-dom@18.2.0)(react@18.2.0)
specifier: ^10.13.0
version: 10.13.0(react-dom@18.2.0)(react@18.2.0)
get-urls:
specifier: ^11.0.0
version: 11.0.0
@ -2210,7 +2210,7 @@ packages:
postcss: ^8.1.0
dependencies:
browserslist: 4.21.9
caniuse-lite: 1.0.30001516
caniuse-lite: 1.0.30001517
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
@ -2272,8 +2272,8 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001516
electron-to-chromium: 1.4.464
caniuse-lite: 1.0.30001517
electron-to-chromium: 1.4.465
node-releases: 2.0.13
update-browserslist-db: 1.0.11(browserslist@4.21.9)
dev: true
@ -2333,8 +2333,8 @@ packages:
engines: {node: '>=6'}
dev: false
/caniuse-lite@1.0.30001516:
resolution: {integrity: sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==}
/caniuse-lite@1.0.30001517:
resolution: {integrity: sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==}
dev: true
/ccount@2.0.1:
@ -2735,8 +2735,8 @@ packages:
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
/electron-to-chromium@1.4.464:
resolution: {integrity: sha512-guZ84yoou4+ILNdj0XEbmGs6DEWj6zpVOWYpY09GU66yEb0DSYvP/biBPzHn0GuW/3RC/pnaYNUWlQE1fJYtgA==}
/electron-to-chromium@1.4.465:
resolution: {integrity: sha512-XQcuHvEJRMU97UJ75e170mgcITZoz0lIyiaVjk6R+NMTJ8KBIvUHYd1779swgOppUlzxR+JsLpq59PumaXS1jQ==}
dev: true
/emoji-regex@8.0.0:
@ -3327,8 +3327,8 @@ packages:
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
dev: true
/framer-motion@10.12.22(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-bBGYPOxvxcfzS7/py9MEqDucmXBkVl2g42HNlXXPieSTSGGkr8L7+MilCnrU6uX3HrNk/tcB++1SkWE8BosHFw==}
/framer-motion@10.13.0(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-xKhw9VCizmwEHbopOfluaoVunGHSZyMztGbTvsgOYqCjaKu6qtlwWY1J+6GhL41NY1P157JgEikjDm67XCFnvQ==}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
@ -6025,8 +6025,8 @@ packages:
inline-style-parser: 0.1.1
dev: false
/sucrase@3.33.0:
resolution: {integrity: sha512-ARGC7vbufOHfpvyGcZZXFaXCMZ9A4fffOGC5ucOW7+WHDGlAe8LJdf3Jts1sWhDeiI1RSWrKy5Hodl+JWGdW2A==}
/sucrase@3.34.0:
resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==}
engines: {node: '>=8'}
hasBin: true
dependencies:
@ -6100,7 +6100,7 @@ packages:
postcss-nested: 6.0.1(postcss@8.4.26)
postcss-selector-parser: 6.0.13
resolve: 1.22.2
sucrase: 3.33.0
sucrase: 3.34.0
transitivePeerDependencies:
- ts-node
dev: true

View File

@ -121,8 +121,8 @@ fn main() {
tauri_plugin_stronghold::Builder::new(|password| {
let config = argon2::Config {
lanes: 2,
mem_cost: 50_000,
time_cost: 30,
mem_cost: 10_000,
time_cost: 10,
thread_mode: argon2::ThreadMode::from_threads(2),
variant: argon2::Variant::Argon2id,
..Default::default()

View File

@ -32,12 +32,9 @@ export function CreateStep2Screen() {
const [passwordInput, setPasswordInput] = useState('password');
const [loading, setLoading] = useState(false);
const [privkey, setPassword] = useStronghold((state) => [
state.privkey,
state.setPassword,
]);
const pubkey = useOnboarding((state) => state.privkey);
const privkey = useStronghold((state) => state.privkey);
const pubkey = useOnboarding((state) => state.pubkey);
const { save } = useSecureStorage();
@ -60,9 +57,6 @@ export function CreateStep2Screen() {
const onSubmit = async (data: { [x: string]: string }) => {
setLoading(true);
if (data.password.length > 3) {
// add password to local state
setPassword(data.password);
// save privkey to secure storage
await save(pubkey, privkey, data.password);

View File

@ -137,7 +137,7 @@ export function CreateStep5Screen() {
};
const update = useMutation({
mutationFn: (follows: any) => {
mutationFn: (follows: string[]) => {
return updateAccount('follows', follows, account.pubkey);
},
onSuccess: () => {

View File

@ -32,11 +32,8 @@ export function ImportStep2Screen() {
const [passwordInput, setPasswordInput] = useState('password');
const [loading, setLoading] = useState(false);
const [privkey, setPassword] = useStronghold((state) => [
state.privkey,
state.setPassword,
]);
const privkey = useStronghold((state) => state.privkey);
const pubkey = useOnboarding((state) => state.pubkey);
const { save } = useSecureStorage();
@ -60,9 +57,6 @@ export function ImportStep2Screen() {
const onSubmit = async (data: { [x: string]: string }) => {
setLoading(true);
if (data.password.length > 3) {
// add password to local state
setPassword(data.password);
// save privkey to secure storage
await save(pubkey, privkey, data.password);
@ -115,9 +109,9 @@ export function ImportStep2Screen() {
</div>
<div className="text-sm text-zinc-500">
<p>
Password is use to secure your key store in local machine, when you move
to other clients, you just need to copy your private key as nsec or
hexstring
Password is use to unlock app and secure your key store in local machine.
When you move to other clients, you just need to copy your private key as
nsec or hexstring
</p>
</div>
<span className="text-sm text-red-400">

View File

@ -33,13 +33,10 @@ const resolver: Resolver<FormValues> = async (values) => {
export function MigrateScreen() {
const queryClient = useQueryClient();
const navigate = useNavigate();
const setPrivkey = useStronghold((state) => state.setPrivkey);
const [passwordInput, setPasswordInput] = useState('password');
const [loading, setLoading] = useState(false);
const [setPassword, setPrivkey] = useStronghold((state) => [
state.setPassword,
state.setPrivkey,
]);
const { account } = useAccount();
const { save } = useSecureStorage();
@ -63,9 +60,6 @@ export function MigrateScreen() {
const onSubmit = async (data: { [x: string]: string }) => {
setLoading(true);
if (data.password.length > 3) {
// add password to local state
setPassword(data.password);
// load private in secure storage
try {
// save privkey to secure storage

View File

@ -21,8 +21,7 @@ export function OnboardingScreen() {
// publish event
publish({
content:
'Running Lume, fighting for better future, join us here: https://lume.nu',
content: 'Running Lume, join with me: https://lume.nu',
kind: 1,
tags: [],
});
@ -55,18 +54,15 @@ export function OnboardingScreen() {
<User pubkey={account.pubkey} time={Math.floor(Date.now() / 1000)} />
)}
<div className="-mt-6 select-text whitespace-pre-line break-words pl-[49px] text-base text-zinc-100">
<p>Running Lume, fighting for better future</p>
<p>
join us here:{' '}
<a
href="https://lume.nu"
className="font-normal text-fuchsia-500 no-underline hover:text-fuchsia-600"
target="_blank"
rel="noreferrer"
>
https://lume.nu
</a>
</p>
<p>Running Lume, join with me</p>
<a
href="https://lume.nu"
className="font-normal text-fuchsia-500 no-underline hover:text-fuchsia-600"
target="_blank"
rel="noreferrer"
>
https://lume.nu
</a>
</div>
</div>
</div>

View File

@ -29,13 +29,10 @@ const resolver: Resolver<FormValues> = async (values) => {
export function UnlockScreen() {
const navigate = useNavigate();
const setPrivkey = useStronghold((state) => state.setPrivkey);
const [passwordInput, setPasswordInput] = useState('password');
const [loading, setLoading] = useState(false);
const [setPrivkey, setPassword] = useStronghold((state) => [
state.setPrivkey,
state.setPassword,
]);
const { account } = useAccount();
const { load } = useSecureStorage();
@ -59,9 +56,6 @@ export function UnlockScreen() {
const onSubmit = async (data: { [x: string]: string }) => {
setLoading(true);
if (data.password.length > 3) {
// add password to local state
setPassword(data.password);
// load private in secure storage
try {
const privkey = await load(account.pubkey, data.password);

View File

@ -13,7 +13,7 @@ import {
updateLastLogin,
} from '@libs/storage';
import { LoaderIcon, LumeIcon } from '@shared/icons';
import { LoaderIcon } from '@shared/icons';
import { nHoursAgo } from '@utils/date';
import { useAccount } from '@utils/hooks/useAccount';
@ -175,27 +175,24 @@ export function Root() {
}, [status]);
return (
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-black dark:text-zinc-100">
<div className="relative h-full overflow-hidden">
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-zinc-950 dark:text-zinc-100">
<div className="flex h-screen w-full flex-col">
<div
data-tauri-drag-region
className="absolute left-0 top-0 z-20 h-16 w-full bg-transparent"
className="relative h-11 shrink-0 border border-zinc-100 bg-white dark:border-zinc-900 dark:bg-black"
/>
<div className="relative flex h-full flex-col items-center justify-center">
<div className="flex flex-col items-center gap-2">
<LumeIcon className="h-16 w-16 text-black dark:text-zinc-100" />
<div className="relative flex min-h-0 w-full flex-1 items-center justify-center">
<div className="flex flex-col items-center justify-center gap-4">
<LoaderIcon className="h-6 w-6 animate-spin text-zinc-100" />
<div className="text-center">
<h3 className="text-lg font-semibold leading-tight text-zinc-900 dark:text-zinc-100">
Here&apos;s an interesting fact:
<h3 className="text-lg font-semibold leading-tight text-zinc-100">
Prefetching data...
</h3>
<p className="font-medium text-zinc-300 dark:text-zinc-600">
Bitcoin and Nostr can be used by anyone, and no one can stop you!
<p className="text-zinc-600">
This may take a few seconds, please don&apos;t close app.
</p>
</div>
</div>
<div className="absolute bottom-16 left-1/2 -translate-x-1/2 transform">
<LoaderIcon className="h-5 w-5 animate-spin text-black dark:text-zinc-100" />
</div>
</div>
</div>
</div>

View File

@ -19,7 +19,7 @@ export function useNewsfeed() {
useEffect(() => {
if (status === 'success' && account) {
const follows = account ? JSON.parse(account.follows) : [];
const follows = account ? JSON.parse(account.follows as string) : [];
const filter: NDKFilter = {
kinds: [1, 6],
@ -30,7 +30,6 @@ export function useNewsfeed() {
sub.current = ndk.subscribe(filter, { closeOnEose: false });
sub.current.addListener('event', (event: NDKEvent) => {
console.log('new note: ', event);
// add to db
createNote(
event.id,
@ -46,7 +45,9 @@ export function useNewsfeed() {
}
return () => {
sub.current.stop();
if (sub.current) {
sub.current.stop();
}
};
}, [status]);
}

View File

@ -6,7 +6,7 @@ import { useStronghold } from '@stores/stronghold';
import { useAccount } from '@utils/hooks/useAccount';
export function Protected({ children }: { children: ReactNode }) {
const password = useStronghold((state) => state.password);
const privkey = useStronghold((state) => state.privkey);
const { status, account } = useAccount();
if (status === 'success' && !account) {
@ -17,7 +17,7 @@ export function Protected({ children }: { children: ReactNode }) {
return <Navigate to="/auth/migrate" replace />;
}
if (status === 'success' && account && !password) {
if (status === 'success' && account && !privkey) {
return <Navigate to="/auth/unlock" replace />;
}

View File

@ -3,11 +3,8 @@ import { create } from 'zustand';
interface OnboardingState {
profile: { [x: string]: string };
pubkey: string;
privkey: string;
createProfile: (data: { [x: string]: string }) => void;
setPubkey: (pubkey: string) => void;
setPrivkey: (privkey: string) => void;
clearPrivkey: (privkey: string) => void;
}
export const useOnboarding = create<OnboardingState>((set) => ({
@ -20,10 +17,4 @@ export const useOnboarding = create<OnboardingState>((set) => ({
setPubkey: (pubkey: string) => {
set({ pubkey: pubkey });
},
setPrivkey: (privkey: string) => {
set({ privkey: privkey });
},
clearPrivkey: () => {
set({ privkey: '' });
},
}));

View File

@ -1,19 +1,22 @@
import { create } from 'zustand';
import { createJSONStorage, persist } from 'zustand/middleware';
interface StrongholdState {
password: null | string;
privkey: null | string;
setPassword: (password: string) => void;
setPrivkey: (privkey: string) => void;
}
export const useStronghold = create<StrongholdState>((set) => ({
password: null,
privkey: null,
setPassword: (password: string) => {
set({ password: password });
},
setPrivkey: (privkey: string) => {
set({ privkey: privkey });
},
}));
export const useStronghold = create<StrongholdState>()(
persist(
(set) => ({
privkey: null,
setPrivkey: (privkey: string) => {
set({ privkey: privkey });
},
}),
{
name: 'stronghold',
storage: createJSONStorage(() => sessionStorage),
}
)
);

View File

@ -5,14 +5,12 @@ import { useNDK } from '@libs/ndk/provider';
import { useStronghold } from '@stores/stronghold';
import { useAccount } from '@utils/hooks/useAccount';
import { useSecureStorage } from '@utils/hooks/useSecureStorage';
export function usePublish() {
const { ndk } = useNDK();
const { account } = useAccount();
const { load } = useSecureStorage();
const cachePrivkey = useStronghold((state) => state.privkey);
const privkey = useStronghold((state) => state.privkey);
const publish = async ({
content,
@ -23,12 +21,7 @@ export function usePublish() {
kind: NDKKind | number;
tags: string[][];
}): Promise<NDKEvent> => {
let privkey: string;
if (cachePrivkey) {
privkey = cachePrivkey;
} else {
privkey = await load(account.pubkey);
}
if (!privkey) throw new Error('Private key not found');
const event = new NDKEvent(ndk);
const signer = new NDKPrivateKeySigner(privkey);

View File

@ -1,13 +1,9 @@
import { appConfigDir } from '@tauri-apps/api/path';
import { Stronghold } from 'tauri-plugin-stronghold-api';
import { useStronghold } from '@stores/stronghold';
const dir = await appConfigDir();
export function useSecureStorage() {
const password = useStronghold((state) => state.password);
async function getClient(stronghold: Stronghold) {
try {
return await stronghold.loadClient('lume');
@ -16,22 +12,16 @@ export function useSecureStorage() {
}
}
const save = async (key: string, value: string, userpass?: string) => {
const stronghold = await Stronghold.load(
`${dir}lume.stronghold`,
userpass ? userpass : password
);
const save = async (key: string, value: string, password: string) => {
const stronghold = await Stronghold.load(`${dir}lume.stronghold`, password);
const client = await getClient(stronghold);
const store = client.getStore();
await store.insert(key, Array.from(new TextEncoder().encode(value)));
return await stronghold.save();
};
const load = async (key: string, userpass?: string) => {
const stronghold = await Stronghold.load(
`${dir}lume.stronghold`,
userpass ? userpass : password
);
const load = async (key: string, password: string) => {
const stronghold = await Stronghold.load(`${dir}lume.stronghold`, password);
const client = await getClient(stronghold);
const store = client.getStore();
const value = await store.get(key);