basic session management, not really working

This commit is contained in:
Jörn-Michael Miehe 2019-02-14 17:47:47 +01:00
parent 678a30e94d
commit d30f92aa46
7 changed files with 129 additions and 79 deletions

View file

@ -1,4 +1,4 @@
# libraries # node libraries
bcrypt = (require 'bcrypt') bcrypt = (require 'bcrypt')
sqlite3 = (require 'sqlite3').verbose() sqlite3 = (require 'sqlite3').verbose()
logger = (require 'logging').default 'db' logger = (require 'logging').default 'db'
@ -28,10 +28,11 @@ FFTCGDB = (filename, truncate) ->
user integer PRIMARY KEY, user integer PRIMARY KEY,
login text NOT NULL COLLATE NOCASE, login text NOT NULL COLLATE NOCASE,
pwdhash text NOT NULL, pwdhash text NOT NULL,
settings text,
UNIQUE(login) UNIQUE(login)
); );
''', (err) -> ''', (err) ->
FFTCGLOG.error err.message if err logger.error err.message if err
that.db.run 'DROP TABLE IF EXISTS decks;', (err) -> that.db.run 'DROP TABLE IF EXISTS decks;', (err) ->
logger.error err.message if err logger.error err.message if err
@ -46,7 +47,7 @@ FFTCGDB = (filename, truncate) ->
''', (err) -> ''', (err) ->
logger.error err.message if err logger.error err.message if err
logger.info 'recreated DB' logger.info 'recreated sqlite3 db'
return return
@ -74,7 +75,7 @@ FFTCGDB::register = (login, password) ->
# hash password # hash password
bcrypt.hash password, saltRounds, (err, hash) -> bcrypt.hash password, saltRounds, (err, hash) ->
if err if err
logger.info "reg: hash fail for name '#{login}'" logger.warn "reg: hash fail for name '#{login}'"
reject 'hash' reject 'hash'
# try creating row in users table # try creating row in users table
@ -117,7 +118,7 @@ FFTCGDB::login = (login, password) ->
else else
bcrypt.compare password, row.pwdhash, (err, res) -> bcrypt.compare password, row.pwdhash, (err, res) ->
if err if err
logger.info "login: hash fail for name '#{login}'" logger.warn "login: hash fail for name '#{login}'"
reject 'hash' reject 'hash'
if res == true if res == true

View file

@ -22,6 +22,7 @@
"fastify-static": "^1.1.0", "fastify-static": "^1.1.0",
"fastify-ws": "^1.0.0", "fastify-ws": "^1.0.0",
"logging": "^3.2.0", "logging": "^3.2.0",
"redis": "^2.8.0",
"sqlite3": "^4.0.4" "sqlite3": "^4.0.4"
} }
} }

View file

@ -1,13 +1,15 @@
# node libraries # node libraries
express = (require 'express')
path = (require 'path') path = (require 'path')
# my libraries # my libraries
FFTCGDB = (require './db') FFTCGDB = (require './db')
logger = (require 'logging').default 'router' FFTCGSESSION = (require './session')
logger = (require 'logging').default 'routes'
# open fftcg db # open fftcg.db (persistent data)
fftcgdb = new FFTCGDB path.resolve(__dirname, 'fftcg.db') fftcgdb = new FFTCGDB path.resolve(__dirname, 'fftcg.db'), true
# open session storage (volatile data)
session = new FFTCGSESSION
module.exports = [ module.exports = [
# test # test
@ -15,6 +17,7 @@ module.exports = [
method: 'POST' method: 'POST'
handler: (request, reply) -> handler: (request, reply) ->
logger.info 'Cookies', request.cookies logger.info 'Cookies', request.cookies
logger.info 'Body', request.body
logger.info 'Query', request.query logger.info 'Query', request.query
logger.info 'Params', request.params logger.info 'Params', request.params
@ -26,16 +29,16 @@ module.exports = [
url: '/user/register' url: '/user/register'
method: 'POST' method: 'POST'
handler: (request, reply) -> handler: (request, reply) ->
fftcgdb.register req.body.login, req.body.password fftcgdb.register request.body.login, request.body.password
.then (user) -> .then (user) ->
# registration successful, return JSON status # registration successful
reply.send reply.send
status: 'ok' status: 'ok'
user: user.user user: user.user
login: user.login login: user.login
.catch (err) -> .catch (err) ->
# registration failed, return JSON status # registration failed
reply.send reply.send
status: 'fail' status: 'fail'
text: err text: err
@ -44,20 +47,28 @@ module.exports = [
url: '/user/login' url: '/user/login'
method: 'POST' method: 'POST'
handler: (request, reply) -> handler: (request, reply) ->
fftcgdb.login req.body.login, req.body.password session_id = request.cookies.session
logger.info session_id
session.action session_id
.then (user) -> .then (user) ->
# login successful, save stuff in cookie logger.info user
.catch (err) ->
logger.error err
fftcgdb.login request.body.login, request.body.password
.then (user) ->
# login successful
reply.setCookie 'user', JSON.stringify user reply.setCookie 'user', JSON.stringify user
# return JSON status # return JSON status
res.json reply.send
status: 'ok' status: 'ok'
user: user.user user: user.user
login: user.login login: user.login
.catch (err) -> .catch (err) ->
# login failed, return JSON status # login failed
res.json reply.send
status: 'fail' status: 'fail'
text: err text: err
, ,

View file

@ -1,40 +0,0 @@
# node libraries
bodyParser = (require 'body-parser')
express = (require 'express')
sharedSession = (require 'express-socket.io-session')
helmet = (require 'helmet')
http = (require 'http')
path = (require 'path')
logger = (require 'logging').default 'FFTCG'
# my libraries
FFTCGSOCKET = (require './socket')
FFTCGSESSION = (require './session')
FFTCGROUTER = (require './router')
# express framework
app = express()
app.use helmet()
app.use bodyParser.urlencoded
extended: true
# sessions
sessionMiddleware = FFTCGSESSION(app)
app.use sessionMiddleware
# routes
app.use FFTCGROUTER
# socket.io
web = http.Server app
socket = new FFTCGSOCKET web, sharedSession sessionMiddleware
# Create server
web.listen 3001, ->
logger.info 'Listening on port 3001 ...'
# Handle termination
process.on 'SIGINT', ->
socket.close()
logger.info 'shutting down after SIGINT'
process.exit()

View file

@ -1,22 +1,66 @@
# node libraries # node libraries
expressSession = (require 'express-session') redis = (require 'redis')
RedisStore = (require 'connect-redis')(expressSession) crypto = (require 'crypto')
logger = (require 'logging').default 'session'
module.exports = (app) -> # expiry times in seconds
session = TIMES =
secret: 'keyboard cat' minute: 60
store: new RedisStore hour: 60 * 60
host: 'redis' day: 60 * 60 * 24
port: 6379 week: 60 * 60 * 24 * 7
cookie: month: 60 * 60 * 24 * 7 * 4
httpOnly: true
sameSite: 'strict'
proxy: true
resave: true
saveUninitialized: true
if app.get 'env' == 'production' EXPIRY =
app.set 'trust proxy', 1 # games expire 1 week after last action
session.cookie.secure = true game: 1 * TIMES.week
# logins expire 1 month after last action
login: 1 * TIMES.month
expressSession session
FFTCGSESSION = () ->
@db = redis.createClient 6379, 'redis'
@db.on 'error', (err) ->
logger.error err.message
return
FFTCGSESSION::login = (login) ->
that = @
new Promise (resolve, reject) ->
hmac = crypto.createHmac 'sha256', Math.random().toString()
hmac.update login
digest = hmac.digest 'hex'
that.db.setex digest, EXPIRY.login, login, (err) ->
if err
reject err
else
resolve digest
FFTCGSESSION::action = (digest) ->
that = @
new Promise (resolve, reject) ->
that.db.get digest (err, res) ->
logger.info 'err', err, 'res', res
if err
reject err
else if res == 0
resolve null
else
that.db.expire digest, EXPIRY.login, (err, res) ->
if err
reject err
else
resolve res
module.exports = FFTCGSESSION

View file

@ -17,12 +17,21 @@
ws.send('Ping') // Send the message 'Ping' to the server ws.send('Ping') // Send the message 'Ping' to the server
} }
console.log(JSON.stringify(document.cookie)) axios.post('/user/register',{
axios.post('/test',{ login: 'jmm',
x: 123 password: '123'
}) })
.then( (response) => { .then( (response) => {
console.log(response) console.log('register', response)
})
axios.post('/user/login',{
login: 'jmm',
password: '123'
})
.then( (response) => {
console.log('login', response)
console.log('cookie', document.cookie)
}) })
</script> </script>
</body> </body>

View file

@ -586,6 +586,11 @@ dot-prop@^4.1.0:
dependencies: dependencies:
is-obj "^1.0.0" is-obj "^1.0.0"
double-ended-queue@^2.1.0-0:
version "2.1.0-0"
resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=
duplexer3@^0.1.4: duplexer3@^0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
@ -1996,6 +2001,25 @@ readdirp@^2.2.1:
micromatch "^3.1.10" micromatch "^3.1.10"
readable-stream "^2.0.2" readable-stream "^2.0.2"
redis-commands@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.4.0.tgz#52f9cf99153efcce56a8f86af986bd04e988602f"
integrity sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==
redis-parser@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b"
integrity sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=
redis@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02"
integrity sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==
dependencies:
double-ended-queue "^2.1.0-0"
redis-commands "^1.2.0"
redis-parser "^2.6.0"
regex-not@^1.0.0, regex-not@^1.0.2: regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"