diff --git a/.eslintrc.js b/.eslintrc.js index 3eea15a..c98172d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,7 +23,12 @@ module.exports = { 'max-lines-per-function': ['error', { max: 75, skipComments: true }], 'no-underscore-dangle': 0, 'react/jsx-props-no-spreading': 0, - 'react/prop-types': 0 - + 'react/prop-types': 0, + 'prettier/prettier': [ + 'error', + { + endOfLine: 'auto' + } + ] } }; diff --git a/src/models/AuthCode.test.ts b/src/models/AuthCode.test.ts index 4ad4acd..64113ee 100644 --- a/src/models/AuthCode.test.ts +++ b/src/models/AuthCode.test.ts @@ -1,13 +1,7 @@ import { TEST_USER } from '../../jest.setup'; import AuthCode from './AuthCode'; -/** - * TODO: (1.05) - * - Remove the ".skip" from the following function. - * - Go to your terminal and run the following command: - * npm run test AuthCode - * - Delete this comment. - */ + describe('Model: AuthCode', () => { test('Should auto generate an OTP for value.', async () => { // Even though we don't specify a value for the OTP code, it should diff --git a/src/models/AuthCode.ts b/src/models/AuthCode.ts index 0bff1dd..14287b6 100644 --- a/src/models/AuthCode.ts +++ b/src/models/AuthCode.ts @@ -34,15 +34,7 @@ const authCodeSchema: Schema = new Schema( { timestamps: true } ); -/** - * (1.04) TODO: - * - Add a line of code here that will elete every document in the "AuthCode" - * collection after 5 minutes (60 seconds * 5). - * - To be very clear, the only way you're going to figure this out is by - * Googling around for the answer. The solution is one line. - * - Once you find something, add the code to this document and include a link - * to the code you found in a comment. - * */ +authCodeSchema.index({ createdAt: 1 }, { expireAfterSeconds: 60 * 5 }); authCodeSchema.index({ createdAt: 1 }, { expireAfterSeconds: 60 * 5 }); diff --git a/src/routes/LogoutRoute.test.ts b/src/routes/LogoutRoute.test.ts index 48688b4..0846ca7 100644 --- a/src/routes/LogoutRoute.test.ts +++ b/src/routes/LogoutRoute.test.ts @@ -1,14 +1,7 @@ import { TEST_AUTH_COOKIE } from '../../jest.setup'; import TestUtils from '../utils/TestUtils'; -/** - * TODO: (9.03) - * - Remove the ".skip" from the following function. - * - Go to your terminal and run the following command: - * npm run test Logout - * - Delete this comment. - */ -describe.skip('POST /logout', () => { +describe('POST /logout', () => { test('If the user is not authenticated, should return a 401.', async () => { await TestUtils.agent.post('/logout').expect(401); }); diff --git a/src/routes/LogoutRoute.ts b/src/routes/LogoutRoute.ts index 4546792..1f23cdb 100644 --- a/src/routes/LogoutRoute.ts +++ b/src/routes/LogoutRoute.ts @@ -7,17 +7,9 @@ import { RouteMethod } from '../utils/constants'; export default class LogoutRoute extends BaseRoute { constructor() { super({ - /** - * TODO: (9.01) - * - Should the user be authenticated to hit this route? - * - Replace null with the correct route type from the RouteMethod enum - * in the constants.ts file. - * - Fill in the path string with the appropriate path to this endpoint. - * - Delete this comment. - */ - authenticated: false, - method: null, - path: '/' + authenticated: true, + method: RouteMethod.POST, + path: '/logout' }); } @@ -29,9 +21,9 @@ export default class LogoutRoute extends BaseRoute { * Returns true in all cases. */ async content(_: ApplicationRequest, res: Response): Promise { - // TODO: (9.02) Use the res.clearCookie('') function to remove the - // accessToken and refreshToken from their cookies. Return true after! + res.clearCookie('accessToken'); + res.clearCookie('refreshToken'); - return false; + return true; } } diff --git a/src/routes/VerifyCodeRoute.test.ts b/src/routes/VerifyCodeRoute.test.ts index ed8a12e..f6f3669 100644 --- a/src/routes/VerifyCodeRoute.test.ts +++ b/src/routes/VerifyCodeRoute.test.ts @@ -2,14 +2,7 @@ import { TEST_USER } from '../../jest.setup'; import AuthCode, { AuthCodeDocument } from '../models/AuthCode'; import TestUtils from '../utils/TestUtils'; -/** - * TODO: (8.08) - * - Remove the ".skip" from the following function. - * - Go to your terminal and run the following command: - * npm run test VerifyCode - * - Delete this comment. - */ -describe.skip('POST /verify', () => { +describe('POST /verify', () => { test('If code is not a number, return a 400.', async () => { await TestUtils.agent.post('/verify').send({ code: '123456' }).expect(400); }); diff --git a/src/routes/VerifyCodeRoute.ts b/src/routes/VerifyCodeRoute.ts index 64f258a..f9f2f10 100644 --- a/src/routes/VerifyCodeRoute.ts +++ b/src/routes/VerifyCodeRoute.ts @@ -18,15 +18,8 @@ type VerifyCodeRequest = ApplicationRequest<{}, VerifyCodeBody>; export default class VerifyCodeRoute extends BaseRoute { constructor() { super({ - /** - * TODO: (8.01) - * - Replace null with the correct route type from the RouteMethod enum - * in the constants.ts file. - * - Fill in the path string with the appropriate path to this endpoint. - * - Delete this comment. - */ - method: null, - path: '/' + method: RouteMethod.POST, + path: '/verify' }); } @@ -36,14 +29,13 @@ export default class VerifyCodeRoute extends BaseRoute { * - body.phoneNumber */ middleware() { - /** - * TODO: (8.02) - * - Add another validation in the returned array to verify that the code - * from the body of the request is a 6-digit number. - * - We've left in the code that will verify that the phone number is a - * valid US phone number and checks if its in our database. - */ return [ + body('code') + .isInt() + .withMessage('Invalid input. Expected an integer') + .isLength({ max: 6, min: 6 }) + .withMessage('The code must be a 6-digit number'), + body('phoneNumber') .isMobilePhone('en-US') .withMessage('The phone number you inputted was not valid.') @@ -70,27 +62,29 @@ export default class VerifyCodeRoute extends BaseRoute { * @throws {RouteError} - If the code does not match what is in DB. */ async content(req: VerifyCodeRequest, res: Response): Promise { - // TODO: (8.03) Get the code and phone number from the request body. + const { code, phoneNumber } = req.body; + + const authCode: AuthCodeDocument = await AuthCode.findOne({ phoneNumber }); - // TODO: (8.04) Find the real code associated with the number from our - // database. + if (authCode.value !== code) { + throw new RouteError({ + message: 'Invalid code!', + statusCode: 401 + }); + } - // TODO: (8.05) Compare the code we received in the request body with the - // one from our database. If they differ, throw a RouteError and them know - // what's wrong. + let user: UserDocument = await User.findOne({ phoneNumber }); - // TODO: (8.06) First try to get the user by fetching them from DB. But, if - // they don't already exist, then just create a new user. - const user: UserDocument = null; + if (!user) { + user = await User.create({ phoneNumber }); + } // Renew's the user's tokens and attaches these new tokens on the // Express response object to send back to the client. const { accessToken, refreshToken } = await user.renewToken(); MiddlewareUtils.attachTokens(res, { accessToken, refreshToken }); - // TODO: (8.07) In the case that the user properly authenticates with the - // code, we no longer want to store the authentication code - // (it's short-lived), so we delete it! + await AuthCode.deleteOne({ phoneNumber }); return true; } diff --git a/src/utils/AuthUtils.ts b/src/utils/AuthUtils.ts index 1c985aa..0884c1d 100644 --- a/src/utils/AuthUtils.ts +++ b/src/utils/AuthUtils.ts @@ -8,6 +8,19 @@ import { APP } from './constants'; * all 0's. */ const generateOTP = (): number => { + + // Generate a number between 0 and 1. + const randomFraction: number = Math.random(); + + // Multiply that number by 900000 + const sixDigit: number = randomFraction * 900000; + + // Get rid of decimal + const sixDigitNumber: number = Math.floor(sixDigit); + + // return 6-digit number + return sixDigitNumber + 100000; +======= // Generate a number between 0 and 1 const randomFraction: number = Math.random(); @@ -19,6 +32,7 @@ const generateOTP = (): number => { // return the 6 digit number return sixDigitWholeNumber + 100000; + }; /**