Create Web3 signature verification endpoint
cgen-090d937f1e7f4dacb9ac9c5b2202f349
This commit is contained in:
parent
437b7fd7f2
commit
65663b8725
1 changed files with 130 additions and 0 deletions
130
api/web3/verify.ts
Normal file
130
api/web3/verify.ts
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
import type { VercelRequest, VercelResponse } from "@vercel/node";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import { verifyMessage } from "ethers";
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.SUPABASE_URL || "",
|
||||
process.env.SUPABASE_SERVICE_ROLE || "",
|
||||
);
|
||||
|
||||
export default async function handler(req: VercelRequest, res: VercelResponse) {
|
||||
if (req.method !== "POST") {
|
||||
res.setHeader("Allow", "POST");
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
try {
|
||||
const { wallet_address, signature, message, nonce } = req.body;
|
||||
|
||||
if (!wallet_address || !signature || !message || !nonce) {
|
||||
return res.status(400).json({ error: "Missing required fields" });
|
||||
}
|
||||
|
||||
const normalizedAddress = wallet_address.toLowerCase();
|
||||
|
||||
// Verify the signature
|
||||
let recoveredAddress: string;
|
||||
try {
|
||||
recoveredAddress = verifyMessage(message, signature).toLowerCase();
|
||||
} catch (error) {
|
||||
console.error("Signature verification failed:", error);
|
||||
return res.status(401).json({ error: "Invalid signature" });
|
||||
}
|
||||
|
||||
// Check if recovered address matches provided address
|
||||
if (recoveredAddress !== normalizedAddress) {
|
||||
return res.status(401).json({ error: "Signature does not match wallet" });
|
||||
}
|
||||
|
||||
// Verify nonce exists and is not expired
|
||||
const { data: nonceData, error: nonceError } = await supabase
|
||||
.from("web3_nonces")
|
||||
.select("*")
|
||||
.eq("wallet_address", normalizedAddress)
|
||||
.eq("nonce", nonce)
|
||||
.single();
|
||||
|
||||
if (nonceError || !nonceData) {
|
||||
return res.status(401).json({ error: "Invalid or expired nonce" });
|
||||
}
|
||||
|
||||
const expiresAt = new Date(nonceData.expires_at);
|
||||
if (expiresAt < new Date()) {
|
||||
return res.status(401).json({ error: "Nonce has expired" });
|
||||
}
|
||||
|
||||
// Mark nonce as used
|
||||
await supabase
|
||||
.from("web3_nonces")
|
||||
.update({ used_at: new Date().toISOString() })
|
||||
.eq("nonce", nonce);
|
||||
|
||||
// Check if user already exists with this wallet
|
||||
const { data: existingUser } = await supabase
|
||||
.from("user_profiles")
|
||||
.select("id, auth_id")
|
||||
.eq("wallet_address", normalizedAddress)
|
||||
.single();
|
||||
|
||||
if (existingUser) {
|
||||
// User exists, link to their account
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
existing_user: true,
|
||||
user_id: existingUser.id,
|
||||
});
|
||||
}
|
||||
|
||||
// Create new Web3 user
|
||||
const email = `${normalizedAddress.substring(2)}@web3.aethex.dev`;
|
||||
const username = normalizedAddress.substring(2, 10);
|
||||
|
||||
// Create Supabase auth user
|
||||
const { data: authData, error: authError } = await supabase.auth.admin.createUser({
|
||||
email,
|
||||
password: require("crypto").randomBytes(32).toString("hex"),
|
||||
email_confirm: true,
|
||||
user_metadata: {
|
||||
wallet_address: normalizedAddress,
|
||||
auth_method: "web3",
|
||||
},
|
||||
});
|
||||
|
||||
if (authError || !authData.user) {
|
||||
console.error("Failed to create auth user:", authError);
|
||||
return res.status(500).json({ error: "Failed to create account" });
|
||||
}
|
||||
|
||||
// Create user profile
|
||||
const { data: profileData, error: profileError } = await supabase
|
||||
.from("user_profiles")
|
||||
.insert({
|
||||
auth_id: authData.user.id,
|
||||
email,
|
||||
username,
|
||||
wallet_address: normalizedAddress,
|
||||
user_type: "game_developer",
|
||||
full_name: `Web3 User ${username}`,
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (profileError) {
|
||||
console.error("Failed to create user profile:", profileError);
|
||||
return res.status(500).json({ error: "Failed to create user profile" });
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
user_id: profileData.id,
|
||||
email,
|
||||
username,
|
||||
wallet_address: normalizedAddress,
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error("Web3 verification error:", error);
|
||||
return res.status(500).json({
|
||||
error: error?.message || "Verification failed",
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue