fix: container DNS, nginx chown, onboarding guard, seed UX, install flow

Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
  Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
  (fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)

Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
  signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
  back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
  installed/installing apps from marketplace and discover views

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-01 13:06:57 +01:00
co-authored by Claude Opus 4.6
parent b4a57e83d0
commit 6d3704fff5
14 changed files with 3874 additions and 233 deletions
+20 -2
View File
@@ -1,6 +1,6 @@
<template>
<div class="h-[100dvh] flex items-center justify-center p-3 sm:p-4 md:p-6">
<div class="max-w-[800px] w-full max-h-full relative z-10 path-glass-container onb-scroll-container flex flex-col">
<div class="max-w-[800px] w-full max-h-full relative z-10 onb-scroll-container flex flex-col">
<!-- Header (hidden after verification) -->
<div v-if="!verified" class="text-center flex-shrink-0 px-3 sm:px-4 pt-4 sm:pt-6 pb-2 sm:pb-3">
<h1 class="text-xl sm:text-2xl md:text-[26px] font-semibold text-white/96 mb-1.5 drop-shadow-[0_2px_6px_rgba(0,0,0,0.4)]">
@@ -168,7 +168,24 @@ onMounted(() => {
return
}
words.value = JSON.parse(stored)
challengeIndices.value = pickRandomIndices(4, 24)
// Restore challenge indices so going back and returning asks the same words
const savedIndices = sessionStorage.getItem('_seed_challenge_indices')
if (savedIndices) {
try {
const parsed = JSON.parse(savedIndices)
if (Array.isArray(parsed) && parsed.length === 4) {
challengeIndices.value = parsed
} else {
challengeIndices.value = pickRandomIndices(4, 24)
}
} catch {
challengeIndices.value = pickRandomIndices(4, 24)
}
} else {
challengeIndices.value = pickRandomIndices(4, 24)
}
sessionStorage.setItem('_seed_challenge_indices', JSON.stringify(challengeIndices.value))
nextTick(() => {
setTimeout(() => inputRefs.value[0]?.focus({ preventScroll: true }), 300)
@@ -232,6 +249,7 @@ async function verify() {
localStorage.setItem('neode_did', res.did)
if (res.nostr_npub) localStorage.setItem('neode_nostr_npub', res.nostr_npub)
sessionStorage.removeItem('_seed_words')
sessionStorage.removeItem('_seed_challenge_indices')
nextTick(() => {
setTimeout(() => continueButton.value?.focus({ preventScroll: true }), 100)