BattleSim/server/auth.coffee

219 lines
6.7 KiB
CoffeeScript

{_} = require 'underscore'
crypto = require('crypto')
querystring = require('querystring');
Cookies = require( "cookies" )
request = require 'request'
authHeaders = {AUTHUSER: process.env.AUTHUSER, AUTHTOKEN: process.env.AUTHTOKEN}
request = request.defaults(json: true, headers: authHeaders, timeout: 30 * 1000)
config = require './config'
redis = require './redis'
USER_KEY = "users"
AUTH_KEY = "auth"
BANS_KEY = "bans"
MUTE_KEY = "mute"
return_sso_url="./"
secretstring = config.SECRET_KEY
loggedin = false
# This middleware checks if a user is authenticated through the site. If yes,
# then information about the user is stored in req.user. In addition, we store
# a token associated with that user into req.user.token.
#
# User information is also stored in redis.
exports.middleware = -> (req, res, next) ->
cookies = new Cookies( req, res )
return next() if req.path.match(/^\/css|^\/js|^\/fonts|^\/Sprites|^\/tiers|^\/pokemon|^\/ping|^\/replays\/\b/)
return next() if req.path.match(/^\/leaderboard/) # add some proper site authentication later instead
authenticate req, (body) ->
if !loggedin
if req.query.sso
sso = req.query.sso
sig = req.query.sig
cryptedret = crypto.createHmac('SHA256', secretstring).update(sso).digest('hex')
if cryptedret != sig
return
else
base64decode = new Buffer(sso, 'base64').toString('ascii')
userobject = querystring.parse(base64decode)
nonce = cookies.get("nonce")
noncereturn = userobject.nonce
if noncereturn != nonce
return
else
setdatabasedata(req, cookies, userobject, next)
else
parameters = getparameters(req)
nonce = new Date().getTime() + '' + new Date().getMilliseconds();
cookies.set("nonce", nonce)
console.log(req.headers.host)
if req.headers.host is "91.121.152.74:8000"
return_sso_url="http://" + req.headers.host + req.url
else
return_sso_url="https://" + req.headers.host + req.url
payload = "nonce=" + nonce + "&return_sso_url=" + return_sso_url
base64payload = new Buffer(payload).toString('base64')
urlencoded = encodeURIComponent(base64payload)
crypted = crypto.createHmac('SHA256', secretstring).update(base64payload).digest('hex')
console.log(req.headers.host)
if req.headers.host is "91.121.152.74:8000"
return res.redirect("http://91.121.152.74/session/sso_provider?sso=" + urlencoded + "&sig=" + crypted)
else
return res.redirect("https://forums.p-insurgence.com/session/sso_provider?sso=" + urlencoded + "&sig=" + crypted)
exports.matchToken = (req, id, token, next) ->
hmac = crypto.createHmac('sha256', config.SECRET_KEY)
rawcookies = req.headers.cookie
rawcookiesarr = rawcookies.split('; ')
noncearr = rawcookiesarr.filter (x) -> x.substring(0, 6) == "nonce="
if (noncearr[0])
noncecookie = noncearr[0].replace("nonce=", "")
if token != noncecookie
return next(new Error("Invalid session!"))
redis.shard 'hget', USER_KEY, id, (err, jsonString) ->
if err then return next(err)
json = JSON.parse(jsonString)
return next(new Error("Invalid session!")) if !json
exports.getAuth json.name, (err, authLevel) ->
if err then return next(err)
json.authority = authLevel
return next(null, json)
setdatabasedata = (req, cookies, object, next) ->
username = object.username
id = object.external_id
admin = object.admin
mod = object.moderator
req.user = {}
req.user.token = cookies.get("nonce")
req.user.id = id
req.user.name = username
OWNERUSERNAMES = ["Deukhoofd", "thesuzerain"]
if username in OWNERUSERNAMES && admin == "true"
exports.setAuth username, exports.levels.OWNER
else if admin == "true"
exports.setAuth username, exports.levels.ADMIN
else if mod == "true"
exports.setAuth username, exports.levels.MOD
else
exports.setAuth username, exports.levels.USER
toJSON = {
name : username,
token : cookies.get("nonce")
id : id
}
redis.shard('hset', USER_KEY, id, JSON.stringify(toJSON), next)
authenticate = (req, next) ->
return next()
getparameters = (req) ->
return("1")
generateUsername = (req) ->
name = req.param('user')
return name if name
{SpeciesData} = require './xy/data'
randomName = (name for name of SpeciesData)
randomName = randomName[Math.floor(Math.random() * randomName.length)]
randomName = randomName.split(/\s+/)[0]
randomName += "Fan" + Math.floor(Math.random() * 10000)
randomName
generateId = (req) ->
req.param('id') || Math.floor(1000000 * Math.random())
generateUser = (req) ->
{id: generateId(req), username: generateUsername(req)}
# Authorization
exports.levels =
USER : 1
DRIVER : 2
MOD : 3
MODERATOR : 3
ADMIN : 4
ADMINISTRATOR : 4
OWNER : 5
LEVEL_VALUES = (value for key, value of exports.levels)
exports.getAuth = (id, next) ->
id = String(id).toLowerCase()
redis.hget AUTH_KEY, id, (err, auth) ->
if err then return next(err)
auth = parseInt(auth, 10) || exports.levels.USER
next(null, auth)
exports.setAuth = (id, newAuthLevel, next) ->
id = String(id).toLowerCase()
if newAuthLevel not in LEVEL_VALUES
next(new Error("Incorrect auth level: #{newAuthLevel}"))
redis.hset(AUTH_KEY, id, newAuthLevel, next)
# Ban
# Length is in seconds.
exports.ban = (id, reason, length, next) ->
id = id.toLowerCase()
key = "#{BANS_KEY}:#{id}"
if length > 0
redis.setex(key, length, reason, next)
else
redis.set(key, reason, next)
exports.unban = (id, next) ->
id = String(id).toLowerCase()
redis.del("#{BANS_KEY}:#{id}", next)
exports.getBanReason = (id, next) ->
id = String(id).toLowerCase()
redis.get("#{BANS_KEY}:#{id}", next)
exports.getBanTTL = (id, next) ->
id = String(id).toLowerCase()
key = "#{BANS_KEY}:#{id}"
redis.exists key, (err, result) ->
if !result
# In older versions of Redis, TTL returns -1 if key doesn't exist.
return next(null, -2)
else
redis.ttl(key, next)
# Mute
# Length is in seconds.
exports.mute = (id, reason, length, next) ->
id = String(id).toLowerCase()
key = "#{MUTE_KEY}:#{id}"
if length > 0
redis.setex(key, length, reason, next)
else
redis.set(key, reason, next)
exports.unmute = (id, next) ->
id = String(id).toLowerCase()
key = "#{MUTE_KEY}:#{id}"
redis.del(key, next)
exports.getMuteTTL = (id, next) ->
id = String(id).toLowerCase()
key = "#{MUTE_KEY}:#{id}"
redis.exists key, (err, result) ->
if !result
# In older versions of Redis, TTL returns -1 if key doesn't exist.
return next(null, -2)
else
redis.ttl(key, next)