Skip to content

Commit 46e614f

Browse files
Merge pull request #90 from TTMordred/pls_portfolio
ghhhhhh
2 parents 3b54e9f + 8a039c0 commit 46e614f

12 files changed

Lines changed: 1521 additions & 209 deletions

File tree

app/login/page.tsx

Lines changed: 133 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -22,63 +22,31 @@ import okxModule from "@web3-onboard/okx";
2222
import frontierModule from "@web3-onboard/frontier";
2323
import { useAuth } from "@/lib/context/AuthContext";
2424
import { useSettings } from "@/components/context/SettingsContext";
25-
import CryptoJS from "crypto-js"; // Still imported but not used in encryption here
26-
import bcrypt from "bcryptjs"; // Import bcryptjs
25+
import { Subscription } from "@supabase/supabase-js";
26+
import bcrypt from "bcryptjs"; // Thêm bcryptjs để hash mật khẩu
27+
import crypto from "crypto"; // Dùng crypto để mã hóa dữ liệu
2728

28-
// Secret key (should ideally be stored in environment variables)
29-
const SECRET_KEY = process.env.NEXT_PUBLIC_ENCRYPTION_KEY || "my-secret-key-1234567890";
30-
31-
// Function to hash a password
32-
const hashPassword = (password: string): string => {
33-
const salt = bcrypt.genSaltSync(10);
34-
return bcrypt.hashSync(password, salt);
35-
};
36-
37-
// Function to hash data (replacing encryptData)
38-
const encryptData = (data: string): string => {
39-
return bcrypt.hashSync(data, 10);
40-
};
41-
42-
// Function to "decrypt" data (not possible with bcrypt)
43-
const decryptData = (encryptedData: string): string => {
44-
// bcrypt is a one-way hashing algorithm, so we cannot decrypt
45-
throw new Error("Cannot decrypt data hashed with bcrypt");
46-
};
47-
48-
// Rest of your wallet configurations remain unchanged
49-
const dcent = dcentModule();
29+
// Web3-Onboard configuration
5030
const INFURA_KEY = "7d389678fba04ceb9510b2be4fff5129";
51-
5231
const walletConnect = walletConnectModule({
5332
projectId: "b773e42585868b9b143bb0f1664670f1",
5433
optionalChains: [1, 137],
5534
});
5635

57-
const injected = injectedModule();
58-
const coinbase = coinbaseModule();
59-
const infinityWallet = infinityWalletModule();
60-
const safe = safeModule();
61-
const sequence = sequenceModule();
62-
const taho = tahoModule();
63-
const trust = trustModule();
64-
const okx = okxModule();
65-
const frontier = frontierModule();
66-
const trezor = trezorModule({ email: "test@test.com", appUrl: "https://www.blocknative.com" });
67-
const magic = magicModule({ apiKey: "pk_live_E9B0C0916678868E" });
68-
6936
const wallets = [
70-
infinityWallet,
71-
sequence,
72-
injected,
73-
trust,
74-
okx,
75-
frontier,
76-
taho,
77-
coinbase,
78-
dcent,
37+
infinityWalletModule(),
38+
sequenceModule(),
39+
injectedModule(),
40+
trustModule(),
41+
okxModule(),
42+
frontierModule(),
43+
tahoModule(),
44+
coinbaseModule(),
45+
dcentModule(),
7946
walletConnect,
80-
safe,
81-
magic,
47+
safeModule(),
48+
magicModule({ apiKey: "pk_live_E9B0C0916678868E" }),
49+
trezorModule({ email: "test@test.com", appUrl: "https://www.blocknative.com" }),
8250
];
8351

8452
const chains = [
@@ -104,43 +72,103 @@ const appMetadata = {
10472

10573
const web3Onboard = init({ wallets, chains, appMetadata });
10674

75+
// Debounce utility with proper TypeScript types
76+
const debounce = <T extends (...args: any[]) => void>(
77+
func: T,
78+
wait: number
79+
): ((...args: Parameters<T>) => void) => {
80+
let timeout: NodeJS.Timeout | undefined;
81+
return (...args: Parameters<T>) => {
82+
clearTimeout(timeout);
83+
timeout = setTimeout(() => func(...args), wait);
84+
};
85+
};
86+
87+
// Khóa bí mật để mã hóa dữ liệu (nên lưu trong biến môi trường trong thực tế)
88+
const ENCRYPTION_KEY = process.env.NEXT_PUBLIC_ENCRYPTION_KEY || "your-secret-key-here-32bytes-long";
89+
const IV_LENGTH = 16; // Độ dài IV cho AES
90+
91+
// Hàm mã hóa dữ liệu
92+
const encryptData = (text: string): string => {
93+
const iv = crypto.randomBytes(IV_LENGTH);
94+
const cipher = crypto.createCipheriv("aes-256-cbc", Buffer.from(ENCRYPTION_KEY), iv);
95+
let encrypted = cipher.update(text);
96+
encrypted = Buffer.concat([encrypted, cipher.final()]);
97+
return iv.toString("hex") + ":" + encrypted.toString("hex");
98+
};
99+
100+
// Hàm giải mã dữ liệu
101+
const decryptData = (text: string): string => {
102+
const [iv, encryptedText] = text.split(":");
103+
const decipher = crypto.createDecipheriv(
104+
"aes-256-cbc",
105+
Buffer.from(ENCRYPTION_KEY),
106+
Buffer.from(iv, "hex")
107+
);
108+
let decrypted = decipher.update(Buffer.from(encryptedText, "hex"));
109+
decrypted = Buffer.concat([decrypted, decipher.final()]);
110+
return decrypted.toString();
111+
};
112+
107113
function LoginPageContent() {
108114
const router = useRouter();
109115
const { signInWithWalletConnect, signIn } = useAuth();
110116
const { updateProfile, addWallet, syncWithSupabase } = useSettings();
111117

112-
const [email, setEmail] = useState("");
113-
const [password, setPassword] = useState("");
114-
const [emailError, setEmailError] = useState("");
115-
const [passwordError, setPasswordError] = useState("");
116-
const [showPassword, setShowPassword] = useState(false);
117-
const [isLoading, setIsLoading] = useState(false);
118+
const [email, setEmail] = useState<string>("");
119+
const [password, setPassword] = useState<string>("");
120+
const [emailError, setEmailError] = useState<string>("");
121+
const [passwordError, setPasswordError] = useState<string>("");
122+
const [showPassword, setShowPassword] = useState<boolean>(false);
123+
const [isLoading, setIsLoading] = useState<boolean>(false);
118124

119125
const [{ wallet, connecting }, connect, disconnect] = useConnectWallet();
120-
const [isLoggedOut, setIsLoggedOut] = useState(false);
126+
const [isLoggedOut, setIsLoggedOut] = useState<boolean>(false);
121127

122128
interface Account {
123129
address: string;
124130
ens: string | null;
125131
}
126132

127-
const formatWalletAddress = (walletAddress: string) => {
133+
const [account, setAccount] = useState<Account | null>(null);
134+
135+
const formatWalletAddress = (walletAddress: string): string => {
128136
if (!walletAddress) return "";
129137
return `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;
130138
};
131139

132-
const [account, setAccount] = useState<Account | null>(null);
133-
140+
// Check session and listen to auth state changes
134141
useEffect(() => {
135142
const checkExistingSession = async () => {
136-
const { data: { session } } = await supabase.auth.getSession();
143+
const { data: { session }, error } = await supabase.auth.getSession();
144+
if (error) {
145+
console.error("Error checking session:", error.message);
146+
return;
147+
}
137148
if (session) {
149+
console.log("Initial session found, redirecting to dashboard");
138150
router.push("/");
139151
}
140152
};
141153
checkExistingSession();
154+
155+
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
156+
console.log("Auth state changed:", event);
157+
if (event === "SIGNED_IN" && session) {
158+
console.log("User signed in, redirecting to dashboard");
159+
router.push("/");
160+
} else if (event === "SIGNED_OUT") {
161+
console.log("User signed out, staying on login page");
162+
setIsLoggedOut(true);
163+
}
164+
});
165+
166+
return () => {
167+
subscription.unsubscribe();
168+
};
142169
}, [router]);
143170

171+
// Handle wallet connection and authentication
144172
useEffect(() => {
145173
if (wallet?.provider && !isLoggedOut) {
146174
const { address, ens } = wallet.accounts[0];
@@ -149,11 +177,27 @@ function LoginPageContent() {
149177
const authenticateWithWallet = async () => {
150178
try {
151179
setIsLoading(true);
180+
const hashedAddress = await bcrypt.hash(address, 10); // Hash địa chỉ ví
152181
const { data, error } = await signInWithWalletConnect(address);
153182
if (error) {
154-
console.error("Wallet auth error:", error);
155-
toast.error(`Failed to authenticate with wallet: ${error.message}`);
156-
return;
183+
if (error.message.includes("User already registered")) {
184+
toast.info("User already exists. Logging in instead.");
185+
const { data: loginData, error: loginError } = await supabase.auth.signInWithPassword({
186+
email: `${address}@cryptopath.local`,
187+
password: hashedAddress, // Sử dụng hashed address làm mật khẩu
188+
});
189+
if (loginError) throw new Error(loginError.message);
190+
if (!loginData.session) throw new Error("No session returned from login");
191+
const encryptedToken = encryptData(JSON.stringify(loginData.session.access_token));
192+
localStorage.setItem("userToken", encryptedToken);
193+
} else {
194+
throw new Error(error.message);
195+
}
196+
} else if (!data || !data.session) {
197+
throw new Error("No session data returned from sign-in");
198+
} else {
199+
const encryptedToken = encryptData(JSON.stringify(data.session.access_token));
200+
localStorage.setItem("userToken", encryptedToken);
157201
}
158202

159203
updateProfile({
@@ -169,15 +213,16 @@ function LoginPageContent() {
169213
name: ens?.name || formatWalletAddress(address),
170214
isLoggedIn: true,
171215
};
172-
// Hash before storing in localStorage
173-
localStorage.setItem("userDisplayInfo", encryptData(JSON.stringify(publicUserData)));
174-
localStorage.setItem("userToken", encryptData(data.session?.access_token || ""));
216+
const encryptedUserData = encryptData(JSON.stringify(publicUserData));
217+
localStorage.setItem("userDisplayInfo", encryptedUserData);
175218

219+
console.log("Wallet login successful, redirecting to dashboard");
176220
toast.success("Successfully authenticated with wallet");
177221
router.push("/");
178-
} catch (error: any) {
179-
console.error("Error authenticating with wallet:", error);
180-
toast.error(`Authentication failed: ${error?.message || "Unknown error"}`);
222+
} catch (error: unknown) {
223+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
224+
console.error("Wallet authentication error:", error);
225+
toast.error(`Authentication failed: ${errorMessage}`);
181226
} finally {
182227
setIsLoading(false);
183228
}
@@ -187,27 +232,25 @@ function LoginPageContent() {
187232
}
188233
}, [wallet, router, isLoggedOut, signInWithWalletConnect, updateProfile, addWallet, syncWithSupabase]);
189234

235+
// Handle email/password login
190236
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
191237
e.preventDefault();
192238
setEmailError("");
193239
setPasswordError("");
194240
setIsLoading(true);
195241

196242
try {
197-
// Hash the password before sending it to the signIn function
198-
const hashedPassword = hashPassword(password);
199-
const { data, error } = await signIn(email, hashedPassword); // Assuming signIn accepts hashed password
243+
const hashedPassword = await bcrypt.hash(password, 10); // Hash mật khẩu trước khi gửi
244+
const { data, error } = await signIn(email, hashedPassword); // Gửi hashed password
200245
if (error) {
201246
if (error.message.includes("email")) setEmailError(error.message);
202247
else if (error.message.includes("password")) setPasswordError(error.message);
203248
else toast.error(error.message);
204-
setIsLoading(false);
205249
return;
206250
}
207251

208-
if (!data.user) {
252+
if (!data.user || !data.session) {
209253
toast.error("Something went wrong with the login");
210-
setIsLoading(false);
211254
return;
212255
}
213256

@@ -230,35 +273,38 @@ function LoginPageContent() {
230273
email,
231274
isLoggedIn: true,
232275
};
233-
// Hash before storing in localStorage
234-
localStorage.setItem("currentUser", encryptData(JSON.stringify(publicUserData)));
235-
localStorage.setItem("userToken", encryptData(data.session?.access_token || ""));
276+
const encryptedUserData = encryptData(JSON.stringify(publicUserData));
277+
const encryptedToken = encryptData(JSON.stringify(data.session.access_token));
278+
localStorage.setItem("currentUser", encryptedUserData);
279+
localStorage.setItem("userToken", encryptedToken);
236280

281+
console.log("Email login successful, redirecting to dashboard");
237282
toast.success("Login successful!");
238283
router.push("/");
239-
} catch (error: any) {
284+
} catch (error: unknown) {
285+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
240286
console.error("Login error:", error);
241-
toast.error("An unexpected error occurred. Please try again.");
287+
toast.error(`An unexpected error occurred: ${errorMessage}`);
242288
} finally {
243289
setIsLoading(false);
244290
}
245291
};
246292

247-
const handleWalletConnect = async () => {
293+
// Handle wallet connect/disconnect with debounce
294+
const handleWalletConnect = debounce(async () => {
248295
if (!wallet) {
249-
connect();
296+
await connect();
250297
} else {
251-
disconnect({ label: wallet.label });
298+
await disconnect({ label: wallet.label });
252299
setAccount(null);
253300
setIsLoggedOut(true);
254301
await supabase.auth.signOut();
255302
localStorage.removeItem("userDisplayInfo");
256303
localStorage.removeItem("userToken");
257304
router.push("/login");
258305
}
259-
};
306+
}, 1000);
260307

261-
// The rest of your JSX remains unchanged
262308
return (
263309
<>
264310
<div className="relative">
@@ -347,9 +393,10 @@ function LoginPageContent() {
347393
options: { redirectTo: `${window.location.origin}/` },
348394
});
349395
if (error) throw error;
350-
} catch (error) {
396+
} catch (error: unknown) {
397+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
351398
console.error("Google login error:", error);
352-
toast.error("Google login failed. Please try again.");
399+
toast.error(`Google login failed: ${errorMessage}`);
353400
} finally {
354401
setIsLoading(false);
355402
}

0 commit comments

Comments
 (0)