feat: osv-scanner in the deps job + desktop welcome sign-in modal
- update-deps.sh now runs osv-scanner (OSV DB) pre/post update, alongside npm audit; it immediately found 107 known vulns (5 critical) npm audit missed (vite/vitest dev deps, xlsx with no fix, zod patch). - Layout opens the themed LoginDialog once for a logged-out desktop visitor (non-native, >=1024px, ~900ms), dismissible and remembered; it also offers SignupDialog. Reuses the existing extension/bunker/Amber/nsec/NostrConnect methods.
This commit is contained in:
parent
4d9389fa48
commit
aa2a70e9fd
3 changed files with 77 additions and 1 deletions
20
AGENTS.md
20
AGENTS.md
|
|
@ -1522,6 +1522,16 @@ session with **no other memory of this project**. So:
|
|||
(which also `saveLastLocation()`s), so `MapPage`'s mount-time
|
||||
`getLastLocation()` opens centered on their area. The logged-out wallet
|
||||
section's dead disabled "Log in first" button became a plain line.
|
||||
- **Desktop welcome sign-in modal (2026-10-26):** `Layout` opens the themed
|
||||
`LoginDialog` **once** for a logged-out **desktop** visitor (non-native,
|
||||
`min-width: 1024px`, after ~900 ms) as a welcome/sign-in offer; dismissal is
|
||||
remembered in `skatespots:desktop-welcome-dismissed`, and it also offers the
|
||||
normal `SignupDialog`. It reuses the existing methods (browser extension,
|
||||
bunker/signer, Amber on Android, nsec, and the **NostrConnect QR**), which is
|
||||
what the reference screenshot showed — the dialog is still **tabbed**, not
|
||||
the reference's 3-card layout (a restyle would need a visual QA pass).
|
||||
⚠️ `SignupDialog` is a **default-only** export, so lazy-load it as
|
||||
`lazy(() => import('…/SignupDialog'))`.
|
||||
- **First-run checklist + backup-reminder gating (fixed 2026-10-12).** Two
|
||||
onboarding prompts nagged returning users:
|
||||
1. `FirstRunChecklist` (map) showed for **any logged-in user** until they
|
||||
|
|
@ -2268,6 +2278,16 @@ Rules:
|
|||
bounds the push (`timeout 180`) since the git remote signs via the remote signer.
|
||||
Timer: `scripts/install-deps-timer.sh` → `skatespots-deps.timer` (daily tick).
|
||||
Flags: `--scan-only`, `--no-push`, `--force`. Logs: `journalctl --user -u skatespots-deps`.
|
||||
**osv-scanner added (2026-10-26):** the scan block now also runs
|
||||
`osv-scanner scan source -L package-lock.json` (binary at
|
||||
`~/go/bin/osv-scanner`, installed with `go install
|
||||
github.com/google/osv-scanner/v2/cmd/osv-scanner@latest`; override with
|
||||
`OSV_BIN`), pre- and post-update, report-only. ⚠️ It immediately found **107
|
||||
known vulnerabilities (5 critical, 53 high)** that `npm audit` was NOT
|
||||
surfacing — mostly **dev-only** `vite`/`vitest` (patchable within-range) plus
|
||||
`xlsx@0.18.5` (two high; **no fix published**) and `zod` (patch). Dev-dep CVEs
|
||||
don't ship to users; `xlsx` is lazy-loaded for exports. Run `--force` to apply
|
||||
the fixable ones (gated on tests).
|
||||
|
||||
### Community relay — self-hosted Newlay (2026-10-12)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ STATE_DIR="${DEPS_STATE_DIR:-$HOME/.local/state/skatespots-deps}"
|
|||
mkdir -p "$STATE_DIR"
|
||||
LAST="$STATE_DIR/last-run"
|
||||
REPORT="$STATE_DIR/report-$(LC_ALL=C date +%F).txt"
|
||||
# OSV-Scanner (broader than npm audit: queries the OSV database for the lockfile).
|
||||
# Installed with: go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest
|
||||
OSV_BIN="${OSV_BIN:-$HOME/go/bin/osv-scanner}"
|
||||
|
||||
SCAN_ONLY=0; NO_PUSH=0; FORCE=0
|
||||
for a in "$@"; do
|
||||
|
|
@ -64,6 +67,13 @@ fi
|
|||
echo
|
||||
echo "=== npm audit ==="
|
||||
npm audit 2>&1 || true
|
||||
echo
|
||||
echo "=== osv-scanner (OSV database) ==="
|
||||
if [ -x "$OSV_BIN" ]; then
|
||||
"$OSV_BIN" scan source -L package-lock.json 2>&1 || true
|
||||
else
|
||||
echo "osv-scanner not installed (expected $OSV_BIN)"
|
||||
fi
|
||||
} | tee "$REPORT"
|
||||
|
||||
if [ "$SCAN_ONLY" -eq 1 ]; then
|
||||
|
|
@ -86,6 +96,8 @@ npm update 2>&1 | tail -3
|
|||
npm audit fix 2>&1 | tail -3
|
||||
{
|
||||
echo; echo "=== post-update npm audit ==="; npm audit 2>&1 || true
|
||||
echo; echo "=== post-update osv-scanner ==="
|
||||
if [ -x "$OSV_BIN" ]; then "$OSV_BIN" scan source -L package-lock.json 2>&1 || true; fi
|
||||
} | tee -a "$REPORT"
|
||||
|
||||
# ── gate: full tests + boot smoke ───────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useRef, lazy, Suspense } from 'react';
|
||||
import { useState, useRef, useEffect, lazy, Suspense } from 'react';
|
||||
import { Link, Outlet, useLocation } from 'react-router-dom';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
|
@ -81,6 +81,7 @@ const LazySetStatusDialog = lazy(() =>
|
|||
const LazyLoginDialog = lazy(() =>
|
||||
import('@/components/auth/LoginDialog').then((m) => ({ default: m.LoginDialog })),
|
||||
);
|
||||
const LazySignupDialog = lazy(() => import('@/components/auth/SignupDialog'));
|
||||
const LazyBackupReminder = lazy(() =>
|
||||
import('@/components/BackupReminder').then((m) => ({ default: m.BackupReminder })),
|
||||
);
|
||||
|
|
@ -516,6 +517,26 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
const [showAddAccount, setShowAddAccount] = useState(false);
|
||||
const { currentMessage, dismissCurrentMessage } = useSasquatchGuide();
|
||||
const { user } = useCurrentUser();
|
||||
|
||||
// Desktop, logged-out, first visit: offer the sign-in modal once. Reuses the
|
||||
// themed LoginDialog/SignupDialog (extension, bunker/signer, Amber, nsec,
|
||||
// NostrConnect QR). Dismissal is remembered so it never nags again.
|
||||
const WELCOME_LOGIN_DISMISSED = 'skatespots:desktop-welcome-dismissed';
|
||||
const [showWelcomeLogin, setShowWelcomeLogin] = useState(false);
|
||||
const [showWelcomeSignup, setShowWelcomeSignup] = useState(false);
|
||||
const dismissWelcomeLogin = () => {
|
||||
try { localStorage.setItem(WELCOME_LOGIN_DISMISSED, '1'); } catch { /* ignore */ }
|
||||
setShowWelcomeLogin(false);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (user || isNativePlatform()) return;
|
||||
try {
|
||||
if (localStorage.getItem(WELCOME_LOGIN_DISMISSED) === '1') return;
|
||||
} catch { return; }
|
||||
if (typeof window === 'undefined' || !window.matchMedia?.('(min-width: 1024px)').matches) return;
|
||||
const timer = window.setTimeout(() => setShowWelcomeLogin(true), 900);
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [user]);
|
||||
const { t } = useTranslation();
|
||||
const { currentUser: currentAccount, removeLogin } = useLoggedInAccounts();
|
||||
const author = useAuthor(user?.pubkey || '');
|
||||
|
|
@ -1163,6 +1184,29 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
/>
|
||||
</Suspense>
|
||||
|
||||
{/* Desktop, logged-out, first visit — one-time sign-in offer */}
|
||||
<Suspense fallback={null}>
|
||||
<LazyLoginDialog
|
||||
isOpen={showWelcomeLogin}
|
||||
onClose={dismissWelcomeLogin}
|
||||
onLogin={dismissWelcomeLogin}
|
||||
onSignup={() => {
|
||||
dismissWelcomeLogin();
|
||||
setShowWelcomeSignup(true);
|
||||
}}
|
||||
/>
|
||||
</Suspense>
|
||||
<Suspense fallback={null}>
|
||||
<LazySignupDialog
|
||||
isOpen={showWelcomeSignup}
|
||||
onClose={() => setShowWelcomeSignup(false)}
|
||||
onUseAmber={() => {
|
||||
setShowWelcomeSignup(false);
|
||||
setShowWelcomeLogin(true);
|
||||
}}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{/* Newsletter: floating pill + Monday admin reminder */}
|
||||
<NewsletterOverlay />
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue