feat(auth): add Secret Service and env var support for login
- Introduce `secret_tool_lookup` to retrieve passwords via `secret-tool` - Extract `login_with_username` to try Secret Service before prompting - Read `JASPER_USERNAME` env var to skip username prompt when set - Fall back to `inputsecret` prompt if Secret Service lookup fails
This commit is contained in:
@@ -88,24 +88,42 @@ function M.login(username, password)
|
|||||||
return data.auth_token, nil
|
return data.auth_token, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Interactively ask the user for credentials using vim.ui.input,
|
--- Try to retrieve a password from the system Secret Service via secret-tool.
|
||||||
--- then call login(). Calls `callback(token)` on success, `callback(nil)` on failure.
|
--- @param username string
|
||||||
|
--- @return string|nil password
|
||||||
|
local function secret_tool_lookup(username)
|
||||||
|
local result = vim.system({ "secret-tool", "lookup", "service", "jasper", "user", username }, { text = true })
|
||||||
|
:wait()
|
||||||
|
if result.code == 0 and result.stdout and result.stdout ~= "" then
|
||||||
|
-- strip trailing newline
|
||||||
|
return (result.stdout:gsub("%s+$", ""))
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Attempt login with the given username: try Secret Service first, then prompt.
|
||||||
|
--- @param username string
|
||||||
--- @param callback fun(token: string|nil)
|
--- @param callback fun(token: string|nil)
|
||||||
function M.prompt_login(callback)
|
local function login_with_username(username, callback)
|
||||||
vim.ui.input({ prompt = "Jasper username: " }, function(username)
|
local password = secret_tool_lookup(username)
|
||||||
if not username or username == "" then
|
if password then
|
||||||
vim.notify("[Jasper] Login cancelled", vim.log.levels.WARN)
|
|
||||||
callback(nil)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- vim.fn.inputsecret() is native Neovim: hides typed characters in all environments
|
|
||||||
local password = vim.fn.inputsecret("Jasper password: ")
|
|
||||||
if not password or password == "" then
|
|
||||||
vim.notify("[Jasper] Login cancelled", vim.log.levels.WARN)
|
|
||||||
callback(nil)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local token, err = M.login(username, password)
|
local token, err = M.login(username, password)
|
||||||
|
if token and not err then
|
||||||
|
vim.notify("[Jasper] Login successful (Secret Service)", vim.log.levels.INFO)
|
||||||
|
callback(token)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Secret Service password was wrong or login failed — fall through to prompt
|
||||||
|
vim.notify("[Jasper] Secret Service password failed, prompting", vim.log.levels.WARN)
|
||||||
|
end
|
||||||
|
-- Prompt for password
|
||||||
|
local pwd = vim.fn.inputsecret("Jasper password: ")
|
||||||
|
if not pwd or pwd == "" then
|
||||||
|
vim.notify("[Jasper] Login cancelled", vim.log.levels.WARN)
|
||||||
|
callback(nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local token, err = M.login(username, pwd)
|
||||||
if err or not token then
|
if err or not token then
|
||||||
vim.notify("[Jasper] " .. (err or "Login failed"), vim.log.levels.ERROR)
|
vim.notify("[Jasper] " .. (err or "Login failed"), vim.log.levels.ERROR)
|
||||||
callback(nil)
|
callback(nil)
|
||||||
@@ -113,7 +131,26 @@ function M.prompt_login(callback)
|
|||||||
end
|
end
|
||||||
vim.notify("[Jasper] Login successful", vim.log.levels.INFO)
|
vim.notify("[Jasper] Login successful", vim.log.levels.INFO)
|
||||||
callback(token)
|
callback(token)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Interactively ask the user for credentials using vim.ui.input,
|
||||||
|
--- then call login(). Calls `callback(token)` on success, `callback(nil)` on failure.
|
||||||
|
--- Checks JASPER_USERNAME env var and Secret Service before prompting.
|
||||||
|
--- @param callback fun(token: string|nil)
|
||||||
|
function M.prompt_login(callback)
|
||||||
|
local env_username = os.getenv("JASPER_USERNAME")
|
||||||
|
if env_username and env_username ~= "" then
|
||||||
|
login_with_username(env_username, callback)
|
||||||
|
else
|
||||||
|
vim.ui.input({ prompt = "Jasper username: " }, function(username)
|
||||||
|
if not username or username == "" then
|
||||||
|
vim.notify("[Jasper] Login cancelled", vim.log.levels.WARN)
|
||||||
|
callback(nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
login_with_username(username, callback)
|
||||||
end)
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
Reference in New Issue
Block a user