starting users
This commit is contained in:
181
apps/users.lua
Normal file
181
apps/users.lua
Normal file
@ -0,0 +1,181 @@
|
||||
local app = require("lapis").Application()
|
||||
|
||||
local db = require("lapis.db")
|
||||
local constants = require("constants")
|
||||
|
||||
local bcrypt = require("bcrypt")
|
||||
local rand = require("openssl.rand")
|
||||
|
||||
local models = require("models")
|
||||
local Users = models.Users
|
||||
local Sessions = models.Sessions
|
||||
|
||||
local function authenticate_user(user, password)
|
||||
return bcrypt.verify(password, user.password_hash)
|
||||
end
|
||||
|
||||
local function create_session_key()
|
||||
return rand.bytes(16):gsub(".", function(c) return string.format("%02x", string.byte(c)) end)
|
||||
end
|
||||
|
||||
local function create_session(user_id)
|
||||
local days = 30
|
||||
local expires_at = os.time() + (days * 24 * 60 * 60)
|
||||
|
||||
return Sessions:create({
|
||||
key = create_session_key(),
|
||||
user_id = user_id,
|
||||
expires_at = expires_at,
|
||||
})
|
||||
end
|
||||
|
||||
local function validate_session(session_key)
|
||||
local session = db.select('* FROM "sessions" WHERE "key" = ? AND "expires_at" > "?" LIMIT 1', session_key, os.time())
|
||||
print(#session)
|
||||
if #session > 0 then
|
||||
return Users:find({id = session[1].user_id})
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function validate_password(password)
|
||||
if #password < 10 or password:match("%s") then
|
||||
return false
|
||||
end
|
||||
|
||||
if #password > 255 then
|
||||
return false
|
||||
end
|
||||
|
||||
local r = password:match("%u+") and
|
||||
password:match("%l+") and
|
||||
password:match("%d+") and
|
||||
password:match("%p+")
|
||||
return r ~= nil and true
|
||||
end
|
||||
|
||||
local function validate_username(username)
|
||||
if #username < 3 or #username > 20 then
|
||||
return false
|
||||
end
|
||||
|
||||
return username:match("^[%w_-]+$") and true
|
||||
end
|
||||
|
||||
app:get("user", "/:username", function(self)
|
||||
local user = Users:find({username = self.params.username})
|
||||
if not user then
|
||||
return {status = 404}
|
||||
end
|
||||
|
||||
if self.session.flash.just_logged_in then
|
||||
self.just_logged_in = true
|
||||
self.session.flash = {}
|
||||
end
|
||||
local me = validate_session(self.session.session_key)
|
||||
if not me and user.permission == constants.PermissionLevel.GUEST then
|
||||
return {status = 404}
|
||||
end
|
||||
self.user = user
|
||||
return {render = "user.user"}
|
||||
end)
|
||||
|
||||
app:get("user_login", "/login", function(self)
|
||||
if self.session.session_key then
|
||||
local user = validate_session(self.session.session_key)
|
||||
if user ~= nil then
|
||||
return {redirect_to = self:url_for("user", {username = user.username})}
|
||||
end
|
||||
end
|
||||
|
||||
if self.session.flash then
|
||||
self.err = self.session.flash.error
|
||||
self.session.flash = {}
|
||||
end
|
||||
return {render = "user.login"}
|
||||
end)
|
||||
|
||||
app:post("user_login", "/login", function(self)
|
||||
if self.session.session_key then
|
||||
local user = validate_session(self.session.session_key)
|
||||
if user ~= nil then
|
||||
return {redirect_to = self:url_for("user", {username = user.username})}
|
||||
end
|
||||
end
|
||||
local username = self.params.username
|
||||
local password = self.params.password
|
||||
local user = Users:find({username = username})
|
||||
if not user then
|
||||
self.session.flash = {error = "Invalid username or password"}
|
||||
return {redirect_to = self:url_for("user_login")}
|
||||
end
|
||||
if not authenticate_user(user, password) then
|
||||
self.session.flash = {error = "Invalid username or password"}
|
||||
return {redirect_to = self:url_for("user_login")}
|
||||
end
|
||||
local session = create_session(user.id)
|
||||
self.session.flash = {just_logged_in = true}
|
||||
self.session.session_key = session.key
|
||||
return {redirect_to = self:url_for("user", {username = username})}
|
||||
end)
|
||||
|
||||
app:get("user_signup", "/signup", function(self)
|
||||
if self.session.session_key then
|
||||
local user = validate_session(self.session.session_key)
|
||||
if user ~= nil then
|
||||
return {redirect_to = self:url_for("user", {username = user.username})}
|
||||
end
|
||||
end
|
||||
if self.session.flash then
|
||||
self.err = self.session.flash.error
|
||||
self.session.flash = {}
|
||||
end
|
||||
return {render = "user.signup"}
|
||||
end)
|
||||
|
||||
app:post("user_signup", "/signup", function(self)
|
||||
if self.session.session_key then
|
||||
local user = validate_session(self.session.session_key)
|
||||
if user ~= nil then
|
||||
return {redirect_to = self:url_for("user", {username = user.username})}
|
||||
end
|
||||
end
|
||||
|
||||
local username = self.params.username
|
||||
local password = self.params.password
|
||||
local password2 = self.params.password2
|
||||
local user = Users:find({username = username})
|
||||
if user then
|
||||
self.session.flash = {error = "Username '" .. username .. "' is already taken."}
|
||||
return {redirect_to = self:url_for("user_signup")}
|
||||
end
|
||||
|
||||
if not validate_username(username) then
|
||||
self.session.flash = {error = "Username must be 3-20 characters with only upper and lowercase letters, hyphens, and underscores."}
|
||||
return {redirect_to = self:url_for("user_signup")}
|
||||
end
|
||||
|
||||
if not validate_password(password) then
|
||||
self.session.flash = {error = "Password must be 10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces."}
|
||||
return {redirect_to = self:url_for("user_signup")}
|
||||
end
|
||||
|
||||
if password ~= password2 then
|
||||
self.session.flash = {error = "Passwords do not match."}
|
||||
return {redirect_to = self:url_for("user_signup")}
|
||||
end
|
||||
|
||||
local new_user = Users:create({
|
||||
username = username,
|
||||
password_hash = bcrypt.digest(password, constants.BCRYPT_ROUNDS),
|
||||
permission = constants.PermissionLevel.GUEST,
|
||||
})
|
||||
|
||||
local session = create_session(new_user.id)
|
||||
self.session.flash = {just_logged_in = true}
|
||||
self.session.session_key = session.key
|
||||
return {redirect_to = self:url_for("user", {username = username})}
|
||||
end)
|
||||
|
||||
return app
|
Reference in New Issue
Block a user