Skip to content

Commit afead1e

Browse files
committed
useTypedLoaderData type fix
1 parent 5cfc7df commit afead1e

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

apps/webapp/app/routes/admin._index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export async function action({ request }: ActionFunctionArgs) {
7878

7979
export default function AdminDashboardRoute() {
8080
const user = useUser();
81-
const { users, filters, page, pageCount } = useTypedLoaderData<typeof loader>();
81+
const { users, filters, page, pageCount } = useTypedLoaderData<typeof loader>() as any;
8282

8383
return (
8484
<main

apps/webapp/app/routes/api.v1.plain.customer-cards.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ActionFunctionArgs } from "@remix-run/server-runtime";
22
import { json } from "@remix-run/server-runtime";
3+
import { timingSafeEqual } from "crypto";
34
import { uiComponent } from "@team-plain/typescript-sdk";
45
import { z } from "zod";
56
import { prisma } from "~/db.server";
@@ -37,7 +38,14 @@ function authenticatePlainRequest(request: Request): boolean {
3738
// Support both "Bearer <token>" and plain token formats
3839
const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
3940

40-
return token === expectedSecret;
41+
// Use constant-time comparison to prevent timing attacks
42+
const encoder = new TextEncoder();
43+
const tokenBuffer = encoder.encode(token);
44+
const secretBuffer = encoder.encode(expectedSecret);
45+
if (tokenBuffer.byteLength !== secretBuffer.byteLength) {
46+
return false;
47+
}
48+
return timingSafeEqual(tokenBuffer, secretBuffer);
4149
}
4250

4351
export async function action({ request }: ActionFunctionArgs) {
@@ -76,6 +84,9 @@ export async function action({ request }: ActionFunctionArgs) {
7684
where: { id: customer.externalId },
7785
include: {
7886
orgMemberships: {
87+
where: {
88+
organization: { deletedAt: null },
89+
},
7990
include: {
8091
organization: {
8192
include: {
@@ -96,6 +107,9 @@ export async function action({ request }: ActionFunctionArgs) {
96107
where: { email: customer.email },
97108
include: {
98109
orgMemberships: {
110+
where: {
111+
organization: { deletedAt: null },
112+
},
99113
include: {
100114
organization: {
101115
include: {
@@ -129,7 +143,7 @@ export async function action({ request }: ActionFunctionArgs) {
129143
switch (cardKey) {
130144
case "account-details": {
131145
// Build the impersonate URL
132-
const impersonateUrl = `${env.APP_ORIGIN || "https://cloud.trigger.dev"}/admin?impersonate=${user.id}`;
146+
const impersonateUrl = `${env.APP_ORIGIN}/admin?impersonate=${user.id}`;
133147

134148
cards.push({
135149
key: "account-details",
@@ -283,7 +297,7 @@ export async function action({ request }: ActionFunctionArgs) {
283297
uiComponent.spacer({ size: "XS" }),
284298
uiComponent.linkButton({
285299
label: "View in Dashboard",
286-
url: `https://cloud.trigger.dev/@/orgs/${org.slug}`,
300+
url: `${env.APP_ORIGIN}/@/orgs/${org.slug}`,
287301
}),
288302
];
289303
}
@@ -365,7 +379,7 @@ export async function action({ request }: ActionFunctionArgs) {
365379
asideContent: [
366380
uiComponent.linkButton({
367381
label: "View",
368-
url: `https://cloud.trigger.dev/orgs/${project.orgSlug}/projects/${project.slug}`,
382+
url: `${env.APP_ORIGIN}/orgs/${project.orgSlug}/projects/${project.slug}`,
369383
}),
370384
],
371385
}),

0 commit comments

Comments
 (0)