Skip to content

Commit

Permalink
Merge pull request #580 from douglasnaphas/v2-login
Browse files Browse the repository at this point in the history
Allow link retrieval by the leader, remove v1 flow
  • Loading branch information
douglasnaphas authored Apr 10, 2024
2 parents 3646bce + 726f46a commit 6068e95
Show file tree
Hide file tree
Showing 28 changed files with 1,041 additions and 598 deletions.
24 changes: 0 additions & 24 deletions .github/workflows/feature-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,30 +132,6 @@ jobs:
working-directory: content
run: |
npm run deploy
itest:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
needs: [frontend, content]
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.DEV_ROLE_ARN }}
aws-region: us-east-1
- name: Install itest
working-directory: itest
run: |
npm install
- name: Run smoke test (dev account)
working-directory: itest
env:
AWS_DEFAULT_REGION: "us-east-1"
AWS_REGION: "us-east-1"
run: |
npm run itest
itest-links-2023:
runs-on: ubuntu-latest
permissions:
Expand Down
8 changes: 0 additions & 8 deletions backend-v2/Configs.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,6 @@ class Configs {
return /[^A-Z]/g;
}

static gameNameBlacklist() {
return /[^-A-Za-z ,0-9]/g;
}

static libBlacklist() {
return /[^-A-Za-z ,0-9."'?!/]/g;
}

static roomCodeRetries() {
return 10;
}
Expand Down
6 changes: 6 additions & 0 deletions backend-v2/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const getRpw = require("./lib/getRpw");
const validateReadLink = require("./lib/validateReadLink");
const getSederSummary = require("./lib/getSederSummary");
const getGameName = require("./lib/getGameName");
const user = require("./lib/user");
const mySeders = require("./lib/my-seders");

const router = express.Router();

Expand Down Expand Up @@ -87,6 +89,10 @@ router.get("/scripts", async function (req, res) {

router.use(cookieParser());

router.get("/user", user());

router.get("/my-seders", mySeders());

router.get("/", function (req, res) {
res.send({
Output: "This is /v2/ ... ",
Expand Down
20 changes: 9 additions & 11 deletions backend-v2/lib/blacklistPostParams.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@
* calls next otherwise.
*/
function blackListPostParams(req, res, next) {
const Configs = require('../Configs');
const responses = require('../responses');
if(
(req.body.roomCode && req.body.roomCode.match(Configs.roomCodeBlacklist()))
||
(req.body.gameName && req.body.gameName.match(Configs.gameNameBlacklist()))
||
(req.body.libAnswer && req.body.libAnswer.match(Configs.libBlacklist()))
)
{
const Configs = require("../Configs");
const responses = require("../responses");
if (
req.body.roomCode &&
req.body.roomCode.match(Configs.roomCodeBlacklist())
) {
console.log("bad post param(s)");
console.log("req.body", req.body);
return res.status(400).send(responses.BAD_REQUEST);
}
return next();
}
module.exports = blackListPostParams;
module.exports = blackListPostParams;
65 changes: 27 additions & 38 deletions backend-v2/lib/blacklistPostParams.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* globals expect */
describe('blackListPostParams', () => {
const blackListPostParams = require('./blacklistPostParams');
const responses = require('../responses');
const runTest = ({req, expect400, expectNext}) => {
describe("blackListPostParams", () => {
const blackListPostParams = require("./blacklistPostParams");
const responses = require("../responses");
const runTest = ({ req, expect400, expectNext }) => {
let statusToSend = 200;
let sentStatus;
let nextCalled = false;
Expand All @@ -14,53 +14,42 @@ describe('blackListPostParams', () => {
send: (d) => {
sentStatus = statusToSend;
sentData = d;
}
}
},
};
},
sent: (d) => { sentStatus = statusToSend; sentData =d; }
sent: (d) => {
sentStatus = statusToSend;
sentData = d;
},
};
const next = () => {
nextCalled = true;
};
const next = () => {nextCalled = true};
blackListPostParams(req, res, next);
if(expect400) {
if (expect400) {
expect(sentStatus).toEqual(400);
expect(sentData).toEqual(responses.BAD_REQUEST);
}
if(expectNext) {
if (expectNext) {
expect(nextCalled).toBeTruthy();
}
}
test('bad room code', () => {
const req = {
body: {
roomCode: 'R<script>src="alert(hacked);"</script>'
}
};
runTest({req: req, expect400: true});
});
test('bad game name', () => {
};
test("bad room code", () => {
const req = {
body: {
gameName: 'R<script>src="alert(hacked);"</script>'
}
roomCode: 'R<script>src="alert(hacked);"</script>',
},
};
runTest({req: req, expect400: true});
runTest({ req: req, expect400: true });
});
test('bad lib', () => {
test("all valid characters", () => {
const req = {
body: {
libAnswer: 'R<script>src="alert(hacked);"</script>'
}
roomCode: "ABCDEF",
gameName: "Ab-Me, the 33rd",
libAnswer: 'Oh...so you\'re "Ab-Me the 33rd," eh?',
},
};
runTest({req: req, expect400: true});
});
test('all valid characters', () => {
const req = {
body: {
roomCode: 'ABCDEF',
gameName: 'Ab-Me, the 33rd',
libAnswer: 'Oh...so you\'re "Ab-Me the 33rd," eh?'
}
}
runTest({req: req, expectNext: true});
runTest({ req: req, expectNext: true });
});
});
});
1 change: 1 addition & 0 deletions backend-v2/lib/checkBody.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function checkBody(expectedBodyParams) {
}
expectedBodyParams.forEach(e => {
if(!req.body.hasOwnProperty(e) && !req.body[`${e}`]) {
console.log("missing property", e);
return res.status(400).send(responses.BAD_REQUEST);
}
});
Expand Down
2 changes: 0 additions & 2 deletions backend-v2/lib/getLoginCookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const getMadLnJwksFromAws = require("./getMadLnJwksFromAws");
const jwk2Pem = require("jwk-to-pem");
const checkJwt = require("./checkJwt");
const jwt = require("jsonwebtoken");
const setJwtCookies = require("./setJwtCookies");
const getUserInfo = require("./getUserInfo");
const getPostLoginURI = require("./getPostLoginURI");
const Configs = require("../Configs");
Expand All @@ -28,7 +27,6 @@ const getLoginCookies = [
exchangeCodeForTokens(axios, Configs),
getMadLnJwksFromAws(axios),
checkJwt({ jwk2Pem, jwt, tokenType: "id", verifyJwt, refreshAccessToken }),
setJwtCookies(),
getUserInfo(jwt),
getPostLoginURI(),
generateOpaqueCookie({ randomCapGenerator }),
Expand Down
7 changes: 7 additions & 0 deletions backend-v2/lib/joinSederMiddleware/joinSederMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ const succeed = require("./succeed");
const logger = require("../../logger");

const joinSederMiddleware = [
(req, res, next) => {
console.log("in joinSederMiddleware...");
console.log("req.body", req.body);
return next();
},
// check for required body params
checkBody(["sederCode", "pw", "email", "gameName"]),
// make sure email is ok
(req, res, next) => {
if (validator.validate(req.body.email)) {
return next();
}
console.log("bad email", req.body.email);
return res.status(400).send({ err: "email should be an email address" });
},
// save pwHash
Expand Down Expand Up @@ -66,6 +72,7 @@ const joinSederMiddleware = [
// check pwHash, return or reject
(req, res, next) => {
if (res.locals.pwHash !== res.locals.correctPwHash) {
console.log("v2/joinSederMiddleware: wrong hash...");
logger.log(
`v2/joinSederMiddleware: wrong hash ${res.locals.pwHash.substring(
0,
Expand Down
89 changes: 89 additions & 0 deletions backend-v2/lib/my-seders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
const {
DynamoDBDocumentClient,
QueryCommand,
} = require("@aws-sdk/lib-dynamodb");
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const schema = require("../schema");
const dynamoDBClient = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(dynamoDBClient);
const mySeders = () => [
// 401 if no login cookie
(req, res, next) => {
if (!req.cookies.login) {
return res.status(401).send({ err: "unauthenticated" });
}
return next();
},
// Get the cookie from the db, note the user email
async (req, res, next) => {
const getCookieQueryCommand = new QueryCommand({
TableName: schema.TABLE_NAME,
IndexName: schema.OPAQUE_COOKIE_INDEX,
KeyConditionExpression: `#OC = :oc`,
ExpressionAttributeNames: { "#OC": schema.OPAQUE_COOKIE },
ExpressionAttributeValues: { ":oc": req.cookies.login },
});
const getCookieQueryResponse = await docClient.send(getCookieQueryCommand);
if (
!getCookieQueryResponse ||
!getCookieQueryResponse.Items ||
!getCookieQueryResponse.Items[0]
) {
console.log(
"problem getting user nickname and email, getCookieQueryResponse",
getCookieQueryResponse
);
return res.status(401).send({ err: "unauthenticated" });
}
const { user_nickname, user_email } = getCookieQueryResponse.Items[0];
res.locals.user_email = user_email;
return next();
},
// Get the seders the user started
async (req, res, next) => {
const getMySedersQueryCommand = new QueryCommand({
TableName: schema.TABLE_NAME,
IndexName: schema.LEADER_EMAIL_INDEX,
KeyConditionExpression: `#LE = :le`,
ExpressionAttributeNames: { "#LE": schema.LEADER_EMAIL },
ExpressionAttributeValues: { ":le": res.locals.user_email },
});
const getMySedersQueryResponse = await docClient.send(
getMySedersQueryCommand
);
if (!getMySedersQueryResponse) {
console.log(
"problem getting leader's seders, getMySedersQueryResponse",
getMySedersQueryResponse
);
return res.status(500).send({ err: "server error" });
}
if (
!getMySedersQueryResponse.Items ||
!Array.isArray(getMySedersQueryResponse.Items)
) {
return res.send([]);
}
try {
res.locals.mySeders = getMySedersQueryResponse.Items.filter(
(item) => item.lib_id === schema.SEDER_PREFIX
).map((item) => {
return {
room_code: item.room_code,
created: item.created,
pw: item.pw,
timestamp: item.timestamp,
};
});
} catch (err) {
console.log(
"my-seders: problem getting seders from query response",
res.locals.user_email
);
console.log(err);
return res.status(500).send({ err: "server error" });
}
return res.send(res.locals.mySeders);
},
];
module.exports = mySeders;
19 changes: 0 additions & 19 deletions backend-v2/lib/setJwtCookies.js

This file was deleted.

42 changes: 42 additions & 0 deletions backend-v2/lib/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const {
DynamoDBDocumentClient,
QueryCommand,
} = require("@aws-sdk/lib-dynamodb");
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const schema = require("../schema");
const dynamoDBClient = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(dynamoDBClient);
const user = () => [
// 401 if no login cookie
(req, res, next) => {
if (!req.cookies.login) {
return res.status(401).send({ err: "unauthenticated" });
}
return next();
},
// Get the cookie from the db
async (req, res, next) => {
const getCookieQueryCommand = new QueryCommand({
TableName: schema.TABLE_NAME,
IndexName: schema.OPAQUE_COOKIE_INDEX,
KeyConditionExpression: `#OC = :oc`,
ExpressionAttributeNames: { "#OC": schema.OPAQUE_COOKIE },
ExpressionAttributeValues: { ":oc": req.cookies.login },
});
const getCookieQueryResponse = await docClient.send(getCookieQueryCommand);
if (
!getCookieQueryResponse ||
!getCookieQueryResponse.Items ||
!getCookieQueryResponse.Items[0]
) {
console.log(
"problem getting user nickname and email, getCookieQueryResponse",
getCookieQueryResponse
);
return res.status(401).send({ err: "unauthenticated" });
}
const { user_nickname, user_email } = getCookieQueryResponse.Items[0];
return res.send({ user_nickname, user_email });
},
];
module.exports = user;
Loading

0 comments on commit 6068e95

Please sign in to comment.