From faddda83f04b46bcdaab5c225cab696fc7a820cd Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 10 Jun 2022 11:55:09 -0500 Subject: (WIP) Add initial API client --- src/api/index.ts | 97 +++++++++++++++++++++++++++++++++++++++++++++ src/screens/Login.tsx | 26 +++++++++--- src/screens/Signup.tsx | 50 ++++++++++++++--------- src/state/env.ts | 3 ++ src/state/models/session.ts | 58 ++++++++++++++++++++++++++- 5 files changed, 209 insertions(+), 25 deletions(-) create mode 100644 src/api/index.ts (limited to 'src') diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 000000000..f83e65411 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,97 @@ +import {MicroblogDelegator, MicroblogReader, auth} from '@adx/common' +import * as ucan from 'ucans' + +export class API { + userCfg?: UserConfig + reader?: MicroblogReader + writer?: MicroblogDelegator + + setUserCfg(cfg: UserConfig) { + this.userCfg = cfg + this.createReader() + this.createWriter() + } + + private createReader() { + if (!this.userCfg?.serverUrl) { + this.reader = undefined + } else { + this.reader = new MicroblogReader( + this.userCfg.serverUrl, + this.userCfg.did, + ) + } + } + + private createWriter() { + if ( + this.userCfg?.serverUrl && + this.userCfg?.did && + this.userCfg?.keypair && + this.userCfg?.ucanStore + ) { + this.writer = new MicroblogDelegator( + this.userCfg.serverUrl, + this.userCfg.did, + this.userCfg.keypair, + this.userCfg.ucanStore, + ) + } else { + this.writer = undefined + } + } +} + +export interface SerializedUserConfig { + serverUrl?: string + secretKeyStr?: string + rootAuthToken?: string +} + +export class UserConfig { + serverUrl?: string + did?: string + keypair?: ucan.EdKeypair + rootAuthToken?: string + ucanStore?: ucan.Store + + get hasWriteCaps() { + return Boolean(this.did && this.keypair && this.ucanStore) + } + + static async createTest(serverUrl: string) { + const cfg = new UserConfig() + cfg.serverUrl = serverUrl + cfg.keypair = await ucan.EdKeypair.create() + cfg.did = cfg.keypair.did() + cfg.rootAuthToken = (await auth.claimFull(cfg.did, cfg.keypair)).encoded() + cfg.ucanStore = await ucan.Store.fromTokens([cfg.rootAuthToken]) + return cfg + } + + static async hydrate(state: SerializedUserConfig) { + const cfg = new UserConfig() + await cfg.hydrate(state) + return cfg + } + + async serialize(): Promise { + return { + serverUrl: this.serverUrl, + secretKeyStr: this.keypair + ? await this.keypair.export('base64') + : undefined, + rootAuthToken: this.rootAuthToken, + } + } + + async hydrate(state: SerializedUserConfig) { + this.serverUrl = state.serverUrl + if (state.secretKeyStr && state.rootAuthToken) { + this.keypair = ucan.EdKeypair.fromSecretKey(state.secretKeyStr) + this.did = this.keypair.did() + this.rootAuthToken = state.rootAuthToken + this.ucanStore = await ucan.Store.fromTokens([this.rootAuthToken]) + } + } +} diff --git a/src/screens/Login.tsx b/src/screens/Login.tsx index 0eea085d5..8451eb3c8 100644 --- a/src/screens/Login.tsx +++ b/src/screens/Login.tsx @@ -1,18 +1,34 @@ import React from 'react' -import {Text, Button, View} from 'react-native' +import {Text, Button, View, ActivityIndicator} from 'react-native' +import {observer} from 'mobx-react-lite' import {Shell} from '../platform/shell' import type {RootTabsScreenProps} from '../routes/types' import {useStores} from '../state' -export function Login({navigation}: RootTabsScreenProps<'Login'>) { +export const Login = observer(({navigation}: RootTabsScreenProps<'Login'>) => { const store = useStores() return ( Sign In -