Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 2,357 Bytes
ee0b555 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | """Private per-origin, per-paper credential files. Secrets never enter edit documents."""
import hashlib
import json
import os
from pathlib import Path
import stat
import tempfile
from pwc_cli.transport import ResponseError
class CredentialStore:
def __init__(self, base_url: str):
self.base_url = base_url
self.root = Path.home() / ".config" / "pwc" / "edit-credentials"
def path(self, paper_id: int) -> Path:
key = hashlib.sha256(f"{self.base_url}:{paper_id}".encode()).hexdigest()
return self.root / f"{key}.json"
def save(self, paper_id: int, credential: dict) -> None:
self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
info = self.root.lstat()
if (
not stat.S_ISDIR(info.st_mode)
or info.st_uid != os.getuid()
or info.st_mode & 0o077
):
raise ResponseError(
"Credential directory must be owned by you with mode 0700"
)
fd, name = tempfile.mkstemp(dir=self.root)
try:
with os.fdopen(fd, "w") as handle:
json.dump({**credential, "base_url": self.base_url}, handle)
os.replace(name, self.path(paper_id))
finally:
if os.path.exists(name):
os.unlink(name)
def load(self, paper_id: int) -> dict:
path = self.path(paper_id)
try:
fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
except FileNotFoundError as error:
raise ResponseError(
"No authorization for this paper and API. Run pwc auth login --paper PAPER"
) from error
with os.fdopen(fd) as handle:
info = os.fstat(handle.fileno())
if (
not stat.S_ISREG(info.st_mode)
or info.st_uid != os.getuid()
or info.st_mode & 0o077
):
raise ResponseError(
"Credential file must be owned by you with mode 0600"
)
value = json.load(handle)
if value.get("base_url") != self.base_url or value.get("paper_id") != paper_id:
raise ResponseError("Credential origin or paper does not match")
return value
def remove(self, paper_id: int) -> None:
self.path(paper_id).unlink(missing_ok=True)
|