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, }