Compare commits
No commits in common. "d30f92aa46c4027be692bb3c0e95900ecefec430" and "2ea24ad1da17929078c913d4da39b23f65f6cb7d" have entirely different histories.
d30f92aa46
...
2ea24ad1da
10 changed files with 166 additions and 223 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
# node libraries
|
# 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,11 +28,10 @@ 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) ->
|
||||||
logger.error err.message if err
|
FFTCGLOG.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
|
||||||
|
|
@ -47,7 +46,7 @@ FFTCGDB = (filename, truncate) ->
|
||||||
''', (err) ->
|
''', (err) ->
|
||||||
logger.error err.message if err
|
logger.error err.message if err
|
||||||
|
|
||||||
logger.info 'recreated sqlite3 db'
|
logger.info 'recreated DB'
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -75,7 +74,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.warn "reg: hash fail for name '#{login}'"
|
logger.info "reg: hash fail for name '#{login}'"
|
||||||
reject 'hash'
|
reject 'hash'
|
||||||
|
|
||||||
# try creating row in users table
|
# try creating row in users table
|
||||||
|
|
@ -118,7 +117,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.warn "login: hash fail for name '#{login}'"
|
logger.info "login: hash fail for name '#{login}'"
|
||||||
reject 'hash'
|
reject 'hash'
|
||||||
|
|
||||||
if res == true
|
if res == true
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
60
backend/router.coffee
Normal file
60
backend/router.coffee
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# node libraries
|
||||||
|
express = (require 'express')
|
||||||
|
path = (require 'path')
|
||||||
|
|
||||||
|
# my libraries
|
||||||
|
FFTCGDB = (require './db')
|
||||||
|
logger = (require 'logging').default 'router'
|
||||||
|
|
||||||
|
# open fftcg db
|
||||||
|
fftcgdb = new FFTCGDB path.resolve(__dirname, 'fftcg.db')
|
||||||
|
|
||||||
|
# create router
|
||||||
|
FFTCGROUTER = express.Router()
|
||||||
|
|
||||||
|
# request logging
|
||||||
|
FFTCGROUTER.use (req, res, next) ->
|
||||||
|
if req.session.user
|
||||||
|
logger.debug "user '#{req.session.user.login}' requested '#{req.url}'"
|
||||||
|
else
|
||||||
|
logger.debug "requested '#{req.url}'"
|
||||||
|
|
||||||
|
next()
|
||||||
|
|
||||||
|
# register user
|
||||||
|
FFTCGROUTER.post '/register', (req, res) ->
|
||||||
|
fftcgdb.register req.body.login, req.body.password
|
||||||
|
.then (user) ->
|
||||||
|
# registration successful, return JSON status
|
||||||
|
res.json
|
||||||
|
status: 'ok'
|
||||||
|
user: user.user
|
||||||
|
login: user.login
|
||||||
|
|
||||||
|
.catch (err) ->
|
||||||
|
# registration failed, return JSON status
|
||||||
|
res.json
|
||||||
|
status: 'fail'
|
||||||
|
text: err
|
||||||
|
|
||||||
|
# log in user
|
||||||
|
FFTCGROUTER.post '/login', (req, res) ->
|
||||||
|
fftcgdb.login req.body.login, req.body.password
|
||||||
|
.then (user) ->
|
||||||
|
# login successful, save stuff in session
|
||||||
|
req.session.user = user
|
||||||
|
req.session.save()
|
||||||
|
|
||||||
|
# return JSON status
|
||||||
|
res.json
|
||||||
|
status: 'ok'
|
||||||
|
user: user.user
|
||||||
|
login: user.login
|
||||||
|
|
||||||
|
.catch (err) ->
|
||||||
|
# login failed, return JSON status
|
||||||
|
res.json
|
||||||
|
status: 'fail'
|
||||||
|
text: err
|
||||||
|
|
||||||
|
module.exports = FFTCGROUTER
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
# node libraries
|
|
||||||
path = (require 'path')
|
|
||||||
|
|
||||||
# my libraries
|
|
||||||
FFTCGDB = (require './db')
|
|
||||||
FFTCGSESSION = (require './session')
|
|
||||||
logger = (require 'logging').default 'routes'
|
|
||||||
|
|
||||||
# open fftcg.db (persistent data)
|
|
||||||
fftcgdb = new FFTCGDB path.resolve(__dirname, 'fftcg.db'), true
|
|
||||||
# open session storage (volatile data)
|
|
||||||
session = new FFTCGSESSION
|
|
||||||
|
|
||||||
module.exports = [
|
|
||||||
# test
|
|
||||||
url: '/test'
|
|
||||||
method: 'POST'
|
|
||||||
handler: (request, reply) ->
|
|
||||||
logger.info 'Cookies', request.cookies
|
|
||||||
logger.info 'Body', request.body
|
|
||||||
logger.info 'Query', request.query
|
|
||||||
logger.info 'Params', request.params
|
|
||||||
|
|
||||||
reply.setCookie 'foo', 'foo'
|
|
||||||
reply.send
|
|
||||||
hello: 'world'
|
|
||||||
,
|
|
||||||
# register user
|
|
||||||
url: '/user/register'
|
|
||||||
method: 'POST'
|
|
||||||
handler: (request, reply) ->
|
|
||||||
fftcgdb.register request.body.login, request.body.password
|
|
||||||
.then (user) ->
|
|
||||||
# registration successful
|
|
||||||
reply.send
|
|
||||||
status: 'ok'
|
|
||||||
user: user.user
|
|
||||||
login: user.login
|
|
||||||
|
|
||||||
.catch (err) ->
|
|
||||||
# registration failed
|
|
||||||
reply.send
|
|
||||||
status: 'fail'
|
|
||||||
text: err
|
|
||||||
,
|
|
||||||
# log in user
|
|
||||||
url: '/user/login'
|
|
||||||
method: 'POST'
|
|
||||||
handler: (request, reply) ->
|
|
||||||
session_id = request.cookies.session
|
|
||||||
logger.info session_id
|
|
||||||
session.action session_id
|
|
||||||
.then (user) ->
|
|
||||||
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
|
|
||||||
|
|
||||||
# return JSON status
|
|
||||||
reply.send
|
|
||||||
status: 'ok'
|
|
||||||
user: user.user
|
|
||||||
login: user.login
|
|
||||||
|
|
||||||
.catch (err) ->
|
|
||||||
# login failed
|
|
||||||
reply.send
|
|
||||||
status: 'fail'
|
|
||||||
text: err
|
|
||||||
,
|
|
||||||
]
|
|
||||||
|
|
@ -4,9 +4,9 @@ fastify = (require 'fastify') logger: logger
|
||||||
path = (require 'path')
|
path = (require 'path')
|
||||||
|
|
||||||
# my libraries
|
# my libraries
|
||||||
socket = (require './socket')
|
# FFTCGSOCKET = (require './socket')
|
||||||
# FFTCGSESSION = (require './session')
|
# FFTCGSESSION = (require './session')
|
||||||
routes = (require './routes')
|
# FFTCGROUTER = (require './router')
|
||||||
|
|
||||||
# fastify framework
|
# fastify framework
|
||||||
fastify.register (require 'fastify-cookie')
|
fastify.register (require 'fastify-cookie')
|
||||||
|
|
@ -16,15 +16,29 @@ fastify.register (require 'fastify-static'), root: path.join __dirname, 'tmpfron
|
||||||
|
|
||||||
fastify.ready()
|
fastify.ready()
|
||||||
.then ->
|
.then ->
|
||||||
fastify.ws.on 'connection', socket
|
fastify.ws.on 'connection', (socket) ->
|
||||||
|
logger.info 'Client connected.'
|
||||||
|
|
||||||
|
socket.on 'message', (msg) ->
|
||||||
|
# echo server
|
||||||
|
logger.info "Echo '#{msg}'."
|
||||||
|
socket.send "Re: #{msg}"
|
||||||
|
|
||||||
|
socket.on 'close', ->
|
||||||
|
logger.info 'Client disconnected.'
|
||||||
|
|
||||||
.catch (err) ->
|
.catch (err) ->
|
||||||
logger.error err
|
logger.error err
|
||||||
process.exit 1
|
process.exit 1
|
||||||
|
|
||||||
|
|
||||||
for route in routes
|
fastify.get '/api', (request, reply) ->
|
||||||
fastify.route route
|
logger.info request.cookies
|
||||||
|
|
||||||
|
reply
|
||||||
|
.setCookie 'foo', 'bar'
|
||||||
|
.send hello: 'world'
|
||||||
|
|
||||||
|
|
||||||
fastify.listen 3001, '0.0.0.0'
|
fastify.listen 3001, '0.0.0.0'
|
||||||
.catch (err) ->
|
.catch (err) ->
|
||||||
|
|
|
||||||
40
backend/server_old.coffee
Normal file
40
backend/server_old.coffee
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# 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()
|
||||||
|
|
@ -1,66 +1,22 @@
|
||||||
# node libraries
|
# node libraries
|
||||||
redis = (require 'redis')
|
expressSession = (require 'express-session')
|
||||||
crypto = (require 'crypto')
|
RedisStore = (require 'connect-redis')(expressSession)
|
||||||
logger = (require 'logging').default 'session'
|
|
||||||
|
|
||||||
# expiry times in seconds
|
module.exports = (app) ->
|
||||||
TIMES =
|
session =
|
||||||
minute: 60
|
secret: 'keyboard cat'
|
||||||
hour: 60 * 60
|
store: new RedisStore
|
||||||
day: 60 * 60 * 24
|
host: 'redis'
|
||||||
week: 60 * 60 * 24 * 7
|
port: 6379
|
||||||
month: 60 * 60 * 24 * 7 * 4
|
cookie:
|
||||||
|
httpOnly: true
|
||||||
|
sameSite: 'strict'
|
||||||
|
proxy: true
|
||||||
|
resave: true
|
||||||
|
saveUninitialized: true
|
||||||
|
|
||||||
EXPIRY =
|
if app.get 'env' == 'production'
|
||||||
# games expire 1 week after last action
|
app.set 'trust proxy', 1
|
||||||
game: 1 * TIMES.week
|
session.cookie.secure = true
|
||||||
# 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
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,32 @@
|
||||||
# node libraries
|
# node libraries
|
||||||
|
socketio = (require 'socket.io')
|
||||||
path = (require 'path')
|
path = (require 'path')
|
||||||
logger = (require 'logging').default 'socket'
|
logger = (require 'logging').default 'socket'
|
||||||
|
|
||||||
# my libraries
|
# my libraries
|
||||||
|
|
||||||
module.exports = (socket) ->
|
FFTCGSOCKET = (http, session) ->
|
||||||
logger.info 'Client connected.'
|
that = @
|
||||||
|
|
||||||
socket.on 'message', (msg) ->
|
# create server socket
|
||||||
# echo server
|
@io = socketio http
|
||||||
logger.info "Echo '#{msg}'."
|
@io.use session
|
||||||
socket.send "Re: #{msg}"
|
|
||||||
|
|
||||||
socket.on 'close', ->
|
# on new connection
|
||||||
logger.info 'Client disconnected.'
|
@io.on 'connection', (socket) ->
|
||||||
|
@session = socket.handshake.session
|
||||||
|
logger.debug "session '#{@session.id}' connected"
|
||||||
|
logger.debug "is user '#{@session.userID}'" if @session.userID
|
||||||
|
|
||||||
# FFTCGSOCKET = (http, session) ->
|
socket.on 'disconnect', ->
|
||||||
# that = @
|
logger.debug "session '#{that.session.id}' disconnected"
|
||||||
#
|
logger.debug "is user '#{that.session.userID}'" if that.session.userID
|
||||||
# # create server socket
|
|
||||||
# @io = socketio http
|
return
|
||||||
# @io.use session
|
|
||||||
#
|
|
||||||
# # on new connection
|
FFTCGSOCKET::close = ->
|
||||||
# @io.on 'connection', (socket) ->
|
logger.info 'shutting down'
|
||||||
# @session = socket.handshake.session
|
|
||||||
# logger.debug "session '#{@session.id}' connected"
|
|
||||||
# logger.debug "is user '#{@session.userID}'" if @session.userID
|
module.exports = FFTCGSOCKET
|
||||||
#
|
|
||||||
# socket.on 'disconnect', ->
|
|
||||||
# logger.debug "session '#{that.session.id}' disconnected"
|
|
||||||
# logger.debug "is user '#{that.session.userID}'" if that.session.userID
|
|
||||||
#
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# FFTCGSOCKET::close = ->
|
|
||||||
# logger.info 'shutting down'
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# module.exports = FFTCGSOCKET
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Hello World
|
Hello World
|
||||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
const host = location.origin.replace(/^http/, 'ws')
|
const host = location.origin.replace(/^http/, 'ws')
|
||||||
const ws = new WebSocket(host)
|
const ws = new WebSocket(host)
|
||||||
|
|
@ -17,22 +16,7 @@
|
||||||
ws.send('Ping') // Send the message 'Ping' to the server
|
ws.send('Ping') // Send the message 'Ping' to the server
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.post('/user/register',{
|
console.log(JSON.stringify(document.cookie))
|
||||||
login: 'jmm',
|
|
||||||
password: '123'
|
|
||||||
})
|
|
||||||
.then( (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>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -586,11 +586,6 @@ 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"
|
||||||
|
|
@ -2001,25 +1996,6 @@ 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"
|
||||||
|
|
|
||||||
Reference in a new issue