feat: minor improved security measures

This commit is contained in:
Barrett Ruth 2026-03-07 19:05:43 -05:00
parent 27d7a4e6b5
commit d1b2117fa2
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
3 changed files with 29 additions and 11 deletions

View file

@ -56,8 +56,11 @@ function M.load()
end end
if vim.fn.filereadable(cache_file) == 0 then if vim.fn.filereadable(cache_file) == 0 then
vim.fn.writefile({}, cache_file) vim.fn.mkdir(vim.fn.fnamemodify(cache_file, ':h'), 'p')
vim.fn.setfperm(cache_file, 'rw-------') local tmpfile = vim.fn.tempname()
vim.fn.writefile({}, tmpfile)
vim.fn.setfperm(tmpfile, 'rw-------')
vim.uv.fs_rename(tmpfile, cache_file)
loaded = true loaded = true
return return
end end
@ -107,8 +110,10 @@ function M.save()
cache_data._version = CACHE_VERSION cache_data._version = CACHE_VERSION
local encoded = vim.json.encode(cache_data) local encoded = vim.json.encode(cache_data)
local lines = vim.split(encoded, '\n') local lines = vim.split(encoded, '\n')
vim.fn.writefile(lines, cache_file) local tmpfile = vim.fn.tempname()
vim.fn.setfperm(cache_file, 'rw-------') vim.fn.writefile(lines, tmpfile)
vim.fn.setfperm(tmpfile, 'rw-------')
vim.uv.fs_rename(tmpfile, cache_file)
end) end)
end end

View file

@ -120,8 +120,10 @@ function M.logout(platform)
local ok, data = pcall(vim.fn.json_decode, vim.fn.readfile(cookie_file, 'b')) local ok, data = pcall(vim.fn.json_decode, vim.fn.readfile(cookie_file, 'b'))
if ok and type(data) == 'table' then if ok and type(data) == 'table' then
data[platform] = nil data[platform] = nil
vim.fn.writefile({ vim.fn.json_encode(data) }, cookie_file) local tmpfile = vim.fn.tempname()
vim.fn.setfperm(cookie_file, 'rw-------') vim.fn.writefile({ vim.fn.json_encode(data) }, tmpfile)
vim.fn.setfperm(tmpfile, 'rw-------')
vim.uv.fs_rename(tmpfile, cookie_file)
end end
end end
logger.log(display .. ' credentials cleared', { level = vim.log.levels.INFO, override = true }) logger.log(display .. ' credentials cleared', { level = vim.log.levels.INFO, override = true })

View file

@ -3,6 +3,7 @@ import json
import os import os
import re import re
import sys import sys
import tempfile
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@ -20,6 +21,18 @@ from .models import (
_COOKIE_FILE = Path.home() / ".cache" / "cp-nvim" / "cookies.json" _COOKIE_FILE = Path.home() / ".cache" / "cp-nvim" / "cookies.json"
def _atomic_write(path: Path, content: str) -> None:
fd, tmp = tempfile.mkstemp(dir=path.parent, prefix=".tmp-")
try:
os.fchmod(fd, 0o600)
with os.fdopen(fd, "w") as f:
f.write(content)
os.replace(tmp, path)
except BaseException:
os.unlink(tmp)
raise
def load_platform_cookies(platform: str) -> Any | None: def load_platform_cookies(platform: str) -> Any | None:
try: try:
data = json.loads(_COOKIE_FILE.read_text()) data = json.loads(_COOKIE_FILE.read_text())
@ -29,22 +42,20 @@ def load_platform_cookies(platform: str) -> Any | None:
def save_platform_cookies(platform: str, data: Any) -> None: def save_platform_cookies(platform: str, data: Any) -> None:
_COOKIE_FILE.parent.mkdir(parents=True, exist_ok=True) _COOKIE_FILE.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
try: try:
existing = json.loads(_COOKIE_FILE.read_text()) existing = json.loads(_COOKIE_FILE.read_text())
except Exception: except Exception:
existing = {} existing = {}
existing[platform] = data existing[platform] = data
_COOKIE_FILE.write_text(json.dumps(existing)) _atomic_write(_COOKIE_FILE, json.dumps(existing))
_COOKIE_FILE.chmod(0o600)
def clear_platform_cookies(platform: str) -> None: def clear_platform_cookies(platform: str) -> None:
try: try:
existing = json.loads(_COOKIE_FILE.read_text()) existing = json.loads(_COOKIE_FILE.read_text())
existing.pop(platform, None) existing.pop(platform, None)
_COOKIE_FILE.write_text(json.dumps(existing)) _atomic_write(_COOKIE_FILE, json.dumps(existing))
_COOKIE_FILE.chmod(0o600)
except Exception: except Exception:
pass pass