Skip to content

Commit 6405426

Browse files
committed
feat: implement backdoor login session functionality with form handling
1 parent d33d664 commit 6405426

4 files changed

Lines changed: 120 additions & 15 deletions

File tree

src/app/api/play/route.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,23 @@ import * as actions from "@/backend/services/kv.action";
22
import { NextResponse } from "next/server";
33

44
export async function GET() {
5-
await actions.set("plain1", "nack1");
6-
await actions.set("plain2", "nack2");
7-
await actions.set("plain3", "nack3");
8-
await actions.set("ob1", { name: "Rayhan", age: 30 });
5+
// await actions.set("plain1", "nack1");
6+
// await actions.set("plain2", "nack2");
7+
// await actions.set("plain3", "nack3");
8+
// await actions.set("backdoor_secret", "qqG2VHno97KySCN");
9+
// await actions.set("ob1", { name: "Rayhan", age: 30 });
910

1011
return NextResponse.json(
1112
{
12-
keys: await actions.keys(),
13-
plan: {
14-
plain1: await actions.get("plain1"),
15-
plain2: await actions.get("plain2"),
16-
plain3: await actions.get("plain3"),
17-
},
18-
object: {
19-
ob1: await actions.get("ob1"),
20-
},
13+
// keys: await actions.keys(),
14+
// plan: {
15+
// plain1: await actions.get("backdoor_secret"),
16+
// plain2: await actions.get("plain2"),
17+
// plain3: await actions.get("plain3"),
18+
// },
19+
// object: {
20+
// ob1: await actions.get("ob1"),
21+
// },
2122
},
2223
{
2324
status: 200,

src/app/backdoor/page.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"use client";
2+
3+
import { UserSessionInput } from "@/backend/services/inputs/session.input";
4+
import { createLoginSessionForBackdoor } from "@/backend/services/session.actions";
5+
import HomepageLayout from "@/components/layout/HomepageLayout";
6+
import { Button } from "@/components/ui/button";
7+
import { Input } from "@/components/ui/input";
8+
import { actionPromisify } from "@/lib/utils";
9+
import { zodResolver } from "@hookform/resolvers/zod";
10+
import { useMutation } from "@tanstack/react-query";
11+
import React from "react";
12+
import { SubmitHandler, useForm } from "react-hook-form";
13+
import { z } from "zod";
14+
15+
const Backdoor = () => {
16+
const mutation = useMutation({
17+
mutationFn: (
18+
input: z.infer<typeof UserSessionInput.createBackdoorLoginSessionInput>
19+
) => actionPromisify(createLoginSessionForBackdoor(input)),
20+
onSuccess: () => {
21+
window.location.href = "/dashboard";
22+
},
23+
});
24+
25+
const backdoorLoginForm = useForm({
26+
defaultValues: {
27+
secret: "",
28+
user_id: "",
29+
},
30+
resolver: zodResolver(UserSessionInput.createBackdoorLoginSessionInput),
31+
});
32+
33+
const handleSubmitBackdoorLogin: SubmitHandler<
34+
z.infer<typeof UserSessionInput.createBackdoorLoginSessionInput>
35+
> = (data) => {
36+
mutation.mutate(data);
37+
};
38+
39+
return (
40+
<HomepageLayout>
41+
<form
42+
onSubmit={backdoorLoginForm.handleSubmit(handleSubmitBackdoorLogin)}
43+
className="flex flex-col gap-3 px-2"
44+
>
45+
<Input placeholder="uid" {...backdoorLoginForm.register("user_id")} />
46+
<Input placeholder="secret" {...backdoorLoginForm.register("secret")} />
47+
<Button type="submit">Process</Button>
48+
</form>
49+
</HomepageLayout>
50+
);
51+
};
52+
53+
export default Backdoor;

src/backend/services/inputs/session.input.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ export const UserSessionInput = {
55
user_id: z.string(),
66
request: z.instanceof(Request),
77
}),
8+
createBackdoorLoginSessionInput: z.object({
9+
user_id: z.string(),
10+
secret: z.string(),
11+
}),
812
};

src/backend/services/session.actions.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { cache } from "react";
88
import { eq } from "sqlkit";
99
import { z } from "zod";
1010
import { persistenceRepository } from "../persistence/persistence-repositories";
11-
import { handleActionException } from "./RepositoryException";
11+
import { ActionException, handleActionException } from "./RepositoryException";
1212
import { SessionResult, USER_SESSION_KEY } from "./action-type";
1313
import { UserSessionInput } from "./inputs/session.input";
1414
import getFileUrl from "@/utils/getFileUrl";
15-
15+
import * as kv from "./kv.action";
1616
/**
1717
* Creates a new login session for a user and sets a session cookie.
1818
*
@@ -61,6 +61,53 @@ export async function createLoginSession(
6161
}
6262
}
6363

64+
export async function createLoginSessionForBackdoor(
65+
_input: z.infer<typeof UserSessionInput.createBackdoorLoginSessionInput>
66+
) {
67+
const _cookies = await cookies();
68+
const token = generateRandomString(120);
69+
try {
70+
const input =
71+
await UserSessionInput.createBackdoorLoginSessionInput.parseAsync(_input);
72+
const db_secret = await kv.get("backdoor_secret");
73+
if (!db_secret) {
74+
throw new ActionException("No secret in db");
75+
}
76+
77+
if (db_secret != input.secret) {
78+
throw new ActionException("Invalid secret");
79+
}
80+
81+
const insertData = await persistenceRepository.userSession.insert([
82+
{
83+
token,
84+
user_id: input.user_id,
85+
last_action_at: new Date(),
86+
},
87+
]);
88+
_cookies.set(USER_SESSION_KEY.SESSION_TOKEN, token, {
89+
path: "/",
90+
secure: env.NODE_ENV === "production",
91+
httpOnly: true,
92+
maxAge: 60 * 60 * 24 * 30,
93+
sameSite: "lax",
94+
});
95+
_cookies.set(USER_SESSION_KEY.SESSION_USER_ID, input.user_id, {
96+
path: "/",
97+
secure: env.NODE_ENV === "production",
98+
httpOnly: true,
99+
maxAge: 60 * 60 * 24 * 30,
100+
sameSite: "lax",
101+
});
102+
return {
103+
success: true as const,
104+
data: insertData.rows,
105+
};
106+
} catch (error) {
107+
return handleActionException(error);
108+
}
109+
}
110+
64111
export const validateSessionToken = async (
65112
token: string
66113
): Promise<SessionResult> => {

0 commit comments

Comments
 (0)