Hash passwords with bcrypt

This commit is contained in:
viktorstrate
2019-08-20 16:37:15 +02:00
parent 4d563f3815
commit a5513e3343
7 changed files with 162 additions and 34 deletions

View File

@@ -5,4 +5,5 @@ NEO4J_PASSWORD=letmein
GRAPHQL_LISTEN_PORT=4001
API_ENDPOINT=http://localhost:4001/
JWT_SECRET=You-sh0uld_Change-Th1s
JWT_SECRET=You-sh0uld_Change-Th1s
ENCRYPTION_SALT_ROUNDS=12

View File

@@ -13,7 +13,8 @@
"sourceType": "module"
},
"rules": {
"no-unused-vars": "off"
"no-unused-vars": "off",
"require-atomic-updates": "off"
},
"parser": "babel-eslint"
}

123
api/package-lock.json generated
View File

@@ -1170,8 +1170,7 @@
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"accepts": {
"version": "1.3.7",
@@ -1736,8 +1735,7 @@
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"base": {
"version": "0.11.2",
@@ -1799,6 +1797,22 @@
"resolved": "https://registry.npmjs.org/batch-cluster/-/batch-cluster-5.6.7.tgz",
"integrity": "sha512-IyXDIg9XoRlfqXJr2mXem44plYswk8c4wERfeXuZ16fXf8PqZkLRXsuJtuWOBSEqO1Xo4vQ2zK6irYiEpA8VGA=="
},
"bcrypt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.6.tgz",
"integrity": "sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==",
"requires": {
"nan": "2.13.2",
"node-pre-gyp": "0.12.0"
},
"dependencies": {
"nan": {
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
"integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw=="
}
}
},
"binary-extensions": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
@@ -1869,7 +1883,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -2205,8 +2218,7 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"configstore": {
"version": "3.1.2",
@@ -3325,8 +3337,7 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "1.2.9",
@@ -3958,7 +3969,6 @@
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -4317,6 +4327,14 @@
"integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=",
"dev": true
},
"ignore-walk": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"requires": {
"minimatch": "^3.0.4"
}
},
"image-extensions": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/image-extensions/-/image-extensions-1.1.0.tgz",
@@ -4367,7 +4385,6 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@@ -5385,7 +5402,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -5494,6 +5510,26 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
"needle": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz",
"integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==",
"requires": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
@@ -5553,6 +5589,34 @@
"resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
"integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA="
},
"node-pre-gyp": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4"
},
"dependencies": {
"nopt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
}
}
}
},
"node-releases": {
"version": "1.1.26",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.26.tgz",
@@ -5623,6 +5687,20 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
"npm-bundled": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g=="
},
"npm-packlist": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz",
"integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==",
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1"
}
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -5794,8 +5872,16 @@
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"output-file-sync": {
"version": "2.0.1",
@@ -5909,8 +5995,7 @@
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-is-inside": {
"version": "1.0.2",
@@ -6437,7 +6522,6 @@
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
@@ -6491,6 +6575,11 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",

View File

@@ -22,6 +22,7 @@
"apollo-link-http": "^1.5.14",
"apollo-server": "^2.8.1",
"babel-runtime": "^6.26.0",
"bcrypt": "^3.0.6",
"body-parser": "^1.19.0",
"core-js": "^3.2.0",
"dotenv": "^8.0.0",

View File

@@ -1,6 +1,15 @@
import path from 'path'
// set environment variables from ../.env
require('dotenv').config()
let encryptionSaltRounds = 10
if (parseInt(process.env.ENCRYPTION_SALT_ROUNDS)) {
encryptionSaltRounds = parseInt(process.env.ENCRYPTION_SALT_ROUNDS)
}
export default {
cachePath: process.env.PHOTO_CACHE || path.resolve(__dirname, 'cache'),
host: new URL(process.env.API_ENDPOINT || 'http://localhost:4001/'),
encryptionSaltRounds,
}

View File

@@ -3,7 +3,6 @@ import express from 'express'
import bodyParser from 'body-parser'
import cors from 'cors'
import { v1 as neo4j } from 'neo4j-driver'
import dotenv from 'dotenv'
import http from 'http'
import PhotoScanner from './scanner/Scanner'
import _ from 'lodash'
@@ -11,9 +10,6 @@ import config from './config'
import { getUserFromToken, getTokenFromBearer } from './token'
// set environment variables from ../.env
dotenv.config()
const app = express()
app.use(bodyParser.json())
app.use(cors())

View File

@@ -1,18 +1,20 @@
import jwt from 'jsonwebtoken'
import generateID from '../id-generator'
import fs from 'fs-extra'
import bcrypt from 'bcrypt'
import { neo4jgraphql } from 'neo4j-graphql-js'
import config from '../config'
const Mutation = {
async authorizeUser(root, args, ctx, info) {
console.log('Authorize user')
let { username, password } = args
let { username } = args
let session = ctx.driver.session()
let result = await session.run(
'MATCH (usr:User {username: {username}, password: {password} }) RETURN usr.id, usr.admin',
{ username, password }
'MATCH (user:User {username: {username}}) RETURN user',
{ username }
)
if (result.records.length == 0) {
@@ -25,16 +27,23 @@ const Mutation = {
const record = result.records[0]
const userId = record.get('usr.id')
const userAdmin = record.get('usr.admin')
const user = record.get('user').properties
if ((await bcrypt.compare(args.password, user.password)) == false) {
return {
success: false,
status: 'Username or password was invalid',
token: null,
}
}
let roles = []
if (userAdmin) {
if (user.admin) {
roles.push('admin')
}
const token = jwt.sign({ id: userId, roles }, process.env.JWT_SECRET)
const token = jwt.sign({ id: user.id, roles }, process.env.JWT_SECRET)
return {
success: true,
@@ -43,7 +52,7 @@ const Mutation = {
}
},
async registerUser(root, args, ctx, info) {
let { username, password, rootPath } = args
let { username, rootPath } = args
let session = ctx.driver.session()
let findResult = await session.run(
@@ -67,9 +76,14 @@ const Mutation = {
}
}
const hashedPassword = await bcrypt.hash(
args.password,
config.encryptionSaltRounds
)
const registerResult = await session.run(
'CREATE (n:User { username: {username}, password: {password}, id: {id}, admin: false, rootPath: {rootPath} }) return n.id',
{ username, password, id: generateID(), rootPath }
{ username, password: hashedPassword, id: generateID(), rootPath }
)
let id = registerResult.records[0].get('n.id')
@@ -91,6 +105,12 @@ const Mutation = {
}
}
if (args.password)
args.password = await bcrypt.hash(
args.password,
config.encryptionSaltRounds
)
return neo4jgraphql(root, args, ctx, info)
},
async createUser(root, args, ctx, info) {
@@ -103,6 +123,12 @@ const Mutation = {
// eslint-disable-next-line require-atomic-updates
args.id = generateID()
if (args.password)
args.password = await bcrypt.hash(
args.password,
config.encryptionSaltRounds
)
return neo4jgraphql(root, args, ctx, info)
},
async changeUserPassword(root, args, ctx, info) {
@@ -110,11 +136,16 @@ const Mutation = {
const session = ctx.driver.session()
const hashedPassword = await bcrypt.hash(
newPassword,
config.encryptionSaltRounds
)
await session.run(
`MATCH (u:User { id: {id} }) SET u.password = {newPassword}`,
`MATCH (u:User { id: {id} }) SET u.password = {password}`,
{
id,
newPassword,
password: hashedPassword,
}
)