--This modules is used to do operations on databse file--

module("db", package.seeall)

--includes
require("config/main_conf")
local sqlite3 = require("lsqlite3")
--------------------------------
-- Modified 20 September 2012 --
-- dylan@kses.net             --
-----------------------------------------------
-- Require command.lua for executing openssl --
-----------------------------------------------
require("luamods/command")
------------------------------------------------

--Open Database
dbase = sqlite3.open( main_conf.database_file_path )

--Check if user exists in database
function getusers()
    usertb = {}
    for username, salt, hash, priv in dbase:urows( [[ SELECT * FROM users ]] ) do
        local user = {}
        user.name = username
        user.salt = salt
        user.hash = hash
        user.priv = priv
        table.insert(usertb, user)
    end

    return usertb;
end

function getUserDetails(username)
    for username, salt, hash, priv in dbase:urows( [[ SELECT * FROM users WHERE username=']]..username..[[']] ) do
        local user = {}
        user.name = username
        user.salt = salt
        user.hash = hash
        user.priv = priv
        return user
    end
end    

--Check if user exists in database
function checkUser(usrn)
	for usr in dbase:urows( [[ SELECT username FROM users ]] ) do
		if usr == usrn then
			return true
		end
	end
	return false
end

-------------------------------
-- Modified 04 December 2012 --
-- dylan@kses.net            --
----------------------------------------------------------------------------
-- Create user with hash of salted password instead of plaintext password --
-- User type is now included (administrator, regular user, etc.)
----------------------------------------------------------------------------
function createUser(usrn, pasw, usertype)
    if usrn == nil or pasw == nil then
        return false
    end

    check = checkUser(usrn)
    if check == false then
        s = command.ex("openssl passwd -1 "..pasw)

        for a,salt,hash in s:gmatch("$([^$]+)$([^$]+)$([^$]+)\n") do
            dbase:exec( [[ INSERT INTO users VALUES (']]..usrn..[[',']]..salt..[[',']]..hash..[[',']]..usertype..[[')]] )
        end

        return true
    end
    return false
end
----------------------------------------------------------------------------
-- End of modification
----------------------------------------------------------------------------

--Delete a user
function removeUser(usrn)
    dbase:exec([[ DELETE FROM users WHERE username=']]..usrn..[[' ]])
    dbase:exec([[ DELETE FROM sessions WHERE user=']]..usrn..[[' ]])
    return true
end

--------------------------------
-- Modified 20 September 2012 --
-- dylan@kses.net             --
---------------------------------------------------------------------------------------
-- Authenticate by comparing stored hash with hash of stored salt + entered password --
---------------------------------------------------------------------------------------
function verifyUser(usrn, pasw)
    if usrn == nil or pasw == nil then
        return false
    end

    for usr,salt,hash in dbase:urows( [[ SELECT * FROM users WHERE username=']]..usrn..[[' ]] ) do
        -- Why is this test here?
        if usr == usrn then
            s = command.ex("openssl passwd -1 -salt "..salt.." "..pasw)
            if s == "$1$"..salt.."$"..hash.."\n" then
                return true
            else
                return false
            end
        end
    end
    return false
end

--------------------------------
-- Modified 20 September 2012 --
-- dylan@kses.net             --
------------------------------------------------------------------------------
-- Changing password creates new salt + hash and updates these in the table --
------------------------------------------------------------------------------
function changePassword(usrn, newpasw)
    s = command.ex("openssl passwd -1 "..newpasw)
    for a,salt,hash in s:gmatch("$([^$]+)$([^$]+)$([^$]+)\n") do
        dbase:exec( [[ UPDATE users SET salt=']]..salt..[[', hash=']]..hash..[[' WHERE username=']]..usrn..[[' ]] )
    end
    dbase:exec([[ DELETE FROM sessions WHERE user=']]..usrn..[[' ]])
    return true
end

function changePriv(usrn, priv)
    if (priv == 0) or (priv == 1) or (priv == 2) then
        dbase:exec( [[ UPDATE users SET type=']]..priv..[[' WHERE username=']]..usrn..[[' ]] )
        return true
    end
    return false
end


------------------------------
-- Modified 16 October 2012 --
-- dylan@kses.net           --
---------------------------------------------------------------------------
-- Sessions will now expire after 20 minutes of inactivity by default    --
---------------------------------------------------------------------------
function createSession(usrn,ipadd)
	check = true
	while check ~= false do
                math.randomseed(os.time())
		sessionID = math.random(1000)
		check = false
		for sID in dbase:urows( [[ SELECT sessionID FROM sessions ]] ) do
			if sID == sessionID then
				check = true
				break
			end
		end
	end
	expire = os.time() + 1800
	dbase:exec( [[ INSERT INTO sessions VALUES (']]..sessionID..[[',']]..usrn..[[',']]..expire..[[',']]..ipadd..[[') ]] )
	return sessionID
end

------------------------------
-- Modified 16 October 2012 --
-- dylan@kses.net           --
------------------------------------------------------------------------------------
-- Don't bother to check if session exists before deleting, database will do this --
------------------------------------------------------------------------------------
function terminateSession(sesID)
    dbase:exec("DELETE FROM sessions WHERE sessionID='"..sesID.."'")
    return true
end


function verifySession(sesID,userID)
    if sesID == nil or userID == nil then
        return 3
    end
    
    -- Check all other sessions in database for expiry
    for tempSesID,expire in dbase:urows("SELECT sessionID, expire FROM sessions WHERE sessionID != '"..sesID.."'") do
        if os.time() > expire then
            -- Expired
            terminateSession(tempSesID)
        end
    end
    
    -- Now check for this specific one
    if sesID == nil or userID == nil then return 3 end
    for sesID,expire in dbase:urows("SELECT sessionID, expire FROM sessions WHERE user='"..userID.."' and sessionID='"..sesID.."'") do
        if os.time() > expire then
            -- Expired
            terminateSession(sesID)
            return 2
        else
            -- All good, extend expiry time
            if ((getPriv(userID)) == 2) then
                newExpire = os.time() + 3600
            else
                newExpire = os.time() + 1800
            end
            dbase:exec( [[ UPDATE sessions SET expire=']]..newExpire..[[' WHERE sessionID=']]..sesID..[[' ]] )
            return 1
        end
    end
    --No such session
    return 3
end

function getPriv(userID)
    if userID == nil then return 1 end
    for p in dbase:urows( [[ SELECT type FROM users WHERE username="]]..userID..[[" ]] ) do
        return p
    end
end
