extendvcc-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- extendvcc/__init__.py +46 -0
- extendvcc/_exit_codes.py +24 -0
- extendvcc/_jsonl.py +35 -0
- extendvcc/_paths.py +28 -0
- extendvcc/auth.py +900 -0
- extendvcc/cards.py +761 -0
- extendvcc/cli.py +883 -0
- extendvcc/client.py +491 -0
- extendvcc/imap_otp.py +170 -0
- extendvcc/ledger.py +535 -0
- extendvcc/models.py +74 -0
- extendvcc/py.typed +0 -0
- extendvcc_cli-0.1.0.dist-info/METADATA +179 -0
- extendvcc_cli-0.1.0.dist-info/RECORD +17 -0
- extendvcc_cli-0.1.0.dist-info/WHEEL +4 -0
- extendvcc_cli-0.1.0.dist-info/entry_points.txt +2 -0
- extendvcc_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
extendvcc/__init__.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""extendvcc — unofficial Extend virtual card client."""
|
|
2
|
+
|
|
3
|
+
from extendvcc.cards import (
|
|
4
|
+
activate_credit_card,
|
|
5
|
+
cancel_card,
|
|
6
|
+
close_card,
|
|
7
|
+
create_card,
|
|
8
|
+
create_cards_bulk,
|
|
9
|
+
enroll_credit_card,
|
|
10
|
+
get_card,
|
|
11
|
+
list_cards,
|
|
12
|
+
list_credit_cards,
|
|
13
|
+
list_issuers,
|
|
14
|
+
reconcile,
|
|
15
|
+
reveal_card,
|
|
16
|
+
update_card,
|
|
17
|
+
usage,
|
|
18
|
+
)
|
|
19
|
+
from extendvcc.models import CardStatus, CreditCard, Issuer, Recurrence, VirtualCard
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
# models
|
|
23
|
+
"CardStatus",
|
|
24
|
+
"CreditCard",
|
|
25
|
+
"Issuer",
|
|
26
|
+
"Recurrence",
|
|
27
|
+
"VirtualCard",
|
|
28
|
+
# reads
|
|
29
|
+
"get_card",
|
|
30
|
+
"list_cards",
|
|
31
|
+
"list_credit_cards",
|
|
32
|
+
"list_issuers",
|
|
33
|
+
"usage",
|
|
34
|
+
# mutations
|
|
35
|
+
"cancel_card",
|
|
36
|
+
"close_card",
|
|
37
|
+
"create_card",
|
|
38
|
+
"create_cards_bulk",
|
|
39
|
+
"reconcile",
|
|
40
|
+
"update_card",
|
|
41
|
+
# reveal
|
|
42
|
+
"reveal_card",
|
|
43
|
+
# enroll
|
|
44
|
+
"activate_credit_card",
|
|
45
|
+
"enroll_credit_card",
|
|
46
|
+
]
|
extendvcc/_exit_codes.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Stable process exit codes for the extendvcc CLI.
|
|
2
|
+
|
|
3
|
+
These integers are part of the CLI's contract: scripts and CI pipelines can
|
|
4
|
+
branch on them. Map exceptions to codes in ``cli.main`` — do not invent new
|
|
5
|
+
codes ad hoc.
|
|
6
|
+
|
|
7
|
+
| Code | Name | Meaning |
|
|
8
|
+
|------|--------------------|------------------------------------------------------|
|
|
9
|
+
| 0 | EXIT_OK | Success. |
|
|
10
|
+
| 1 | EXIT_ERROR | Generic failure (library error, aborted confirm). |
|
|
11
|
+
| 2 | EXIT_USAGE | CLI input/usage error (bad flags, validation). |
|
|
12
|
+
| 3 | EXIT_AUTH_REQUIRED | Authentication needed or failed (login/OTP/session).|
|
|
13
|
+
| 4 | EXIT_DISABLED | Kill switch / account-risk: automation disabled. |
|
|
14
|
+
| 5 | EXIT_API_ERROR | Extend API returned an error response. |
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
EXIT_OK = 0
|
|
20
|
+
EXIT_ERROR = 1
|
|
21
|
+
EXIT_USAGE = 2
|
|
22
|
+
EXIT_AUTH_REQUIRED = 3
|
|
23
|
+
EXIT_DISABLED = 4
|
|
24
|
+
EXIT_API_ERROR = 5
|
extendvcc/_jsonl.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Vendored JSONL append helper."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def append_jsonl(path: Path, rows: list[dict], *, fsync: bool = False) -> None:
|
|
11
|
+
if not rows:
|
|
12
|
+
return
|
|
13
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
14
|
+
# Create the file owner-only (0600) regardless of umask. The ledger stores
|
|
15
|
+
# card ids/names/last4 — no PAN/CVC — but on shared machines a world-readable
|
|
16
|
+
# first write would still leak that local audit trail. Existing files are
|
|
17
|
+
# opened append-only and never have their mode altered.
|
|
18
|
+
is_new = not path.exists()
|
|
19
|
+
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
|
|
20
|
+
try:
|
|
21
|
+
if is_new:
|
|
22
|
+
# O_CREAT's mode is masked by umask; force 0600 so umask cannot widen it.
|
|
23
|
+
os.chmod(path, 0o600)
|
|
24
|
+
f = os.fdopen(fd, "a", encoding="utf-8")
|
|
25
|
+
except BaseException:
|
|
26
|
+
# os.fdopen/os.chmod failing leaves the raw fd open — close it before raising.
|
|
27
|
+
os.close(fd)
|
|
28
|
+
raise
|
|
29
|
+
with f:
|
|
30
|
+
for row in rows:
|
|
31
|
+
f.write(json.dumps(row, sort_keys=True, ensure_ascii=False))
|
|
32
|
+
f.write("\n")
|
|
33
|
+
if fsync:
|
|
34
|
+
f.flush()
|
|
35
|
+
os.fsync(f.fileno())
|
extendvcc/_paths.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Lazy path resolution with CLI override, env var, and default fallback."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
_state_dir_override = None
|
|
9
|
+
_ledger_path_override = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def configure(*, state_dir=None, ledger_path=None):
|
|
13
|
+
global _state_dir_override, _ledger_path_override
|
|
14
|
+
_state_dir_override = Path(state_dir) if state_dir else None
|
|
15
|
+
_ledger_path_override = Path(ledger_path) if ledger_path else None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def state_dir() -> Path:
|
|
19
|
+
return _state_dir_override or Path(os.environ.get("EXTENDVCC_STATE_DIR") or (Path.home() / ".config" / "extendvcc"))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def ledger_path() -> Path:
|
|
23
|
+
if _ledger_path_override:
|
|
24
|
+
return _ledger_path_override
|
|
25
|
+
env = os.environ.get("EXTENDVCC_LEDGER_PATH")
|
|
26
|
+
if env:
|
|
27
|
+
return Path(env)
|
|
28
|
+
return Path.home() / ".local" / "share" / "extendvcc" / "cards.jsonl"
|