forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinsecure-password-protected.tsx
More file actions
108 lines (101 loc) · 3.63 KB
/
Copy pathinsecure-password-protected.tsx
File metadata and controls
108 lines (101 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
'use client';
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
interface InsecurePasswordProtectedProps {
password?: string;
unauthenticatedComponent?: React.ReactNode;
children: React.ReactNode;
}
const defaultUnauthenticatedComponent = (
<div className="space-y-4 text-center">
<h3 className="text-xl font-bold">This content is protected by a password.</h3>
<div className="text-base mx-auto">
<p>
This content is for an upcoming release and not yet publicly available. If you’d like to apply for early access, please
<a target="_blank" rel="noreferrer" href="https://go.copilotkit.ai/earlyaccess" className="ml-1 underline">click here.</a>
</p>
<p>If you’re already apart of the early adopter group, please enter your password!</p>
</div>
</div>
)
/**
* This component is used to "protect" content that is not intended for public consumption yet, i.e. early access content.
*
* For the moment this is completely insecure, as it relies on a single shared password for all users that is publicly
* viewable. Additionally, the password can be easily bypassed.
*
* However, this is fine for us as the content is not a secret or sensitive. We just want to prevent dissuade users from
* using the content outside of the early adopter group, not completely prevent it.
*/
export function InsecurePasswordProtected({
password = process.env.NEXT_PUBLIC_LGC_DOCS_PASSWORD,
unauthenticatedComponent = defaultUnauthenticatedComponent,
children
}: InsecurePasswordProtectedProps) {
const [input, setInput] = useState('');
const [error, setError] = useState('');
const [storedPassword, setStoredPassword] = useState(() => {
// Initialize state from localStorage if available
if (typeof window !== 'undefined') {
return localStorage.getItem('storedPassword') || '';
}
return '';
});
if (!password) {
return <>{children}</>;
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (input === password) {
setStoredPassword(input);
setError('');
localStorage.setItem('storedPassword', input);
} else {
setError('Incorrect password');
setInput('');
}
};
if (storedPassword === password) {
return <>{children}</>;
}
return (
<div className="w-full">
<div className="hidden">
If you're looking at this code, you'll probably notice that this is a very shallow layer of security. This
is very intentional, we don't want to make it impossible for users to access this content just
difficult until we're ready to make it readily available.
</div>
<div className="flex flex-col gap-6 p-8 border rounded-lg shadow-lg">
{unauthenticatedComponent}
<hr className="my-0" />
<div className="flex gap-4">
<Input
type="password"
autoComplete="off"
className='w-full'
placeholder="Enter password..."
onKeyDown={(e) => {
if (e.key === 'Enter') {
handleSubmit(e);
}
}}
value={input}
onChange={(e) => {
setInput(e.target.value);
setError('');
}}
aria-invalid={!!error}
aria-describedby={error ? "password-error" : undefined}
/>
<Button onClick={handleSubmit}>Submit</Button>
</div>
{error && (
<p id="password-error" className="text-sm text-red-500 mt-1">
{error}
</p>
)}
</div>
</div>
);
}