Compare commits

...

5 commits

15 changed files with 73 additions and 216 deletions

View file

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

View file

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

View file

@ -14,11 +14,9 @@ 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
err: err
message: err

View file

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

View file

@ -5,14 +5,9 @@ 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 * 7 * 4
login: 1 * 60 * 60 * 24 * 30
class FFTCGSESSION
@ -43,6 +43,6 @@ class FFTCGSESSION
else
@db.get digest, (err, res) ->
logger.info "OK '#{digest}' resumed"
resolve JSON.parse res
resolve digest
module.exports = new FFTCGSESSION

View file

@ -408,11 +408,6 @@ 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"
@ -451,7 +446,7 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.1:
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==
@ -519,16 +514,6 @@ 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"
@ -559,21 +544,6 @@ 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"
@ -584,11 +554,6 @@ 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"
@ -692,14 +657,6 @@ 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"
@ -708,23 +665,13 @@ fastify-cors@^2.1.3:
fastify-plugin "^1.5.0"
vary "^1.1.2"
fastify-plugin@^1.4.0, fastify-plugin@^1.5.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"
@ -818,11 +765,6 @@ 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"
@ -984,16 +926,6 @@ 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"
@ -1040,7 +972,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.3:
inherits@2, 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=
@ -1403,11 +1335,6 @@ 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"
@ -1678,13 +1605,6 @@ 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"
@ -1840,11 +1760,6 @@ 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"
@ -2047,25 +1962,6 @@ 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"
@ -2091,11 +1987,6 @@ 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"
@ -2210,16 +2101,6 @@ 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,6 +31,7 @@
"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,6 +26,8 @@
<script>
import FormDialog from './FormDialog.vue'
import * as Cookies from 'js-cookie'
import axios from '@/plugins/axios'
export default {
name: 'LoginForm',
@ -42,15 +44,19 @@ export default {
methods: {
confirm() {
window.pkgs.axios
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)
console.log('cookie', document.cookie)
if (response.data.success) {
Cookies.set('session', response.data.message, { expires: 30 })
console.log('cookie', Cookies.get())
}
})
}
}

View file

@ -38,6 +38,7 @@
<script>
import FormDialog from './FormDialog.vue'
import axios from '@/plugins/axios'
export default {
name: 'RegisterForm',
@ -54,21 +55,22 @@ 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() {
window.pkgs.axios
axios
.post('/user/register', {
session: null,
login: this.login,
password: this.password
})

View file

@ -5,14 +5,6 @@ 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

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

View file

@ -1,49 +1,34 @@
<template>
<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>
<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>
</template>
<script>
import * as Cookies from 'js-cookie'
import axios from '@/plugins/axios'
export default {
name: 'About',
data() {
return {
dialog: false
}
data: () => ({
sessionID: ''
}),
mounted() {
axios
.post('/user/login', {
session: Cookies.get('session')
})
.then(response => {
this.sessionID = response.data.message
})
}
}
</script>

View file

@ -6019,6 +6019,11 @@ 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"