-
-
Notifications
You must be signed in to change notification settings - Fork 173
Settings screen update / Fix Drizzle Kit Studio #1109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
c8bb708
d42a9f3
9192b73
85f4047
a0222ab
1e5a151
a18b18a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,44 +1,96 @@ | ||
| import { getServerAuthSession } from "@/server/auth"; | ||
| import { db } from "@/server/db"; | ||
| import { | ||
| deleteTokenFromDb, | ||
| getTokenFromDb, | ||
| updateEmail, | ||
| } from "@/utils/emailToken"; | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| emailChangeRequest, | ||
| user, | ||
| emailChangeHistory, | ||
| } from "@/server/db/schema"; | ||
| import { and, eq, gte } from "drizzle-orm"; | ||
| import { type NextRequest } from "next/server"; | ||
|
|
||
| export async function GET(req: NextRequest, res: NextResponse) { | ||
| export async function GET(req: NextRequest) { | ||
| try { | ||
| const token = req.nextUrl.searchParams.get("token"); | ||
|
|
||
| if (!token) | ||
| return NextResponse.json({ message: "Invalid request" }, { status: 400 }); | ||
| if (!token) { | ||
| return new Response(JSON.stringify({ message: "Invalid request" }), { | ||
| status: 400, | ||
| headers: { "Content-Type": "application/json" }, | ||
| }); | ||
| } | ||
|
|
||
| const session = await getServerAuthSession(); | ||
|
|
||
| if (!session || !session.user) | ||
| return NextResponse.json({ message: "Unauthorized" }, { status: 401 }); | ||
| if (!session || !session.user) { | ||
| return new Response(JSON.stringify({ message: "Unauthorized" }), { | ||
| status: 401, | ||
| headers: { "Content-Type": "application/json" }, | ||
| }); | ||
| } | ||
|
|
||
| const tokenFromDb = await getTokenFromDb(token, session.user.id); | ||
| const userId = session.user.id; | ||
|
|
||
| if (!tokenFromDb || !tokenFromDb.length) | ||
| return NextResponse.json({ message: "Invalid token" }, { status: 400 }); | ||
| const request = await db.query.emailChangeRequest.findFirst({ | ||
| where: and( | ||
| eq(emailChangeRequest.token, token), | ||
| eq(emailChangeRequest.userId, userId), | ||
| gte(emailChangeRequest.expiresAt, new Date()), | ||
| ), | ||
| }); | ||
|
|
||
| const { userId, expiresAt, email } = tokenFromDb[0]; | ||
| if (expiresAt < new Date()) | ||
| return NextResponse.json({ message: "Token expired" }, { status: 400 }); | ||
| if (!request) { | ||
| return new Response( | ||
| JSON.stringify({ message: "Invalid or expired token" }), | ||
| { | ||
| status: 400, | ||
| headers: { "Content-Type": "application/json" }, | ||
| }, | ||
| ); | ||
| } | ||
|
|
||
| await updateEmail(userId, email); | ||
| const currentUser = await db.query.user.findFirst({ | ||
| where: eq(user.id, userId), | ||
| }); | ||
|
|
||
| await deleteTokenFromDb(token); | ||
| if (!currentUser) { | ||
| return new Response(JSON.stringify({ message: "User not found" }), { | ||
| status: 404, | ||
| headers: { "Content-Type": "application/json" }, | ||
| }); | ||
| } | ||
|
|
||
| return NextResponse.json( | ||
| { message: "Email successfully verified" }, | ||
| { status: 200 }, | ||
| await db | ||
| .update(user) | ||
| .set({ | ||
| email: request.newEmail, | ||
| emailVerified: new Date().toISOString(), | ||
| }) | ||
| .where(eq(user.id, userId)); | ||
|
|
||
| await db.insert(emailChangeHistory).values({ | ||
| userId, | ||
| oldEmail: currentUser.email ?? "", | ||
| newEmail: request.newEmail, | ||
| ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? "", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification IP Address Extraction Validation Needs Improvement The current implementation directly accesses the
🔗 Analysis chainValidate client IP address extraction When extracting the client's IP address from the
You can verify the presence of the header with the following script: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check for usage of 'x-forwarded-for' header in codebase
# Test: Search for instances where 'x-forwarded-for' is used
rg --type typescript '"x-forwarded-for"'
Length of output: 77 Script: #!/bin/bash
# Description: Check for usage of 'x-forwarded-for' header in TypeScript codebase
# Test: Search for instances where 'x-forwarded-for' is used
rg --type ts '"x-forwarded-for"'
Length of output: 145 Script: #!/bin/bash
# Description: Check for trusted proxy or middleware configurations handling client IP extraction in TypeScript codebase
# Test: Search for usage of 'trust proxy' or related middleware configurations
rg --type ts 'trust proxy|middleware'
Length of output: 589 |
||
| userAgent: req.headers.get("user-agent") ?? "", | ||
| }); | ||
|
|
||
| await db | ||
| .delete(emailChangeRequest) | ||
| .where(eq(emailChangeRequest.id, request.id)); | ||
|
|
||
| return new Response( | ||
| JSON.stringify({ message: "Email updated successfully" }), | ||
| { | ||
| status: 200, | ||
| headers: { "Content-Type": "application/json" }, | ||
| }, | ||
| ); | ||
| } catch (error) { | ||
| return NextResponse.json( | ||
| { error: "Internal server error" }, | ||
| { status: 500 }, | ||
| ); | ||
| console.error("Error verifying email:", error); | ||
| return new Response(JSON.stringify({ error: "Internal server error" }), { | ||
| status: 500, | ||
| headers: { "Content-Type": "application/json" }, | ||
| }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| CREATE TABLE IF NOT EXISTS "EmailChangeHistory" ( | ||
| "id" serial PRIMARY KEY NOT NULL, | ||
| "userId" text NOT NULL, | ||
| "oldEmail" text NOT NULL, | ||
| "newEmail" text NOT NULL, | ||
| "changedAt" timestamp DEFAULT now() NOT NULL, | ||
| "ipAddress" text, | ||
| "userAgent" text | ||
| ); | ||
| --> statement-breakpoint | ||
| CREATE TABLE IF NOT EXISTS "EmailChangeRequest" ( | ||
| "id" serial PRIMARY KEY NOT NULL, | ||
| "userId" text NOT NULL, | ||
| "newEmail" text NOT NULL, | ||
| "token" text NOT NULL, | ||
| "createdAt" timestamp DEFAULT now() NOT NULL, | ||
| "expiresAt" timestamp NOT NULL, | ||
| CONSTRAINT "EmailChangeRequest_token_unique" UNIQUE("token") | ||
| ); | ||
| --> statement-breakpoint | ||
| DROP TABLE "EmailVerificationToken";--> statement-breakpoint | ||
| DROP TABLE "verificationToken";--> statement-breakpoint | ||
| DO $$ BEGIN | ||
| ALTER TABLE "EmailChangeHistory" ADD CONSTRAINT "EmailChangeHistory_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; | ||
| EXCEPTION | ||
| WHEN duplicate_object THEN null; | ||
| END $$; | ||
| --> statement-breakpoint | ||
| DO $$ BEGIN | ||
| ALTER TABLE "EmailChangeRequest" ADD CONSTRAINT "EmailChangeRequest_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; | ||
| EXCEPTION | ||
| WHEN duplicate_object THEN null; | ||
| END $$; | ||
| --> statement-breakpoint | ||
| CREATE INDEX IF NOT EXISTS "Comment_postId_index" ON "Comment" USING btree ("postId");--> statement-breakpoint | ||
| CREATE INDEX IF NOT EXISTS "Notification_userId_index" ON "Notification" USING btree ("userId");--> statement-breakpoint | ||
| CREATE INDEX IF NOT EXISTS "Post_slug_index" ON "Post" USING btree ("slug");--> statement-breakpoint | ||
| CREATE INDEX IF NOT EXISTS "Post_userId_index" ON "Post" USING btree ("userId");--> statement-breakpoint | ||
| CREATE INDEX IF NOT EXISTS "User_username_index" ON "user" USING btree ("username"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure correct data type for
emailVerifiedfieldThe
emailVerifiedfield is being set usingnew Date().toISOString(), which returns a string. If the database schema expects aDateobject, consider passingnew Date()instead to ensure type consistency.Apply this diff to fix the issue:
📝 Committable suggestion