[fix] bandit assert warnings (#3243)
Co-authored-by: dni ⚡ <office@dnilabs.com>
This commit is contained in:
parent
76ecf113c3
commit
fa89313e6f
28 changed files with 196 additions and 220 deletions
|
|
@ -320,9 +320,8 @@ async def extensions_list():
|
||||||
from lnbits.app import build_all_installed_extensions_list
|
from lnbits.app import build_all_installed_extensions_list
|
||||||
|
|
||||||
for ext in await build_all_installed_extensions_list():
|
for ext in await build_all_installed_extensions_list():
|
||||||
assert (
|
if not ext.meta or not ext.meta.installed_release:
|
||||||
ext.meta and ext.meta.installed_release
|
raise ValueError(f"Extension {ext.id} has no installed_release")
|
||||||
), f"Extension {ext.id} has no installed_release"
|
|
||||||
click.echo(f" - {ext.id} ({ext.meta.installed_release.version})")
|
click.echo(f" - {ext.id} ({ext.meta.installed_release.version})")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -608,9 +607,10 @@ async def update_extension(
|
||||||
|
|
||||||
click.echo(f"Current '{extension}' version: {installed_ext.installed_version}.")
|
click.echo(f"Current '{extension}' version: {installed_ext.installed_version}.")
|
||||||
|
|
||||||
assert (
|
if not installed_ext.meta or not installed_ext.meta.installed_release:
|
||||||
installed_ext.meta and installed_ext.meta.installed_release
|
raise ValueError(
|
||||||
), "Cannot find previously installed release. Please uninstall first."
|
"Cannot find previously installed release. Please uninstall first."
|
||||||
|
)
|
||||||
|
|
||||||
release = await _select_release(extension, repo_index, source_repo)
|
release = await _select_release(extension, repo_index, source_repo)
|
||||||
if not release:
|
if not release:
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ async def drop_extension_db(ext_id: str, conn: Optional[Connection] = None) -> N
|
||||||
{"id": ext_id},
|
{"id": ext_id},
|
||||||
)
|
)
|
||||||
# Check that 'ext_id' is a valid extension id and not a malicious string
|
# Check that 'ext_id' is a valid extension id and not a malicious string
|
||||||
assert row, f"Extension '{ext_id}' db version cannot be found"
|
if not row:
|
||||||
|
raise Exception(f"Extension '{ext_id}' db version cannot be found")
|
||||||
|
|
||||||
is_file_based_db = await Database.clean_ext_db_files(ext_id)
|
is_file_based_db = await Database.clean_ext_db_files(ext_id)
|
||||||
if is_file_based_db:
|
if is_file_based_db:
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,8 @@ async def create_payment(
|
||||||
# we don't allow the creation of the same invoice twice
|
# we don't allow the creation of the same invoice twice
|
||||||
# note: this can be removed if the db uniqueness constraints are set appropriately
|
# note: this can be removed if the db uniqueness constraints are set appropriately
|
||||||
previous_payment = await get_standalone_payment(checking_id, conn=conn)
|
previous_payment = await get_standalone_payment(checking_id, conn=conn)
|
||||||
assert previous_payment is None, "Payment already exists"
|
if previous_payment is not None:
|
||||||
|
raise ValueError("Payment already exists")
|
||||||
extra = data.extra or {}
|
extra = data.extra or {}
|
||||||
|
|
||||||
payment = Payment(
|
payment = Payment(
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,8 @@ async def update_admin_settings(
|
||||||
async def update_super_user(super_user: str) -> SuperSettings:
|
async def update_super_user(super_user: str) -> SuperSettings:
|
||||||
await set_settings_field("super_user", super_user)
|
await set_settings_field("super_user", super_user)
|
||||||
settings = await get_super_settings()
|
settings = await get_super_settings()
|
||||||
assert settings, "updated super_user settings could not be retrieved"
|
if not settings:
|
||||||
|
raise ValueError("updated super_user settings could not be retrieved")
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -86,7 +87,8 @@ async def create_admin_settings(super_user: str, new_settings: dict) -> SuperSet
|
||||||
await set_settings_field(key, value)
|
await set_settings_field(key, value)
|
||||||
|
|
||||||
settings = await get_super_settings()
|
settings = await get_super_settings()
|
||||||
assert settings, "created admin settings could not be retrieved"
|
if not settings:
|
||||||
|
raise ValueError("created admin settings could not be retrieved")
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ async def create_webpush_subscription(
|
||||||
{"endpoint": endpoint, "user": user, "data": data, "host": host},
|
{"endpoint": endpoint, "user": user, "data": data, "host": host},
|
||||||
)
|
)
|
||||||
subscription = await get_webpush_subscription(endpoint, user)
|
subscription = await get_webpush_subscription(endpoint, user)
|
||||||
assert subscription, "Newly created webpush subscription couldn't be retrieved"
|
if not subscription:
|
||||||
|
raise ValueError("Newly created webpush subscription couldn't be retrieved")
|
||||||
return subscription
|
return subscription
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,8 @@ class ExtensionRelease(BaseModel):
|
||||||
self, amount: int | None = None
|
self, amount: int | None = None
|
||||||
) -> ReleasePaymentInfo | None:
|
) -> ReleasePaymentInfo | None:
|
||||||
url = f"{self.pay_link}?amount={amount}" if amount else self.pay_link
|
url = f"{self.pay_link}?amount={amount}" if amount else self.pay_link
|
||||||
assert url, "Missing URL for payment info."
|
if not url:
|
||||||
|
raise ValueError("Missing URL for payment info.")
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
resp = await client.get(url)
|
resp = await client.get(url)
|
||||||
|
|
@ -376,9 +377,8 @@ class InstallableExtension(BaseModel):
|
||||||
if ext_zip_file.is_file():
|
if ext_zip_file.is_file():
|
||||||
os.remove(ext_zip_file)
|
os.remove(ext_zip_file)
|
||||||
try:
|
try:
|
||||||
assert (
|
if not self.meta or not self.meta.installed_release:
|
||||||
self.meta and self.meta.installed_release
|
raise ValueError("No installed release.")
|
||||||
), "installed_release is none."
|
|
||||||
|
|
||||||
self._restore_payment_info()
|
self._restore_payment_info()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,11 @@ async def install_extension(ext_info: InstallableExtension) -> Extension:
|
||||||
|
|
||||||
ext_info.meta = ext_info.meta or ExtensionMeta()
|
ext_info.meta = ext_info.meta or ExtensionMeta()
|
||||||
|
|
||||||
if ext_info.meta.installed_release:
|
if (
|
||||||
assert (
|
ext_info.meta.installed_release
|
||||||
ext_info.meta.installed_release.is_version_compatible
|
and not ext_info.meta.installed_release.is_version_compatible
|
||||||
), "Incompatible extension version"
|
):
|
||||||
|
raise ValueError("Incompatible extension version")
|
||||||
|
|
||||||
installed_ext = await get_installed_extension(ext_info.id)
|
installed_ext = await get_installed_extension(ext_info.id)
|
||||||
if installed_ext and installed_ext.meta:
|
if installed_ext and installed_ext.meta:
|
||||||
|
|
@ -93,9 +94,8 @@ async def stop_extension_background_work(ext_id: str) -> bool:
|
||||||
old_module = importlib.import_module(ext.module_name)
|
old_module = importlib.import_module(ext.module_name)
|
||||||
|
|
||||||
stop_fn_name = f"{ext_id}_stop"
|
stop_fn_name = f"{ext_id}_stop"
|
||||||
assert hasattr(
|
if not hasattr(old_module, stop_fn_name):
|
||||||
old_module, stop_fn_name
|
raise ValueError(f"No stop function found for '{ext.module_name}'.")
|
||||||
), f"No stop function found for '{ext.module_name}'."
|
|
||||||
|
|
||||||
stop_fn = getattr(old_module, stop_fn_name)
|
stop_fn = getattr(old_module, stop_fn_name)
|
||||||
if stop_fn:
|
if stop_fn:
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,8 @@ async def perform_lnurlauth(
|
||||||
|
|
||||||
headers = {"User-Agent": settings.user_agent}
|
headers = {"User-Agent": settings.user_agent}
|
||||||
async with httpx.AsyncClient(headers=headers) as client:
|
async with httpx.AsyncClient(headers=headers) as client:
|
||||||
assert key.verifying_key, "LNURLauth verifying_key does not exist"
|
if not key.verifying_key:
|
||||||
|
raise ValueError("LNURLauth verifying_key does not exist")
|
||||||
check_callback_url(callback)
|
check_callback_url(callback)
|
||||||
r = await client.get(
|
r = await client.get(
|
||||||
callback,
|
callback,
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ async def pay_invoice(
|
||||||
if settings.lnbits_only_allow_incoming_payments:
|
if settings.lnbits_only_allow_incoming_payments:
|
||||||
raise PaymentError("Only incoming payments allowed.", status="failed")
|
raise PaymentError("Only incoming payments allowed.", status="failed")
|
||||||
invoice = _validate_payment_request(payment_request, max_sat)
|
invoice = _validate_payment_request(payment_request, max_sat)
|
||||||
assert invoice.amount_msat
|
if not invoice.amount_msat:
|
||||||
|
raise ValueError("Missig invoice amount.")
|
||||||
|
|
||||||
async with db.reuse_conn(conn) if conn else db.connect() as new_conn:
|
async with db.reuse_conn(conn) if conn else db.connect() as new_conn:
|
||||||
amount_msat = invoice.amount_msat
|
amount_msat = invoice.amount_msat
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ async def check_webpush_settings():
|
||||||
vapid = Vapid()
|
vapid = Vapid()
|
||||||
vapid.generate_keys()
|
vapid.generate_keys()
|
||||||
privkey = vapid.private_pem()
|
privkey = vapid.private_pem()
|
||||||
assert vapid.public_key, "VAPID public key does not exist"
|
if not vapid.public_key:
|
||||||
|
raise ValueError("VAPID public key does not exist")
|
||||||
pubkey = b64urlencode(
|
pubkey = b64urlencode(
|
||||||
vapid.public_key.public_bytes(
|
vapid.public_key.public_bytes(
|
||||||
serialization.Encoding.X962,
|
serialization.Encoding.X962,
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,8 @@ async def create_user_account_no_ckeck(
|
||||||
logger.error(f"Error enabeling default extension {ext_id}: {e}")
|
logger.error(f"Error enabeling default extension {ext_id}: {e}")
|
||||||
|
|
||||||
user = await get_user_from_account(account)
|
user = await get_user_from_account(account)
|
||||||
assert user, "Cannot find user for account."
|
if not user:
|
||||||
|
raise ValueError("Cannot find user for account.")
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,8 @@ async def api_update_settings(data: UpdateSettings, user: User = Depends(check_a
|
||||||
enqueue_notification(NotificationType.settings_update, {"username": user.username})
|
enqueue_notification(NotificationType.settings_update, {"username": user.username})
|
||||||
await update_admin_settings(data)
|
await update_admin_settings(data)
|
||||||
admin_settings = await get_admin_settings(user.super_user)
|
admin_settings = await get_admin_settings(user.super_user)
|
||||||
assert admin_settings, "Updated admin settings not found."
|
if not admin_settings:
|
||||||
|
raise ValueError("Updated admin settings not found.")
|
||||||
update_cached_settings(admin_settings.dict())
|
update_cached_settings(admin_settings.dict())
|
||||||
core_app_extra.register_new_ratelimiter()
|
core_app_extra.register_new_ratelimiter()
|
||||||
return {"status": "Success"}
|
return {"status": "Success"}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,8 @@ async def api_lnurlscan( # noqa: C901
|
||||||
params.update(callback=url) # with k1 already in it
|
params.update(callback=url) # with k1 already in it
|
||||||
|
|
||||||
lnurlauth_key = wallet.wallet.lnurlauth_key(domain)
|
lnurlauth_key = wallet.wallet.lnurlauth_key(domain)
|
||||||
assert lnurlauth_key.verifying_key
|
if not lnurlauth_key.verifying_key:
|
||||||
|
raise ValueError("LNURL auth key not found for this domain.")
|
||||||
params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex())
|
params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex())
|
||||||
else:
|
else:
|
||||||
headers = {"User-Agent": settings.user_agent}
|
headers = {"User-Agent": settings.user_agent}
|
||||||
|
|
|
||||||
|
|
@ -191,12 +191,14 @@ async def api_create_user_api_token(
|
||||||
data: ApiTokenRequest,
|
data: ApiTokenRequest,
|
||||||
user: User = Depends(check_user_exists),
|
user: User = Depends(check_user_exists),
|
||||||
) -> ApiTokenResponse:
|
) -> ApiTokenResponse:
|
||||||
assert data.expiration_time_minutes > 0, "Expiration time must be in the future."
|
if not data.expiration_time_minutes > 0:
|
||||||
|
raise ValueError("Expiration time must be in the future.")
|
||||||
account = await get_account(user.id)
|
account = await get_account(user.id)
|
||||||
if not account or not account.verify_password(data.password):
|
if not account or not account.verify_password(data.password):
|
||||||
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid credentials.")
|
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid credentials.")
|
||||||
|
|
||||||
assert account.username, "Username must be configured."
|
if not account.username:
|
||||||
|
raise ValueError("Username must be configured.")
|
||||||
|
|
||||||
acls = await get_user_access_control_lists(user.id)
|
acls = await get_user_access_control_lists(user.id)
|
||||||
acl = acls.get_acl_by_id(data.acl_id)
|
acl = acls.get_acl_by_id(data.acl_id)
|
||||||
|
|
@ -223,7 +225,8 @@ async def api_delete_user_api_token(
|
||||||
if not account or not account.verify_password(data.password):
|
if not account or not account.verify_password(data.password):
|
||||||
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid credentials.")
|
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid credentials.")
|
||||||
|
|
||||||
assert account.username, "Username must be configured."
|
if not account.username:
|
||||||
|
raise ValueError("Username must be configured.")
|
||||||
|
|
||||||
acls = await get_user_access_control_lists(user.id)
|
acls = await get_user_access_control_lists(user.id)
|
||||||
acl = acls.get_acl_by_id(data.acl_id)
|
acl = acls.get_acl_by_id(data.acl_id)
|
||||||
|
|
@ -318,7 +321,7 @@ async def update_pubkey(
|
||||||
payload: AccessTokenPayload = Depends(access_token_payload),
|
payload: AccessTokenPayload = Depends(access_token_payload),
|
||||||
) -> Optional[User]:
|
) -> Optional[User]:
|
||||||
if data.user_id != user.id:
|
if data.user_id != user.id:
|
||||||
raise HTTPException(HTTPStatus.BAD_REQUEST, "Invalid user ID.")
|
raise ValueError("Invalid user ID.")
|
||||||
|
|
||||||
_validate_auth_timeout(payload.auth_time)
|
_validate_auth_timeout(payload.auth_time)
|
||||||
if (
|
if (
|
||||||
|
|
@ -326,7 +329,7 @@ async def update_pubkey(
|
||||||
and data.pubkey != user.pubkey
|
and data.pubkey != user.pubkey
|
||||||
and await get_account_by_pubkey(data.pubkey)
|
and await get_account_by_pubkey(data.pubkey)
|
||||||
):
|
):
|
||||||
raise HTTPException(HTTPStatus.BAD_REQUEST, "Public key already in use.")
|
raise ValueError("Public key already in use.")
|
||||||
|
|
||||||
account = await get_account(user.id)
|
account = await get_account(user.id)
|
||||||
if not account:
|
if not account:
|
||||||
|
|
@ -344,7 +347,8 @@ async def update_password(
|
||||||
payload: AccessTokenPayload = Depends(access_token_payload),
|
payload: AccessTokenPayload = Depends(access_token_payload),
|
||||||
) -> Optional[User]:
|
) -> Optional[User]:
|
||||||
_validate_auth_timeout(payload.auth_time)
|
_validate_auth_timeout(payload.auth_time)
|
||||||
assert data.user_id == user.id, "Invalid user ID."
|
if data.user_id != user.id:
|
||||||
|
raise ValueError("Invalid user ID.")
|
||||||
if (
|
if (
|
||||||
data.username
|
data.username
|
||||||
and user.username != data.username
|
and user.username != data.username
|
||||||
|
|
@ -353,12 +357,15 @@ async def update_password(
|
||||||
raise HTTPException(HTTPStatus.BAD_REQUEST, "Username already exists.")
|
raise HTTPException(HTTPStatus.BAD_REQUEST, "Username already exists.")
|
||||||
|
|
||||||
account = await get_account(user.id)
|
account = await get_account(user.id)
|
||||||
assert account, "Account not found."
|
if not account:
|
||||||
|
raise ValueError("Account not found.")
|
||||||
|
|
||||||
# old accounts do not have a password
|
# old accounts do not have a password
|
||||||
if account.password_hash:
|
if account.password_hash:
|
||||||
assert data.password_old, "Missing old password."
|
if not data.password_old:
|
||||||
assert account.verify_password(data.password_old), "Invalid old password."
|
raise ValueError("Missing old password.")
|
||||||
|
if not account.verify_password(data.password_old):
|
||||||
|
raise ValueError("Invalid old password.")
|
||||||
|
|
||||||
account.username = data.username
|
account.username = data.username
|
||||||
account.hash_password(data.password)
|
account.hash_password(data.password)
|
||||||
|
|
@ -376,8 +383,10 @@ async def reset_password(data: ResetUserPassword) -> JSONResponse:
|
||||||
HTTPStatus.FORBIDDEN, "Auth by 'Username and Password' not allowed."
|
HTTPStatus.FORBIDDEN, "Auth by 'Username and Password' not allowed."
|
||||||
)
|
)
|
||||||
|
|
||||||
assert data.password == data.password_repeat, "Passwords do not match."
|
if data.password != data.password_repeat:
|
||||||
assert data.reset_key[:10].startswith("reset_key_"), "This is not a reset key."
|
raise ValueError("Passwords do not match.")
|
||||||
|
if not data.reset_key[:10].startswith("reset_key_"):
|
||||||
|
raise ValueError("This is not a reset key.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
reset_key = base64.b64decode(data.reset_key[10:]).decode()
|
reset_key = base64.b64decode(data.reset_key[10:]).decode()
|
||||||
|
|
@ -385,12 +394,16 @@ async def reset_password(data: ResetUserPassword) -> JSONResponse:
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise ValueError("Invalid reset key.") from exc
|
raise ValueError("Invalid reset key.") from exc
|
||||||
|
|
||||||
assert reset_data_json, "Cannot process reset key."
|
if not reset_data_json:
|
||||||
|
raise ValueError("Cannot process reset key.")
|
||||||
|
|
||||||
action, user_id, request_time = json.loads(reset_data_json)
|
action, user_id, request_time = json.loads(reset_data_json)
|
||||||
assert action, "Missing action."
|
if not action:
|
||||||
assert user_id, "Missing user ID."
|
raise ValueError("Missing action.")
|
||||||
assert request_time, "Missing reset time."
|
if not user_id:
|
||||||
|
raise ValueError("Missing user ID.")
|
||||||
|
if not request_time:
|
||||||
|
raise ValueError("Missing reset time.")
|
||||||
|
|
||||||
_validate_auth_timeout(request_time)
|
_validate_auth_timeout(request_time)
|
||||||
|
|
||||||
|
|
@ -576,28 +589,40 @@ def _nostr_nip98_event(request: Request) -> dict:
|
||||||
event = json.loads(event_json)
|
event = json.loads(event_json)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
assert event, "Nostr login event cannot be parsed."
|
if not event:
|
||||||
|
raise ValueError("Nostr login event cannot be parsed.")
|
||||||
|
|
||||||
if not verify_event(event):
|
if not verify_event(event):
|
||||||
raise HTTPException(HTTPStatus.BAD_REQUEST, "Nostr login event is not valid.")
|
raise HTTPException(HTTPStatus.BAD_REQUEST, "Nostr login event is not valid.")
|
||||||
assert event["kind"] == 27_235, "Invalid event kind."
|
if not event["kind"] == 27_235:
|
||||||
|
raise ValueError("Invalid event kind.")
|
||||||
|
|
||||||
auth_threshold = settings.auth_credetials_update_threshold
|
auth_threshold = settings.auth_credetials_update_threshold
|
||||||
assert (
|
if not (abs(time() - event["created_at"]) < auth_threshold):
|
||||||
abs(time() - event["created_at"]) < auth_threshold
|
raise ValueError(
|
||||||
), f"More than {auth_threshold} seconds have passed since the event was signed."
|
f"More than {auth_threshold} seconds have passed "
|
||||||
|
"since the event was signed."
|
||||||
|
)
|
||||||
|
|
||||||
|
_check_nostr_event_tags(event)
|
||||||
|
|
||||||
|
return event
|
||||||
|
|
||||||
|
|
||||||
|
def _check_nostr_event_tags(event: dict):
|
||||||
method: Optional[str] = next((v for k, v in event["tags"] if k == "method"), None)
|
method: Optional[str] = next((v for k, v in event["tags"] if k == "method"), None)
|
||||||
assert method, "Tag 'method' is missing."
|
if not method:
|
||||||
assert method.upper() == "POST", "Invalid value for tag 'method'."
|
raise ValueError("Tag 'method' is missing.")
|
||||||
|
if not method.upper() == "POST":
|
||||||
|
raise ValueError("Invalid value for tag 'method'.")
|
||||||
|
|
||||||
url = next((v for k, v in event["tags"] if k == "u"), None)
|
url = next((v for k, v in event["tags"] if k == "u"), None)
|
||||||
|
|
||||||
assert url, "Tag 'u' for URL is missing."
|
if not url:
|
||||||
|
raise ValueError("Tag 'u' for URL is missing.")
|
||||||
accepted_urls = [f"{u}/nostr" for u in settings.nostr_absolute_request_urls]
|
accepted_urls = [f"{u}/nostr" for u in settings.nostr_absolute_request_urls]
|
||||||
assert url in accepted_urls, f"Invalid value for tag 'u': '{url}'."
|
if url not in accepted_urls:
|
||||||
|
raise ValueError(f"Invalid value for tag 'u': '{url}'.")
|
||||||
return event
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_auth_timeout(auth_time: Optional[int] = 0):
|
def _validate_auth_timeout(auth_time: Optional[int] = 0):
|
||||||
|
|
|
||||||
|
|
@ -170,11 +170,13 @@ async def api_enable_extension(
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
HTTPStatus.NOT_FOUND, f"Extension '{ext_id}' doesn't exist."
|
HTTPStatus.NOT_FOUND, f"Extension '{ext_id}' doesn't exist."
|
||||||
)
|
)
|
||||||
try:
|
|
||||||
logger.info(f"Enabling extension: {ext_id}.")
|
logger.info(f"Enabling extension: {ext_id}.")
|
||||||
ext = await get_installed_extension(ext_id)
|
ext = await get_installed_extension(ext_id)
|
||||||
assert ext, f"Extension '{ext_id}' is not installed."
|
if not ext:
|
||||||
assert ext.active, f"Extension '{ext_id}' is not activated."
|
raise ValueError(f"Extension '{ext_id}' is not installed.")
|
||||||
|
if not ext.active:
|
||||||
|
raise ValueError(f"Extension '{ext_id}' is not activated.")
|
||||||
|
|
||||||
user_ext = await get_user_extension(user.id, ext_id)
|
user_ext = await get_user_extension(user.id, ext_id)
|
||||||
if not user_ext:
|
if not user_ext:
|
||||||
|
|
@ -194,13 +196,10 @@ async def api_enable_extension(
|
||||||
if user_ext.is_paid:
|
if user_ext.is_paid:
|
||||||
user_ext.active = True
|
user_ext.active = True
|
||||||
await update_user_extension(user_ext)
|
await update_user_extension(user_ext)
|
||||||
return SimpleStatus(
|
return SimpleStatus(success=True, message=f"Paid extension '{ext_id}' enabled.")
|
||||||
success=True, message=f"Paid extension '{ext_id}' enabled."
|
|
||||||
)
|
|
||||||
|
|
||||||
assert (
|
if not ext.meta or not ext.meta.pay_to_enable or not ext.meta.pay_to_enable.wallet:
|
||||||
ext.meta and ext.meta.pay_to_enable and ext.meta.pay_to_enable.wallet
|
raise ValueError(f"Extension '{ext_id}' is missing payment wallet.")
|
||||||
), f"Extension '{ext_id}' is missing payment wallet."
|
|
||||||
|
|
||||||
payment_status = await check_transaction_status(
|
payment_status = await check_transaction_status(
|
||||||
wallet_id=ext.meta.pay_to_enable.wallet,
|
wallet_id=ext.meta.pay_to_enable.wallet,
|
||||||
|
|
@ -218,17 +217,6 @@ async def api_enable_extension(
|
||||||
await update_user_extension(user_ext)
|
await update_user_extension(user_ext)
|
||||||
return SimpleStatus(success=True, message=f"Paid extension '{ext_id}' enabled.")
|
return SimpleStatus(success=True, message=f"Paid extension '{ext_id}' enabled.")
|
||||||
|
|
||||||
except AssertionError as exc:
|
|
||||||
raise HTTPException(HTTPStatus.BAD_REQUEST, str(exc)) from exc
|
|
||||||
except HTTPException as exc:
|
|
||||||
raise exc from exc
|
|
||||||
except Exception as exc:
|
|
||||||
logger.warning(exc)
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
detail=(f"Failed to enable '{ext_id}' "),
|
|
||||||
) from exc
|
|
||||||
|
|
||||||
|
|
||||||
@extension_router.put("/{ext_id}/disable")
|
@extension_router.put("/{ext_id}/disable")
|
||||||
async def api_disable_extension(
|
async def api_disable_extension(
|
||||||
|
|
@ -255,7 +243,8 @@ async def api_activate_extension(ext_id: str) -> SimpleStatus:
|
||||||
logger.info(f"Activating extension: '{ext_id}'.")
|
logger.info(f"Activating extension: '{ext_id}'.")
|
||||||
|
|
||||||
ext = await get_valid_extension(ext_id)
|
ext = await get_valid_extension(ext_id)
|
||||||
assert ext, f"Extension '{ext_id}' doesn't exist."
|
if not ext:
|
||||||
|
raise ValueError(f"Extension '{ext_id}' doesn't exist.")
|
||||||
|
|
||||||
await activate_extension(ext)
|
await activate_extension(ext)
|
||||||
return SimpleStatus(success=True, message=f"Extension '{ext_id}' activated.")
|
return SimpleStatus(success=True, message=f"Extension '{ext_id}' activated.")
|
||||||
|
|
@ -274,7 +263,8 @@ async def api_deactivate_extension(ext_id: str) -> SimpleStatus:
|
||||||
logger.info(f"Deactivating extension: '{ext_id}'.")
|
logger.info(f"Deactivating extension: '{ext_id}'.")
|
||||||
|
|
||||||
ext = await get_valid_extension(ext_id)
|
ext = await get_valid_extension(ext_id)
|
||||||
assert ext, f"Extension '{ext_id}' doesn't exist."
|
if not ext:
|
||||||
|
raise ValueError(f"Extension '{ext_id}' doesn't exist.")
|
||||||
|
|
||||||
await deactivate_extension(ext_id)
|
await deactivate_extension(ext_id)
|
||||||
return SimpleStatus(success=True, message=f"Extension '{ext_id}' deactivated.")
|
return SimpleStatus(success=True, message=f"Extension '{ext_id}' deactivated.")
|
||||||
|
|
@ -354,41 +344,36 @@ async def get_extension_releases(ext_id: str) -> list[ExtensionRelease]:
|
||||||
async def get_pay_to_install_invoice(
|
async def get_pay_to_install_invoice(
|
||||||
ext_id: str, data: CreateExtension
|
ext_id: str, data: CreateExtension
|
||||||
) -> ReleasePaymentInfo:
|
) -> ReleasePaymentInfo:
|
||||||
try:
|
if ext_id != data.ext_id:
|
||||||
assert (
|
raise ValueError(
|
||||||
ext_id == data.ext_id
|
f"Wrong extension id. Expected {ext_id}, but got {data.ext_id}"
|
||||||
), f"Wrong extension id. Expected {ext_id}, but got {data.ext_id}"
|
)
|
||||||
assert data.cost_sats, "A non-zero amount must be specified."
|
if not data.cost_sats:
|
||||||
|
raise ValueError("A non-zero amount must be specified.")
|
||||||
release = await InstallableExtension.get_extension_release(
|
release = await InstallableExtension.get_extension_release(
|
||||||
data.ext_id, data.source_repo, data.archive, data.version
|
data.ext_id, data.source_repo, data.archive, data.version
|
||||||
)
|
)
|
||||||
assert release, "Release not found."
|
if not release:
|
||||||
assert release.pay_link, "Pay link not found for release."
|
raise ValueError("Release not found.")
|
||||||
|
if not release.pay_link:
|
||||||
|
raise ValueError("Pay link not found for release.")
|
||||||
|
|
||||||
payment_info = await release.fetch_release_payment_info(data.cost_sats)
|
payment_info = await release.fetch_release_payment_info(data.cost_sats)
|
||||||
|
|
||||||
assert payment_info and payment_info.payment_request, "Cannot request invoice."
|
if not (payment_info and payment_info.payment_request):
|
||||||
|
raise ValueError("Cannot request invoice.")
|
||||||
invoice = bolt11_decode(payment_info.payment_request)
|
invoice = bolt11_decode(payment_info.payment_request)
|
||||||
|
|
||||||
assert invoice.amount_msat is not None, "Invoic amount is missing."
|
if invoice.amount_msat is None:
|
||||||
|
raise ValueError("Invoic amount is missing.")
|
||||||
invoice_amount = int(invoice.amount_msat / 1000)
|
invoice_amount = int(invoice.amount_msat / 1000)
|
||||||
assert (
|
if invoice_amount != data.cost_sats:
|
||||||
invoice_amount == data.cost_sats
|
raise ValueError(f"Wrong invoice amount: {invoice_amount}.")
|
||||||
), f"Wrong invoice amount: {invoice_amount}."
|
if payment_info.payment_hash != invoice.payment_hash:
|
||||||
assert (
|
raise ValueError("Wrong invoice payment hash.")
|
||||||
payment_info.payment_hash == invoice.payment_hash
|
|
||||||
), "Wrong invoice payment hash."
|
|
||||||
|
|
||||||
return payment_info
|
return payment_info
|
||||||
|
|
||||||
except AssertionError as exc:
|
|
||||||
raise HTTPException(HTTPStatus.BAD_REQUEST, str(exc)) from exc
|
|
||||||
except Exception as exc:
|
|
||||||
logger.warning(exc)
|
|
||||||
raise HTTPException(
|
|
||||||
HTTPStatus.INTERNAL_SERVER_ERROR, "Cannot request invoice"
|
|
||||||
) from exc
|
|
||||||
|
|
||||||
|
|
||||||
@extension_router.put("/{ext_id}/invoice/enable")
|
@extension_router.put("/{ext_id}/invoice/enable")
|
||||||
async def get_pay_to_enable_invoice(
|
async def get_pay_to_enable_invoice(
|
||||||
|
|
|
||||||
|
|
@ -349,11 +349,11 @@ async def api_payments_pay_lnurl(
|
||||||
extra["fiat_currency"] = data.unit
|
extra["fiat_currency"] = data.unit
|
||||||
extra["fiat_amount"] = data.amount / 1000
|
extra["fiat_amount"] = data.amount / 1000
|
||||||
if data.internal_memo is not None:
|
if data.internal_memo is not None:
|
||||||
assert (
|
if len(data.internal_memo) > 512:
|
||||||
len(data.internal_memo) <= 512
|
raise ValueError("Internal memo must be 512 characters or less.")
|
||||||
), "Internal memo must be 512 characters or less."
|
|
||||||
extra["internal_memo"] = data.internal_memo
|
extra["internal_memo"] = data.internal_memo
|
||||||
assert data.description is not None, "description is required"
|
if data.description is None:
|
||||||
|
raise ValueError("Description is required")
|
||||||
|
|
||||||
payment = await pay_invoice(
|
payment = await pay_invoice(
|
||||||
wallet_id=wallet.wallet.id,
|
wallet_id=wallet.wallet.id,
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,8 @@ async def api_users_reset_password(user_id: str) -> str:
|
||||||
reset_data = ["reset", user_id, int(time.time())]
|
reset_data = ["reset", user_id, int(time.time())]
|
||||||
reset_data_json = json.dumps(reset_data, separators=(",", ":"), ensure_ascii=False)
|
reset_data_json = json.dumps(reset_data, separators=(",", ":"), ensure_ascii=False)
|
||||||
reset_key = encrypt_internal_message(reset_data_json)
|
reset_key = encrypt_internal_message(reset_data_json)
|
||||||
assert reset_key, "Cannot generate reset key."
|
if not reset_key:
|
||||||
|
raise ValueError("Cannot generate reset key.")
|
||||||
reset_key_b64 = base64.b64encode(reset_key.encode()).decode()
|
reset_key_b64 = base64.b64encode(reset_key.encode()).decode()
|
||||||
return f"reset_key_{reset_key_b64}"
|
return f"reset_key_{reset_key_b64}"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,6 @@ class AuditMiddleware(BaseHTTPMiddleware):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = await call_next(request)
|
response = await call_next(request)
|
||||||
assert response
|
|
||||||
return response
|
return response
|
||||||
finally:
|
finally:
|
||||||
if request_details:
|
if request_details:
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,8 @@ class InstalledExtensionsSettings(LNbitsSettings):
|
||||||
if r.find_in_conflict(ext_redirect_paths)
|
if r.find_in_conflict(ext_redirect_paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert len(existing_redirects) == 0, (
|
if len(existing_redirects) != 0:
|
||||||
|
raise ValueError(
|
||||||
f"Cannot redirect for extension '{ext_id}'."
|
f"Cannot redirect for extension '{ext_id}'."
|
||||||
f" Already mapped by {existing_redirects}."
|
f" Already mapped by {existing_redirects}."
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ class AESCipher:
|
||||||
self, salt: bytes, output_len: int = 32 + 16
|
self, salt: bytes, output_len: int = 32 + 16
|
||||||
) -> tuple[bytes, bytes]:
|
) -> tuple[bytes, bytes]:
|
||||||
# extended from https://gist.github.com/gsakkis/4546068
|
# extended from https://gist.github.com/gsakkis/4546068
|
||||||
assert len(salt) == 8, "Salt must be 8 bytes"
|
if len(salt) != 8:
|
||||||
|
raise ValueError("Salt must be 8 bytes")
|
||||||
data = self.key + salt
|
data = self.key + salt
|
||||||
key = md5(data).digest()
|
key = md5(data).digest()
|
||||||
final_key = key
|
final_key = key
|
||||||
|
|
|
||||||
|
|
@ -175,14 +175,17 @@ def normalize_private_key(key: str) -> str:
|
||||||
def normalize_bech32_key(hrp: str, key: str) -> str:
|
def normalize_bech32_key(hrp: str, key: str) -> str:
|
||||||
if key.startswith(hrp):
|
if key.startswith(hrp):
|
||||||
_, decoded_data = bech32_decode(key)
|
_, decoded_data = bech32_decode(key)
|
||||||
assert decoded_data, f"Key is not valid {hrp}."
|
if not decoded_data:
|
||||||
|
raise ValueError(f"Key is not valid {hrp}.")
|
||||||
|
|
||||||
decoded_data_bits = convertbits(decoded_data, 5, 8, False)
|
decoded_data_bits = convertbits(decoded_data, 5, 8, False)
|
||||||
assert decoded_data_bits, f"Key is not valid {hrp}."
|
if not decoded_data_bits:
|
||||||
|
raise ValueError(f"Key is not valid {hrp}.")
|
||||||
|
|
||||||
return bytes(decoded_data_bits).hex()
|
return bytes(decoded_data_bits).hex()
|
||||||
|
|
||||||
assert len(key) == 64, "Key has wrong length."
|
if len(key) != 64:
|
||||||
|
raise ValueError("Key has wrong length.")
|
||||||
try:
|
try:
|
||||||
int(key, 16)
|
int(key, 16)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
@ -203,7 +206,8 @@ def hex_to_npub(hex_pubkey: str) -> str:
|
||||||
normalize_public_key(hex_pubkey)
|
normalize_public_key(hex_pubkey)
|
||||||
pubkey_bytes = bytes.fromhex(hex_pubkey)
|
pubkey_bytes = bytes.fromhex(hex_pubkey)
|
||||||
bits = convertbits(pubkey_bytes, 8, 5, True)
|
bits = convertbits(pubkey_bytes, 8, 5, True)
|
||||||
assert bits
|
if not bits:
|
||||||
|
raise ValueError("Invalid Nostr public key.")
|
||||||
return bech32_encode("npub", bits)
|
return bech32_encode("npub", bits)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,8 @@ class BlinkWallet(Wallet):
|
||||||
response = await self._graphql_query(data)
|
response = await self._graphql_query(data)
|
||||||
|
|
||||||
response_data = response.get("data")
|
response_data = response.get("data")
|
||||||
assert response_data is not None
|
if response_data is None:
|
||||||
|
raise ValueError("No data found in response.")
|
||||||
txs_data = (
|
txs_data = (
|
||||||
response_data.get("me", {})
|
response_data.get("me", {})
|
||||||
.get("defaultAccount", {})
|
.get("defaultAccount", {})
|
||||||
|
|
@ -260,7 +261,8 @@ class BlinkWallet(Wallet):
|
||||||
.get("transactionsByPaymentHash", [])
|
.get("transactionsByPaymentHash", [])
|
||||||
)
|
)
|
||||||
tx_data = next((t for t in txs_data if t.get("direction") == "SEND"), None)
|
tx_data = next((t for t in txs_data if t.get("direction") == "SEND"), None)
|
||||||
assert tx_data, "No SEND data found."
|
if not tx_data:
|
||||||
|
raise ValueError("No SEND data found.")
|
||||||
fee = tx_data.get("settlementFee")
|
fee = tx_data.get("settlementFee")
|
||||||
preimage = tx_data.get("settlementVia", {}).get("preImage")
|
preimage = tx_data.get("settlementVia", {}).get("preImage")
|
||||||
status = tx_data.get("status")
|
status = tx_data.get("status")
|
||||||
|
|
@ -284,9 +286,8 @@ class BlinkWallet(Wallet):
|
||||||
await ws.send(json.dumps(self.ws_auth))
|
await ws.send(json.dumps(self.ws_auth))
|
||||||
confirmation = await ws.recv()
|
confirmation = await ws.recv()
|
||||||
ack = json.loads(confirmation)
|
ack = json.loads(confirmation)
|
||||||
assert (
|
if ack.get("type") != "connection_ack":
|
||||||
ack.get("type") == "connection_ack"
|
raise ValueError("Websocket connection not acknowledged.")
|
||||||
), "Websocket connection not acknowledged."
|
|
||||||
|
|
||||||
logger.info("Websocket connection acknowledged.")
|
logger.info("Websocket connection acknowledged.")
|
||||||
subscription_req = {
|
subscription_req = {
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,8 @@ class BoltzWallet(Wallet):
|
||||||
pair_info = await self.rpc.GetPairInfo(pair_request, metadata=self.metadata)
|
pair_info = await self.rpc.GetPairInfo(pair_request, metadata=self.metadata)
|
||||||
invoice = decode(bolt11)
|
invoice = decode(bolt11)
|
||||||
|
|
||||||
assert invoice.amount_msat, "amountless invoice"
|
if not invoice.amount_msat:
|
||||||
|
raise ValueError("amountless invoice")
|
||||||
service_fee: float = invoice.amount_msat * pair_info.fees.percentage / 100
|
service_fee: float = invoice.amount_msat * pair_info.fees.percentage / 100
|
||||||
estimate = service_fee + pair_info.fees.miner_fees * 1000
|
estimate = service_fee + pair_info.fees.miner_fees * 1000
|
||||||
if estimate > fee_limit_msat:
|
if estimate > fee_limit_msat:
|
||||||
|
|
|
||||||
|
|
@ -314,11 +314,12 @@ class CoreLightningRestWallet(Wallet):
|
||||||
)
|
)
|
||||||
paid_invoice = r.json()
|
paid_invoice = r.json()
|
||||||
logger.trace(f"paid invoice: {paid_invoice}")
|
logger.trace(f"paid invoice: {paid_invoice}")
|
||||||
assert self.statuses[
|
if not self.statuses[paid_invoice["invoices"][0]["status"]]:
|
||||||
paid_invoice["invoices"][0]["status"]
|
raise ValueError("streamed invoice not paid")
|
||||||
], "streamed invoice not paid"
|
if "invoices" not in paid_invoice:
|
||||||
assert "invoices" in paid_invoice, "no invoices in response"
|
raise ValueError("no invoices in response")
|
||||||
assert len(paid_invoice["invoices"]), "no invoices in response"
|
if not len(paid_invoice["invoices"]):
|
||||||
|
raise ValueError("no invoices in response")
|
||||||
yield paid_invoice["invoices"][0]["payment_hash"]
|
yield paid_invoice["invoices"][0]["payment_hash"]
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ def load_macaroon(
|
||||||
aes = AESCipher(key.encode())
|
aes = AESCipher(key.encode())
|
||||||
return aes.decrypt(encrypted_macaroon)
|
return aes.decrypt(encrypted_macaroon)
|
||||||
|
|
||||||
assert macaroon, "macaroon must be set here"
|
if not macaroon:
|
||||||
|
raise ValueError("macaroon must be set here")
|
||||||
|
|
||||||
# if the macaroon is a file path, load it and return hex version
|
# if the macaroon is a file path, load it and return hex version
|
||||||
if macaroon.split(".")[-1] == "macaroon":
|
if macaroon.split(".")[-1] == "macaroon":
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,8 @@ class NWCConnection:
|
||||||
self.account_private_key = secp256k1.PrivateKey(bytes.fromhex(secret))
|
self.account_private_key = secp256k1.PrivateKey(bytes.fromhex(secret))
|
||||||
self.account_private_key_hex = secret
|
self.account_private_key_hex = secret
|
||||||
self.account_public_key = self.account_private_key.pubkey
|
self.account_public_key = self.account_private_key.pubkey
|
||||||
assert self.account_public_key
|
if not self.account_public_key:
|
||||||
|
raise ValueError("Missing account public key")
|
||||||
self.account_public_key_hex = self.account_public_key.serialize().hex()[2:]
|
self.account_public_key_hex = self.account_public_key.serialize().hex()[2:]
|
||||||
|
|
||||||
# Extract service key (used for encryption to identify the nwc service provider)
|
# Extract service key (used for encryption to identify the nwc service provider)
|
||||||
|
|
|
||||||
63
poetry.lock
generated
63
poetry.lock
generated
|
|
@ -363,31 +363,6 @@ files = [
|
||||||
{file = "backports_datetime_fromisoformat-2.0.3.tar.gz", hash = "sha256:b58edc8f517b66b397abc250ecc737969486703a66eb97e01e6d51291b1a139d"},
|
{file = "backports_datetime_fromisoformat-2.0.3.tar.gz", hash = "sha256:b58edc8f517b66b397abc250ecc737969486703a66eb97e01e6d51291b1a139d"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bandit"
|
|
||||||
version = "1.8.5"
|
|
||||||
description = "Security oriented static analyser for python code."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.9"
|
|
||||||
groups = ["dev"]
|
|
||||||
files = [
|
|
||||||
{file = "bandit-1.8.5-py3-none-any.whl", hash = "sha256:cb2e57524e99e33ced48833c6cc9c12ac78ae970bb6a450a83c4b506ecc1e2f9"},
|
|
||||||
{file = "bandit-1.8.5.tar.gz", hash = "sha256:db812e9c39b8868c0fed5278b77fffbbaba828b4891bc80e34b9c50373201cfd"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
|
|
||||||
PyYAML = ">=5.3.1"
|
|
||||||
rich = "*"
|
|
||||||
stevedore = ">=1.20.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
baseline = ["GitPython (>=3.1.30)"]
|
|
||||||
sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"]
|
|
||||||
test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"]
|
|
||||||
toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""]
|
|
||||||
yaml = ["PyYAML"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base58"
|
name = "base58"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
|
|
@ -2119,7 +2094,7 @@ version = "3.0.0"
|
||||||
description = "Python port of markdown-it. Markdown parsing, done right!"
|
description = "Python port of markdown-it. Markdown parsing, done right!"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
groups = ["main", "dev"]
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
|
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
|
||||||
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
|
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
|
||||||
|
|
@ -2236,7 +2211,7 @@ version = "0.1.2"
|
||||||
description = "Markdown URL utilities"
|
description = "Markdown URL utilities"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
groups = ["main", "dev"]
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
|
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
|
||||||
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
||||||
|
|
@ -2606,21 +2581,6 @@ files = [
|
||||||
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pbr"
|
|
||||||
version = "6.1.1"
|
|
||||||
description = "Python Build Reasonableness"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.6"
|
|
||||||
groups = ["dev"]
|
|
||||||
files = [
|
|
||||||
{file = "pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76"},
|
|
||||||
{file = "pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
setuptools = "*"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "4.3.8"
|
version = "4.3.8"
|
||||||
|
|
@ -3384,7 +3344,7 @@ version = "14.0.0"
|
||||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
groups = ["main", "dev"]
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"},
|
{file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"},
|
||||||
{file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"},
|
{file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"},
|
||||||
|
|
@ -3793,21 +3753,6 @@ anyio = ">=3.4.0,<5"
|
||||||
[package.extras]
|
[package.extras]
|
||||||
full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
|
full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stevedore"
|
|
||||||
version = "5.4.1"
|
|
||||||
description = "Manage dynamic plugins for Python applications"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.9"
|
|
||||||
groups = ["dev"]
|
|
||||||
files = [
|
|
||||||
{file = "stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe"},
|
|
||||||
{file = "stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pbr = ">=2.0.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tlv8"
|
name = "tlv8"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
|
@ -4475,4 +4420,4 @@ liquid = ["wallycore"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = "~3.12 | ~3.11 | ~3.10"
|
python-versions = "~3.12 | ~3.11 | ~3.10"
|
||||||
content-hash = "17a61e0f0d45c02d99c398f8ddfd68f7bd55a04183cad7d615e170813be43348"
|
content-hash = "53f582a8079540033939ccd1bbd93b8ec1e8190ee26be0c0b8d64d57edb5cdac"
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@ breez = ["breez-sdk", "breez-sdk-liquid"]
|
||||||
liquid = ["wallycore"]
|
liquid = ["wallycore"]
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
bandit = "^1.8.5"
|
|
||||||
black = "^25.1.0"
|
black = "^25.1.0"
|
||||||
mypy = "^1.11.2"
|
mypy = "^1.11.2"
|
||||||
types-protobuf = "^6.30.2.20250516"
|
types-protobuf = "^6.30.2.20250516"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue