Compare commits

..

No commits in common. "b3abb27446062890e5dfc76322038cbea1507efc" and "ea7d97930fba3eb94c4be37af7c76e930c351bf8" have entirely different histories.

8 changed files with 58 additions and 158 deletions

View file

@ -1,11 +0,0 @@
FFTCGLOG = (unit) ->
@unit = unit
return
FFTCGLOG::log = (msg) ->
console.log "[#{@unit}] #{msg}"
FFTCGLOG::error = (msg) ->
console.error "[#{@unit}] #{msg}"
module.exports = FFTCGLOG

View file

@ -1,7 +1,6 @@
# libraries # libraries
bcrypt = (require 'bcrypt') bcrypt = (require 'bcrypt')
sqlite3 = (require 'sqlite3').verbose() sqlite3 = (require 'sqlite3').verbose()
FFTCGLOG = new (require './console')('FFTCGDB')
# bruteforce countermeasure # bruteforce countermeasure
saltRounds = 13 saltRounds = 13
@ -12,17 +11,17 @@ FFTCGDB = (filename, truncate) ->
@db = new sqlite3.Database @filename, (err) -> @db = new sqlite3.Database @filename, (err) ->
if err if err
FFTCGLOG.error err.message console.error err.message
else else
FFTCGLOG.log "Connected to '#{that.filename}'" console.log "[FFTCGDB] Connected to '#{that.filename}'"
that.db.run 'PRAGMA foreign_keys = ON;', (err) -> that.db.run 'PRAGMA foreign_keys = ON;', (err) ->
FFTCGLOG.error err.message if err console.error err.message if err
if truncate == true if truncate == true
that.db.run 'DROP TABLE IF EXISTS users;', (err) -> that.db.run 'DROP TABLE IF EXISTS users;', (err) ->
FFTCGLOG.error err.message if err console.error err.message if err
that.db.run ''' that.db.run '''
CREATE TABLE users ( CREATE TABLE users (
user integer PRIMARY KEY, user integer PRIMARY KEY,
@ -31,22 +30,35 @@ FFTCGDB = (filename, truncate) ->
UNIQUE(login) UNIQUE(login)
); );
''', (err) -> ''', (err) ->
FFTCGLOG.error err.message if err console.error err.message if err
that.db.run 'DROP TABLE IF EXISTS decks;', (err) -> that.db.run 'DROP TABLE IF EXISTS decks;', (err) ->
FFTCGLOG.error err.message if err console.error err.message if err
that.db.run ''' that.db.run '''
CREATE TABLE decks ( CREATE TABLE decks (
deck integer PRIMARY KEY, deck integer PRIMARY KEY,
user integer NOT NULL, user integer NOT NULL,
json text,
FOREIGN KEY (user) REFERENCES users (user) FOREIGN KEY (user) REFERENCES users (user)
ON DELETE CASCADE ON DELETE CASCADE
); );
''', (err) -> ''', (err) ->
FFTCGLOG.error err.message if err console.error err.message if err
FFTCGLOG.log 'recreated DB' that.db.run 'DROP TABLE IF EXISTS decks_cards;', (err) ->
console.error err.message if err
that.db.run '''
CREATE TABLE decks_cards (
deck integer NOT NULL,
card text NOT NULL,
quant integer NOT NULL,
UNIQUE(deck, card),
FOREIGN KEY (deck) REFERENCES decks (deck)
ON DELETE CASCADE
);
''', (err) ->
console.error err.message if err
console.log "[FFTCGDB] recreated DB"
return return
@ -54,11 +66,9 @@ FFTCGDB::close = ->
new Promise (resolve, reject) -> new Promise (resolve, reject) ->
@db.close (err) -> @db.close (err) ->
if err if err
FFTCGLOG.log "Error closing: '#{err.message}'" resolve "[FFTCGDB] Error closing: '#{err.message}'"
resolve 'ok'
else else
FFTCGLOG.error "Closed '#{@filename}'" reject "[FFTCGDB] Closed '#{@filename}'"
reject 'db'
FFTCGDB::register = (login, password) -> FFTCGDB::register = (login, password) ->
that = @ that = @
@ -67,26 +77,26 @@ FFTCGDB::register = (login, password) ->
# validate user input # validate user input
if login == '' or password == '' if login == '' or password == ''
# no user name or password given # no user name or password given
FFTCGLOG.log "reg: user name '#{login}' or password empty" console.log "[FFTCGDB] reg: user name '#{login}' or password empty"
reject 'invalid' reject 'invalid'
# hash password # hash password
bcrypt.hash password, saltRounds, (err, hash) -> bcrypt.hash password, saltRounds, (err, hash) ->
if err if err
FFTCGLOG.log "reg: hash fail for name '#{login}'" console.log "[FFTCGDB] reg: hash fail for name '#{login}'"
reject 'hash' reject 'hash'
# try creating row in users table # try creating row in users table
stmt = that.db.prepare 'INSERT INTO users (login, pwdhash) VALUES (?, ?)' stmt = that.db.prepare 'INSERT INTO users (login, pwdhash) VALUES (?, ?)'
stmt.run [login, hash], (err) -> stmt.run [login, hash], (err) ->
if err if err
FFTCGLOG.log "reg: DB fail '#{err.code}' for name '#{login}'" console.log "[FFTCGDB] reg: DB fail '#{err.code}' for name '#{login}'"
stmt.finalize() stmt.finalize()
# reduce attack surface, don't disclose user names # reduce attack surface, don't disclose user names
reject 'db' # user already exists reject 'db' # user already exists
else else
FFTCGLOG.log "reg: OK '#{login}'" console.log "[FFTCGDB] reg: OK '#{login}'"
stmt.finalize() stmt.finalize()
# registration successful # registration successful
resolve resolve
@ -101,14 +111,14 @@ FFTCGDB::login = (login, password) ->
stmt = that.db.prepare 'SELECT user, login, pwdhash FROM users WHERE login = ?' stmt = that.db.prepare 'SELECT user, login, pwdhash FROM users WHERE login = ?'
stmt.get [login], (err, row) -> stmt.get [login], (err, row) ->
if err if err
FFTCGLOG.log "login: DB fail '#{err.code}' for name '#{login}'" console.log "[FFTCGDB] login: DB fail '#{err.code}' for name '#{login}'"
stmt.finalize() stmt.finalize()
reject 'db' reject 'db'
else if not row else if not row
# hash the password for timing attack reasons # hash the password for timing attack reasons
bcrypt.hash password, saltRounds, (err, hash) -> bcrypt.hash password, saltRounds, (err, hash) ->
FFTCGLOG.log "login: nonexistent '#{login}'" console.log "[FFTCGDB] login: nonexistent '#{login}'"
stmt.finalize() stmt.finalize()
# reduce attack surface, don't disclose user names # reduce attack surface, don't disclose user names
reject 'login' # user doesnt exist reject 'login' # user doesnt exist
@ -116,11 +126,11 @@ FFTCGDB::login = (login, password) ->
else else
bcrypt.compare password, row.pwdhash, (err, res) -> bcrypt.compare password, row.pwdhash, (err, res) ->
if err if err
FFTCGLOG.log "login: hash fail for name '#{login}'" console.log "[FFTCGDB] login: hash fail for name '#{login}'"
reject 'hash' reject 'hash'
if res == true if res == true
FFTCGLOG.log "login: OK '#{row.login}'" console.log "[FFTCGDB] login: OK '#{row.login}'"
stmt.finalize() stmt.finalize()
# login successful # login successful
resolve resolve
@ -128,7 +138,7 @@ FFTCGDB::login = (login, password) ->
login: row.login login: row.login
else else
FFTCGLOG.log "login: wrong password for '#{login}'" console.log "[FFTCGDB] login: wrong password for '#{login}'"
stmt.finalize() stmt.finalize()
# login failed # login failed
reject 'login' reject 'login'
@ -138,85 +148,43 @@ FFTCGDB::addDeck = (user, deckCards) ->
new Promise (resolve, reject) -> new Promise (resolve, reject) ->
# try creating row in decks table # try creating row in decks table
stmt = that.db.prepare 'INSERT INTO decks (user, json) VALUES (?, ?)' stmt = that.db.prepare 'INSERT INTO decks (user) VALUES (?)'
stmt.run [user, JSON.stringify deckCards], (err) -> stmt.run [user], (err) ->
if err if err
FFTCGLOG.log "addDeck: DB fail '#{err.code}' for id '#{user}'" console.log "[FFTCGDB] addDeck: DB fail '#{err.code}' for id '#{user}'"
stmt.finalize() stmt.finalize()
reject 'db' reject 'db'
else else
stmt.finalize() stmt.finalize()
# deck added successfully, now add cards # deck added successfully
that.modDeck(@lastID, deckCards) deckID = @lastID
.then (deckID) ->
resolve deckID
.catch (error) ->
reject error
FFTCGDB::modDeck = (deckID, deckCards) ->
that = @
new Promise (resolve, reject) ->
# delete old deck cards
stmt = that.db.prepare 'DELETE FROM decks_cards WHERE deck = ?'
stmt.run [deckID], (err) ->
stmt.finalize()
if err
FFTCGLOG.log "modDeck: DB fail '#{err.code}' for deck '#{deckID}'"
reject 'db'
else
stmt = that.db.prepare 'INSERT INTO decks_cards (deck, card, quant) VALUES (?, ?, ?)' stmt = that.db.prepare 'INSERT INTO decks_cards (deck, card, quant) VALUES (?, ?, ?)'
# add new cards # add individual cards
that.db.parallelize -> that.db.parallelize ->
# needs to be done in several queries # needs to be done in several queries
promiseCount = deckCards.length promiseCount = deckCards.length
deckCards.forEach (card) -> deckCards.forEach (card) ->
stmt.run [deckID, card.id, card.quant], (err) -> stmt.run [deckID, card.id, card.quant], (err) ->
if err if err
FFTCGLOG.log "modDeck: DB fail '#{err.code}' for card '#{deckID}', '#{card.id}', '#{card.quant}'" console.log "[FFTCGDB] addDeck: DB fail '#{err.code}' for card '#{deckID}', '#{card.id}', '#{card.quant}'"
stmt.finalize() stmt.finalize()
reject 'db' reject 'db'
else else
# check if all queries are done # check if all queries are done
promiseCount -= 1 promiseCount -= 1
if promiseCount == 0 if promiseCount == 0
FFTCGLOG.log "modDeck: OK '#{deckID}'" console.log "[FFTCGDB] addDeck: OK '#{user}'"
stmt.finalize() stmt.finalize()
resolve deckID resolve deckID
FFTCGDB::getDecks = (user) -> FFTCGDB::delDeck = (deck) ->
that = @ that = @
new Promise (resolve, reject) -> new Promise (resolve, reject) ->
# try deleting correct row in decks table # try creating row in decks table
decks = {}
stmt = that.db.prepare 'SELECT decks.deck, decks.json FROM decks INNER JOIN users ON decks.user = users.user WHERE users.user = ?'
stmt.all [user], (err, rows) ->
stmt.finalize()
if err
FFTCGLOG.log "getDeck: DB fail '#{err.code}' for deck '#{deckID}'"
reject 'db'
else
FFTCGLOG.log "getDeck: OK '#{deckID}'"
for row in rows
decks[row.deck] = JSON.parse row.json
resolve decks
FFTCGDB::delDeck = (deckID) ->
that = @
new Promise (resolve, reject) ->
# try deleting correct row in decks table
stmt = that.db.prepare 'DELETE FROM decks WHERE deck = ?' stmt = that.db.prepare 'DELETE FROM decks WHERE deck = ?'
stmt.run [deckID], (err) -> stmt.run [deck], (err)
stmt.finalize()
if err
FFTCGLOG.log "delDeck: DB fail '#{err.code}' for deck '#{deckID}'"
reject 'db'
else
FFTCGLOG.log "delDeck: OK '#{deckID}'"
resolve deckID
module.exports = FFTCGDB module.exports = FFTCGDB

View file

@ -3,8 +3,7 @@ express = (require 'express')
path = (require 'path') path = (require 'path')
# my libraries # my libraries
FFTCGDB = (require './db') FFTCGDB = (require './fftcgdb')
FFTCGLOG = new (require './console')('FFTCGROUTER')
# open fftcg db # open fftcg db
fftcgdb = new FFTCGDB path.resolve(__dirname, '../fftcg.db') fftcgdb = new FFTCGDB path.resolve(__dirname, '../fftcg.db')
@ -15,9 +14,9 @@ FFTCGROUTER = express.Router()
# request logging # request logging
FFTCGROUTER.use (req, res, next) -> FFTCGROUTER.use (req, res, next) ->
if req.session.user if req.session.user
FFTCGLOG.log "user '#{req.session.user.login}' requested '#{req.url}'" console.log "[FFTCGROUTER] user '#{req.session.user.login}' requested '#{req.url}'"
else else
FFTCGLOG.log "requested '#{req.url}'" console.log "[FFTCGROUTER] requested '#{req.url}'"
next() next()
@ -66,6 +65,7 @@ FFTCGROUTER.get '/:template.html', (req, res) ->
if req.session.user and req.params.template == 'index' if req.session.user and req.params.template == 'index'
return res.redirect '/usercp.html' return res.redirect '/usercp.html'
# render requested template # render requested template
res.render (req.params.template + '.pug'), (err, html) -> res.render (req.params.template + '.pug'), (err, html) ->
# redirect invalid requests to index # redirect invalid requests to index

View file

@ -1,7 +1,6 @@
# node libraries # node libraries
socketio = (require 'socket.io') socketio = (require 'socket.io')
path = (require 'path') path = (require 'path')
FFTCGLOG = new (require './console')('FFTCGSOCKET')
# my libraries # my libraries
@ -15,17 +14,17 @@ FFTCGSOCKET = (http, session) ->
# on new connection # on new connection
@io.on 'connection', (socket) -> @io.on 'connection', (socket) ->
@session = socket.handshake.session @session = socket.handshake.session
FFTCGLOG.log "session '#{@session.id}' connected" console.log "session '#{@session.id}' connected"
FFTCGLOG.log "is user '#{@session.userID}'" if @session.userID console.log "is user '#{@session.userID}'" if @session.userID
socket.on 'disconnect', -> socket.on 'disconnect', ->
FFTCGLOG.log "session '#{that.session.id}' disconnected" console.log "session '#{that.session.id}' disconnected"
FFTCGLOG.log "is user '#{that.session.userID}'" if that.session.userID console.log "is user '#{that.session.userID}'" if that.session.userID
return return
FFTCGSOCKET::close = -> FFTCGSOCKET::close = ->
FFTCGLOG.log 'shutting down' console.log '[FFTCGSOCKET] shutting down'
if @db if @db
@db.close() @db.close()
.then (msg) -> .then (msg) ->

View file

@ -7,10 +7,9 @@ http = (require 'http')
path = (require 'path') path = (require 'path')
# my libraries # my libraries
FFTCGSOCKET = (require './inc/socket') FFTCGSOCKET = (require './inc/fftcgsocket')
FFTCGSESSION = (require './inc/session') FFTCGSESSION = (require './inc/fftcgsession')
FFTCGROUTER = (require './inc/router') FFTCGROUTER = (require './inc/fftcgrouter')
FFTCGLOG = new (require './inc/console')('FFTCG')
# express framework # express framework
app = express() app = express()
@ -31,10 +30,10 @@ socket = new FFTCGSOCKET web, sharedSession sessionMiddleware
# Create server # Create server
web.listen 3000, -> web.listen 3000, ->
FFTCGLOG.log 'Listening on port 3000 ...' console.log '[FFTCG] Listening on port 3000 ...'
# Handle termination # Handle termination
process.on 'SIGINT', -> process.on 'SIGINT', ->
socket.close() socket.close()
FFTCGLOG.log 'shutting down after SIGINT' console.log '[FFTCG] shutting down after SIGINT'
process.exit() process.exit()

View file

@ -4,7 +4,6 @@ window.$ = require('jquery')
# import bootstrap # import bootstrap
require './style/custom.scss' require './style/custom.scss'
require 'bootstrap/js/dist/alert' require 'bootstrap/js/dist/alert'
require 'bootstrap/js/dist/collapse'
# on load # on load
$ -> $ ->

View file

@ -4,57 +4,3 @@ html
title Crafty Things title Crafty Things
script(src='/usercp.bundle.js') script(src='/usercp.bundle.js')
body body
header.jumbotron.jumbotron-fluid.py-4.bg-primary.text-light.text-center
div.container
h1 Hello World!
h2 App under development, please don't submit any valuable data!
div.container.bg-light
h3 Yavook!FFTCG
div#alert-area
div.row
div.col-md-8
h4 My Decks
ul.list-group#my-decks
li.list-group-item
div.align-middle
div.d-inline-block.btn-group(role="group")
button.btn.btn-secondary(data-toggle="collapse" data-target="#modDeck0") Edit
button.btn.btn-secondary#delDeck0 Delete
div.d-inline-block.pl-2 item1
form.float-none.collapse#modDeck0(name="modDeck0")
div.form-group
label(for="deck") Decklist:
textarea.form-control.text-monospace(name="deck" required)
div.form-group
button.btn.btn-primary.w-100(type="submit") Add
li.list-group-item
div.align-middle
div.d-inline-block.btn-group(role="group")
button.btn.btn-secondary(data-toggle="collapse" data-target="#modDeck1") Edit
button.btn.btn-secondary#delDeck1 Delete
div.d-inline-block.pl-2 item2
form.float-none.collapse#modDeck1(name="modDeck1")
div.form-group
label(for="deck") Decklist:
textarea.form-control.text-monospace(name="deck" required)
div.form-group
button.btn.btn-primary.w-100(type="submit") Add
div.col-md-4
h4 New Deck
form(name="addDeck")
div.form-group
label(for="deck") Paste decklist:
textarea.form-control.text-monospace(name="deck" required)
div.form-group
button.btn.btn-primary.w-100(type="submit") Add
p Hello