fix: Phase 5 — XSS sanitization, cookie security, redirect validation, input trimming
- BootScreen + Settings: v-html now uses DOMPurify.sanitize() for SVG content - FileBrowser cookie: added Secure flag and 24h expiration - TOTP secret: hidden by default with reveal toggle button - Login redirect: validates URL is local-origin before redirecting - Auth fields: password inputs trimmed before submission - Route params: appId validated against safe pattern, invalid IDs redirect to /apps Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -283,10 +283,16 @@
|
||||
<template v-else-if="totpSetupStep === 2">
|
||||
<h3 class="text-lg font-semibold text-white mb-2">{{ t('settings.scanQrCode') }}</h3>
|
||||
<p class="text-white/60 text-sm mb-4">{{ t('settings.scanQrInstruction') }}</p>
|
||||
<div class="flex justify-center mb-4 bg-white rounded-xl p-4 mx-auto w-fit" v-html="totpQrSvg" />
|
||||
<div class="bg-black/30 rounded-lg px-3 py-2 mb-4">
|
||||
<p class="text-xs text-white/50 mb-1">{{ t('settings.manualEntryKey') }}</p>
|
||||
<p class="text-sm font-mono text-orange-400 break-all select-all">{{ totpSecretBase32 }}</p>
|
||||
<div class="flex justify-center mb-4 bg-white rounded-xl p-4 mx-auto w-fit" v-html="sanitizedQrSvg" />
|
||||
<div v-if="totpSecretBase32" class="bg-black/30 rounded-lg px-3 py-2 mb-4">
|
||||
<p class="text-xs text-white/50 mb-1">Manual entry key (keep secret!):</p>
|
||||
<div v-if="showTotpSecret" class="flex items-center gap-2">
|
||||
<p class="text-sm font-mono text-orange-400 break-all">{{ totpSecretBase32 }}</p>
|
||||
<button type="button" class="glass-button text-xs px-2 py-1" @click="showTotpSecret = false">Hide</button>
|
||||
</div>
|
||||
<button v-else type="button" class="glass-button text-xs px-3 py-1" @click="showTotpSecret = true">
|
||||
Show manual entry key
|
||||
</button>
|
||||
</div>
|
||||
<form @submit.prevent="confirmTotpSetup" class="space-y-4">
|
||||
<input
|
||||
@@ -859,6 +865,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onMounted, nextTick } from 'vue'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { SUPPORTED_LOCALES, setLocale, type SupportedLocale } from '@/i18n'
|
||||
@@ -1018,7 +1025,9 @@ const totpSetupCode = ref('')
|
||||
const totpSetupError = ref('')
|
||||
const totpSetupLoading = ref(false)
|
||||
const totpQrSvg = ref('')
|
||||
const sanitizedQrSvg = computed(() => DOMPurify.sanitize(totpQrSvg.value, { USE_PROFILES: { svg: true } }))
|
||||
const totpSecretBase32 = ref('')
|
||||
const showTotpSecret = ref(false)
|
||||
const totpPendingToken = ref('')
|
||||
const totpBackupCodes = ref<string[]>([])
|
||||
const backupCodesCopied = ref(false)
|
||||
|
||||
Reference in New Issue
Block a user