diff --git a/backend/db.coffee b/backend/db.coffee index 66b7131..bd16241 100644 --- a/backend/db.coffee +++ b/backend/db.coffee @@ -7,6 +7,14 @@ sqlite3 = (require 'sqlite3').verbose() # bruteforce countermeasure saltRounds = 13 +messages = + empty: 'Empty user name or password' + hash: 'Failed to process your data, try again later' + exists: 'User name is already taken' + noexists: 'Wrong user name or password' + password: 'Wrong user name or password' + db: 'Failed to access the database, try again later' + class FFTCGDB constructor: (filename, truncate) -> @filename = filename @@ -56,74 +64,91 @@ class FFTCGDB @db.close (err) -> if err logger.error "FAIL '#{err.message}'" - reject 'db' + reject null else logger.warn "OK close '#{@filename}'" - resolve 'ok' + resolve null + + validate: (login, password) -> + defined = (value) -> value? and value isnt '' + + new Promise (resolve, reject) => + if (defined login) and (defined password) + # both are defined + resolve null + else + # no user name or password given + logger.info "validate: FAIL empty '#{login}' or password" + reject null register: (login, password) -> new Promise (resolve, reject) => # validate user input - if login == '' or password == '' - # no user name or password given - logger.info "reg: FAIL empty '#{login}' or password" - reject 'invalid' + @validate login, password + .then => + # hash password + bcrypt.hash password, saltRounds, (err, hash) => + if err + logger.warn "reg: FAIL hash for '#{login}'" + reject messages.hash - # hash password - bcrypt.hash password, saltRounds, (err, hash) => - if err - logger.warn "reg: FAIL hash for '#{login}'" - reject 'hash' + else + # try creating row in users table + stmt = @db.prepare 'INSERT INTO users (login, pwdhash) VALUES (?, ?)' + stmt.run [login, hash], (err) -> + stmt.finalize() + if err + logger.warn "reg: FAIL db '#{err.code}' for '#{login}'" + reject messages.exists # user already exists - else - # try creating row in users table - stmt = @db.prepare 'INSERT INTO users (login, pwdhash) VALUES (?, ?)' - stmt.run [login, hash], (err) -> - stmt.finalize() - if err - logger.warn "reg: FAIL db '#{err.code}' for '#{login}'" - reject 'existence' # user already exists + else + logger.info "reg: OK '#{login}'" + # registration successful + resolve + user: @lastID + login: login - else - logger.info "reg: OK '#{login}'" - # registration successful - resolve - user: @lastID - login: login + .catch -> + reject messages.empty login: (login, password) -> new Promise (resolve, reject) => - # get users table row - stmt = @db.prepare 'SELECT user, login, pwdhash FROM users WHERE login = ?' - stmt.get [login], (err, row) => - stmt.finalize() - if err - logger.warn "login: FAIL db '#{err.code}' for '#{login}'" - reject 'db' + # validate user input + @validate login, password + .then => + # get users table row + stmt = @db.prepare 'SELECT user, login, pwdhash FROM users WHERE login = ?' + stmt.get [login], (err, row) => + stmt.finalize() + if err + logger.warn "login: FAIL db '#{err.code}' for '#{login}'" + reject messages.db - else if not row - # hash the password for timing attack reasons - bcrypt.hash password, saltRounds, (err, hash) -> - logger.debug "login: FAIL nonexistent '#{login}'" - reject 'existence' # user doesnt exist + else if not row + # hash the password for timing attack reasons + bcrypt.hash password, saltRounds, (err, hash) -> + logger.debug "login: FAIL nonexistent '#{login}'" + reject messages.noexists # user doesnt exist - else - bcrypt.compare password, row.pwdhash, (err, res) -> - if err - logger.warn "login: FAIL hash for '#{login}'" - reject 'hash' + else + bcrypt.compare password, row.pwdhash, (err, res) -> + if err + logger.warn "login: FAIL hash for '#{login}'" + reject messages.hash - if res == true - logger.debug "login: OK '#{row.login}'" - # login successful - resolve - user: row.user - login: row.login + if res == true + logger.debug "login: OK '#{row.login}'" + # login successful + resolve + user: row.user + login: row.login - else - logger.debug "login: FAIL password for '#{login}'" - # login failed - reject 'login' + else + logger.debug "login: FAIL password for '#{login}'" + reject messages.password # login failed + + .catch -> + reject messages.empty addDeck: (user, deckCards) -> new Promise (resolve, reject) => @@ -133,7 +158,7 @@ class FFTCGDB stmt.finalize() if err logger.warn "addDeck: FAIL db '#{err.code}' for '#{user}'" - reject 'db' + reject messages.db else logger.debug "addDeck: OK '#{@lastID}'" @@ -146,7 +171,7 @@ class FFTCGDB stmt.finalize() if err logger.warn "modDeck: FAIL db '#{err.code}' for '#{deckID}'" - reject 'db' + reject messages.db else logger.debug "modDeck: OK '#{deckID}'" resolve deckID @@ -158,7 +183,7 @@ class FFTCGDB stmt.finalize() if err logger.warn "getDeck: FAIL db '#{err.code}' for '#{deckID}'" - reject 'db' + reject messages.db else logger.debug "getDeck: OK '#{deckID}'" resolve (id: row.deck, content: JSON.parse row.json for row, i in rows) @@ -170,7 +195,7 @@ class FFTCGDB stmt.finalize() if err logger.warn "delDeck: FAIL db '#{err.code}' for '#{deckID}'" - reject 'db' + reject messages.db else logger.debug "delDeck: OK '#{deckID}'" resolve deckID