2026-03-22 03:30:21 +00:00
|
|
|
/** Composable for managing app identity selection and NIP-07 identity injection */
|
|
|
|
|
|
|
|
|
|
import { type Ref } from 'vue'
|
|
|
|
|
import { rpcClient } from '@/api/rpc-client'
|
|
|
|
|
|
|
|
|
|
const IDENTITY_KEY = 'archipelago_app_identity_'
|
|
|
|
|
|
|
|
|
|
export interface SelectedIdentity {
|
|
|
|
|
id: string
|
|
|
|
|
name: string
|
|
|
|
|
did: string
|
|
|
|
|
pubkey: string
|
|
|
|
|
nostr_pubkey?: string
|
|
|
|
|
nostr_npub?: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isIdentityAwareApp(id: string): boolean {
|
fix: BUILD_VERSION from Cargo.toml, kiosk scaling, new apps, Rust warnings
Critical:
- BUILD_VERSION was hardcoded as "1.3.0-alpha" — now reads from Cargo.toml
This caused ALL ISOs to show v1.3.0 regardless of actual binary version
Kiosk:
- Remove --disable-gpu flags (broke display scaling on some monitors)
- Add --start-fullscreen --window-size for reliable fullscreen
New apps:
- Nostr VPN, FIPS, Routstr, noStrudel, BotFights, NWNN, 484 Kitchen,
Call the Operator, Arch Presentation, Syntropy Institute, T-0
Rust: suppress dead_code and unused_assignments warnings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 00:35:52 +01:00
|
|
|
return id === 'indeedhub' || id === 'nostrudel' || id === 'routstr'
|
2026-03-22 03:30:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useAppIdentity(
|
|
|
|
|
appId: Ref<string>,
|
|
|
|
|
iframeRef: Ref<HTMLIFrameElement | null>,
|
|
|
|
|
showIdentityPicker: Ref<boolean>,
|
|
|
|
|
) {
|
|
|
|
|
function getStoredIdentity(): SelectedIdentity | null {
|
|
|
|
|
try {
|
|
|
|
|
const stored = localStorage.getItem(IDENTITY_KEY + appId.value)
|
|
|
|
|
return stored ? JSON.parse(stored) as SelectedIdentity : null
|
|
|
|
|
} catch { return null }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function storeIdentity(identity: SelectedIdentity) {
|
|
|
|
|
try { localStorage.setItem(IDENTITY_KEY + appId.value, JSON.stringify(identity)) } catch {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function sendIdentity(identity: SelectedIdentity) {
|
|
|
|
|
try {
|
|
|
|
|
const challenge = `archipelago-identity:${Date.now()}`
|
|
|
|
|
const sigRes = await rpcClient.call<{ signature: string }>({ method: 'identity.sign', params: { id: identity.id, message: challenge } })
|
|
|
|
|
iframeRef.value?.contentWindow?.postMessage({
|
|
|
|
|
type: 'archipelago:identity', did: identity.did, name: identity.name,
|
|
|
|
|
pubkey: identity.pubkey, nostr_pubkey: identity.nostr_pubkey || null,
|
|
|
|
|
nostr_npub: identity.nostr_npub || null, challenge, signature: sigRes.signature
|
|
|
|
|
}, '*')
|
|
|
|
|
} catch {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onIdentitySelected(identity: SelectedIdentity) {
|
|
|
|
|
showIdentityPicker.value = false
|
|
|
|
|
storeIdentity(identity)
|
|
|
|
|
sendIdentity(identity)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Called on iframe load to inject identity if the app supports it */
|
|
|
|
|
function onIframeLoadIdentity() {
|
|
|
|
|
if (isIdentityAwareApp(appId.value)) {
|
|
|
|
|
const stored = getStoredIdentity()
|
|
|
|
|
if (stored) sendIdentity(stored)
|
|
|
|
|
else showIdentityPicker.value = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Handle identity request messages from iframe */
|
|
|
|
|
function handleIdentityRequest() {
|
|
|
|
|
const stored = getStoredIdentity()
|
|
|
|
|
if (stored) sendIdentity(stored)
|
|
|
|
|
else showIdentityPicker.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
getStoredIdentity,
|
|
|
|
|
sendIdentity,
|
|
|
|
|
onIdentitySelected,
|
|
|
|
|
onIframeLoadIdentity,
|
|
|
|
|
handleIdentityRequest,
|
|
|
|
|
}
|
|
|
|
|
}
|