diff --git a/public/_headers b/public/_headers index 655d1d2..4a31ddc 100644 --- a/public/_headers +++ b/public/_headers @@ -3,7 +3,7 @@ X-Frame-Options: DENY Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() - Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; worker-src 'self' blob:; frame-ancestors 'none'; base-uri 'self'; form-action 'self' + Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://static.cloudflareinsights.com; script-src-elem 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: blob:; font-src 'self' data: https://cdn.jsdelivr.net; connect-src 'self' https://api.gemmology.dev https://cloudflareinsights.com https://cdn.jsdelivr.net; worker-src 'self' blob:; frame-ancestors 'none'; base-uri 'self'; form-action 'self' Strict-Transport-Security: max-age=31536000; includeSubDomains; preload # Long-cache versioned static assets (Astro hashed bundle) diff --git a/src/components/auth/LockGate.tsx b/src/components/auth/LockGate.tsx deleted file mode 100644 index 55d3767..0000000 --- a/src/components/auth/LockGate.tsx +++ /dev/null @@ -1,237 +0,0 @@ -/** - * LockGate Component - Protects page content with invite code authentication - */ - -import { useState, type ReactNode, type FormEvent } from 'react'; -import { useAuth } from './useAuth'; -import { Button } from '../ui/Button'; -import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../ui/Card'; -import { Tabs, TabsList, TabsTrigger, TabsContent } from '../ui/Tabs'; -import { cn } from '../ui/cn'; - -interface LockGateProps { - children: ReactNode; -} - -export function LockGate({ children }: LockGateProps) { - const { isAuthenticated, isLoading, verifyCode, requestAccess } = useAuth(); - - // Code entry state - const [code, setCode] = useState(''); - const [codeError, setCodeError] = useState(null); - const [codeLoading, setCodeLoading] = useState(false); - - // Request form state - const [email, setEmail] = useState(''); - const [reason, setReason] = useState(''); - const [requestError, setRequestError] = useState(null); - const [requestSuccess, setRequestSuccess] = useState(false); - const [requestLoading, setRequestLoading] = useState(false); - - // Show loading state while checking session - if (isLoading) { - return ( -
-
Loading...
-
- ); - } - - // If authenticated, render children - if (isAuthenticated) { - return <>{children}; - } - - // Handle code submission - const handleCodeSubmit = async (e: FormEvent) => { - e.preventDefault(); - setCodeError(null); - setCodeLoading(true); - - const result = await verifyCode(code.trim()); - - if (!result.success) { - setCodeError(result.error || 'Invalid code'); - } - setCodeLoading(false); - }; - - // Handle request submission - const handleRequestSubmit = async (e: FormEvent) => { - e.preventDefault(); - setRequestError(null); - setRequestLoading(true); - - const result = await requestAccess(email.trim(), reason.trim()); - - if (result.success) { - setRequestSuccess(true); - } else { - setRequestError(result.error || 'Failed to submit request'); - } - setRequestLoading(false); - }; - - // Render lock overlay - return ( -
- - -
- - - -
- Coming Soon - - This feature is still under development. Access is limited to early testers while we work on finishing it. - -
- - - - - - I have a code - - - Request access - - - - -
-
- - setCode(e.target.value.toUpperCase())} - placeholder="GEMSTONE-XXXX-XXXX" - className={cn( - 'w-full px-3 py-2 rounded-lg border text-center font-mono tracking-wider', - 'focus:outline-none focus:ring-2 focus:ring-crystal-500 focus:border-transparent', - codeError ? 'border-red-300 bg-red-50' : 'border-slate-300' - )} - autoComplete="off" - autoFocus - /> - {codeError && ( -

{codeError}

- )} -
- - -
-
- - - {requestSuccess ? ( -
-
- - - -
-

- Request Submitted -

-

- We'll review your request and send you an invite code by email. -

-
- ) : ( -
-
- - setEmail(e.target.value)} - placeholder="you@example.com" - className={cn( - 'w-full px-3 py-2 rounded-lg border', - 'focus:outline-none focus:ring-2 focus:ring-crystal-500 focus:border-transparent', - requestError ? 'border-red-300 bg-red-50' : 'border-slate-300' - )} - required - /> -
- -
- -