Compare commits

..

No commits in common. "3a0e889626f2bfe75c6df1c03a4bbc8e15c7b83f" and "e8dbb7b161913d280e8de33531c7554a20ca8010" have entirely different histories.

15 changed files with 216 additions and 73 deletions

View file

@ -82,7 +82,8 @@ class FFTCGDB
stmt.finalize()
if err
logger.warn "reg: FAIL db '#{err.code}' for '#{login}'"
reject 'existence' # user already exists
# reduce attack surface, don't disclose user names
reject 'db' # user already exists
else
logger.info "reg: OK '#{login}'"
@ -105,7 +106,8 @@ class FFTCGDB
# hash the password for timing attack reasons
bcrypt.hash password, saltRounds, (err, hash) ->
logger.debug "login: FAIL nonexistent '#{login}'"
reject 'existence' # user doesnt exist
# reduce attack surface, don't disclose user names
reject 'login' # user doesnt exist
else
bcrypt.compare password, row.pwdhash, (err, res) ->

View file

@ -18,7 +18,9 @@
"bcrypt": "^3.0.6",
"coffeescript": "^2.4.1",
"fastify": "^2.3.0",
"fastify-cookie": "^3.0.2",
"fastify-cors": "^2.1.3",
"fastify-static": "^2.4.0",
"fastify-ws": "^1.0.1",
"logging": "^3.2.0",
"redis": "^2.8.0",

View file

@ -12,11 +12,12 @@ module.exports =
handler: (request, reply) ->
new Promise (resolve) ->
session.check request.body.session ? ""
session_id = request.cookies.session ? ''
session.check session_id
.then (user) ->
# active session found
logger.debug "OK '#{user.login}' resumed session '#{request.body.session}'"
resolve request.body.session
logger.debug "OK '#{user.login}' resumed session '#{session_id}'"
resolve user
.catch ->
fftcgdb.login request.body.login, request.body.password
@ -25,17 +26,18 @@ module.exports =
logger.info "OK '#{request.body.login}'"
session.start user
.then (session_id) ->
resolve session_id
reply.setCookie 'session', session_id
resolve user
.catch (err) ->
# login failed
logger.info "FAIL '#{request.body.login}: #{err}'"
logger.info "FAIL '#{request.body.login}'"
reply.send
success: false
message: err
err: err
.then (session_id) ->
#
.then (user) ->
# tell about the user who logged in
reply.send
success: true
message: session_id
user: user

View file

@ -14,9 +14,11 @@ module.exports =
logger.info "OK '#{request.body.login}'"
reply.send
success: true
user: user
return
.catch (err) ->
logger.debug "FAIL '#{request.body.login}'"
reply.send
success: false
message: err
err: err

View file

@ -1,6 +1,5 @@
module.exports =
body:
session: type: 'string'
login: type: 'string'
password: type: 'string'
@ -10,12 +9,20 @@ module.exports =
required: ['success']
properties:
success: type: 'boolean'
message: type: 'string'
# message is required iff not success
err: type: 'string'
user:
type: 'object'
required: ['user', 'login']
properties:
user: type: 'number'
login: type: 'string'
# user is required iff success
# err is required otherwise
if:
properties:
success:
const: false
const: true
then:
required: ['message']
else: true
required: ['user']
else:
required: ['err']

View file

@ -5,9 +5,14 @@ fastify = (require 'fastify')
logger: level: 'warn'
# fastify and plugin framework
fastify.register (require 'fastify-cookie')
fastify.register (require 'fastify-ws'), library: 'uws'
fastify.register (require 'fastify-cors')
# temporary dev frontend; to be uninstalled
path = (require 'path')
fastify.register (require 'fastify-static'), root: (path.join __dirname, 'tmpfront')
# API routes
fastify.route (require "./routes/#{route}") for route in [
# test route

View file

@ -8,7 +8,7 @@ EXPIRY =
# games expire 1 week after creation
game: 1 * 60 * 60 * 24 * 7
# logins expire 1 month after last action
login: 1 * 60 * 60 * 24 * 30
login: 1 * 60 * 60 * 24 * 7 * 4
class FFTCGSESSION
@ -43,6 +43,6 @@ class FFTCGSESSION
else
@db.get digest, (err, res) ->
logger.info "OK '#{digest}' resumed"
resolve digest
resolve JSON.parse res
module.exports = new FFTCGSESSION

View file

@ -408,6 +408,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
cookie@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
@ -446,7 +451,7 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.1:
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.1:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -514,6 +519,16 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
detect-libc@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
@ -544,6 +559,21 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@ -554,6 +584,11 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
etag@~1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
execa@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
@ -657,6 +692,14 @@ fast-safe-stringify@^2.0.6:
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2"
integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==
fastify-cookie@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/fastify-cookie/-/fastify-cookie-3.0.2.tgz#4f36709a5f355af40ad6f42987101c1d5f78a01a"
integrity sha512-eFbMRK1Ydy5XRxjTyqUmt+kVblde1kcCPnEtXecqtg4KBFrBxkQ2C0fYIk3ILzLvJdpY4i1YFS578IDS77I3XA==
dependencies:
cookie "^0.3.1"
fastify-plugin "^1.4.0"
fastify-cors@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/fastify-cors/-/fastify-cors-2.1.3.tgz#5ae8fcc620a47270cd68d46acc3b8dd7919b538b"
@ -665,13 +708,23 @@ fastify-cors@^2.1.3:
fastify-plugin "^1.5.0"
vary "^1.1.2"
fastify-plugin@^1.5.0:
fastify-plugin@^1.4.0, fastify-plugin@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-1.5.0.tgz#4bea12c54112f4749c17f3a1f17356cbdfa661af"
integrity sha512-bXKSTR4Q1lxERf1p/10Aakga570XtcxCCvPR1gby5js1XOtg7E8UV+aHHEPbGowQGV/KVb7ARBROhPk2I4DfBw==
dependencies:
semver "^5.5.0"
fastify-static@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-2.4.0.tgz#7d3937897a8feaa66a920a915f72a11e795c3351"
integrity sha512-JgpxLsy6ask3UUXrHd76Vi0TvBZ6VtFgHaBIBV8hZ02Mn7YY5Vq0n2QOmcyJqSAF4RWc7UjubRE+wTSDXYUYQg==
dependencies:
fastify-plugin "^1.5.0"
glob "^7.1.3"
readable-stream "^3.1.1"
send "^0.16.0"
fastify-ws@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/fastify-ws/-/fastify-ws-1.0.1.tgz#30a788a238e537a050098fde08cd8dd092274c74"
@ -765,6 +818,11 @@ fragment-cache@^0.2.1:
dependencies:
map-cache "^0.2.2"
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
fs-minipass@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
@ -926,6 +984,16 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
http-errors@~1.6.2:
version "1.6.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
dependencies:
depd "~1.1.2"
inherits "2.0.3"
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@ -972,7 +1040,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.3, inherits@~2.0.3:
inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
@ -1335,6 +1403,11 @@ mime-types@^2.1.12, mime-types@~2.1.19:
dependencies:
mime-db "~1.37.0"
mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@ -1605,6 +1678,13 @@ object.pick@^1.3.0:
dependencies:
isobject "^3.0.1"
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
dependencies:
ee-first "1.1.1"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@ -1760,6 +1840,11 @@ quick-format-unescaped@^3.0.2:
resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-3.0.2.tgz#0137e94d8fb37ffeb70040535111c378e75396fb"
integrity sha512-FXTaCkwvpIlkdKeGDNgcq07SXWS383noQUuZjvdE1QcTt+eLuqof6/BDiEPqB59FWLie/l91+HtlJSw7iCViSA==
range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
@ -1962,6 +2047,25 @@ semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
send@^0.16.0:
version "0.16.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
dependencies:
debug "2.6.9"
depd "~1.1.2"
destroy "~1.0.4"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "~1.6.2"
mime "1.4.1"
ms "2.0.0"
on-finished "~2.3.0"
range-parser "~1.2.0"
statuses "~1.4.0"
set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@ -1987,6 +2091,11 @@ set-value@^2.0.0:
is-plain-object "^2.0.3"
split-string "^3.0.1"
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@ -2101,6 +2210,16 @@ static-extend@^0.1.1:
define-property "^0.2.5"
object-copy "^0.1.0"
"statuses@>= 1.4.0 < 2":
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
statuses@~1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"

View file

@ -31,7 +31,6 @@
"craftyjs": "^0.9.0",
"eslint": "^5.8.0",
"eslint-plugin-vue": "^5.0.0",
"js-cookie": "^2.2.0",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.1",
"vue-cli-plugin-coffeescript": "^0.0.3",

View file

@ -26,8 +26,6 @@
<script>
import FormDialog from './FormDialog.vue'
import * as Cookies from 'js-cookie'
import axios from '@/plugins/axios'
export default {
name: 'LoginForm',
@ -44,19 +42,15 @@ export default {
methods: {
confirm() {
axios
window.pkgs.axios
.post('/user/login', {
session: Cookies.get('session'),
login: this.login,
password: this.password
})
.then(response => {
// this.$refs.form.reset()
console.log('login', response.data)
if (response.data.success) {
Cookies.set('session', response.data.message, { expires: 30 })
console.log('cookie', Cookies.get())
}
console.log('cookie', document.cookie)
})
}
}

View file

@ -38,7 +38,6 @@
<script>
import FormDialog from './FormDialog.vue'
import axios from '@/plugins/axios'
export default {
name: 'RegisterForm',
@ -55,22 +54,21 @@ export default {
showPassword: false,
passwordRules: [v => !!v || 'Password is required'],
passwordConfirm: ''
passwordConfirm: '',
}),
computed: {
passwordConfirmRules() {
return [
() => this.password === this.passwordConfirm || 'Passwords must match'
() => this.password === this.passwordConfirm || "Passwords must match"
]
}
},
},
methods: {
confirm() {
axios
window.pkgs.axios
.post('/user/register', {
session: null,
login: this.login,
password: this.password
})

View file

@ -5,6 +5,14 @@ import router from './router'
import 'roboto-fontface/css/roboto/roboto-fontface.css'
import 'material-design-icons-iconfont/dist/material-design-icons.css'
import axios from 'axios'
axios.defaults.baseURL =
window.location.protocol + '//' + window.location.hostname + ':3001'
window.pkgs = {
axios: axios
}
Vue.config.productionTip = false
new Vue({

View file

@ -1,5 +0,0 @@
import axios from 'axios'
axios.defaults.baseURL =
window.location.protocol + '//' + window.location.hostname + ':3001'
export default axios

View file

@ -1,34 +1,49 @@
<template>
<v-container>
<v-flex mb-4>
<h1 class="display-2 font-weight-bold mb-3">Hello World!</h1>
<p class="subheading font-weight-regular">
App under development, please don't submit any valuable data!
</p>
</v-flex>
<p>user session: {{ sessionID }}</p>
</v-container>
<div class="about">
<h1>This is an about page</h1>
<div class="text-xs-center">
<v-dialog v-model="dialog" width="500">
<v-btn slot="activator" color="red lighten-2" dark>
Click Me
</v-btn>
<v-card>
<v-card-title class="headline grey lighten-2" primary-title>
Privacy Policy
</v-card-title>
<v-card-text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" flat @click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</div>
</template>
<script>
import * as Cookies from 'js-cookie'
import axios from '@/plugins/axios'
export default {
name: 'About',
data: () => ({
sessionID: ''
}),
mounted() {
axios
.post('/user/login', {
session: Cookies.get('session')
})
.then(response => {
this.sessionID = response.data.message
})
data() {
return {
dialog: false
}
}
}
</script>

View file

@ -6019,11 +6019,6 @@ js-beautify@^1.6.12, js-beautify@^1.6.14:
mkdirp "~0.5.0"
nopt "~4.0.1"
js-cookie@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.0.tgz#1b2c279a6eece380a12168b92485265b35b1effb"
integrity sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s=
js-levenshtein@^1.1.3:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"