155 lines
4.7 KiB
TypeScript
155 lines
4.7 KiB
TypeScript
import { nostrAuthService } from '@/lib/nostrAuth'
|
|
import { keyManagementService } from '@/lib/keyManagement'
|
|
import { t } from '@/lib/i18n'
|
|
import type { PublicKeys } from './types'
|
|
import { extractKeyFromInput, isValidPrivateKeyFormat } from './keyImportParsing'
|
|
|
|
export interface KeyManagementManagerState {
|
|
publicKeys: PublicKeys | null
|
|
accountExists: boolean
|
|
loading: boolean
|
|
error: string | null
|
|
importKey: string
|
|
importing: boolean
|
|
showImportForm: boolean
|
|
showReplaceWarning: boolean
|
|
recoveryPhrase: string[] | null
|
|
newNpub: string | null
|
|
copiedNpub: boolean
|
|
copiedPublicKey: boolean
|
|
copiedRecoveryPhrase: boolean
|
|
}
|
|
|
|
export type PatchState = (patch: Partial<KeyManagementManagerState>) => void
|
|
|
|
export const INITIAL_KEY_MANAGEMENT_STATE: KeyManagementManagerState = {
|
|
publicKeys: null,
|
|
accountExists: false,
|
|
loading: true,
|
|
error: null,
|
|
importKey: '',
|
|
importing: false,
|
|
showImportForm: false,
|
|
showReplaceWarning: false,
|
|
recoveryPhrase: null,
|
|
newNpub: null,
|
|
copiedNpub: false,
|
|
copiedPublicKey: false,
|
|
copiedRecoveryPhrase: false,
|
|
}
|
|
|
|
export async function loadKeys(params: { patchState: PatchState }): Promise<void> {
|
|
try {
|
|
params.patchState({ loading: true, error: null })
|
|
const exists = await nostrAuthService.accountExists()
|
|
params.patchState({ accountExists: exists })
|
|
if (!exists) {
|
|
params.patchState({ publicKeys: null })
|
|
return
|
|
}
|
|
const keys = await keyManagementService.getPublicKeys()
|
|
params.patchState({ publicKeys: keys ?? null })
|
|
} catch (e) {
|
|
const errorMessage = e instanceof Error ? e.message : t('settings.keyManagement.loading')
|
|
params.patchState({ error: errorMessage })
|
|
console.error('[KeyManagement] Error loading keys:', e)
|
|
} finally {
|
|
params.patchState({ loading: false })
|
|
}
|
|
}
|
|
|
|
export async function handleImport(params: {
|
|
state: KeyManagementManagerState
|
|
patchState: PatchState
|
|
}): Promise<void> {
|
|
const extractedKey = validateAndExtractImportKey({ importKey: params.state.importKey, patchState: params.patchState })
|
|
if (!extractedKey) {
|
|
return
|
|
}
|
|
if (params.state.accountExists) {
|
|
params.patchState({ showReplaceWarning: true })
|
|
return
|
|
}
|
|
await performImport({ key: extractedKey, accountExists: false, patchState: params.patchState })
|
|
}
|
|
|
|
export async function confirmReplace(params: {
|
|
state: KeyManagementManagerState
|
|
patchState: PatchState
|
|
}): Promise<void> {
|
|
const extractedKey = validateAndExtractImportKey({ importKey: params.state.importKey, patchState: params.patchState })
|
|
if (!extractedKey) {
|
|
return
|
|
}
|
|
await performImport({ key: extractedKey, accountExists: true, patchState: params.patchState })
|
|
}
|
|
|
|
function validateAndExtractImportKey(params: { importKey: string; patchState: PatchState }): string | null {
|
|
if (!params.importKey.trim()) {
|
|
params.patchState({ error: t('settings.keyManagement.import.error.required') })
|
|
return null
|
|
}
|
|
const extractedKey = extractKeyFromInput(params.importKey)
|
|
if (!extractedKey) {
|
|
params.patchState({ error: t('settings.keyManagement.import.error.invalid') })
|
|
return null
|
|
}
|
|
if (!isValidPrivateKeyFormat(extractedKey)) {
|
|
params.patchState({ error: t('settings.keyManagement.import.error.invalid') })
|
|
return null
|
|
}
|
|
return extractedKey
|
|
}
|
|
|
|
async function performImport(params: {
|
|
key: string
|
|
accountExists: boolean
|
|
patchState: PatchState
|
|
}): Promise<void> {
|
|
try {
|
|
params.patchState({ importing: true, error: null, showReplaceWarning: false })
|
|
if (params.accountExists) {
|
|
await nostrAuthService.deleteAccount()
|
|
}
|
|
const result = await nostrAuthService.createAccount(params.key)
|
|
params.patchState({
|
|
recoveryPhrase: result.recoveryPhrase,
|
|
newNpub: result.npub,
|
|
importKey: '',
|
|
showImportForm: false,
|
|
})
|
|
await loadKeys({ patchState: params.patchState })
|
|
await maybeStartUserSync({ publicKey: result.publicKey })
|
|
} catch (e) {
|
|
const errorMessage = e instanceof Error ? e.message : t('settings.keyManagement.import.error.failed')
|
|
params.patchState({ error: errorMessage })
|
|
console.error('[KeyManagement] Error importing key:', e)
|
|
} finally {
|
|
params.patchState({ importing: false })
|
|
}
|
|
}
|
|
|
|
async function maybeStartUserSync(params: { publicKey: string | undefined }): Promise<void> {
|
|
if (!params.publicKey) {
|
|
return
|
|
}
|
|
const { swClient } = await import('@/lib/swClient')
|
|
const isReady = await swClient.isReady()
|
|
if (isReady) {
|
|
void swClient.startUserSync(params.publicKey)
|
|
}
|
|
}
|
|
|
|
export async function copyToClipboard(params: {
|
|
text: string
|
|
onCopied: () => void
|
|
onCopyFailed: (error: unknown) => void
|
|
}): Promise<void> {
|
|
try {
|
|
await navigator.clipboard.writeText(params.text)
|
|
params.onCopied()
|
|
} catch (e) {
|
|
params.onCopyFailed(e)
|
|
}
|
|
}
|