wip: multi account

This commit is contained in:
Ren Amamiya 2023-09-28 13:58:50 +07:00
parent 0e6fc65b08
commit 4f4e2f5ccd
11 changed files with 59 additions and 30 deletions

BIN
public/wallpapers/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 MiB

View File

@ -24,7 +24,7 @@ export default function App() {
const accountLoader = async () => { const accountLoader = async () => {
try { try {
const account = await db.checkAccount(); const totalAccount = await db.checkAccount();
const stronghold = sessionStorage.getItem('stronghold'); const stronghold = sessionStorage.getItem('stronghold');
const privkey = JSON.parse(stronghold).state.privkey || null; const privkey = JSON.parse(stronghold).state.privkey || null;
@ -32,7 +32,7 @@ export default function App() {
const onboarding = localStorage.getItem('onboarding'); const onboarding = localStorage.getItem('onboarding');
const step = JSON.parse(onboarding).state.step || null; const step = JSON.parse(onboarding).state.step || null;
if (!account) { if (totalAccount === 0) {
return redirect('/auth/welcome'); return redirect('/auth/welcome');
} else { } else {
if (step) { if (step) {
@ -251,6 +251,13 @@ export default function App() {
return { Component: UnlockScreen }; return { Component: UnlockScreen };
}, },
}, },
{
path: 'lock',
async lazy() {
const { LockScreen } = await import('@app/auth/lock');
return { Component: LockScreen };
},
},
{ {
path: 'migrate', path: 'migrate',
async lazy() { async lazy() {

View File

@ -66,7 +66,7 @@ export function CreateStep2Screen() {
if (!db.secureDB) db.secureDB = stronghold; if (!db.secureDB) db.secureDB = stronghold;
// save privkey to secure storage // save privkey to secure storage
await db.secureSave(pubkey, privkey); await db.secureSave(pubkey, privkey, pubkey);
// redirect to next step // redirect to next step
navigate('/auth/create/step-3', { replace: true }); navigate('/auth/create/step-3', { replace: true });

View File

@ -66,7 +66,7 @@ export function ImportStep2Screen() {
if (!db.secureDB) db.secureDB = stronghold; if (!db.secureDB) db.secureDB = stronghold;
// save privkey to secure storage // save privkey to secure storage
await db.secureSave(pubkey, privkey); await db.secureSave(pubkey, privkey, pubkey);
// redirect to next step // redirect to next step
navigate('/auth/import/step-3', { replace: true }); navigate('/auth/import/step-3', { replace: true });

10
src/app/auth/lock.tsx Normal file
View File

@ -0,0 +1,10 @@
export function LockScreen() {
return (
<div
className="h-full w-full bg-cover bg-center"
style={{ backgroundImage: 'url(/wallpapers/1.png)' }}
>
<p>TODO</p>
</div>
);
}

View File

@ -33,6 +33,7 @@ export function UnlockScreen() {
const navigate = useNavigate(); const navigate = useNavigate();
const setPrivkey = useStronghold((state) => state.setPrivkey); const setPrivkey = useStronghold((state) => state.setPrivkey);
const setWalletConnectURL = useStronghold((state) => state.setWalletConnectURL); const setWalletConnectURL = useStronghold((state) => state.setWalletConnectURL);
const resetStronghold = useStronghold((state) => state.reset);
const [showPassword, setShowPassword] = useState<boolean>(false); const [showPassword, setShowPassword] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
@ -73,6 +74,8 @@ export function UnlockScreen() {
const logout = async () => { const logout = async () => {
// remove account // remove account
db.accountLogout(); db.accountLogout();
// reset stronghold
resetStronghold();
// redirect to welcome screen // redirect to welcome screen
navigate('/auth/welcome'); navigate('/auth/welcome');
}; };
@ -146,7 +149,7 @@ export function UnlockScreen() {
to="/auth/reset" to="/auth/reset"
className="inline-flex h-10 w-full items-center justify-center rounded-lg text-center text-sm font-medium text-white/70 hover:bg-white/20" className="inline-flex h-10 w-full items-center justify-center rounded-lg text-center text-sm font-medium text-white/70 hover:bg-white/20"
> >
Reset password if you still have private key Reset password if you still have a private key
</Link> </Link>
<button <button
type="button" type="button"

View File

@ -68,7 +68,7 @@ export function SplashScreen() {
</h3> </h3>
{ndk ? ( {ndk ? (
<p className="text-sm text-white/50"> <p className="text-sm text-white/50">
Ensure all your data is sync across all Nostr clients, it may take a few Ensure all your data is sync across all Nostr clients. It may take a few
seconds, please don&apos;t close app. seconds, please don&apos;t close app.
</p> </p>
) : null} ) : null}

View File

@ -35,7 +35,6 @@ export class LumeStorage {
const client = await this.getSecureClient(clientKey); const client = await this.getSecureClient(clientKey);
const store = client.getStore(); const store = client.getStore();
console.log('insert key: ', key);
await store.insert(key, Array.from(new TextEncoder().encode(value))); await store.insert(key, Array.from(new TextEncoder().encode(value)));
await this.secureDB.save(); await this.secureDB.save();
@ -46,7 +45,6 @@ export class LumeStorage {
const client = await this.getSecureClient(clientKey); const client = await this.getSecureClient(clientKey);
const store = client.getStore(); const store = client.getStore();
console.log('get key: ', key);
const value = await store.get(key); const value = await store.get(key);
if (!value) return null; if (!value) return null;
@ -60,10 +58,10 @@ export class LumeStorage {
} }
public async checkAccount() { public async checkAccount() {
const result: Array<Account> = await this.db.select( const result: Array<{ total: string }> = await this.db.select(
'SELECT * FROM accounts WHERE is_active = 1;' 'SELECT COUNT(*) AS "total" FROM accounts;'
); );
return result.length > 0; return parseInt(result[0].total);
} }
public async getActiveAccount() { public async getActiveAccount() {
@ -92,16 +90,24 @@ export class LumeStorage {
} }
public async createAccount(npub: string, pubkey: string) { public async createAccount(npub: string, pubkey: string) {
const res = await this.db.execute( const existAccounts: Array<Account> = await this.db.select(
'INSERT OR IGNORE INTO accounts (npub, pubkey, privkey, is_active) VALUES ($1, $2, $3, $4);', 'SELECT * FROM accounts WHERE pubkey = $1 ORDER BY id DESC LIMIT 1;',
[npub, pubkey, 'privkey is stored in secure storage', 1] [pubkey]
); );
if (res) {
const account = await this.getActiveAccount(); if (existAccounts.length > 0) {
return account; await this.db.execute("UPDATE accounts SET is_active = '1' WHERE pubkey = $1;", [
pubkey,
]);
} else { } else {
console.error('create account failed'); await this.db.execute(
'INSERT OR IGNORE INTO accounts (npub, pubkey, privkey, is_active) VALUES ($1, $2, $3, $4);',
[npub, pubkey, 'privkey is stored in secure storage', 1]
);
} }
const account = await this.getActiveAccount();
return account;
} }
public async updateAccount(column: string, value: string | string[]) { public async updateAccount(column: string, value: string | string[]) {
@ -191,7 +197,8 @@ export class LumeStorage {
public async countTotalEvents() { public async countTotalEvents() {
const result: Array<{ total: string }> = await this.db.select( const result: Array<{ total: string }> = await this.db.select(
'SELECT COUNT(*) AS "total" FROM events;' 'SELECT COUNT(*) AS "total" FROM events WHERE account_id = $1;',
[this.account.id]
); );
return parseInt(result[0].total); return parseInt(result[0].total);
} }
@ -206,8 +213,8 @@ export class LumeStorage {
}; };
const query: DBEvent[] = await this.db.select( const query: DBEvent[] = await this.db.select(
'SELECT * FROM events GROUP BY root_id ORDER BY created_at DESC LIMIT $1 OFFSET $2;', 'SELECT * FROM events WHERE account_id = $1 GROUP BY root_id ORDER BY created_at DESC LIMIT $2 OFFSET $3;',
[limit, offset] [this.account.id, limit, offset]
); );
if (query && query.length > 0) { if (query && query.length > 0) {
@ -264,8 +271,8 @@ export class LumeStorage {
}; };
const query: DBEvent[] = await this.db.select( const query: DBEvent[] = await this.db.select(
`SELECT * FROM events WHERE kinds IN (${authorsArr}) ORDER BY created_at DESC LIMIT $1 OFFSET $2;`, `SELECT * FROM events WHERE kinds IN (${authorsArr}) AND account_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3;`,
[limit, offset] [this.account.id, limit, offset]
); );
if (query && query.length > 0) { if (query && query.length > 0) {
@ -284,7 +291,8 @@ export class LumeStorage {
public async isEventsEmpty() { public async isEventsEmpty() {
const results: DBEvent[] = await this.db.select( const results: DBEvent[] = await this.db.select(
'SELECT * FROM events ORDER BY id DESC LIMIT 1;' 'SELECT * FROM events WHERE account_id = $1 ORDER BY id DESC LIMIT 1;',
[this.account.id]
); );
return results.length < 1; return results.length < 1;
@ -351,9 +359,6 @@ export class LumeStorage {
} }
public async accountLogout() { public async accountLogout() {
// delete all events
await this.db.execute('DELETE FROM events WHERE account_id = $1;', [this.account.id]);
// update current account status // update current account status
await this.db.execute("UPDATE accounts SET is_active = '0' WHERE id = $1;", [ await this.db.execute("UPDATE accounts SET is_active = '0' WHERE id = $1;", [
this.account.id, this.account.id,

View File

@ -11,13 +11,13 @@ export function Logout() {
const { db } = useStorage(); const { db } = useStorage();
const navigate = useNavigate(); const navigate = useNavigate();
const clearPrivkey = useStronghold((state) => state.clearPrivkey); const resetStronghold = useStronghold((state) => state.reset);
const logout = async () => { const logout = async () => {
// remove account // remove account
db.accountLogout(); db.accountLogout();
// clear privkey in session storage // clear privkey in session storage
clearPrivkey(); resetStronghold();
// redirect to welcome screen // redirect to welcome screen
navigate('/auth/welcome'); navigate('/auth/welcome');
}; };

View File

@ -56,7 +56,7 @@ export function EventLoader({ firstTime }: { firstTime: boolean }) {
) : ( ) : (
<div className="text-center"> <div className="text-center">
<h3 className="font-semibold leading-tight"> <h3 className="font-semibold leading-tight">
Downloading all events from your last login... Downloading all events while you&apos;re away...
</h3> </h3>
</div> </div>
)} )}

View File

@ -9,6 +9,7 @@ interface StrongholdState {
setWalletConnectURL: (uri: string) => void; setWalletConnectURL: (uri: string) => void;
clearPrivkey: () => void; clearPrivkey: () => void;
setIsFetched: () => void; setIsFetched: () => void;
reset: () => void;
} }
export const useStronghold = create<StrongholdState>()( export const useStronghold = create<StrongholdState>()(
@ -29,6 +30,9 @@ export const useStronghold = create<StrongholdState>()(
setIsFetched: () => { setIsFetched: () => {
set({ isFetched: true }); set({ isFetched: true });
}, },
reset: () => {
set({ privkey: null, walletConnectURL: null, isFetched: false });
},
}), }),
{ {
name: 'stronghold', name: 'stronghold',