Skip to content

Commit 94730d0

Browse files
committed
devin comments
1 parent 8671cc4 commit 94730d0

File tree

2 files changed

+28
-12
lines changed

2 files changed

+28
-12
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,20 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
2929
return redirect("/");
3030
}
3131

32+
// Check admin BEFORE consuming the one-time token
33+
const user = await requireUser(request);
34+
if (!user.admin) {
35+
return redirect("/");
36+
}
37+
3238
const validatedUserId = await validateAndConsumeImpersonationToken(impersonationToken);
3339

3440
if (!validatedUserId || validatedUserId !== impersonateUserId) {
3541
logger.warn("Invalid or expired impersonation token");
3642
return redirect("/");
3743
}
3844

39-
return handleImpersonationRequest(request, impersonateUserId);
45+
return redirectWithImpersonation(request, impersonateUserId, "/");
4046
};
4147

4248
export async function action({ request }: ActionFunctionArgs) {

apps/webapp/app/services/impersonation.server.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,27 @@ export async function validateAndConsumeImpersonationToken(
108108
return undefined;
109109
}
110110

111-
// Check if token has already been used (prevent replay attacks)
112-
const redis = getImpersonationTokenRedisClient();
113-
const tokenKey = token;
114-
115-
// Try to set the key with NX (only if not exists) and expiration
116-
// This atomically marks the token as used
117-
const result = await redis.set(tokenKey, "1", "EX", IMPERSONATION_TOKEN_EXPIRY_SECONDS, "NX");
118-
119-
if (result !== "OK") {
120-
// Token was already used
121-
return undefined;
111+
// Atomically mark the token as used to prevent replay attacks.
112+
// If Redis is unavailable, fall back to JWT expiry as the only protection.
113+
if (env.CACHE_REDIS_HOST) {
114+
try {
115+
const redis = getImpersonationTokenRedisClient();
116+
const result = await redis.set(
117+
token,
118+
"1",
119+
"EX",
120+
IMPERSONATION_TOKEN_EXPIRY_SECONDS,
121+
"NX"
122+
);
123+
if (result !== "OK") {
124+
// Token was already used
125+
return undefined;
126+
}
127+
} catch (redisError) {
128+
logger.warn("Redis unavailable for impersonation token tracking, relying on JWT expiry only", {
129+
error: redisError instanceof Error ? redisError.message : String(redisError),
130+
});
131+
}
122132
}
123133

124134
return userId;

0 commit comments

Comments
 (0)