feat: add captcha-backed forum security hardening
This commit is contained in:
65
resources/js/lib/security/botFingerprint.js
Normal file
65
resources/js/lib/security/botFingerprint.js
Normal file
@@ -0,0 +1,65 @@
|
||||
async function sha256Hex(value) {
|
||||
if (!window.crypto?.subtle) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const encoded = new TextEncoder().encode(value)
|
||||
const digest = await window.crypto.subtle.digest('SHA-256', encoded)
|
||||
return Array.from(new Uint8Array(digest))
|
||||
.map((part) => part.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
function readWebglVendor() {
|
||||
try {
|
||||
const canvas = document.createElement('canvas')
|
||||
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
|
||||
if (!gl) {
|
||||
return 'no-webgl'
|
||||
}
|
||||
|
||||
const extension = gl.getExtension('WEBGL_debug_renderer_info')
|
||||
if (!extension) {
|
||||
return 'webgl-hidden'
|
||||
}
|
||||
|
||||
return [
|
||||
gl.getParameter(extension.UNMASKED_VENDOR_WEBGL),
|
||||
gl.getParameter(extension.UNMASKED_RENDERER_WEBGL),
|
||||
].join(':')
|
||||
} catch {
|
||||
return 'webgl-error'
|
||||
}
|
||||
}
|
||||
|
||||
export async function buildBotFingerprint() {
|
||||
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'unknown'
|
||||
const screenSize = typeof window.screen !== 'undefined'
|
||||
? `${window.screen.width}x${window.screen.height}x${window.devicePixelRatio || 1}`
|
||||
: 'no-screen'
|
||||
|
||||
const payload = [
|
||||
navigator.userAgent || 'unknown-ua',
|
||||
navigator.language || 'unknown-language',
|
||||
navigator.platform || 'unknown-platform',
|
||||
timezone,
|
||||
screenSize,
|
||||
readWebglVendor(),
|
||||
].join('|')
|
||||
|
||||
return sha256Hex(payload)
|
||||
}
|
||||
|
||||
export async function populateBotFingerprint(form) {
|
||||
if (!form) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const fingerprint = await buildBotFingerprint()
|
||||
const field = form.querySelector('input[name="_bot_fingerprint"]')
|
||||
if (field && fingerprint !== '') {
|
||||
field.value = fingerprint
|
||||
}
|
||||
|
||||
return fingerprint
|
||||
}
|
||||
Reference in New Issue
Block a user