Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
10 changed files
with
371 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
#!/usr/bin/env node | ||
|
||
/** | ||
* Routes File | ||
*/ | ||
|
||
'use strict' | ||
|
||
/* MODULE IMPORTS */ | ||
const Koa = require('koa') | ||
const Router = require('koa-router') | ||
const views = require('koa-views') | ||
const staticDir = require('koa-static') | ||
const bodyParser = require('koa-bodyparser') | ||
const koaBody = require('koa-body')({multipart: true, uploadDir: '.'}) | ||
const session = require('koa-session') | ||
const sqlite = require('sqlite-async') | ||
const bcrypt = require('bcrypt-promise') | ||
const fs = require('fs-extra') | ||
const mime = require('mime-types') | ||
//const jimp = require('jimp') | ||
|
||
/* IMPORT CUSTOM MODULES */ | ||
const accounts = require('./modules/accounts') | ||
|
||
const app = new Koa() | ||
const router = new Router() | ||
|
||
/* CONFIGURING THE MIDDLEWARE */ | ||
app.keys = ['darkSecret'] | ||
app.use(staticDir('public')) | ||
app.use(bodyParser()) | ||
app.use(session(app)) | ||
app.use(views(`${__dirname}/views`, { extension: 'handlebars' }, {map: { handlebars: 'handlebars' }})) | ||
|
||
const port = 8080 | ||
const saltRounds = 10 | ||
|
||
/** | ||
* The secure home page. | ||
* | ||
* @name Home Page | ||
* @route {GET} / | ||
* @authentication This route requires cookie-based authentication. | ||
*/ | ||
router.get('/', async ctx => { | ||
try { | ||
if(ctx.session.authorised !== true) return ctx.redirect('/login?msg=you need to log in') | ||
const data = {} | ||
if(ctx.query.msg) data.msg = ctx.query.msg | ||
await ctx.render('index') | ||
} catch(err) { | ||
await ctx.render('error', {message: err.message}) | ||
} | ||
}) | ||
|
||
/** | ||
* The user registration page. | ||
* | ||
* @name Register Page | ||
* @route {GET} /register | ||
*/ | ||
router.get('/register', async ctx => await ctx.render('register')) | ||
|
||
/** | ||
* The script to process new user registrations. | ||
* | ||
* @name Register Script | ||
* @route {POST} /register | ||
*/ | ||
router.post('/register', koaBody, async ctx => { | ||
try { | ||
const body = ctx.request.body | ||
console.log(body) | ||
// PROCESSING FILE | ||
const {path, type} = ctx.request.files.avatar | ||
const fileExtension = mime.extension(type) | ||
console.log(`path: ${path}`) | ||
console.log(`type: ${type}`) | ||
console.log(`fileExtension: ${fileExtension}`) | ||
await fs.copy(path, 'public/avatars/avatar.png') | ||
// ENCRYPTING PASSWORD AND BUILDING SQL | ||
body.pass = await bcrypt.hash(body.pass, saltRounds) | ||
const sql = `INSERT INTO users(user, pass) VALUES("${body.user}", "${body.pass}")` | ||
console.log(sql) | ||
// DATABASE COMMANDS | ||
const db = await sqlite.open('./website.db') | ||
await db.run(sql) | ||
await db.close() | ||
// REDIRECTING USER TO HOME PAGE | ||
ctx.redirect(`/?msg=new user "${body.name}" added`) | ||
} catch(err) { | ||
await ctx.render('error', {message: err.message}) | ||
} | ||
}) | ||
|
||
router.get('/login', async ctx => { | ||
const data = {} | ||
if(ctx.query.msg) data.msg = ctx.query.msg | ||
if(ctx.query.user) data.user = ctx.query.user | ||
await ctx.render('login', data) | ||
}) | ||
|
||
router.post('/login', async ctx => { | ||
try { | ||
const body = ctx.request.body | ||
const db = await sqlite.open('./website.db') | ||
// DOES THE USERNAME EXIST? | ||
const records = await db.get(`SELECT count(id) AS count FROM users WHERE user="${body.user}";`) | ||
if(!records.count) return ctx.redirect('/login?msg=invalid%20username') | ||
const record = await db.get(`SELECT pass FROM users WHERE user = "${body.user}";`) | ||
await db.close() | ||
// DOES THE PASSWORD MATCH? | ||
const valid = await bcrypt.compare(body.pass, record.pass) | ||
if(valid == false) return ctx.redirect(`/login?user=${body.user}&msg=invalid%20password`) | ||
// WE HAVE A VALID USERNAME AND PASSWORD | ||
ctx.session.authorised = true | ||
return ctx.redirect('/?msg=you are now logged in...') | ||
} catch(err) { | ||
await ctx.render('error', {message: err.message}) | ||
} | ||
}) | ||
|
||
// router.post('/login', async ctx => { // 19 lines reduced to 10! | ||
// const body = ctx.request.body | ||
// try { | ||
// await accounts.checkCredentials(body.user, body.pass) | ||
// ctx.session.authorised = true | ||
// return ctx.redirect('/?msg=you are now logged in...') | ||
// } catch(err) { | ||
// return ctx.redirect(`/login?user=${body.user}&msg=${err.message}`) | ||
// } | ||
// }) | ||
|
||
router.get('/logout', async ctx => { | ||
ctx.session.authorised = null; | ||
ctx.redirect('/') | ||
}) | ||
|
||
app.use(router.routes()) | ||
module.exports = app.listen(port, async() => { | ||
// MAKE SURE WE HAVE A DATABASE WITH THE CORRECT SCHEMA | ||
const db = await sqlite.open('./website.db') | ||
await db.run('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, pass TEXT);') | ||
await db.close() | ||
console.log(`listening on port ${port}`) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
#!/usr/bin/env node | ||
|
||
/** | ||
* Accounts module | ||
* @module modules/accounts | ||
*/ | ||
|
||
'use strict' | ||
|
||
var sqlite = require('sqlite-async'); | ||
let bcrypt = require('bcrypt-promise'); | ||
|
||
/** | ||
* This is a generic function that opens the database, executes a query, | ||
* closes the database connection and returns the data. | ||
* @param {String} query - The SQL statement to execute. | ||
* @returns {Object} - the date returned by the query. | ||
*/ | ||
async function runSQL(query) { | ||
try { | ||
console.log(query) | ||
let DBName = "./website.db"; | ||
const db = await sqlite.open(DBName); | ||
const data = await db.all(query); | ||
await db.close(); | ||
if(data.length === 1) return data[0] | ||
return data; | ||
} catch(err) { | ||
throw err | ||
} | ||
} | ||
|
||
module.exports.checkCredentials = async(username, password)=> { | ||
try { | ||
var records = await runSQL(`SELECT count(id) AS count FROM users WHERE user="${username}";`); | ||
if(!records.count) throw new Error("invalid username") | ||
const record = await runSQL(`SELECT pass FROM users WHERE user = "${username}";`) | ||
const valid = await bcrypt.compare(password, record.pass) | ||
if(valid == false) throw new Error(`invalid password`) | ||
return true | ||
} catch(err) { | ||
throw err | ||
} | ||
} | ||
|
||
|
||
|
||
/* ----------------------------- STUB FUNCTIONS ----------------------------- */ | ||
|
||
/** | ||
* This function checks the database to see if a username already exists in | ||
* the database. If it detects a duplicate it throws an exception. | ||
* @param {String} username - The username to check. | ||
* @returns {boolean} - returns true if the username does not exist. | ||
* @throws {Error} - throws an error if the username already exists. | ||
*/ | ||
async function checkNoDuplicateUsername (username) { | ||
return true | ||
} | ||
|
||
/** | ||
* This function takes data from an uploaded image and saves it to the `avatars` directory. The file name will be the username. | ||
* @param {String} path - the location of the uploaded image | ||
* @param {String} mimeType - the mime type of the uploaded file. | ||
* @returns {boolean} - returns true if the image is valid and is saved. | ||
* @throws {TypeError} - throws an error if the file is not a png or jpg image. | ||
*/ | ||
async function saveImage(path, mimetype) { | ||
return true | ||
} | ||
|
||
/** | ||
* This function adds new users to the database. | ||
* @param {String} username - The username to to add. | ||
* @param {String} password - The password to add. | ||
* @returns {boolean} - returns true if the username does not exist. | ||
* @throws {Error} - throws an error if the new user account has been created. | ||
*/ | ||
module.exports.addUser = async(username, password) => { | ||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
|
||
{ | ||
"name": "10_auth", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"acceptance": "jest --coverage --detectOpenHandles", | ||
"jsdoc": "node_modules/.bin/jsdoc -c jsdoc.conf", | ||
"linter": "node_modules/.bin/eslint .", | ||
"test": "jest --coverage --detectOpenHandles", | ||
"unit": "node_modules/.bin/jest --coverage --runInBand tests/unit/" | ||
}, | ||
"jest": { | ||
"testEnvironment": "node", | ||
"verbose": true, | ||
"collectCoverage": true, | ||
"coverageDirectory": "docs/coverage/", | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 0, | ||
"functions": 0, | ||
"lines": 0, | ||
"statements": 0 | ||
} | ||
} | ||
}, | ||
"author": "", | ||
"license": "ISC", | ||
"dependencies": { | ||
"bcrypt": "^3.0.3", | ||
"bcrypt-promise": "^2.0.0", | ||
"fs-extra": "^7.0.1", | ||
"handlebars": "^4.1.2", | ||
"jimp": "^0.6.0", | ||
"koa": "^2.6.2", | ||
"koa-body": "^4.0.8", | ||
"koa-bodyparser": "^4.2.1", | ||
"koa-router": "^7.4.0", | ||
"koa-session": "^5.10.1", | ||
"koa-static": "^5.0.0", | ||
"koa-views": "^6.1.5", | ||
"mime-types": "^2.1.22", | ||
"sqlite-async": "^1.0.11" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^5.15.2", | ||
"handlebars-validate": "^0.1.2", | ||
"html-validator-cli": "^6.0.0", | ||
"http-status-codes": "^1.3.2", | ||
"jest": "^24.1.0", | ||
"jsdoc": "^3.5.5", | ||
"jsdoc-route-plugin": "^0.1.0", | ||
"puppeteer": "^1.12.2", | ||
"site-validator-cli": "^1.0.1", | ||
"supertest": "^4.0.2" | ||
} | ||
} |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
body { | ||
font-family: Arial, Helvetica, sans-serif; | ||
} | ||
|
||
.msg { | ||
border: 1px solid red; | ||
font-weight: bold; | ||
color: red; | ||
padding: 1em; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!doctype html> | ||
|
||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>ERROR</title> | ||
<meta name="description" content="The HTML5 Template"> | ||
<meta name="author" content="Joe Bloggs"> | ||
<link href="style.css" type="text/css" rel="stylesheet" /> | ||
</head> | ||
<body> | ||
<h1>An Error Has Occurred</h1> | ||
<h2>{{message}}</h2> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!doctype html> | ||
|
||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Home Page</title> | ||
<meta name="description" content="form to add new books"> | ||
<meta name="author" content="Mark Tyers"> | ||
<link href="style.css" type="text/css" rel="stylesheet" /> | ||
</head> | ||
<body> | ||
<h1>Home</h1> | ||
<p>This is a secure page. Users need to have a valid account and be logged in to see it.</p> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
|
||
<!doctype html> | ||
|
||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Log In</title> | ||
<meta name="description" content="form to add new books"> | ||
<meta name="author" content="Mark Tyers"> | ||
<link href="style.css" type="text/css" rel="stylesheet" /> | ||
</head> | ||
<body> | ||
<h1>Log In</h1> | ||
{{#if msg}} | ||
<p class="msg">{{msg}}</p> | ||
{{/if}} | ||
<form action="/login" method="post"> | ||
<p>Username:<br /><input type="text" name="user" placeholder="your username" value="{{user}}" autofocus></p> | ||
<p>Password:<br /><input type="password" name="pass" placeholder="your password" value=""></p> | ||
<p><input type="submit" value="Log in"></p> | ||
</form> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<!doctype html> | ||
|
||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Create an Account</title> | ||
<meta name="description" content="form to add new books"> | ||
<meta name="author" content="Mark Tyers"> | ||
<link href="style.css" type="text/css" rel="stylesheet" /> | ||
</head> | ||
<body> | ||
<h1>Create an Account</h1> | ||
<form action="/register" enctype="multipart/form-data" method="post"> | ||
<p>Username:<br /><input type="text" name="user" placeholder="your preferred username (no spaces)" value=""></p> | ||
<p>Password:<br /><input type="password" name="pass" placeholder="your chosen password" value=""></p> | ||
<p>Profile Picture:<br /><input type="file" name="avatar"></p> | ||
<p><input type="submit" value="Create"></p> | ||
</form> | ||
</body> | ||
</html> |