Skip to content

Commit ec3e3cd

Browse files
elliotBraemitexpert120coderabbitai[bot]
authored
Upgrade staging (#184)
* moderation handle platform_user_id and near account id * standardize activity * fmt * delete tests * fix shared types * activity leaderboard * throw not error * fix services * feat: use tanstack table for leaderboard (#183) * fix: mobile layout improvement feed page (#185) * Refactors create feed flow, steps use router (#188) * wip * feed types * better feed form * Update packages/shared-db/tsconfig.json Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update apps/app/src/routes/_layout/create/feed/settings.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update apps/app/src/routes/_layout/create/feed/index.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * set lock * nitpicks * fmt --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Implements JWT auth flow with 7 day tokens (#187) * better auth services * nit picks * nonce validation * nitpicks * clean up * fix error types * import error * fix auth requests * fix: toast colors not correct (#189) * fix: toast colors not corrent * fmt * fix feed * fix zod type * fix @ and config * fmt --------- Co-authored-by: Zeeshan Ahmad <itexpert120@outlook.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 5080606 commit ec3e3cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+4384
-2161
lines changed

apps/api/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@
3535
"zod": "^3.25.62"
3636
},
3737
"dependencies": {
38+
"@crosspost/scheduler-sdk": "^0.1.1",
3839
"@crosspost/sdk": "^0.3.0",
3940
"@crosspost/types": "^0.3.0",
40-
"@crosspost/scheduler-sdk": "^0.1.1",
4141
"@curatedotfun/shared-db": "workspace:*",
4242
"@curatedotfun/types": "workspace:*",
4343
"@curatedotfun/utils": "workspace:*",
44+
"@fastnear/utils": "^0.9.7",
4445
"@hono/node-server": "^1.8.2",
4546
"@hono/zod-openapi": "^0.9.5",
4647
"@hono/zod-validator": "^0.5.0",
@@ -60,7 +61,7 @@
6061
"lodash": "^4.17.21",
6162
"mustache": "^4.2.0",
6263
"near-api-js": "^5.1.1",
63-
"near-sign-verify": "^0.3.6",
64+
"near-sign-verify": "^0.4.1",
6465
"ora": "^8.1.1",
6566
"pg": "^8.15.6",
6667
"pinata-web3": "^0.5.4",
Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,31 @@
11
import { Context, MiddlewareHandler, Next } from "hono";
2-
import { verify } from "near-sign-verify";
2+
import { verify } from "hono/jwt";
3+
import { getCookie } from "hono/cookie";
34

45
export function createAuthMiddleware(): MiddlewareHandler {
56
return async (c: Context, next: Next) => {
6-
const method = c.req.method;
7+
const token = getCookie(c, "token");
78
let accountId: string | null = null;
89

9-
if (method === "GET") {
10-
const nearAccountHeader = c.req.header("X-Near-Account");
11-
if (
12-
nearAccountHeader &&
13-
nearAccountHeader.toLowerCase() !== "anonymous"
14-
) {
15-
accountId = nearAccountHeader;
10+
if (token) {
11+
const secret = process.env.JWT_SECRET;
12+
if (!secret) {
13+
console.error("JWT_SECRET is not set.");
14+
c.status(500);
15+
return c.json({ error: "Internal Server Error" });
16+
}
17+
try {
18+
const decodedPayload = await verify(token, secret);
19+
if (decodedPayload && typeof decodedPayload.sub === "string") {
20+
accountId = decodedPayload.sub;
21+
}
22+
} catch (error) {
23+
// Invalid token, proceed as anonymous
24+
console.warn("JWT verification failed:", error);
1625
}
17-
// If header is missing or "anonymous", accountId remains null
18-
c.set("accountId", accountId);
19-
await next();
20-
return;
21-
}
22-
23-
// For non-GET requests (POST, PUT, DELETE, PATCH, etc.)
24-
const authHeader = c.req.header("Authorization");
25-
if (!authHeader || !authHeader.startsWith("Bearer ")) {
26-
c.status(401);
27-
return c.json({
28-
error: "Unauthorized",
29-
details: "Missing or malformed Authorization header.",
30-
});
3126
}
3227

33-
const token = authHeader.substring(7); // Remove "Bearer "
34-
35-
try {
36-
const verificationResult = await verify(token, {
37-
expectedRecipient: "curatefun.near",
38-
requireFullAccessKey: false,
39-
nonceMaxAge: 300000, // 5 mins
40-
});
41-
42-
accountId = verificationResult.accountId;
43-
c.set("accountId", accountId);
44-
await next();
45-
} catch (error) {
46-
console.error("Token verification error:", error);
47-
c.status(401);
48-
return c.json({
49-
error: "Unauthorized",
50-
details: "Invalid token signature or recipient.",
51-
});
52-
}
28+
c.set("accountId", accountId);
29+
await next();
5330
};
5431
}

apps/api/src/routes/api/auth.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Hono } from "hono";
2+
import { zValidator } from "@hono/zod-validator";
3+
import { z } from "zod";
4+
import { AuthService } from "../../services/auth.service";
5+
import { Env } from "../../types/app";
6+
import { setCookie } from "hono/cookie";
7+
8+
export const authRoutes = new Hono<Env>();
9+
10+
const CreateAuthRequestSchema = z.object({
11+
accountId: z.string(),
12+
});
13+
14+
const VerifyAuthRequestSchema = z.object({
15+
token: z.string(),
16+
accountId: z.string(),
17+
});
18+
19+
authRoutes.post(
20+
"/initiate-login",
21+
zValidator("json", CreateAuthRequestSchema),
22+
async (c) => {
23+
const payload = c.req.valid("json");
24+
const sp = c.var.sp;
25+
const authService = sp.getService<AuthService>("authService");
26+
const result = await authService.createAuthRequest(payload);
27+
return c.json(result);
28+
},
29+
);
30+
31+
authRoutes.post(
32+
"/verify-login",
33+
zValidator("json", VerifyAuthRequestSchema),
34+
async (c) => {
35+
const payload = c.req.valid("json");
36+
const sp = c.var.sp;
37+
const authService = sp.getService<AuthService>("authService");
38+
try {
39+
const { jwt } = await authService.verifyAuthRequest(payload);
40+
setCookie(c, "token", jwt, {
41+
httpOnly: true,
42+
secure: process.env.NODE_ENV === "production",
43+
sameSite: "Strict",
44+
path: "/",
45+
maxAge: 60 * 60 * 24 * 7, // 7 days
46+
});
47+
return c.json({ success: true });
48+
} catch (error: unknown) {
49+
c.status(401);
50+
return c.json({
51+
success: false,
52+
error: error instanceof Error ? error.message : "Authentication failed",
53+
});
54+
}
55+
},
56+
);
57+
58+
authRoutes.post("/logout", async (c) => {
59+
setCookie(c, "token", "", {
60+
httpOnly: true,
61+
secure: process.env.NODE_ENV === "production",
62+
sameSite: "Strict",
63+
path: "/",
64+
maxAge: 0,
65+
});
66+
return c.json({ success: true });
67+
});

0 commit comments

Comments
 (0)