fix: broken profile images (CSP img-src), AI-answer discoverability, arena compose tag
CI / check (push) Failing after 6m10s
CI / check (push) Failing after 6m10s
1. server/src/app.ts: CSP img-src only allowed 'self'/data:/blob: — nostr profile pictures come from kind:0 metadata, a URL the user sets via their own client, hosted on whatever domain they picked. There's no central image host for a decentralized identity system, so every external profile pic was CSP-blocked and rendered as a broken image. Added https: (broad) — safe here since images can't execute script even from an untrusted origin, unlike script-src which stays locked to 'self'. 2. frontend/src/pages/JoinBoutPage.vue: the new AI-answer option (1.2.7) was reported as invisible — it was gated behind picking POLLING (not the default WEBHOOK) AND behind a collapsed toggle within that. Changed: POLLING is now the default mode (also the documented default in BOTFIGHTS.md), the AI section is expanded by default instead of collapsed, and the POLLING button's own description now mentions the option so it's visible without any extra click. 3. docker-compose.arena.yml: image tag 1.2.1 -> 1.2.7, matching what's actually deployed on the canonical arena (rolled live via ssh+docker compose pull/up this session — this commit just brings the repo's copy of the compose file back in sync with reality). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
|
||||
services:
|
||||
botfights-arena:
|
||||
image: localhost:3000/lfg2025/botfights:1.2.1
|
||||
image: localhost:3000/lfg2025/botfights:1.2.7
|
||||
container_name: botfights-arena
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
|
||||
@@ -33,7 +33,12 @@ const isJoiningPractice = ref(false)
|
||||
|
||||
// Bot connection mode
|
||||
const isVerifyingWebhook = ref(false)
|
||||
const connectionMode = ref<'webhook' | 'polling'>('webhook')
|
||||
// Polling is the documented default (BOTFIGHTS.md: "Use this if you didn't
|
||||
// specify a mode — it's simpler and works from any machine") and is also
|
||||
// the only mode the AI-answer option applies to — defaulting here means
|
||||
// that section is visible immediately with zero clicks, not hidden behind
|
||||
// picking a non-default mode first.
|
||||
const connectionMode = ref<'webhook' | 'polling'>('polling')
|
||||
const botSecret = ref('')
|
||||
const botId = ref('')
|
||||
const setupGuideCopied = ref(false)
|
||||
@@ -562,7 +567,10 @@ const aiApiKey = ref('')
|
||||
const aiConfigured = ref(false)
|
||||
const aiSaving = ref(false)
|
||||
const aiError = ref('')
|
||||
const showAiSetup = ref(false)
|
||||
// Expanded by default (not collapsed) — this is the whole point of the
|
||||
// feature ("don't want to run a script?"), it needs to be immediately
|
||||
// visible the moment poll mode is picked, not hidden behind another click.
|
||||
const showAiSetup = ref(true)
|
||||
|
||||
async function saveAiConfig() {
|
||||
if (!botId.value || !botSecret.value || !aiApiKey.value.trim()) return
|
||||
@@ -1072,7 +1080,8 @@ function handleSignOut() {
|
||||
<span class="font-mono text-[9px] px-1.5 py-0.5 border border-border text-text-muted">EASIEST</span>
|
||||
</div>
|
||||
<p class="font-mono text-[10px] text-text-muted leading-relaxed">
|
||||
Your bot polls us. No public URL needed. Just keep it running.
|
||||
Your bot polls us. No public URL needed. Just keep it running —
|
||||
or skip the script entirely and let BotFights answer with your own AI key.
|
||||
</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
+8
-1
@@ -67,7 +67,14 @@ app.use('*', secureHeaders({
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'", 'blob:', "'wasm-unsafe-eval'"],
|
||||
styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
|
||||
imgSrc: ["'self'", 'data:', 'blob:'],
|
||||
// https: (broad) is required, not optional: profile pictures come from
|
||||
// nostr kind:0 metadata events — a URL the USER sets via their own
|
||||
// client, hosted on whatever domain they picked. There is no central
|
||||
// image host to allowlist for a decentralized identity system. Images
|
||||
// can't execute script even from an untrusted origin, so this is the
|
||||
// standard, safe CSP relaxation for user-supplied avatar URLs (unlike
|
||||
// broadening script-src, which stays locked to 'self').
|
||||
imgSrc: ["'self'", 'data:', 'blob:', 'https:'],
|
||||
connectSrc: ["'self'", 'https://huggingface.co', 'https://*.huggingface.co', 'https://*.hf.co', 'https://cdn.jsdelivr.net', 'wss://relay.damus.io', 'wss://relay.nostr.band', 'wss://nos.lol'],
|
||||
fontSrc: ["'self'", 'https://fonts.gstatic.com'],
|
||||
workerSrc: ["'self'", 'blob:'],
|
||||
|
||||
Reference in New Issue
Block a user