72 lines
2.1 KiB
Vue
72 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
const { $i18n } = useNuxtApp()
|
|
const t = $i18n.t
|
|
|
|
defineProps<{
|
|
modelValue: string
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [value: string]
|
|
}>()
|
|
|
|
function sanitize(text: string): string {
|
|
let clean = text
|
|
clean = clean.replace(/<[^>]*>/g, '')
|
|
clean = clean.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
|
clean = clean.replace(/https?:\/\/[^\s]+/gi, '')
|
|
clean = clean.replace(/www\.[^\s]+/gi, '')
|
|
clean = clean.replace(/javascript\s*:/gi, '')
|
|
clean = clean.replace(/\beval\s*\(/gi, '')
|
|
clean = clean.replace(/\bon\w+\s*=/gi, '')
|
|
clean = clean.replace(/[A-Za-z0-9+/]{50,}={0,2}/g, '')
|
|
clean = clean.replace(/'\s*OR\s+\d+\s*=\s*\d+/gi, '')
|
|
clean = clean.replace(/'\s*--/g, "'")
|
|
clean = clean.replace(/'\s*;\s*DROP\s+TABLE/gi, "'")
|
|
clean = clean.replace(/UNION\s+SELECT/gi, '')
|
|
clean = clean.replace(/xp_cmdshell/gi, '')
|
|
clean = clean.replace(/EXEC\s*\(/gi, '')
|
|
clean = clean.replace(/`[^`]*`/g, '')
|
|
clean = clean.replace(/\$\(.*?\)/g, '')
|
|
clean = clean.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '')
|
|
return clean.slice(0, 500)
|
|
}
|
|
|
|
function onInput(value: string) {
|
|
emit('update:modelValue', sanitize(value))
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<UCard class="w-full max-w-xl shadow-sm">
|
|
<div class="flex flex-col items-center gap-4 py-4">
|
|
<UIcon name="i-lucide-bug" class="size-10 text-carpablue" />
|
|
|
|
<div class="text-center space-y-1">
|
|
<h2 class="text-lg font-semibold text-highlighted">
|
|
{{ t('feedback.title') }}
|
|
</h2>
|
|
<p class="text-sm text-muted leading-relaxed max-w-sm">
|
|
{{ t('feedback.description') }}
|
|
</p>
|
|
</div>
|
|
|
|
<UTextarea
|
|
:model-value="modelValue"
|
|
:placeholder="t('feedback.placeholder')"
|
|
:rows="6"
|
|
:maxlength="500"
|
|
autoresize
|
|
size="lg"
|
|
class="w-full"
|
|
@update:model-value="onInput($event)"
|
|
/>
|
|
|
|
<div class="flex items-center justify-between w-full text-xs text-muted">
|
|
<span>{{ t('feedback.anonymous_notice') }}</span>
|
|
<span>{{ modelValue.length }}/500</span>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
</template>
|