napkin/database.lua

202 lines
4.8 KiB
Lua

local fs = require "fs"
local json = require "json"
local utils = require "./utils"
local foppy = require "./foppy"
local authors = {}
package.loaded["authors"] = authors
do
authors.from_id = function(id, writeable)
return foppy.open("database/authors/" .. id .. ".json", writeable)
end
authors.id_from_token = function(token, writeable)
local data = foppy.open("database/tokens/" .. token .. ".json", writeable)
if not data then
print("token doesnt exist", token)
return nil, 404
end
if data.expires <= os.time() then
data.dead = true
return nil, 401
end
if data.dead then
return nil, 401
end
local exists = fs.existsSync("database/authors/" .. data.of .. ".json")
if not exists then
data.dead = true
return nil, 404
end
return data.of
end
authors.id_from_blog = function(blog, writeable)
local data = foppy.open("database/blogs/" .. blog .. ".json")
if not data then
return nil, 404
end
return data.owner
end
local is_right_password = function(id, password)
local author, code = authors.from_id(id, true)
if not author then
return nil, 404
end
-- check salted password with openssl
local hashed = utils.hash(author.salt .. password)
if author.password ~= hashed then
return nil, 401
end
return author
end
authors.auth = function(id, password)
local author, code = is_right_password(id, password)
if not author then
return nil, code
end
local hash, filename
repeat
hash = utils.uuid()
filename = "database/tokens/" .. hash .. ".json"
until not fs.existsSync(hash)
local token_data = json.encode {
of = id,
expires = os.time() + 2628000, -- 4 months, approximately.
dead = false
}
fs.writeFileSync(filename, token_data)
print(#author.tokens, hash)
author.tokens[#author.tokens + 1] = hash
foppy.sync("database/authors/" .. id .. ".json")
return hash
end
authors.revoke_all_tokens = function(id, password)
local author, code = is_right_password(id, password)
if not author then
return nil, code
end
for _, v in ipairs(author.tokens) do
local f = "database/tokens/" .. v .. ".json"
local token = foppy.open(f, true)
token.dead = true
foppy.sync(f, true)
end
author.tokens = {}
foppy.sync("database/authors/" .. id .. ".json")
end
authors.change_password = function(id, password, new_password)
local author, code = is_right_password(id, password)
if not author then
return nil, code
end
author.salt = utils.uuid()
author.password = utils.data(author.salt .. new_password)
foppy.sync("database/authors/" .. id .. ".json")
end
authors.get_available_id = function()
local id
repeat
id = utils.pin()
until not fs.existsSync("database/authors/" .. id .. ".json")
return id
end
authors.create_account = function(password)
local id = authors.get_available_id()
local salt = utils.uuid()
local account_data = json.encode {
blogs = {},
password = utils.hash(salt .. password),
salt = salt,
tokens = {}
}
fs.writeFileSync(
"database/authors/" .. id .. ".json",
account_data
)
return id
end
end
local blogs = {}
package.loaded["blogs"] = blogs
do
blogs.from_handle = function(handle)
return foppy.open(
"database/blogs/" .. handle .. ".json"
)
end
blogs.new_blog = function(id, handle, title, description)
assert(handle)
if blogs.from_handle(handle) then
return nil, "blog_already_exists"
end
local author = authors.from_id(id, true)
assert(author)
if not utils.is_valid_handle(handle) then
return nil, "blog_handle_invalid"
end
local blog = {
owner = id,
title = title or handle,
handle = handle,
description = description,
banner = { source = nil, alt = nil },
index = {},
created_at = os.time(),
updated_at = os.time()
}
fs.writeFileSync(
"database/blogs/" .. handle .. ".json",
json.encode(blog)
)
author.blogs[#author.blogs + 1] = handle
return blog
end
end
return {
authors = authors,
blogs = blogs,
}