Skip to content

Commit 5036ab7

Browse files
committed
initial
0 parents  commit 5036ab7

17 files changed

+11713
-0
lines changed

.eslintrc.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"env": {
3+
"commonjs": true,
4+
"es2021": true,
5+
"node": true,
6+
"jest": true
7+
},
8+
"extends": "eslint:recommended",
9+
"parserOptions": {
10+
"ecmaVersion": "latest"
11+
},
12+
"rules": {
13+
}
14+
}

.github/lockdown.yml

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# PLEASE DO NOT REMOVE THIS FILE
2+
3+
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
4+
5+
# Skip issues and pull requests created before a given timestamp. Timestamp must
6+
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
7+
skipCreatedBefore: false
8+
9+
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
10+
exemptLabels: []
11+
12+
# Comment to post before closing or locking. Set to `false` to disable
13+
comment: false
14+
15+
# Label to add before closing or locking. Set to `false` to disable
16+
label: false
17+
18+
# Close issues and pull requests
19+
close: true
20+
21+
# Lock issues and pull requests
22+
lock: true
23+
24+
# Limit to only `issues` or `pulls`
25+
only: pulls
26+
# Optionally, specify configuration settings just for `issues` or `pulls`
27+
# issues:
28+
# label: wontfix
29+
30+
# pulls:
31+
# comment: >
32+
# This repository does not accept pull requests, see the README for details.
33+
# lock: false
34+
35+
# Repository to extend settings from
36+
# _extends: repo

.gitignore

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
9+
# Diagnostic reports (https://nodejs.org/api/report.html)
10+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
*.pid.lock
17+
18+
# Directory for instrumented libs generated by jscoverage/JSCover
19+
lib-cov
20+
21+
# Coverage directory used by tools like istanbul
22+
coverage
23+
*.lcov
24+
25+
# nyc test coverage
26+
.nyc_output
27+
28+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29+
.grunt
30+
31+
# Bower dependency directory (https://bower.io/)
32+
bower_components
33+
34+
# node-waf configuration
35+
.lock-wscript
36+
37+
# Compiled binary addons (https://nodejs.org/api/addons.html)
38+
build/Release
39+
40+
# Dependency directories
41+
node_modules/
42+
jspm_packages/
43+
44+
# Snowpack dependency directory (https://snowpack.dev/)
45+
web_modules/
46+
47+
# TypeScript cache
48+
*.tsbuildinfo
49+
50+
# Optional npm cache directory
51+
.npm
52+
53+
# Optional eslint cache
54+
.eslintcache
55+
56+
# Microbundle cache
57+
.rpt2_cache/
58+
.rts2_cache_cjs/
59+
.rts2_cache_es/
60+
.rts2_cache_umd/
61+
62+
# Optional REPL history
63+
.node_repl_history
64+
65+
# Output of 'npm pack'
66+
*.tgz
67+
68+
# Yarn Integrity file
69+
.yarn-integrity
70+
71+
# dotenv environment variables file
72+
.env
73+
.env.test
74+
75+
# parcel-bundler cache (https://parceljs.org/)
76+
.cache
77+
.parcel-cache
78+
79+
# Next.js build output
80+
.next
81+
out
82+
83+
# Nuxt.js build / generate output
84+
.nuxt
85+
dist
86+
87+
# Gatsby files
88+
.cache/
89+
# Comment in the public line in if your project uses Gatsby and not Next.js
90+
# https://nextjs.org/blog/next-9-1#public-directory-support
91+
# public
92+
93+
# vuepress build output
94+
.vuepress/dist
95+
96+
# Serverless directories
97+
.serverless/
98+
99+
# FuseBox cache
100+
.fusebox/
101+
102+
# DynamoDB Local files
103+
.dynamodb/
104+
105+
# TernJS port file
106+
.tern-port
107+
108+
# Stores VSCode versions used for testing VSCode extensions
109+
.vscode-test
110+
111+
# yarn v2
112+
.yarn/cache
113+
.yarn/unplugged
114+
.yarn/build-state.yml
115+
.yarn/install-state.gz
116+
.pnp.*
117+
118+
# Mac Cruft
119+
.DS_Store
120+
121+
# VSCode
122+
.vscode
123+
124+
# databases
125+
*.db3

README.md

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Authentication and Testing Sprint Challenge
2+
3+
**Read these instructions carefully. Understand exactly what is expected _before_ starting this Sprint Challenge.**
4+
5+
This challenge allows you to practice the concepts and techniques learned over the past sprint and apply them in a concrete project. This sprint explored **Authentication and Testing**. During this sprint, you studied **authentication, JSON web tokens, unit testing, and backend testing**. In your challenge this week, you will demonstrate your mastery of these skills by creating **a dad jokes app**.
6+
7+
This is an individual assessment. All work must be your own. All projects will be submitted to Codegrade for automated review. You will also be given feedback by code reviewers on Monday following the challenge submission. For more information on the review process [click here.](https://www.notion.so/bloomtech/How-to-View-Feedback-in-CodeGrade-c5147cee220c4044a25de28bcb6bb54a)
8+
9+
You are not allowed to collaborate during the sprint challenge.
10+
11+
## Project Setup
12+
13+
- [ ] Run `npm install` to install your dependencies.
14+
- [ ] Build your database executing `npm run migrate`.
15+
- [ ] Run tests locally executing `npm test`.
16+
17+
## Project Instructions
18+
19+
Dad jokes are all the rage these days! In this challenge, you will build a real wise-guy application.
20+
21+
Users must be able to call the `[POST] /api/auth/register` endpoint to create a new account, and the `[POST] /api/auth/login` endpoint to get a token.
22+
23+
We also need to make sure nobody without the token can call `[GET] /api/jokes` and gain access to our dad jokes.
24+
25+
We will hash the user's password using `bcryptjs`, and use JSON Web Tokens and the `jsonwebtoken` library.
26+
27+
### MVP
28+
29+
Your finished project must include all of the following requirements (further instructions are found inside each file):
30+
31+
- [ ] An authentication workflow with functionality for account creation and login, implemented inside `api/auth/auth-router.js`.
32+
- [ ] Middleware used to restrict access to resources from non-authenticated requests, implemented inside `api/middleware/restricted.js`.
33+
- [ ] A minimum of 2 tests per API endpoint, written inside `api/server.test.js`.
34+
35+
**IMPORTANT Notes:**
36+
37+
- Do not exceed 2^8 rounds of hashing with `bcryptjs`.
38+
- If you use environment variables make sure to provide fallbacks in the code (e.g. `process.env.SECRET || "shh"`).
39+
- You are welcome to create additional files but **do not move or rename existing files** or folders.
40+
- Do not alter your `package.json` file except to install extra libraries. Do not update existing packages.
41+
- The database already has the `users` table, but if you run into issues, the migration is available.
42+
- In your solution, it is essential that you follow best practices and produce clean and professional results.
43+
- Schedule time to review, refine, and assess your work and perform basic professional polishing.
44+
45+
## Submission format
46+
47+
- [ ] Submit via Codegrade by pushing commits to your `main` branch on Github.
48+
- [ ] Check Codegrade before the deadline to compare its results against your local tests.
49+
- [ ] Check Codegrade on the days following the Sprint Challenge for reviewer feedback.
50+
- [ ] New commits will be evaluated by Codegrade if pushed _before_ the sprint challenge deadline.
51+
52+
## Interview Questions
53+
54+
Be prepared to demonstrate your understanding of this week's concepts by answering questions on the following topics.
55+
56+
1. Differences between using _sessions_ or _JSON Web Tokens_ for authentication.
57+
2. What does `bcryptjs` do to help us store passwords in a secure manner?
58+
3. How are unit tests different from integration and end-to-end testing?
59+
4. How does _Test Driven Development_ change the way we write applications and tests?

api/auth/auth-router.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const router = require('express').Router();
2+
3+
router.post('/register', (req, res) => {
4+
res.end('implement register, please!');
5+
/*
6+
IMPLEMENT
7+
You are welcome to build additional middlewares to help with the endpoint's functionality.
8+
DO NOT EXCEED 2^8 ROUNDS OF HASHING!
9+
10+
1- In order to register a new account the client must provide `username` and `password`:
11+
{
12+
"username": "Captain Marvel", // must not exist already in the `users` table
13+
"password": "foobar" // needs to be hashed before it's saved
14+
}
15+
16+
2- On SUCCESSFUL registration,
17+
the response body should have `id`, `username` and `password`:
18+
{
19+
"id": 1,
20+
"username": "Captain Marvel",
21+
"password": "2a$08$jG.wIGR2S4hxuyWNcBf9MuoC4y0dNy7qC/LbmtuFBSdIhWks2LhpG"
22+
}
23+
24+
3- On FAILED registration due to `username` or `password` missing from the request body,
25+
the response body should include a string exactly as follows: "username and password required".
26+
27+
4- On FAILED registration due to the `username` being taken,
28+
the response body should include a string exactly as follows: "username taken".
29+
*/
30+
});
31+
32+
router.post('/login', (req, res) => {
33+
res.end('implement login, please!');
34+
/*
35+
IMPLEMENT
36+
You are welcome to build additional middlewares to help with the endpoint's functionality.
37+
38+
1- In order to log into an existing account the client must provide `username` and `password`:
39+
{
40+
"username": "Captain Marvel",
41+
"password": "foobar"
42+
}
43+
44+
2- On SUCCESSFUL login,
45+
the response body should have `message` and `token`:
46+
{
47+
"message": "welcome, Captain Marvel",
48+
"token": "eyJhbGciOiJIUzI ... ETC ... vUPjZYDSa46Nwz8"
49+
}
50+
51+
3- On FAILED login due to `username` or `password` missing from the request body,
52+
the response body should include a string exactly as follows: "username and password required".
53+
54+
4- On FAILED login due to `username` not existing in the db, or `password` being incorrect,
55+
the response body should include a string exactly as follows: "invalid credentials".
56+
*/
57+
});
58+
59+
module.exports = router;

api/jokes/jokes-data.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// do not make changes to this file
2+
const jokes = [
3+
{
4+
"id": "0189hNRf2g",
5+
"joke": "I'm tired of following my dreams. I'm just going to ask them where they are going and meet up with them later."
6+
},
7+
{
8+
"id": "08EQZ8EQukb",
9+
"joke": "Did you hear about the guy whose whole left side was cut off? He's all right now."
10+
},
11+
{
12+
"id": "08xHQCdx5Ed",
13+
"joke": "Why didn’t the skeleton cross the road? Because he had no guts."
14+
},
15+
];
16+
17+
module.exports = jokes;

api/jokes/jokes-router.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// do not make changes to this file
2+
const router = require('express').Router();
3+
const jokes = require('./jokes-data');
4+
5+
router.get('/', (req, res) => {
6+
res.status(200).json(jokes);
7+
});
8+
9+
module.exports = router;

api/middleware/restricted.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module.exports = (req, res, next) => {
2+
next();
3+
/*
4+
IMPLEMENT
5+
6+
1- On valid token in the Authorization header, call next.
7+
8+
2- On missing token in the Authorization header,
9+
the response body should include a string exactly as follows: "token required".
10+
11+
3- On invalid or expired token in the Authorization header,
12+
the response body should include a string exactly as follows: "token invalid".
13+
*/
14+
};

api/server.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const express = require('express');
2+
const cors = require('cors');
3+
const helmet = require('helmet');
4+
5+
const restrict = require('./middleware/restricted.js');
6+
7+
const authRouter = require('./auth/auth-router.js');
8+
const jokesRouter = require('./jokes/jokes-router.js');
9+
10+
const server = express();
11+
12+
server.use(helmet());
13+
server.use(cors());
14+
server.use(express.json());
15+
16+
server.use('/api/auth', authRouter);
17+
server.use('/api/jokes', restrict, jokesRouter); // only logged-in users should have access!
18+
19+
module.exports = server;

api/server.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Write your tests here
2+
test('sanity', () => {
3+
expect(true).toBe(false)
4+
})

data/dbConfig.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// do not make changes to this file
2+
const knex = require('knex');
3+
const knexConfig = require('../knexfile.js');
4+
const environment = process.env.NODE_ENV || 'development';
5+
6+
module.exports = knex(knexConfig[environment]);
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
exports.up = function (knex) {
2+
return knex.schema.createTable('users', users => {
3+
users.increments();
4+
users.string('username', 255).notNullable().unique();
5+
users.string('password', 255).notNullable();
6+
});
7+
};
8+
9+
exports.down = function (knex) {
10+
return knex.schema.dropTableIfExists('users');
11+
};

index.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const server = require('./api/server.js');
2+
3+
const PORT = process.env.PORT || 3300;
4+
server.listen(PORT, () => {
5+
console.log(`\n=== Server listening on port ${PORT} ===\n`);
6+
});

0 commit comments

Comments
 (0)