2022-02-27 18:48:19 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
add config and auth support
diff --git a/app.lua b/app.lua index 3359006..14f3a57 100644 --- a/app.lua +++ b/app.lua @@ -1,5 +1,6 @@ local git = require "git" local scan = require "scan" +local hash = require "hash" local lud = require "ludweb" @@ -45,50 +46,124 @@ local function diff_cb(line_type, line) return line .. "\n" end -local path = "/tmp/cogit" -local limit = 20 +local function allowed(user, gname) + if gname == "public" then + return true + elseif user == nil then + return false + end + for _, ok in ipairs(user.groups) do + if gname == ok then + return true + end + end + return false +end + +local LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG = 0, 1, 2, 3 + +local path = arg[1] +local conf = dofile(path.."/conf.lua") git.init() local groups = scan.scanrepos(path) +local me + local routes = { {"GET", "/?", function (req) + local user = conf.users[me] local gnames = {} for gname in pairs(groups) do - table.insert(gnames, gname) + if allowed(user, gname) then + table.insert(gnames, gname) + end end - return lud.template.render_file("view/home.html", {gnames=gnames}) + return lud.template.render_file("view/home.html", {user=user, gnames=gnames}) + end}, + {"GET", "/login", + function (req) + return lud.template.render_file("view/login.html", {}) + end}, + {"POST", "/login", + function (req) + local uname = req.form.username + local pass = req.form.password + local user = conf.users[uname] + local salt, h + if user == nil then + -- hash something as if we're trying to login anyway + salt = hash.get_salt() + h = hash.hash_pass(pass, salt) + conf.log(LOG_INFO, "invalid username") + else + salt = lud.crypt.b64_dec(user.salt) + h = hash.hash_pass(pass, salt) + if h == lud.crypt.b64_dec(user.hash) then + me = uname + conf.log(LOG_INFO, "logged in as "..uname) + return "/", 303 + else + conf.log(LOG_INFO, "invalid password") + end + end + return "/login", 303 + end}, + {"GET", "/logout", + function (req) + me = nil + return "/", 303 end}, {"GET", "/group/([%w_-]+)", function (req, gname) + local user = conf.users[me] + if not allowed(user, gname) then + return "/login", 303 + end local rnames = {} for rname in pairs(groups[gname]) do table.insert(rnames, rname) end - return lud.template.render_file("view/group.html", {gname=gname, rnames=rnames}) + local env = {user=user, gname=gname, rnames=rnames} + return lud.template.render_file("view/group.html", env) end}, {"GET", "/group/([%w_-]+)/repo/([%w_-]+)", function (req, gname, rname) + local user = conf.users[me] + if not allowed(user, gname) then + return "/login", 303 + end local repo = groups[gname][rname] local bnames = repo:branches() local tnames = repo:tags() - local env = {repo=repo, gname=gname, rname=rname, bnames=bnames, tnames=tnames} + local env = { + user=user, repo=repo, gname=gname, + rname=rname, bnames=bnames, tnames=tnames, + } return lud.template.render_file("view/repo.html", env) end}, {"GET", "/group/([%w_-]+)/repo/([%w_-]+)/history/([%w_-]+)", function (req, gname, rname, first) + local user = conf.users[me] + if not allowed(user, gname) then + return "/login", 303 + end local repo = groups[gname][rname] local commit = repo:commit(first) - local prev = repo:find_prev(commit:id(), limit) + local prev = repo:find_prev(commit:id(), conf.limit) local env = { - gname=gname, rname=rname, bname=bname, commit=commit, - limit=limit, prev=prev, first=first, + user=user, gname=gname, rname=rname, bname=bname, + commit=commit, limit=conf.limit, prev=prev, first=first, } return lud.template.render_file("view/history.html", env) end}, {"GET", "/group/([%w_-]+)/repo/([%w_-]+)/commit/([%w_-]+)", function (req, gname, rname, cid) + local user = conf.users[me] + if not allowed(user, gname) then + return "/login", 303 + end local repo = groups[gname][rname] local commit = repo:commit(cid) local prev = repo:find_prev(commit:id(), 1) @@ -96,13 +171,17 @@ local routes = { local time_str = time_fmt(sig) local diff = repo:diff(commit, diff_cb) local env = { - gname=gname, rname=rname, bname=bname, commit=commit, + user=user, gname=gname, rname=rname, bname=bname, commit=commit, time_str=time_str, sig=sig, cid=cid, prev=prev, diff=diff, } return lud.template.render_file("view/commit.html", env) end}, {"GET", "/group/([%w_-]+)/repo/([%w_-]+)/commit/([%w_-]+)/tree/(.*)", function (req, gname, rname, cid, path) + local user = conf.users[me] + if not allowed(user, gname) then + return "/login", 303 + end local repo = groups[gname][rname] local commit = repo:commit(cid) local node = commit:tree_entry(path) @@ -118,8 +197,8 @@ local routes = { base = base .. "/" end local env = { - gname=gname, rname=rname, cid=cid, path=path, - base=base, parts=parts, node=node, + user=user, gname=gname, rname=rname, cid=cid, + path=path, base=base, parts=parts, node=node, } if node.type_ == "dir" then return lud.template.render_file("view/dir.html", env) diff --git a/conf.lua b/conf.lua new file mode 100644 index 0000000..09cc124 --- /dev/null +++ b/conf.lua @@ -0,0 +1,25 @@ +--[[ +Put this file on the same folder as public/ and customize it. +]] + +local LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG = 0, 1, 2, 3 +local level_str = {"ERROR", "WARN", "INFO", "DEBUG"} +local log_level = LOG_DEBUG + +return { + ["log"] = function (level, msg) -- logging function + if log_level >= level then + print(("[%s] %s"):format(level_str[level+1], msg)) + end + end, + limit = 20, -- page size, for pagination + users = { + ["guest"] = { + salt = "GfwhQ/F6HYnv6g5qrpv58NgMWmOF6nsQXc8RVr6C8Fc=", + hash = "uxfQEiPSWAuu96rYpqYfi0kcue0ZiTvSCDX3ngFjC3RqLa7v9OouFd5UglJ7vh52nNDh2E9cG/f0RlVrLzIE9Q==", + nick = "guest", + name = "Guest", + groups = {"guests"}, + }, + }, +} diff --git a/hash.lua b/hash.lua new file mode 100644 index 0000000..c396c66 --- /dev/null +++ b/hash.lua @@ -0,0 +1,38 @@ +local lud = require "ludweb" + +local function get_pass(prompt) + io.write(prompt) + os.execute("stty -echo") + local pass = io.read() + os.execute("stty echo") + io.write("\n") + return pass +end + +local function get_salt() + return lud.crypt.urandom(32) +end + +local function hash_pass(pass, salt) + return lud.crypt.pbkdf2(pass, salt, 10000, 64) +end + +if arg[0] ~= "hash.lua" then + return {get_salt=get_salt, hash_pass=hash_pass} +end + +local pass, pass2 + +repeat + pass = get_pass("password: ") + pass2 = get_pass("repeat : ") +until pass2 == pass + +local salt = get_salt() +local hash = hash_pass(pass, salt) + +local salt_b64 = lud.crypt.b64_enc(salt) +local hash_b64 = lud.crypt.b64_enc(hash) + +print("salt: " .. salt_b64) +print("hash: " .. hash_b64) diff --git a/view/commit.html b/view/commit.html index 2fe374f..cdf216c 100644 --- a/view/commit.html +++ b/view/commit.html @@ -4,6 +4,8 @@ <meta charset="utf-8"> <title>cogit - {{$gname}} - {{$rname}} - {{$cid}}</title> <style> + #nav-bar { float: left; } + #auth-bar { float: right; } .diff_file_hdr { font-weight: bold; } .diff_hunk_hdr { font-weight: bold; color: blue; } .diff_add { color: green; } @@ -13,7 +15,7 @@ </style> </head> <body> - <p> + <div id="nav-bar"> <a href="/">home</a> > <a href="/group/{{$gname}}">{{$gname}}</a> @@ -25,7 +27,16 @@ {{$cid}} > <a href="/group/{{$gname}}/repo/{{$rname}}/commit/{{$cid}}/tree/">tree</a> - </p> + </div> + <div id="auth-bar"> + % if $user == nil then + <a href="/login">login</a> + % else + <strong>{{$user.name}}</strong> + <a href="/logout">(logout)</a> + % end + </div> + <br> % if $prev then <a href="/group/{{$gname}}/repo/{{$rname}}/commit/{{$prev:id()}}"><</a> % else diff --git a/view/dir.html b/view/dir.html index 109390c..c53d6a6 100644 --- a/view/dir.html +++ b/view/dir.html @@ -3,9 +3,13 @@ <head> <meta charset="utf-8"> <title>cogit - {{$gname}} - {{$rname}} - {{$cid}} - {{$path}}</title> + <style> + #nav-bar { float: left; } + #auth-bar { float: right; } + </style> </head> <body> - <p> + <div id="nav-bar"> <a href="/">home</a> > <a href="/group/{{$gname}}">{{$gname}}</a> @@ -21,7 +25,16 @@ > <a href="{{$partial}}">{{$part}}</a> % end - </p> + </div> + <div id="auth-bar"> + % if $user == nil then + <a href="/login">login</a> + % else + <strong>{{$user.name}}</strong> + <a href="/logout">(logout)</a> + % end + </div> + <br> <ul> % for child in $node.children do <li><a href="{{$base..$child}}">{{$child}}</a></li> diff --git a/view/file.html b/view/file.html index b4ea240..1190b83 100644 --- a/view/file.html +++ b/view/file.html @@ -3,9 +3,13 @@ <head> <meta charset="utf-8"> <title>cogit - {{$gname}} - {{$rname}} - {{$cid}} - {{$path}}</title> + <style> + #nav-bar { float: left; } + #auth-bar { float: right; } + </style> </head> <body> - <p> + <div id="nav-bar"> <a href="/">home</a> > <a href="/group/{{$gname}}">{{$gname}}</a> @@ -21,7 +25,16 @@ > <a href="{{$partial}}">{{$part}}</a> % end - </p> + </div> + <div id="auth-bar"> + % if $user == nil then + <a href="/login">login</a> + % else + <strong>{{$user.name}}</strong> + <a href="/logout">(logout)</a> + % end + </div> + <br> % if $node.bin then <p><em>binary file</em></p> % else diff --git a/view/group.html b/view/group.html index 6579b54..2d37c75 100644 --- a/view/group.html +++ b/view/group.html @@ -3,13 +3,26 @@ <head> <meta charset="utf-8"> <title>cogit - {{$gname}}</title> + <style> + #nav-bar { float: left; } + #auth-bar { float: right; } + </style> </head> <body> - <p> + <div id="nav-bar"> <a href="/">home</a> > {{$gname}} - </p> + </div> + <div id="auth-bar"> + % if $user == nil then + <a href="/login">login</a> + % else + <strong>{{$user.name}}</strong> + <a href="/logout">(logout)</a> + % end + </div> + <br> <p>Repos:</p> <ul> % for rname in $rnames do diff --git a/view/history.html b/view/history.html index 310b4d2..118229e 100644 --- a/view/history.html +++ b/view/history.html @@ -3,9 +3,13 @@ <head> <meta charset="utf-8"> <title>cogit - {{$gname}} - {{$rname}} - history</title> + <style> + #nav-bar { float: left; } + #auth-bar { float: right; } + </style> </head> <body> - <p> + <div id="nav-bar"> <a href="/">home</a> > <a href="/group/{{$gname}}">{{$gname}}</a> @@ -15,7 +19,16 @@ history > <a href="/group/{{$gname}}/repo/{{$rname}}/commit/{{$first}}/tree/">tree</a> - <p> + </div> + <div id="auth-bar"> + % if $user == nil then + <a href="/login">login</a> + % else + <strong>{{$user.name}}</strong> + <a href="/logout">(logout)</a> + % end + </div> + <br> % if $prev then <a href="/group/{{$gname}}/repo/{{$rname}}/history/{{$prev:id()}}"><</a> % else diff --git a/view/home.html b/view/home.html index be3f067..74253d2 100644 --- a/view/home.html +++ b/view/home.html @@ -3,9 +3,22 @@ <head> <meta charset="utf-8"> <title>cogit</title> + <style> + #nav-bar { float: left; } + #auth-bar { float: right; } + </style> </head> <body> - <p>home</p> + <div id="nav-bar">home</div> + <div id="auth-bar"> + % if $user == nil then + <a href="/login">login</a> + % else + <strong>{{$user.name}}</strong> + <a href="/logout">(logout)</a> + % end + </div> + <br> <p>Groups:</p> <ul> % for gname in $gnames do diff --git a/view/login.html b/view/login.html new file mode 100644 index 0000000..28dd562 --- /dev/null +++ b/view/login.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>cogit - login</title> + <style> + .centered { text-align: center; } + .ul-form { + padding: 0; + list-style-type: none; + } + .flat-field { + margin: 5px; + font-size: 18px; + background: white; + border-width: 1px; + border-style: solid; + border-color: #B4C2AA; + border-radius: 0px; + } + .flat-field:invalid { + border-color: lightcoral; + } + .flat-button { + margin: 10px; + box-shadow: none; + background: none; + background-color: #F5FFE2; + border-radius: 6px; + border: 3px solid #B4C2AA; + font-weight: bold; + padding: 5px 20px; + cursor: default; + color: black; + font-size: 16px; + text-decoration: none; + text-shadow: 1px 1px 0px white; + } + + .flat-button:hover { + background-color: var(--color-2); + } + </style> +</head> +<body> + <h1 class="centered">Login</h1> + <form action="/login" method="post"> + <ul class="centered ul-form"> + <li><input type="text" class="flat-field" name="username" placeholder="User" autofocus></li> + <li><input type="password" class="flat-field" name="password" placeholder="Password"></li> + <li><input type="submit" class="flat-button" value="Login"></li> + </ul> + </form> +</body> +</html> diff --git a/view/repo.html b/view/repo.html index 926994d..b0b6808 100644 --- a/view/repo.html +++ b/view/repo.html @@ -3,15 +3,28 @@ <head> <meta charset="utf-8"> <title>cogit - {{$gname}} - {{$rname}}</title> + <style> + #nav-bar { float: left; } + #auth-bar { float: right; } + </style> </head> <body> - <p> + <div id="nav-bar"> <a href="/">home</a> > <a href="/group/{{$gname}}">{{$gname}}</a> > {{$rname}} - </p> + </div> + <div id="auth-bar"> + % if $user == nil then + <a href="/login">login</a> + % else + <strong>{{$user.name}}</strong> + <a href="/logout">(logout)</a> + % end + </div> + <br> <p>Branches:</p> <ul> % for bname in $bnames do