Mercurial Hosting > freedit
changeset 3:fc3ee39d7764
login
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 19 Jun 2022 20:47:31 -0600 |
parents | fc2383eb48a9 |
children | a17e400ddaa1 |
files | src/account.html.luan src/index.html.luan src/lib/Db.luan src/lib/Shared.luan src/lib/User.luan src/login.html.luan src/logout.html.luan |
diffstat | 7 files changed, 343 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/account.html.luan Sun Jun 19 20:47:31 2022 -0600 @@ -0,0 +1,33 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" +local Shared = require "site:/lib/Shared.luan" +local head = Shared.head or error() +local header = Shared.header or error() +local footer = Shared.footer or error() +local Forum = require "site:/lib/Forum.luan" +local forum_title = Forum.title or error() + + +return function() + Io.stdout = Http.response.text_writer() +%> +<!doctype html> +<html> + <head> +<% head() %> + <title><%=forum_title%> - Your Account</title> + </head> + <body> +<% header() %> + <div content> + <h1>Your Account</h1> + + <p><a href="/logout.html">logout</a></p> + </div> +<% footer() %> + </body> +</html> +<% +end
--- a/src/index.html.luan Thu Jun 16 20:52:24 2022 -0600 +++ b/src/index.html.luan Sun Jun 19 20:47:31 2022 -0600 @@ -7,6 +7,7 @@ local header = Shared.header or error() local footer = Shared.footer or error() local Forum = require "site:/lib/Forum.luan" +local forum_title = Forum.title or error() return function() @@ -16,7 +17,7 @@ <html> <head> <% head() %> - <title><%=Forum.title%></title> + <title><%=forum_title%></title> </head> <body> <% header() %>
--- a/src/lib/Db.luan Thu Jun 16 20:52:24 2022 -0600 +++ b/src/lib/Db.luan Sun Jun 19 20:47:31 2022 -0600 @@ -9,4 +9,7 @@ local Db = Lucene.index( dir, {} ) +Db.indexed_fields.user_email = Lucene.type.lowercase +Db.indexed_fields.user_name = Lucene.type.lowercase + return Db
--- a/src/lib/Shared.luan Thu Jun 16 20:52:24 2022 -0600 +++ b/src/lib/Shared.luan Sun Jun 19 20:47:31 2022 -0600 @@ -1,6 +1,10 @@ local Luan = require "luan:Luan.luan" local error = Luan.error +local Http = require "luan:http/Http.luan" local Forum = require "site:/lib/Forum.luan" +local User = require "site:/lib/User.luan" +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "Shared" local Shared = {} @@ -15,9 +19,16 @@ end function Shared.header() + local user = User.current() %> <div header> <a href="/"><%=Forum.title%></a> + - +<% if user == nil then %> + <a href="/login.html">login</a> +<% else %> + <a href="/account.html"><%=user.name_html%></a> +<% end %> </div> <% end @@ -30,4 +41,8 @@ <% end +function Shared.base_url() + return Http.request.scheme.."://"..Http.request.headers["host"] +end + return Shared
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/User.luan Sun Jun 19 20:47:31 2022 -0600 @@ -0,0 +1,118 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local set_metatable = Luan.set_metatable or error() +local range = Luan.range or error() +local String = require "luan:String.luan" +local sub_string = String.sub or error() +local Table = require "luan:Table.luan" +local concat = Table.concat or error() +local Math = require "luan:Math.luan" +local random = Math.random or error() +local Time = require "luan:Time.luan" +local time_now = Time.now or error() +local Html = require "luan:Html.luan" +local html_encode = Html.encode or error() +local Lucene = require "luan:lucene/Lucene.luan" +local lucene_quote = Lucene.quote or error() +local Http = require "luan:http/Http.luan" +local Db = require "site:/lib/Db.luan" + + +local User = {} + +local function from_doc(doc) + doc.type == "user" or error "wrong type" + return User.new { + id = doc.id + email = doc.user_email + password = doc.password + name = doc.user_name + created = doc.created + } +end + +local function to_doc(user) + local email = user.email + return { + type = "user" + id = user.id + user_email = email + password = user.password + user_name = user.name + created = user.created or time_now() + } +end + +local metatable = {} +function metatable.__index(user,key) + if key == "name_html" then + user.name_html = html_encode(user.name) + return user.name_html + end + return nil +end + +function User.new(user) + + function user.save() + local doc = to_doc(user) + Db.save(doc) + user.id = doc.id + end + + set_metatable(user,metatable) + return user +end + +function User.get_by_email(email) + local doc = Db.get_document("user_email:"..lucene_quote(email)) + return doc and from_doc(doc) +end + +local function get_by_name(name) + local doc = Db.get_document("user_name:"..lucene_quote(name)) + return doc and from_doc(doc) +end +User.get_by_name = get_by_name + +function User.current() + local name = Http.request.cookies.user + local password = Http.request.cookies.password + if name == nil or password == nil then + return nil + end + local user = get_by_name(name) + if user == nil or user.password ~= password then + return nil + end + return user +end + +local password_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +do + local t = {} + for i in range(1,#password_chars) do + t[#t+1] = sub_string(password_chars,i,i) + end + password_chars = t +end + +local function new_password() + local n = #password_chars + local t = {} + for _ in range(1,10) do + t[#t+1] = password_chars[random(n)] + end + return concat(t) +end + +function User.get_or_create_by_email(email) + local user = User.get_by_email(email) + if user == nil then + user = User.new{ email=email, password=new_password() } + user.save() + end + return user +end + +return User
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/login.html.luan Sun Jun 19 20:47:31 2022 -0600 @@ -0,0 +1,135 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local String = require "luan:String.luan" +local trim = String.trim or error() +local Html = require "luan:Html.luan" +local url_encode = Html.url_encode or error() +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" +local Shared = require "site:/lib/Shared.luan" +local head = Shared.head or error() +local header = Shared.header or error() +local footer = Shared.footer or error() +local base_url = Shared.base_url or error() +local Forum = require "site:/lib/Forum.luan" +local forum_title = Forum.title or error() +local User = require "site:/lib/User.luan" +local Db = require "site:/lib/Db.luan" +local run_in_transaction = Db.run_in_transaction or error() + + +local function get_user(email,password) + local user = User.get_by_email(email) + user or error "email not found" + user.password == password or error "wrong password" + return user +end + +local function login(user) + Http.response.set_persistent_cookie("user",user.name) + Http.response.set_persistent_cookie("password",user.password) + Http.request.cookies.user = user.name + Http.request.cookies.password = user.password +end + +local function register_form(user,name,error_message) + if error_message ~= nil then %> + <p error>Error: <%= error_message %></p> +<% end %> + <form> + <input type="hidden" name="email" value="<%= user.email %>" > + <input type="hidden" name="password" value="<%= user.password %>" > + <label>User name for <%= user.email %></label> + <input type="text" name="name" value="<%= name or "" %>" autofocus required> + <input type="submit" value="Register"> + </form> +<% +end + +local function page(contents) + Io.stdout = Http.response.text_writer() +%> +<!doctype html> +<html> + <head> +<% head() %> + <title><%=forum_title%> - Login or Register</title> + </head> + <body> +<% header() %> + <div content> + <h1>Login or Register</h1> +<% + contents() +%> + </div> +<% footer() %> + </body> +</html> +<% +end + +return function() + local email = Http.request.parameters.email + local password = Http.request.parameters.password + local name = Http.request.parameters.name + if email == nil then + page(function() +%> + <form> + <label>Email address</label> + <input type="email" name="email" autofocus required> + <input type="submit" value="Login or Register"> + </form> +<% + end) + elseif password == nil then + local user = User.get_or_create_by_email(email) + page(function() +%> + <p>We have sent you an email. Please check your email to login or register.</p> + <p>hack - <a href="<%=base_url()%>/login.html?email=<%=url_encode(email)%>&password=<%=user.password%>">link</a></p> +<% + end) + elseif name == nil then + local user = get_user(email,password) + if user.name == nil then + page(function() + register_form(user) + end) + else + login(user) + page(function() +%> + <p>You are now logged in.</p> +<% + end) + end + else + name = trim(name) + #name > 0 or error "empty name" + local error_message = nil + local user + run_in_transaction( function() + user = get_user(email,password) + if user.name ~= name and User.get_by_name(name) ~= nil then + error_message = "Name already in use" + else + user.name = name + user.save() + end + end ) + if error_message ~= nil then + page(function() + register_form(user,name,error_message) + end) + else + login(user) + page(function() +%> + <p>You are now registered.</p> +<% + end) + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/logout.html.luan Sun Jun 19 20:47:31 2022 -0600 @@ -0,0 +1,37 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" +local Shared = require "site:/lib/Shared.luan" +local head = Shared.head or error() +local header = Shared.header or error() +local footer = Shared.footer or error() +local Forum = require "site:/lib/Forum.luan" +local forum_title = Forum.title or error() + + +return function() + Http.response.remove_cookie("user") + Http.response.remove_cookie("password") + Http.request.cookies.user = nil + Http.request.cookies.password = nil + Io.stdout = Http.response.text_writer() +%> +<!doctype html> +<html> + <head> +<% head() %> + <title><%=forum_title%> - Logout</title> + </head> + <body> +<% header() %> + <div content> + <h1>Logout</h1> + + <p>You have been logged out.</p> + </div> +<% footer() %> + </body> +</html> +<% +end