- Add nwc_hub_manager.py: AlbyHubManager with real Alby Hub API (setup, auth, CRUD, drain, delete, invoice) - Add nwc_lnurl_service.py: dedicated loopback LNURL service on port 8181 - server.py: remove JSON scaffolding (state.json, fake invoice generator, fake NWC URI, LNURL routes); replace with real manager calls; update service maps to albyhub.service; remove LNURL auth-exempt paths - nwc_wallet_cli.py: rewrite to use real AlbyHubManager instead of JSON state - modules/nwc-wallets.nix: replace with albyhub user/service, nwc-lnurl service, LND macaroon, unlock-password generation - modules/core/caddy.nix: proxy LNURL routes to port 8181 (dedicated service) instead of 8937 (Hub) - modules/core/sovran-hub.nix: service tile points to albyhub.service - docs/wallet-connections.md: document real architecture, Alby Hub pin/patches, backup sensitivity - test_wallet_connections.py: replace scaffolding tests with 54 real manager tests using mocked Alby Hub
116 lines
3.5 KiB
Python
116 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
|
|
from . import nwc_hub_manager as _mgr_mod
|
|
from .server import _nwc_domain, _nwc_validate_alias, _nwc_test_address
|
|
|
|
|
|
def _print(data) -> None:
|
|
print(json.dumps(data, indent=2, sort_keys=True))
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(prog="nwc-wallet")
|
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
|
|
create = sub.add_parser("create")
|
|
create.add_argument("name")
|
|
create.add_argument("alias")
|
|
preset_group = create.add_mutually_exclusive_group()
|
|
preset_group.add_argument("--receive-only", action="store_true")
|
|
preset_group.add_argument("--limit-sats", type=int)
|
|
|
|
sub.add_parser("list")
|
|
|
|
drain = sub.add_parser("drain")
|
|
drain.add_argument("wallet")
|
|
|
|
delete = sub.add_parser("delete")
|
|
delete.add_argument("wallet")
|
|
|
|
addr = sub.add_parser("address")
|
|
addr_sub = addr.add_subparsers(dest="address_cmd", required=True)
|
|
addr_show = addr_sub.add_parser("show")
|
|
addr_show.add_argument("alias")
|
|
|
|
sub.add_parser("health")
|
|
|
|
args = parser.parse_args(argv)
|
|
manager = _mgr_mod.get_manager()
|
|
domain = _nwc_domain()
|
|
|
|
if args.cmd == "list":
|
|
try:
|
|
wallets = manager.list_wallets(domain)
|
|
except _mgr_mod.AlbyHubError as exc:
|
|
print(f"Error: {exc.code} - {exc}", file=sys.stderr)
|
|
return 1
|
|
_print({"wallets": wallets})
|
|
return 0
|
|
|
|
if args.cmd == "health":
|
|
result = manager.health()
|
|
_print(result)
|
|
return 0 if result.get("ok") else 1
|
|
|
|
if args.cmd == "address" and args.address_cmd == "show":
|
|
alias = args.alias.strip().lower()
|
|
test = _nwc_test_address(alias)
|
|
_print(test)
|
|
return 0 if test.get("ok") else 1
|
|
|
|
if args.cmd == "drain":
|
|
try:
|
|
result = manager.drain_wallet(args.wallet)
|
|
except _mgr_mod.AlbyHubError as exc:
|
|
print(f"Error: {exc.code} - {exc}", file=sys.stderr)
|
|
return 1
|
|
_print(result)
|
|
return 0
|
|
|
|
if args.cmd == "delete":
|
|
try:
|
|
result = manager.delete_wallet(args.wallet)
|
|
except _mgr_mod.AlbyHubError as exc:
|
|
print(f"Error: {exc.code} - {exc}", file=sys.stderr)
|
|
return 1
|
|
_print(result)
|
|
return 0
|
|
|
|
if args.cmd == "create":
|
|
alias = args.alias.strip().lower()
|
|
if not _nwc_validate_alias(alias):
|
|
print("Error: alias_invalid - Alias must be lowercase letters, digits, '_' or '-'.", file=sys.stderr)
|
|
return 1
|
|
access_preset = "send_receive_limited" if args.limit_sats is not None else "receive_only"
|
|
try:
|
|
result = manager.create_wallet(
|
|
args.name.strip(),
|
|
alias,
|
|
access_preset,
|
|
args.limit_sats if access_preset == "send_receive_limited" else None,
|
|
domain,
|
|
)
|
|
except _mgr_mod.AlbyHubError as exc:
|
|
print(f"Error: {exc.code} - {exc}", file=sys.stderr)
|
|
return 1
|
|
# Print the pairing URI once — this is the only time it is shown
|
|
_print(
|
|
{
|
|
"wallet": result["wallet"],
|
|
"pairing_uri": result.get("pairing_uri", ""),
|
|
"message": "Keep the NWC connection secret private. It cannot be displayed again.",
|
|
"result": result.get("result", {}),
|
|
}
|
|
)
|
|
return 0
|
|
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|