-- GIA auth provider for legacy Prosody builds that do not ship
-- external auth modules. Delegates auth checks to external_auth_command.

local new_sasl = require "util.sasl".new;

local host = module.host;
local log = module._log;
local auth_cmd = module:get_option_string(
    "external_auth_command",
    "/code/utilities/prosody/auth_django.sh"
);

local provider = {};

local function shell_quote(value)
    return "'" .. tostring(value or ""):gsub("'", "'\\''") .. "'";
end

local function run_external(line)
    local cmd = "printf %s\\\\n " .. shell_quote(line) .. " | " .. shell_quote(auth_cmd);
    local handle = io.popen(cmd, "r");
    if not handle then
        return false;
    end
    local output = handle:read("*a") or "";
    handle:close();
    output = output:gsub("%s+", "");
    return output == "1";
end

function provider.test_password(username, password)
    if not username or username == "" then
        return nil, "Auth failed. Invalid username.";
    end
    if not password or password == "" then
        return nil, "Auth failed. Invalid password.";
    end
    local ok = run_external("auth:" .. username .. ":" .. host .. ":" .. password);
    if ok then
        return true;
    end
    return nil, "Auth failed. Invalid username or password.";
end

function provider.user_exists(username)
    if not username or username == "" then
        return nil, "Auth failed. Invalid username.";
    end
    if run_external("isuser:" .. username .. ":" .. host) then
        return true;
    end
    return nil, "Auth failed. Invalid username.";
end

function provider.set_password()
    return nil, "method not implemented";
end

function provider.users()
    return function() return nil end;
end

function provider.create_user()
    return nil, "method not implemented";
end

function provider.delete_user()
    return nil, "method not implemented";
end

function provider.get_sasl_handler()
    return new_sasl(host, {
        plain_test = function(_, username, password)
            local ok = provider.test_password(username, password);
            if ok then
                return true, true;
            end
            return false, nil;
        end
    });
end

log("debug", "initializing GIA auth provider for host '%s'", host);
module:provides("auth", provider);
