Skip to content

Commit

Permalink
Implement hashed user ID cookie for analytics on Gitpod domains (#20231)
Browse files Browse the repository at this point in the history
* Set hashed user ID cookie on JWT refresh for specific Gitpod domains

* refactor: Update setHashedUserIdCookie method in session handler for testing purposes

* attempt 2 to fix test

* refactor: Clear gitpod_hashed_user_id cookie after logout
  • Loading branch information
Siddhant-K-code committed Sep 18, 2024
1 parent fdbf605 commit 92f3ec0
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 32 deletions.
32 changes: 0 additions & 32 deletions components/server/src/analytics-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { Config } from "./config";
import { RateLimited } from "./api/rate-limited";
import { RateLimitter } from "./rate-limitter";
import { RateLimiterRes } from "rate-limiter-flexible";
import * as crypto from "crypto";

@injectable()
export class AnalyticsController {
Expand Down Expand Up @@ -70,7 +69,6 @@ export class AnalyticsController {
const clientHeaderFields = toClientHeaderFields(req);
const event = req.body as RemoteIdentifyMessage;
this.identifyUser(req.user.id, event, clientHeaderFields);
this.setHashedUserIdCookie(req.user.id, req, res);
res.sendStatus(200);
} catch (e) {
console.error("failed to identify user", e);
Expand Down Expand Up @@ -179,34 +177,4 @@ export class AnalyticsController {
throw e;
}
}

private setHashedUserIdCookie(userId: string, req: express.Request, res: express.Response): void {
const hashedUserId = crypto.createHash("md5").update(userId).digest("hex");
const oneYearInSeconds = 365 * 24 * 60 * 60;

/**
* This implementation is inspired by isGitpodIo() from /workspace/gitpod/components/dashboard/src/utils.ts
* We're using a server-side equivalent here because:
* 1. The original function is client-side code using window.location
* 2. This is server-side code that needs to use the request object
* 3. We need to determine the appropriate domain for setting the cookie
*/
const hostname = req.hostname;
if (
hostname === "gitpod.io" ||
hostname === "gitpod-staging.com" ||
hostname.endsWith("gitpod-dev.com") ||
hostname.endsWith("gitpod-io-dev.com")
) {
const domain = `.${hostname}`;

res.cookie("gitpod_hashed_user_id", hashedUserId, {
domain: domain,
maxAge: oneYearInSeconds * 1000, // Convert to milliseconds
httpOnly: true,
secure: true,
sameSite: "lax",
});
}
}
}
3 changes: 3 additions & 0 deletions components/server/src/session-handler.spec.db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ describe("SessionHandler", () => {
beforeEach(async () => {
container = createTestContainer();
sessionHandler = container.get(SessionHandler);
(sessionHandler as any).setHashedUserIdCookie = () => {
return;
};
jwtSessionHandler = sessionHandler.jwtSessionConvertor();
const userService = container.get(UserService);
// insert some users to the DB to reproduce INC-379
Expand Down
36 changes: 36 additions & 0 deletions components/server/src/session-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import express from "express";
import { inject, injectable } from "inversify";
import websocket from "ws";
import * as crypto from "crypto";

import { User } from "@gitpod/gitpod-protocol";
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
Expand Down Expand Up @@ -81,6 +82,8 @@ export class SessionHandler {
}
}

this.setHashedUserIdCookie(req, res);

res.status(200);
res.send("User session already has a valid JWT session.");
};
Expand Down Expand Up @@ -230,6 +233,39 @@ export class SessionHandler {
sameSite,
secure,
});
res.clearCookie("gitpod_hashed_user_id", {
domain: `.${res.req.hostname}`,
httpOnly: true,
secure: true,
sameSite: "lax",
});
}

private setHashedUserIdCookie(req: express.Request, res: express.Response): void {
const user = req.user as User;
if (!user) return;

const hostname = req.hostname;
if (
hostname === "gitpod.io" ||
hostname === "gitpod-staging.com" ||
hostname.endsWith("gitpod-dev.com") ||
hostname.endsWith("gitpod-io-dev.com")
) {
const existingHashedId = req.cookies["gitpod_hashed_user_id"];
if (!existingHashedId) {
const hashedUserId = crypto.createHash("md5").update(user.id).digest("hex");
const oneYearInMilliseconds = 365 * 24 * 60 * 60 * 1000;

res.cookie("gitpod_hashed_user_id", hashedUserId, {
domain: `.${hostname}`,
maxAge: oneYearInMilliseconds,
httpOnly: true,
secure: true,
sameSite: "lax",
});
}
}
}
}

Expand Down

0 comments on commit 92f3ec0

Please sign in to comment.