diff --git a/docker-compose.arena.yml b/docker-compose.arena.yml index cc25ee7..42d9d93 100644 --- a/docker-compose.arena.yml +++ b/docker-compose.arena.yml @@ -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: diff --git a/frontend/src/pages/JoinBoutPage.vue b/frontend/src/pages/JoinBoutPage.vue index bfc648d..8163ca9 100644 --- a/frontend/src/pages/JoinBoutPage.vue +++ b/frontend/src/pages/JoinBoutPage.vue @@ -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() { EASIEST
- 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.
diff --git a/server/src/app.ts b/server/src/app.ts index b26e7ea..da05249 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -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:'],