diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 670bdab..4fc684c 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -453,7 +453,6 @@ COMMANDS *cp-commands* any previously saved credentials. If [platform] is omitted, uses the active platform. Examples: > - :CP login :CP login atcoder :CP login codeforces < @@ -461,7 +460,6 @@ COMMANDS *cp-commands* Remove stored credentials for a platform. If [platform] is omitted, uses the active platform. Examples: > - :CP logout :CP logout atcoder < :CP {platform} signup diff --git a/lua/cp/cache.lua b/lua/cp/cache.lua index 7ff1824..9448910 100644 --- a/lua/cp/cache.lua +++ b/lua/cp/cache.lua @@ -57,7 +57,6 @@ function M.load() if vim.fn.filereadable(cache_file) == 0 then vim.fn.writefile({}, cache_file) - vim.fn.setfperm(cache_file, 'rw-------') loaded = true return end @@ -108,7 +107,6 @@ function M.save() local encoded = vim.json.encode(cache_data) local lines = vim.split(encoded, '\n') vim.fn.writefile(lines, cache_file) - vim.fn.setfperm(cache_file, 'rw-------') end) end diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index c13b196..9ea34a4 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -326,10 +326,6 @@ local function parse_command(args) end end - if (first == 'login' or first == 'logout' or first == 'signup') and #args == 1 then - return { type = 'action', action = first, requires_context = true, platform = nil } - end - if #args == 1 then return { type = 'problem_jump', @@ -382,7 +378,6 @@ function M.handle_command(opts) if not restore.restore_from_current_file() then return end - vim.cmd.redraw() end local setup = require('cp.setup') @@ -426,43 +421,22 @@ function M.handle_command(opts) end vim.ui.open(url) elseif cmd.action == 'login' then - local p = cmd.platform or state.get_platform() - if not p then - logger.log( - 'No platform active. Usage: :CP login', - { level = vim.log.levels.ERROR } - ) + if not check_platform_enabled(cmd.platform) then return end - if not check_platform_enabled(p) then - return - end - require('cp.credentials').login(p) + require('cp.credentials').login(cmd.platform) elseif cmd.action == 'logout' then - local p = cmd.platform or state.get_platform() - if not p then - logger.log( - 'No platform active. Usage: :CP logout', - { level = vim.log.levels.ERROR } - ) + if not check_platform_enabled(cmd.platform) then return end - if not check_platform_enabled(p) then - return - end - require('cp.credentials').logout(p) + require('cp.credentials').logout(cmd.platform) elseif cmd.action == 'signup' then - local p = cmd.platform or state.get_platform() - if not p then - logger.log( - 'No platform active. Usage: :CP signup', - { level = vim.log.levels.ERROR } - ) - return - end - local url = constants.SIGNUP_URLS[p] + local url = constants.SIGNUP_URLS[cmd.platform] if not url then - logger.log(("No signup URL available for '%s'"):format(p), { level = vim.log.levels.WARN }) + logger.log( + ("No signup URL available for '%s'"):format(cmd.platform), + { level = vim.log.levels.WARN } + ) return end vim.ui.open(url) diff --git a/lua/cp/credentials.lua b/lua/cp/credentials.lua index 4f22038..a1258c4 100644 --- a/lua/cp/credentials.lua +++ b/lua/cp/credentials.lua @@ -14,50 +14,46 @@ local STATUS_MESSAGES = { ---@param platform string ---@param display string local function prompt_and_login(platform, display) - vim.ui.input( - { prompt = '[cp.nvim]: ' .. display .. ' username ( to cancel): ' }, - function(username) - if not username or username == '' then - logger.log(display .. ' login cancelled', { level = vim.log.levels.WARN }) - return - end - vim.fn.inputsave() - local password = vim.fn.inputsecret('[cp.nvim]: ' .. display .. ' password: ') - vim.fn.inputrestore() - if not password or password == '' then - logger.log(display .. ' login cancelled', { level = vim.log.levels.WARN }) - return - end - - local credentials = { username = username, password = password } - - local scraper = require('cp.scraper') - scraper.login(platform, credentials, function(ev) - vim.schedule(function() - local msg = STATUS_MESSAGES[ev.status] or ev.status - logger.log(display .. ': ' .. msg, { level = vim.log.levels.INFO, override = true }) - end) - end, function(result) - vim.schedule(function() - if result.success then - cache.set_credentials(platform, credentials) - logger.log( - display .. ' login successful', - { level = vim.log.levels.INFO, override = true } - ) - else - local err = result.error or 'unknown error' - cache.clear_credentials(platform) - logger.log( - display .. ' login failed: ' .. (constants.LOGIN_ERRORS[err] or err), - { level = vim.log.levels.ERROR } - ) - prompt_and_login(platform, display) - end - end) - end) + vim.ui.input({ prompt = '[cp.nvim]: ' .. display .. ' username: ' }, function(username) + if not username or username == '' then + logger.log('Cancelled', { level = vim.log.levels.WARN }) + return end - ) + vim.fn.inputsave() + local password = vim.fn.inputsecret('[cp.nvim]: ' .. display .. ' password: ') + vim.fn.inputrestore() + if not password or password == '' then + logger.log('Cancelled', { level = vim.log.levels.WARN }) + return + end + + local credentials = { username = username, password = password } + + local scraper = require('cp.scraper') + scraper.login(platform, credentials, function(ev) + vim.schedule(function() + local msg = STATUS_MESSAGES[ev.status] or ev.status + logger.log(display .. ': ' .. msg, { level = vim.log.levels.INFO, override = true }) + end) + end, function(result) + vim.schedule(function() + if result.success then + cache.set_credentials(platform, credentials) + logger.log( + display .. ' login successful', + { level = vim.log.levels.INFO, override = true } + ) + else + local err = result.error or 'unknown error' + cache.clear_credentials(platform) + logger.log( + display .. ' login failed: ' .. (constants.LOGIN_ERRORS[err] or err), + { level = vim.log.levels.ERROR } + ) + end + end) + end) + end) end ---@param platform string? @@ -121,7 +117,6 @@ function M.logout(platform) if ok and type(data) == 'table' then data[platform] = nil vim.fn.writefile({ vim.fn.json_encode(data) }, cookie_file) - vim.fn.setfperm(cookie_file, 'rw-------') end end logger.log(display .. ' credentials cleared', { level = vim.log.levels.INFO, override = true }) diff --git a/lua/cp/scraper.lua b/lua/cp/scraper.lua index 4ad46bc..02f20b3 100644 --- a/lua/cp/scraper.lua +++ b/lua/cp/scraper.lua @@ -344,7 +344,7 @@ function M.login(platform, credentials, on_status, callback) local done = false run_scraper(platform, 'login', {}, { ndjson = true, - stdin = vim.json.encode(credentials), + env_extra = { CP_CREDENTIALS = vim.json.encode(credentials) }, on_event = function(ev) if ev.credentials ~= nil and next(ev.credentials) ~= nil then require('cp.cache').set_credentials(platform, ev.credentials) @@ -392,9 +392,9 @@ function M.submit( local done = false run_scraper(platform, 'submit', { contest_id, problem_id, language, source_file }, { ndjson = true, - stdin = vim.json.encode(credentials), + env_extra = { CP_CREDENTIALS = vim.json.encode(credentials) }, on_event = function(ev) - if ev.credentials ~= nil and next(ev.credentials) ~= nil then + if ev.credentials ~= nil then require('cp.cache').set_credentials(platform, ev.credentials) end if ev.status ~= nil then diff --git a/lua/cp/submit.lua b/lua/cp/submit.lua index 5a661ec..68b9b90 100644 --- a/lua/cp/submit.lua +++ b/lua/cp/submit.lua @@ -19,27 +19,23 @@ local function prompt_credentials(platform, callback) callback(saved) return end - local display = constants.PLATFORM_DISPLAY_NAMES[platform] or platform - vim.ui.input( - { prompt = '[cp.nvim]: ' .. display .. ' username ( to cancel): ' }, - function(username) - if not username or username == '' then - logger.log('Submit cancelled', { level = vim.log.levels.WARN }) - return - end - vim.fn.inputsave() - local password = vim.fn.inputsecret('[cp.nvim]: ' .. display .. ' password: ') - vim.fn.inputrestore() - vim.cmd.redraw() - if not password or password == '' then - logger.log('Submit cancelled', { level = vim.log.levels.WARN }) - return - end - local creds = { username = username, password = password } - cache.set_credentials(platform, creds) - callback(creds) + vim.ui.input({ prompt = platform .. ' username: ' }, function(username) + if not username or username == '' then + logger.log('Submit cancelled', { level = vim.log.levels.WARN }) + return end - ) + vim.fn.inputsave() + local password = vim.fn.inputsecret(platform .. ' password: ') + vim.fn.inputrestore() + vim.cmd.redraw() + if not password or password == '' then + logger.log('Submit cancelled', { level = vim.log.levels.WARN }) + return + end + local creds = { username = username, password = password } + cache.set_credentials(platform, creds) + callback(creds) + end) end ---@param opts { language?: string }? @@ -90,7 +86,7 @@ function M.submit(opts) end end - local function do_submit(creds) + prompt_credentials(platform, function(creds) vim.cmd.update() require('cp.scraper').submit( @@ -116,24 +112,16 @@ function M.submit(opts) local err = result and result.error or 'unknown error' if err == 'bad_credentials' or err:match('^Login failed') then cache.clear_credentials(platform) - logger.log( - 'Submit failed: ' .. (constants.LOGIN_ERRORS[err] or err), - { level = vim.log.levels.ERROR } - ) - prompt_credentials(platform, do_submit) - else - logger.log( - 'Submit failed: ' .. (constants.LOGIN_ERRORS[err] or err), - { level = vim.log.levels.ERROR } - ) end + logger.log( + 'Submit failed: ' .. (constants.LOGIN_ERRORS[err] or err), + { level = vim.log.levels.ERROR } + ) end end) end ) - end - - prompt_credentials(platform, do_submit) + end) end return M diff --git a/plugin/cp.lua b/plugin/cp.lua index b1430f2..531a5f3 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -43,10 +43,6 @@ end, { vim.list_extend(candidates, platforms) table.insert(candidates, 'cache') table.insert(candidates, 'pick') - if platform then - table.insert(candidates, 'login') - table.insert(candidates, 'logout') - end if platform and contest_id then vim.list_extend( candidates, diff --git a/scrapers/base.py b/scrapers/base.py index e98990c..035495a 100644 --- a/scrapers/base.py +++ b/scrapers/base.py @@ -36,7 +36,6 @@ def save_platform_cookies(platform: str, data: Any) -> None: existing = {} existing[platform] = data _COOKIE_FILE.write_text(json.dumps(existing)) - _COOKIE_FILE.chmod(0o600) def clear_platform_cookies(platform: str) -> None: @@ -44,7 +43,6 @@ def clear_platform_cookies(platform: str) -> None: existing = json.loads(_COOKIE_FILE.read_text()) existing.pop(platform, None) _COOKIE_FILE.write_text(json.dumps(existing)) - _COOKIE_FILE.chmod(0o600) except Exception: pass @@ -162,7 +160,7 @@ class BaseScraper(ABC): ).model_dump_json() ) return 1 - creds_raw = sys.stdin.read() + creds_raw = os.environ.get("CP_CREDENTIALS", "{}") try: credentials = json.loads(creds_raw) except json.JSONDecodeError: @@ -175,7 +173,7 @@ class BaseScraper(ABC): return 0 if result.success else 1 case "login": - creds_raw = sys.stdin.read() + creds_raw = os.environ.get("CP_CREDENTIALS", "{}") try: credentials = json.loads(creds_raw) except json.JSONDecodeError: diff --git a/scrapers/kattis.py b/scrapers/kattis.py index 4417628..8b0099f 100644 --- a/scrapers/kattis.py +++ b/scrapers/kattis.py @@ -415,6 +415,7 @@ class KattisScraper(BaseScraper): return LoginResult( success=True, error="", + credentials={"username": username, "password": password}, ) print(json.dumps({"status": "logging_in"}), flush=True) @@ -425,6 +426,7 @@ class KattisScraper(BaseScraper): return LoginResult( success=True, error="", + credentials={"username": username, "password": password}, ) diff --git a/scrapers/usaco.py b/scrapers/usaco.py index d878886..e463881 100644 --- a/scrapers/usaco.py +++ b/scrapers/usaco.py @@ -533,6 +533,7 @@ class USACOScraper(BaseScraper): return LoginResult( success=True, error="", + credentials={"username": username, "password": password}, ) print(json.dumps({"status": "logging_in"}), flush=True) @@ -548,6 +549,7 @@ class USACOScraper(BaseScraper): return LoginResult( success=True, error="", + credentials={"username": username, "password": password}, )