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
122 lines (115 loc) · 3.74 KB
/
Copy pathinsecure-password-protected.tsx
File metadata and controls
122 lines (115 loc) · 3.74 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"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>
);
}