Skip to content

Commit 5451808

Browse files
authored
cookie v2 containing role and userId (#1922)
* add authorities file * add logic to send cookie-v2 * write test * fix auth test * test check cookie v2 * fix the issue with rdsUiUrl * remove done() * address review comment
1 parent 9a7602b commit 5451808

File tree

6 files changed

+67
-8
lines changed

6 files changed

+67
-8
lines changed

config/default.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ module.exports = {
6464

6565
userToken: {
6666
cookieName: `rds-session-${NODE_ENV}`,
67+
cookieV2Name: `rds-session-v2-${NODE_ENV}`,
6768
ttl: 30 * 24 * 60 * 60, // in seconds
6869
refreshTtl: 180 * 24 * 60 * 60, // in seconds
6970
publicKey: "<publicKey>",

config/production.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module.exports = {
1010
discordMissedUpdatesRoleId: "1183553844811153458",
1111
userToken: {
1212
cookieName: "rds-session",
13+
cookieV2Name: "rds-session-v2",
1314
},
1415

1516
services: {

constants/authorities.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const AUTHORITIES = {
2+
SUPERUSER: "super_user",
3+
MEMBER: "member",
4+
USER: "user",
5+
};
6+
7+
module.exports = { AUTHORITIES };

controllers/auth.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,18 @@ const githubAuthCallback = (req, res, next) => {
4545
const rdsUiUrl = new URL(config.get("services.rdsUi.baseUrl"));
4646
let authRedirectionUrl = rdsUiUrl;
4747
let devMode = false;
48+
let isV2FlagPresent = false;
49+
4850
if ("state" in req.query) {
4951
try {
5052
const redirectUrl = new URL(req.query.state);
5153
if (redirectUrl.searchParams.get("isMobileApp") === "true") {
5254
isMobileApp = true;
5355
redirectUrl.searchParams.delete("isMobileApp");
5456
}
57+
58+
if (redirectUrl.searchParams.get("v2") === "true") isV2FlagPresent = true;
59+
5560
if (`.${redirectUrl.hostname}`.endsWith(`.${rdsUiUrl.hostname}`)) {
5661
// Matching *.realdevsquad.com
5762
authRedirectionUrl = redirectUrl;
@@ -78,18 +83,25 @@ const githubAuthCallback = (req, res, next) => {
7883
updated_at: Date.now(),
7984
};
8085

81-
const { userId, incompleteUserDetails } = await users.addOrUpdate(userData);
86+
const { userId, incompleteUserDetails, role } = await users.addOrUpdate(userData);
8287

8388
const token = authService.generateAuthToken({ userId });
8489

85-
// respond with a cookie
86-
res.cookie(config.get("userToken.cookieName"), token, {
90+
const cookieOptions = {
8791
domain: rdsUiUrl.hostname,
8892
expires: new Date(Date.now() + config.get("userToken.ttl") * 1000),
8993
httpOnly: true,
9094
secure: true,
9195
sameSite: "lax",
92-
});
96+
};
97+
// respond with a cookie
98+
res.cookie(config.get("userToken.cookieName"), token, cookieOptions);
99+
100+
/* redirectUrl woud be like https://realdevsquad.com?v2=true */
101+
if (isV2FlagPresent) {
102+
const tokenV2 = authService.generateAuthToken({ userId, role });
103+
res.cookie(config.get("userToken.cookieV2Name"), tokenV2, cookieOptions);
104+
}
93105

94106
if (!devMode) {
95107
// TODO: Revisit incompleteUserDetails redirect condition
@@ -112,12 +124,15 @@ const githubAuthCallback = (req, res, next) => {
112124
const signout = (req, res) => {
113125
const cookieName = config.get("userToken.cookieName");
114126
const rdsUiUrl = new URL(config.get("services.rdsUi.baseUrl"));
115-
res.clearCookie(cookieName, {
127+
const cookieOptions = {
116128
domain: rdsUiUrl.hostname,
117129
httpOnly: true,
118130
secure: true,
119131
sameSite: "lax",
120-
});
132+
};
133+
res.clearCookie(cookieName, cookieOptions);
134+
const cookieV2Name = config.get("userToken.cookieV2Name");
135+
res.clearCookie(cookieV2Name, cookieOptions);
121136
return res.json({
122137
message: "Signout successful",
123138
});

models/users.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const photoVerificationModel = firestore.collection("photo-verification");
2222
const { ITEM_TAG, USER_STATE } = ALLOWED_FILTER_PARAMS;
2323
const admin = require("firebase-admin");
2424
const { INTERNAL_SERVER_ERROR } = require("../constants/errorMessages");
25+
const { AUTHORITIES } = require("../constants/authorities");
2526

2627
/**
2728
* Adds or updates the user data
@@ -59,13 +60,15 @@ const addOrUpdate = async (userData, userId = null) => {
5960
if (!user || (user && user.empty)) {
6061
user = await userModel.where("github_id", "==", userData.github_id).limit(1).get();
6162
}
62-
if (user && !user.empty) {
63+
if (user && !user.empty && user.docs !== null) {
6364
await userModel.doc(user.docs[0].id).set(userData, { merge: true });
65+
const data = user.docs[0].data();
6466
return {
6567
isNewUser: false,
6668
userId: user.docs[0].id,
6769
incompleteUserDetails: user.docs[0].data().incompleteUserDetails,
6870
updated_at: Date.now(),
71+
role: Object.values(AUTHORITIES).find((role) => data.roles[role]) || AUTHORITIES.USER,
6972
};
7073
}
7174

@@ -78,7 +81,13 @@ const addOrUpdate = async (userData, userId = null) => {
7881
userData.roles = { archived: false, in_discord: false };
7982
userData.incompleteUserDetails = true;
8083
const userInfo = await userModel.add(userData);
81-
return { isNewUser: true, userId: userInfo.id, incompleteUserDetails: true, updated_at: Date.now() };
84+
return {
85+
isNewUser: true,
86+
role: AUTHORITIES.USER,
87+
userId: userInfo.id,
88+
incompleteUserDetails: true,
89+
updated_at: Date.now(),
90+
};
8291
} catch (err) {
8392
logger.error("Error in adding or updating user", err);
8493
throw err;

test/integration/auth.test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,30 @@ describe("auth", function () {
227227
return done();
228228
});
229229
});
230+
231+
it("should send rds-session-v2 in res cookie", async function () {
232+
const rdsUiUrl = new URL(config.get("services.rdsUi.baseUrl"));
233+
234+
sinon.stub(passport, "authenticate").callsFake((strategy, options, callback) => {
235+
callback(null, "accessToken", githubUserInfo[0]);
236+
return (req, res, next) => {};
237+
});
238+
239+
const res = await chai
240+
.request(app)
241+
.get("/auth/github/callback")
242+
.query({ code: "codeReturnedByGithub", state: rdsUiUrl.href + "?v2=true" })
243+
.redirects(0);
244+
245+
expect(res).to.have.status(302);
246+
// rds-session-v2=token; Domain=realdevsquad.com; Path=/; Expires=Tue, 06 Oct 2020 11:23:07 GMT; HttpOnly; Secure
247+
expect(res.headers["set-cookie"]).to.have.length(2); /* res has 2 cookies rds-session & rds-session-v2 */
248+
expect(res.headers["set-cookie"][1])
249+
.to.be.a("string")
250+
.and.satisfy((msg) => msg.startsWith(config.get("userToken.cookieV2Name")));
251+
expect(res.headers["set-cookie"][1]).to.include("HttpOnly");
252+
expect(res.headers["set-cookie"][1]).to.include("Secure");
253+
expect(res.headers["set-cookie"][1]).to.include(`Domain=${rdsUiUrl.hostname}`);
254+
expect(res.headers["set-cookie"][1]).to.include("SameSite=Lax");
255+
});
230256
});

0 commit comments

Comments
 (0)