Skip to content

Commit f78b5c2

Browse files
committed
Fixes
1 parent 5ac44ca commit f78b5c2

5 files changed

Lines changed: 59 additions & 30 deletions

File tree

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@
5858
"uint8array-extras": "^1.4.0",
5959
"uuid": "^11.0.5",
6060
"viem": "^2.23.2",
61-
"zod": "^3.24.1",
62-
"zod-prisma-types": "^3.2.4"
61+
"zod": "^3.24.1"
6362
},
6463
"devDependencies": {
6564
"@bufbuild/buf": "^1.50.0",
@@ -82,7 +81,7 @@
8281
"prisma": "^6.17.0",
8382
"rimraf": "^6.0.1",
8483
"typescript": "^5.7.3",
85-
"typescript-eslint": "^8.20.0"
86-
},
87-
"packageManager": "yarn@4.6.0+sha512.5383cc12567a95f1d668fbe762dfe0075c595b4bfff433be478dbbe24e05251a8e8c3eb992a986667c1d53b6c3a9c85b8398c35a960587fbd9fa3a0915406728"
84+
"typescript-eslint": "^8.20.0",
85+
"zod-prisma-types": "^3.2.4"
86+
}
8887
}

src/api/shared/notifications/webhook-handler.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
import { getPushNotificationService } from "@/api/shared/notifications/services/push-notification.service";
99
import {
1010
createNotificationClient,
11+
webhookNotificationBodySchema,
1112
type WebhookNotificationBody,
1213
} from "@/notifications/client";
1314
import { getHttpDeliveryNotificationAuthHeader } from "@/notifications/utils";
@@ -32,7 +33,21 @@ export async function handleXmtpNotification(req: Request, res: Response) {
3233
} | null = null;
3334

3435
try {
35-
const notification = req.body as WebhookNotificationBody;
36+
// Validate webhook body structure
37+
const parseResult = webhookNotificationBodySchema.safeParse(req.body);
38+
if (!parseResult.success) {
39+
req.log.error(
40+
{ errors: parseResult.error.errors },
41+
"Invalid webhook payload",
42+
);
43+
res.status(400).json({
44+
error: "Invalid webhook payload",
45+
details: parseResult.error.errors,
46+
});
47+
return;
48+
}
49+
50+
const notification = parseResult.data;
3651

3752
// Log the notification for debugging
3853
req.log.info(

src/api/v2/notifications/handlers/register.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export async function register(
3636
});
3737

3838
res.status(200).send();
39+
return;
3940
} catch (error) {
4041
if (error instanceof z.ZodError) {
4142
res.status(400).json({ error: "Invalid request body" });

src/notifications/client.ts

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { create } from "@bufbuild/protobuf";
22
import { createClient } from "@connectrpc/connect";
33
import { createConnectTransport } from "@connectrpc/connect-node";
44
import { type HmacKey } from "@xmtp/node-sdk";
5+
import { z } from "zod";
56
import {
67
Notifications,
78
Subscription_HmacKeySchema,
@@ -25,30 +26,35 @@ export type Topic = {
2526
hmacKeys: HmacKey[];
2627
};
2728

28-
export type WebhookNotificationBody = {
29-
idempotency_key: string;
30-
message: {
31-
content_topic: string;
32-
timestamp_ns: string;
33-
message: string;
34-
};
35-
message_context: {
36-
message_type: string;
37-
should_push?: boolean;
38-
};
39-
installation: {
40-
id: string;
41-
delivery_mechanism: {
42-
kind: string;
43-
token: string;
44-
};
45-
};
46-
subscription: {
47-
created_at: string;
48-
topic: string;
49-
is_silent: boolean;
50-
};
51-
};
29+
// Zod schema for webhook notification validation
30+
export const webhookNotificationBodySchema = z.object({
31+
idempotency_key: z.string(),
32+
message: z.object({
33+
content_topic: z.string(),
34+
timestamp_ns: z.string(),
35+
message: z.string(),
36+
}),
37+
message_context: z.object({
38+
message_type: z.string(),
39+
should_push: z.boolean().optional(),
40+
}),
41+
installation: z.object({
42+
id: z.string(),
43+
delivery_mechanism: z.object({
44+
kind: z.string(),
45+
token: z.string(),
46+
}),
47+
}),
48+
subscription: z.object({
49+
created_at: z.string(),
50+
topic: z.string(),
51+
is_silent: z.boolean(),
52+
}),
53+
});
54+
55+
export type WebhookNotificationBody = z.infer<
56+
typeof webhookNotificationBodySchema
57+
>;
5258

5359
export async function subscribeToTopics(
5460
// The installationId we want to apply the subscription to

src/utils/v2/jwt.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ export const createV2JwtToken = async (args: {
2121
metadata?: V2JWTMetadata;
2222
expirationTime?: string;
2323
}) => {
24+
if (!process.env.JWT_SECRET) {
25+
throw new AppError(500, "JWT_SECRET is not configured");
26+
}
27+
2428
// Validate metadata size to prevent JWT bloat
2529
if (args.metadata) {
2630
const metadataSize = JSON.stringify(args.metadata).length;
@@ -60,6 +64,10 @@ export const createV2JwtToken = async (args: {
6064
};
6165

6266
export const verifyV2JwtToken = async (args: { token: string }) => {
67+
if (!process.env.JWT_SECRET) {
68+
throw new AppError(500, "JWT_SECRET is not configured");
69+
}
70+
6371
const { data: verified, error: verifyError } = await tryCatch(
6472
jose.jwtVerify(
6573
args.token,

0 commit comments

Comments
 (0)