- Changed community IDs for various components in graph.json to reflect updated associations. - Added Cache-Control headers to the challenge and config methods in CaptchaController to prevent caching by CDNs and proxies. - Updated the Altcha widget in home.html.twig to include a language attribute for better localization. - Added a new AST cache file for CaptchaController to improve performance. - Updated manifest.json with new modification times and AST hashes for several files.
70 lines
2.8 KiB
TypeScript
70 lines
2.8 KiB
TypeScript
import React, { useEffect, useRef, useState } from 'react';
|
|
import 'altcha';
|
|
import 'altcha/i18n/fa'; // ثبت locale رسمی فارسی → با language="fa" فعال میشود
|
|
|
|
// ALTCHA خودمیزبان: widget با گرفتن challenge از بکاند، proof-of-work را در
|
|
// پسزمینهی مرورگر حل میکند و مقدار base64 حلشده را در event `verified` میدهد.
|
|
// این مقدار باید در بدنهی درخواستِ endpoint عمومی با کلید `altcha` ارسال شود.
|
|
|
|
interface AltchaProps {
|
|
onVerified: (payload: string) => void;
|
|
challengeUrl?: string;
|
|
}
|
|
|
|
// altcha-widget یک custom element است؛ به JSX معرفی میشود (React 19: namespace زیر React.JSX).
|
|
declare module 'react' {
|
|
namespace JSX {
|
|
interface IntrinsicElements {
|
|
'altcha-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
|
|
challengeurl?: string;
|
|
strings?: string;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
export default function Altcha({ onVerified, challengeUrl = '/api/v1/altcha/challenge' }: AltchaProps) {
|
|
const ref = useRef<HTMLElement>(null);
|
|
// null=در حال بررسی وضعیت، true/false=فعال/غیرفعال بودن کپچا در سرور
|
|
const [enabled, setEnabled] = useState<boolean | null>(null);
|
|
|
|
useEffect(() => {
|
|
let alive = true;
|
|
fetch('/api/v1/altcha/config')
|
|
.then((r) => r.json())
|
|
.then((c) => {
|
|
if (!alive) return;
|
|
setEnabled(!!c.enabled);
|
|
if (!c.enabled) onVerified(''); // کپچا خاموش → فرم بدون مانع ارسال شود
|
|
})
|
|
.catch(() => { if (alive) setEnabled(false); });
|
|
return () => { alive = false; };
|
|
}, [onVerified]);
|
|
|
|
// config (challengeurl/strings/auto) را با setAttribute ست میکنیم، نه JSX prop —
|
|
// React ممکن است پراپ custom element را بهصورت property ست کند و widget آن را
|
|
// نخواند؛ نتیجه challengeurl خالی و fetch صفحهی جاری (HTML) بهجای JSON بود.
|
|
useEffect(() => {
|
|
if (enabled !== true) return;
|
|
const el = ref.current;
|
|
if (!el) return;
|
|
|
|
const onStateChange = (e: Event) => {
|
|
const detail = (e as CustomEvent).detail as { state?: string; payload?: string };
|
|
if (detail?.state === 'verified' && detail.payload) {
|
|
onVerified(detail.payload);
|
|
}
|
|
};
|
|
|
|
el.setAttribute('challengeurl', challengeUrl);
|
|
el.setAttribute('language', 'fa');
|
|
el.setAttribute('auto', 'onload');
|
|
el.addEventListener('statechange', onStateChange);
|
|
return () => el.removeEventListener('statechange', onStateChange);
|
|
}, [onVerified, enabled, challengeUrl]);
|
|
|
|
if (enabled !== true) return null;
|
|
|
|
return <altcha-widget ref={ref as React.Ref<HTMLElement>} />;
|
|
}
|