Skip to content

Commit

Permalink
dev(auth): save auth context to session
Browse files Browse the repository at this point in the history
  • Loading branch information
theborakompanioni committed Sep 22, 2023
1 parent 9a07601 commit 1b11609
Show file tree
Hide file tree
Showing 17 changed files with 87 additions and 59 deletions.
6 changes: 3 additions & 3 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ export default function App() {
const isReloadingWalletInfo = useMemo(() => reloadingWalletInfoCounter > 0, [reloadingWalletInfoCounter])

const startWallet = useCallback(
(name: Api.WalletName, token: Api.ApiToken) => {
setSession({ name, token })
setCurrentWallet({ name, token })
(name: Api.WalletName, auth: Api.ApiAuthContext) => {
setSession({ name, auth })
setCurrentWallet({ name, token: auth.token })
},
[setCurrentWallet],
)
Expand Down
2 changes: 1 addition & 1 deletion src/components/BitcoinQR.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import QRCode from 'qrcode'

import { satsToBtc } from '../utils'
Expand Down
4 changes: 2 additions & 2 deletions src/components/CoinjoinPreconditionViolationAlert.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { forwardRef } from 'react'
import { Ref, forwardRef } from 'react'
import * as rb from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import { useSettings } from '../context/SettingsContext'
Expand All @@ -14,7 +14,7 @@ interface CoinjoinPreconditionViolationAlertProps {
}

export const CoinjoinPreconditionViolationAlert = forwardRef(
({ summary, i18nPrefix = '' }: CoinjoinPreconditionViolationAlertProps, ref: React.Ref<HTMLDivElement>) => {
({ summary, i18nPrefix = '' }: CoinjoinPreconditionViolationAlertProps, ref: Ref<HTMLDivElement>) => {
const { t } = useTranslation()
const settings = useSettings()

Expand Down
15 changes: 11 additions & 4 deletions src/components/CreateWallet.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,15 @@ export default function CreateWallet({ parentRoute, startWallet }) {
const res = await Api.postWalletCreate({}, { walletname: walletName, password })
const body = await (res.ok ? res.json() : Api.Helper.throwError(res))

const { seedphrase, token, walletname: createdWalletFileName } = body
setCreatedWallet({ walletFileName: createdWalletFileName, seedphrase, password, token })
const { seedphrase, walletname: createdWalletFileName } = body
const auth = {
token: body.token,
token_type: body.token_type,
expires_in: body.expires_in,
scope: body.scope,
refresh_token: body.refresh_token,
}
setCreatedWallet({ walletFileName: createdWalletFileName, seedphrase, password, auth })
} catch (e) {
const message = t('create_wallet.error_creating_failed', {
reason: e.message || 'Unknown reason',
Expand All @@ -112,9 +119,9 @@ export default function CreateWallet({ parentRoute, startWallet }) {
)

const walletConfirmed = useCallback(() => {
if (createdWallet?.walletFileName && createdWallet?.token) {
if (createdWallet?.walletFileName && createdWallet?.auth) {
setAlert(null)
startWallet(createdWallet.walletFileName, createdWallet.token)
startWallet(createdWallet.walletFileName, createdWallet.auth)
navigate(routes.wallet)
} else {
setAlert({ variant: 'danger', message: t('create_wallet.alert_confirmation_failed') })
Expand Down
1 change: 0 additions & 1 deletion src/components/EarnReport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { useTheme } from '@table-library/react-table-library/theme'
import * as rb from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import * as Api from '../libs/JmWalletApi'
// @ts-ignore
import { useSettings } from '../context/SettingsContext'
import Balance from './Balance'
import Sprite from './Sprite'
Expand Down
32 changes: 23 additions & 9 deletions src/components/ImportWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ enum ImportWalletSteps {

interface ImportWalletProps {
parentRoute: Route
startWallet: (name: Api.WalletName, token: Api.ApiToken) => void
startWallet: (name: Api.WalletName, auth: Api.ApiAuthContext) => void
}

export default function ImportWallet({ parentRoute, startWallet }: ImportWalletProps) {
Expand All @@ -388,9 +388,9 @@ export default function ImportWallet({ parentRoute, startWallet }: ImportWalletP
const [alert, setAlert] = useState<SimpleAlert>()
const [createWalletFormValues, setCreateWalletFormValues] = useState<CreateWalletFormValues>()
const [importDetailsFormValues, setImportDetailsFormValues] = useState<ImportWalletDetailsFormValues>()
const [recoveredWallet, setRecoveredWallet] = useState<{ walletFileName: Api.WalletName; token: Api.ApiToken }>()
const [recoveredWallet, setRecoveredWallet] = useState<{ walletFileName: Api.WalletName; auth: Api.ApiAuthContext }>()

const isRecovered = useMemo(() => !!recoveredWallet?.walletFileName && recoveredWallet?.token, [recoveredWallet])
const isRecovered = useMemo(() => !!recoveredWallet?.walletFileName && recoveredWallet?.auth, [recoveredWallet])
const canRecover = useMemo(
() => !isRecovered && !serviceInfo?.walletName && !serviceInfo?.rescanning,
[isRecovered, serviceInfo],
Expand Down Expand Up @@ -441,13 +441,20 @@ export default function ImportWallet({ parentRoute, startWallet }: ImportWalletP
const recoverBody = await (recoverResponse.ok ? recoverResponse.json() : Api.Helper.throwError(recoverResponse))

const { walletname: importedWalletFileName } = recoverBody
setRecoveredWallet({ walletFileName: importedWalletFileName, token: recoverBody.token })
let auth: Api.ApiAuthContext = {
token: recoverBody.token,
token_type: recoverBody.token_type,
expires_in: recoverBody.token_type,
scope: recoverBody.token_type,
refresh_token: recoverBody.token_type,
}
setRecoveredWallet({ walletFileName: importedWalletFileName, auth })

// Step #2: update the gaplimit config value if necessary
const originalGaplimit = await refreshConfigValues({
signal,
keys: [JM_GAPLIMIT_CONFIGKEY],
wallet: { name: importedWalletFileName, token: recoverBody.token },
wallet: { name: importedWalletFileName, token: auth.token },
})
.then((it) => it[JM_GAPLIMIT_CONFIGKEY.section] || {})
.then((it) => parseInt(it[JM_GAPLIMIT_CONFIGKEY.field] || String(JM_GAPLIMIT_DEFAULT), 10))
Expand All @@ -465,16 +472,23 @@ export default function ImportWallet({ parentRoute, startWallet }: ImportWalletP
value: String(gaplimit),
},
],
wallet: { name: importedWalletFileName, token: recoverBody.token },
wallet: { name: importedWalletFileName, token: auth.token },
})
}

// Step #3: lock and unlock the wallet (for new addresses to be imported)
const lockResponse = await Api.getWalletLock({ walletName: importedWalletFileName, token: recoverBody.token })
const lockResponse = await Api.getWalletLock({ walletName: importedWalletFileName, token: auth.token })
if (!lockResponse.ok) await Api.Helper.throwError(lockResponse)

const unlockResponse = await Api.postWalletUnlock({ walletName: importedWalletFileName }, { password })
const unlockBody = await (unlockResponse.ok ? unlockResponse.json() : Api.Helper.throwError(unlockResponse))
auth = {
token: unlockBody.token,
token_type: unlockBody.token_type,
expires_in: unlockBody.expires_in,
scope: unlockBody.scope,
refresh_token: unlockBody.refresh_token,
}

// Step #4: reset `gaplimit´ to previous value if necessary
if (gaplimitUpdateNecessary) {
Expand All @@ -487,7 +501,7 @@ export default function ImportWallet({ parentRoute, startWallet }: ImportWalletP
value: String(originalGaplimit),
},
],
wallet: { name: importedWalletFileName, token: unlockBody.token },
wallet: { name: importedWalletFileName, token: auth.token },
})
}

Expand All @@ -508,7 +522,7 @@ export default function ImportWallet({ parentRoute, startWallet }: ImportWalletP
})
}

startWallet(importedWalletFileName, unlockBody.token)
startWallet(importedWalletFileName, auth)
navigate(routes.wallet)
} catch (e: any) {
if (signal.aborted) return
Expand Down
3 changes: 1 addition & 2 deletions src/components/LogOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import * as rb from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { Helper as ApiHelper } from '../libs/JmWalletApi'
import { fetchLog } from '../libs/JamApi'
// @ts-ignore
import { useSettings } from '../context/SettingsContext'
import { CurrentWallet } from '../context/WalletContext'
import Sprite from './Sprite'
Expand Down
4 changes: 2 additions & 2 deletions src/components/ToggleSwitch.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import { ChangeEvent } from 'react'
import styles from './ToggleSwitch.module.css'

interface ToggleSwitchProps {
Expand All @@ -16,7 +16,7 @@ export default function ToggleSwitch({
toggledOn,
disabled = false,
}: ToggleSwitchProps) {
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation()
onToggle(e.currentTarget.checked)
}
Expand Down
10 changes: 8 additions & 2 deletions src/components/Wallets.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,14 @@ export default function Wallets({ currentWallet, startWallet, stopWallet }) {

setUnlockWalletName(undefined)

const { walletname: unlockedWalletName, token } = body
startWallet(unlockedWalletName, token)
const auth = {
token: body.token,
token_type: body.token_type,
expires_in: body.expires_in,
scope: body.scope,
refresh_token: body.refresh_token,
}
startWallet(body.walletname, auth)
navigate(routes.wallet)
} catch (e) {
const message = e.message.replace('Wallet', walletName)
Expand Down
6 changes: 2 additions & 4 deletions src/components/jar_details/DisplayBranch.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React from 'react'
import { ReactNode } from 'react'
import * as rb from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
// @ts-ignore
import Balance from '../Balance'
// @ts-ignore
import { useSettings } from '../../context/SettingsContext'
import { Branch, BranchEntry } from '../../context/WalletContext'
import styles from './DisplayBranch.module.css'
Expand All @@ -28,7 +26,7 @@ const toSimpleStatus = (value: string) => {
return value.substring(0, indexOfBracket).trim()
}

const toLabelNode = (simpleStatus: string): React.ReactNode => {
const toLabelNode = (simpleStatus: string): ReactNode => {
if (simpleStatus === 'new') return <rb.Badge bg="success">{simpleStatus}</rb.Badge>
if (simpleStatus === 'used') return <rb.Badge bg="secondary">{simpleStatus}</rb.Badge>

Expand Down
5 changes: 2 additions & 3 deletions src/context/ServiceConfigContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { createContext, useCallback, useContext, useEffect, useRef } from 'react'
// @ts-ignore
import { PropsWithChildren, createContext, useCallback, useContext, useEffect, useRef } from 'react'
import { CurrentWallet, useCurrentWallet } from './WalletContext'

import * as Api from '../libs/JmWalletApi'
Expand Down Expand Up @@ -105,7 +104,7 @@ export interface ServiceConfigContextEntry {

const ServiceConfigContext = createContext<ServiceConfigContextEntry | undefined>(undefined)

const ServiceConfigProvider = ({ children }: React.PropsWithChildren<{}>) => {
const ServiceConfigProvider = ({ children }: PropsWithChildren<{}>) => {
const currentWallet = useCurrentWallet()
const serviceConfig = useRef<ServiceConfig | null>(null)

Expand Down
17 changes: 13 additions & 4 deletions src/context/ServiceInfoContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import React, { createContext, useCallback, useContext, useReducer, useState, useEffect, useRef } from 'react'
// @ts-ignore
import {
PropsWithChildren,
Dispatch,
createContext,
useCallback,
useContext,
useReducer,
useState,
useEffect,
useRef,
} from 'react'
import { useCurrentWallet, useSetCurrentWallet } from './WalletContext'
// @ts-ignore
import { useWebsocket } from './WebsocketContext'
Expand Down Expand Up @@ -101,13 +110,13 @@ const toSemVer = (data: JmGetInfoData): SemVer => {
interface ServiceInfoContextEntry {
serviceInfo: ServiceInfo | null
reloadServiceInfo: ({ signal }: { signal: AbortSignal }) => Promise<ServiceInfo>
dispatchServiceInfo: React.Dispatch<Partial<ServiceInfo>>
dispatchServiceInfo: Dispatch<Partial<ServiceInfo>>
connectionError?: Error
}

const ServiceInfoContext = createContext<ServiceInfoContextEntry | undefined>(undefined)

const ServiceInfoProvider = ({ children }: React.PropsWithChildren<{}>) => {
const ServiceInfoProvider = ({ children }: PropsWithChildren<{}>) => {
const currentWallet = useCurrentWallet()
const setCurrentWallet = useSetCurrentWallet()
const websocket = useWebsocket()
Expand Down
4 changes: 2 additions & 2 deletions src/context/WalletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ const WalletContext = createContext<WalletContextEntry | undefined>(undefined)

const restoreWalletFromSession = (): CurrentWallet | null => {
const session = getSession()
return session && session.name && session.token
return session && session.name && session.auth && session.auth.token
? {
name: session.name,
token: session.token,
token: session.auth.token,
}
: null
}
Expand Down
9 changes: 4 additions & 5 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react'
import { StrictMode } from 'react'
import ReactDOM from 'react-dom'
// @ts-ignore

import App from './components/App'
// @ts-ignore
import { SettingsProvider } from './context/SettingsContext'
// @ts-ignore
import { WebsocketProvider } from './context/WebsocketContext'
Expand All @@ -15,7 +14,7 @@ import './index.css'
import './i18n/config'

ReactDOM.render(
<React.StrictMode>
<StrictMode>
<SettingsProvider>
<WalletProvider>
<ServiceConfigProvider>
Expand All @@ -27,6 +26,6 @@ ReactDOM.render(
</ServiceConfigProvider>
</WalletProvider>
</SettingsProvider>
</React.StrictMode>,
</StrictMode>,
document.getElementById('root'),
)
6 changes: 3 additions & 3 deletions src/libs/JmWalletApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ export type TxId = string
export type UtxoId = `${TxId}:${Vout}`

// for JM versions <0.9.11
export type SingleApiTokenContext = {
export type SingleTokenAuthContext = {
token: ApiToken
}

// for JM versions >=0.9.11
export type RefreshApiTokenContext = SingleApiTokenContext & {
export type RefreshTokenAuthContext = SingleTokenAuthContext & {
token_type: string // "bearer"
expires_in: Seconds // 1800
scope: string
refresh_token: ApiToken
}

export type ApiTokenContext = SingleApiTokenContext | RefreshApiTokenContext
export type ApiAuthContext = SingleTokenAuthContext | RefreshTokenAuthContext

type WithWalletName = {
walletName: WalletName
Expand Down
10 changes: 5 additions & 5 deletions src/session.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { WalletName, ApiToken } from './libs/JmWalletApi'
import { WalletName, ApiAuthContext } from './libs/JmWalletApi'

const SESSION_KEY = 'joinmarket'

export interface SessionItem {
name: WalletName
token: ApiToken
auth: ApiAuthContext
}

export const setSession = (session: SessionItem) => sessionStorage.setItem(SESSION_KEY, JSON.stringify(session))

export const getSession = (): SessionItem | null => {
const json = sessionStorage.getItem(SESSION_KEY)
const { name, token }: any = (json && JSON.parse(json)) || {}
if (name && token) {
return { name, token }
const { name, auth }: any = (json && JSON.parse(json)) || {}
if (name && auth?.token) {
return { name, auth }
} else {
clearSession()
return null
Expand Down
12 changes: 5 additions & 7 deletions src/testUtils.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import React from 'react'
import { StrictMode, ReactElement } from 'react'
import { render, RenderOptions } from '@testing-library/react'
import { I18nextProvider } from 'react-i18next'
import { WalletProvider } from './context/WalletContext'
import { ServiceInfoProvider } from './context/ServiceInfoContext'
import { ServiceConfigProvider } from './context/ServiceConfigContext'
// @ts-ignore
import { SettingsProvider } from './context/SettingsContext'
// @ts-ignore
import { WebsocketProvider } from './context/WebsocketContext'
import i18n from './i18n/testConfig'

const AllTheProviders = ({ children }: { children: React.ReactElement }) => {
const AllTheProviders = ({ children }: { children: ReactElement }) => {
return (
<React.StrictMode>
<StrictMode>
<I18nextProvider i18n={i18n}>
<SettingsProvider>
<WalletProvider>
Expand All @@ -24,12 +23,11 @@ const AllTheProviders = ({ children }: { children: React.ReactElement }) => {
</WalletProvider>
</SettingsProvider>
</I18nextProvider>
</React.StrictMode>
</StrictMode>
)
}

const customRender = (ui: React.ReactElement, options?: RenderOptions) =>
render(ui, { wrapper: AllTheProviders, ...options })
const customRender = (ui: ReactElement, options?: RenderOptions) => render(ui, { wrapper: AllTheProviders, ...options })

// re-export everything
export * from '@testing-library/react'
Expand Down

0 comments on commit 1b11609

Please sign in to comment.