-- Licensed to the public under the Apache License 2.0.

local rad2 = require "luci.controller.radicale2"
local fs = require("nixio.fs")
local util = require("luci.util")

local m = Map("radicale2", translate("Radicale 2.x"),
	      translate("A lightweight CalDAV/CardDAV server"))

local s = m:section(NamedSection, "auth", "section", translate("Authentication"))
s.addremove = true
s.anonymous = false

local at = s:option(ListValue, "type", translate("Authentication Type"))
at:value("", translate("Default (htpasswd file from users below)"))
at:value("htpasswd", translate("htpasswd file (manually populated)"))
at:value("none", translate("No authentication"))
at:value("remote_user", translate("REMOTE_USER from web server"))
at:value("http_x_remote_user", translate("X-Remote-User from web server"))
at.default = ""
at.rmempty = true

local o = s:option(Value, "htpasswd_filename", translate("Filename"), translate("htpasswd-formatted file filename"))
o:depends("type", "htpasswd")
o.rmempty = true
o.placeholder = "/etc/radicale2/users"
o.default = ""

local hte = s:option(ListValue, "htpasswd_encryption", translate("Encryption"), translate("Password encryption method"))
hte:depends("type", "htpasswd")
hte:depends("type", "")
hte:value("plain", translate("Plaintext"))
hte:value("sha1", translate("SHA1"))
hte:value("ssha", translate("SSHA"))
hte:value("crypt", translate("crypt"))
if rad2.pymodexists("passlib") then
	hte:value("md5", translate("md5"))
	if rad2.pymodexists("bcrypt") then
		hte:value("bcrypt", translate("bcrypt"))
	end
end
hte.default = "plain"
hte.rmempty = true

if not rad2.pymodexists("bcrypt") then
	o = s:option(DummyValue, "nobcrypt", translate("Insecure hashes"), translate("Install python3-passlib and python3-bcrypt to enable a secure hash"))
else
	o = s:option(DummyValue, "nobcrypt", translate("Insecure hashes"), translate("Select bcrypt above to enable a secure hash"))
	o:depends("htpasswd_encrypt","")
	o:depends("htpasswd_encrypt","plain")
	o:depends("htpasswd_encrypt","sha1")
	o:depends("htpasswd_encrypt","ssha")
	o:depends("htpasswd_encrypt","crypt")
	o:depends("htpasswd_encrypt","md5")
end

o = s:option(Value, "delay", translate("Retry Delay"), translate("Required time between a failed authentication attempt and trying again"))
o.rmempty = true
o.default = 1
o.datatype = "uinteger"
o:depends("type", "")
o:depends("type", "htpasswd")
o:depends("type", "remote_user")
o:depends("type", "http_x_remote_user")

s = m:section(TypedSection, "user", translate("User"), translate("Users and Passwords"))
s.addremove = true
s.anonymous = true

o = s:option(Value, "name", translate("Username"))
o.rmempty = true
o.placeholder = "johndoe"

if rad2.pymodexists("passlib") then

local plainpass = s:option(Value, "plain_pass", translate("Plaintext Password"))
plainpass.placeholder = "Example password"
plainpass.password = true

local ppconfirm = s:option(Value, "plain_pass_confirm", translate("Confirm Plaintext Password"))
ppconfirm.placeholder = "Example password"
ppconfirm.password = true

plainpass.cfgvalue = function(self, section)
	return self:formvalue(section)
end

plainpass.write = function(self, section)
	return true
end


ppconfirm.cfgvalue = plainpass.cfgvalue
ppconfirm.write = plainpass.write

plainpass.validate = function(self, value, section)
	if self:cfgvalue(section) ~= ppconfirm:cfgvalue(section) then
		return nil, translate("Password and confirmation do not match")
	end
	return AbstractValue.validate(self, value, section)
end

ppconfirm.validate = function(self, value, section)
	if self:cfgvalue(section) ~= plainpass:cfgvalue(section) then
		return nil, translate("Password and confirmation do not match")
	end
	return AbstractValue.validate(self, value, section)
end

local pass = s:option(Value, "password", translate("Encrypted Password"), translate("If 'Plaintext Password' filled and matches 'Confirm Plaintext Password' then this field becomes of hash of that password, otherwise this field remains the existing hash (you can also put your own hash value for the type of hash listed above)."))
pass.password = true
pass.rmempty = false

function encpass(self, section)
	local plainvalue = plainpass:cfgvalue(section)
	local pvc = ppconfirm:cfgvalue(section)
	local encvalue, err

	if not plainvalue or not pvc or plainvalue == "" or pvc == "" or plainvalue ~= pvc then
		return nil
	end
	local enctype = hte:formvalue("auth")
	if not enctype then
		enctype = hte:cfgvalue("auth")
	end
	if not enctype or enctype == "" or enctype == "plain" then
		return plainvalue
	end

	encvalue, err = util.ubus("rad2-enc", "encrypt", { type = enctype, plainpass = plainvalue })
	if not encvalue then
		return nil
	end

	return encvalue and encvalue.encrypted_password
end

pass.cfgvalue = function(self, section)
	if not plainpass:formvalue(section) then
		return Value.cfgvalue(self, section)
	else
		return Value.formvalue(self, section)
	end
end

pass.formvalue = function(self, section)
	if not plainpass:formvalue(section) then
		return Value.formvalue(self, section)
	else
		return encpass(self, section) or Value.formvalue(self, section)
	end
end

else
local pass = s:option(Value, "password", translate("Encrypted Password"), translate("Generate this field using a generator for Apache htpasswd-style authentication files (for the hash format you have chosen above), or install python3-passlib to enable the ability to create the hash by entering the plaintext in a field that will appear on this page if python3-passlib is installed."))
pass.password = true
pass.rmempty = false

end -- python3-passlib installed

-- TODO: Allow configuration of rights file from this page
local s = m:section(NamedSection, "section", "rights", translate("Rights"), translate("User-based ACL Settings"))
s.addremove = true
s.anonymous = false

o = s:option(ListValue, "type", translate("Rights Type"))
o:value("", translate("Default (owner only)"))
o:value("owner_only", translate("RO: None, RW: Owner"))
o:value("authenticated", translate("RO: None, RW: Authenticated Users"))
o:value("owner_write", translate("RO: Authenticated Users, RW: Owner"))
o:value("from_file", translate("Based on settings in 'Rights File'"))
o:value("none", translate("RO: All, RW: All"))
o.default = ""
o.rmempty = true

rights_file = s:option(FileUpload, "file", translate("Rights File"))
rights_file.rmempty = true
rights_file:depends("type", "from_file")

o = s:option(Button, "remove_conf",
	translate("Remove configuration for rights file"),
	translate("This permanently deletes the rights file and configuration to use same."))
o.inputstyle = "remove"
o:depends("type", "from_file")

function o.write(self, section)
	if cert_file:cfgvalue(section) and fs.access(o:cfgvalue(section)) then fs.unlink(rights_file:cfgvalue(section)) end
	self.map:del(section, "file")
	self.map:del(section, "rights_file")
	luci.http.redirect(luci.dispatcher.build_url("admin", "services", "radicale2", "auth"))
end

-- TODO: Allow configuration rights file from this page

return m
