chore(v2): lint pass — black + ruff auto-fix + mypy regressions (#29 v1.1)
Pre-merge lint hygiene on the PR #30 touched files:
- `black` reformatted 9 files (cassette_transport, crud, models, tasks,
views_api, nip44, all 3 cassette test files, migrations). Cosmetic:
line lengths, trailing commas, multi-line argument layout.
- `ruff check --fix` cleared 176 of 202 errors auto-fixed. Mostly
`UP006` `typing.Optional` → `| None` modernization, `I001` import
sort order, `UP035` typing-extensions cleanup.
- Two new mypy regressions introduced by the migration commit dcb7de0
fixed:
- `crud.py:apply_bootstrap_state` — annotated `existing_first: dict
| None` on the dedup fetch.
- `tasks.py:_cassette_consumer_tick` — `# type: ignore[arg-type]` on
the `nostr_client.relay_manager.add_subscription` call; nostrclient's
upstream typing declares `list[str]` for filters but the actual
Nostr protocol takes `list[<filter-dict>]`. The runtime accepts it
(live smoke at 13:43Z dispatched `nip44_decrypt` cleanly through
this subscription); the typing mismatch is upstream's.
Remaining lint state, intentionally not addressed in this commit
(all pre-existing baseline, not regressions):
- 8 mypy errors in `calculations.py` + the unchanged-by-this-PR parts
of `crud.py` — pre-existing on v2-bitspire.
- 26 ruff style warnings: 14 are N805 false-positives on Pydantic
validators (`cls` first-arg is correct for `@validator`-decorated
methods); 4 are N818 exception-name-suffix preferences on my new
exception classes (renaming would touch many call sites; keep
`OperatorIdentityMissing` / `SignerUnavailable` / `RelayUnavailable`
/ `_NostrclientUnavailable` as-is for clarity); 5 are E501 line-too-
long on docstrings (the long lines are formatted for clarity);
1 RUF002 unicode-minus in a docstring.
Tests: 155 passed, 1 pre-existing async-plugin failure unchanged.
Live smoke (both publish + consume directions through the bunker)
unaffected — this is purely a code-style pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dcb7de0c27
commit
d448fab0d2
10 changed files with 249 additions and 352 deletions
23
nip44.py
23
nip44.py
|
|
@ -57,7 +57,6 @@ import hashlib
|
|||
import hmac as hmac_stdlib
|
||||
import os
|
||||
import struct
|
||||
from typing import Optional
|
||||
|
||||
import coincurve
|
||||
from cryptography.hazmat.primitives import hashes, hmac
|
||||
|
|
@ -71,7 +70,9 @@ _MIN_PLAINTEXT_LEN = 1
|
|||
_MAX_PLAINTEXT_LEN = 65535
|
||||
_NONCE_LEN = 32
|
||||
_MAC_LEN = 32
|
||||
_MIN_PAYLOAD_LEN = 1 + _NONCE_LEN + (2 + 32) + _MAC_LEN # version + nonce + min padded + mac
|
||||
_MIN_PAYLOAD_LEN = (
|
||||
1 + _NONCE_LEN + (2 + 32) + _MAC_LEN
|
||||
) # version + nonce + min padded + mac
|
||||
_MAX_PAYLOAD_LEN = 1 + _NONCE_LEN + (2 + 65536) + _MAC_LEN
|
||||
|
||||
|
||||
|
|
@ -98,8 +99,8 @@ class Nip44LengthError(Nip44Error):
|
|||
|
||||
def _calc_padded_len(plaintext_len: int) -> int:
|
||||
"""Per NIP-44 v2 padding scheme:
|
||||
if L <= 32: padded_len = 32
|
||||
else: chunk = max(32, next_power_2(L-1) // 8); padded_len = chunk * ((L-1) // chunk + 1)
|
||||
if L <= 32: padded_len = 32
|
||||
else: chunk = max(32, next_power_2(L-1) // 8); padded_len = chunk * ((L-1) // chunk + 1)
|
||||
"""
|
||||
if plaintext_len <= 32:
|
||||
return 32
|
||||
|
|
@ -205,7 +206,7 @@ def encrypt_with_conversation_key(
|
|||
plaintext: str,
|
||||
conversation_key: bytes,
|
||||
*,
|
||||
nonce: Optional[bytes] = None,
|
||||
nonce: bytes | None = None,
|
||||
) -> str:
|
||||
"""Encrypt `plaintext` under a precomputed `conversation_key` (32B PRK).
|
||||
|
||||
|
|
@ -224,9 +225,9 @@ def encrypt_with_conversation_key(
|
|||
chacha_key, chacha_nonce, hmac_key = _derive_message_keys(conversation_key, nonce)
|
||||
ciphertext = _chacha20(chacha_key, chacha_nonce, padded)
|
||||
mac = _hmac_aad(hmac_key, nonce, ciphertext)
|
||||
return base64.b64encode(
|
||||
bytes([_VERSION]) + nonce + ciphertext + mac
|
||||
).decode("ascii")
|
||||
return base64.b64encode(bytes([_VERSION]) + nonce + ciphertext + mac).decode(
|
||||
"ascii"
|
||||
)
|
||||
|
||||
|
||||
def decrypt_with_conversation_key(payload_b64: str, conversation_key: bytes) -> str:
|
||||
|
|
@ -239,7 +240,9 @@ def decrypt_with_conversation_key(payload_b64: str, conversation_key: bytes) ->
|
|||
"""
|
||||
try:
|
||||
raw = base64.b64decode(payload_b64, validate=True)
|
||||
except Exception as exc: # noqa: BLE001 — we want any base64 failure surfaced uniformly
|
||||
except (
|
||||
Exception
|
||||
) as exc:
|
||||
raise Nip44LengthError(f"payload is not valid base64: {exc}") from exc
|
||||
|
||||
if len(raw) < _MIN_PAYLOAD_LEN or len(raw) > _MAX_PAYLOAD_LEN:
|
||||
|
|
@ -272,7 +275,7 @@ def encrypt_for(
|
|||
sender_privkey_hex: str,
|
||||
recipient_pubkey_hex: str,
|
||||
*,
|
||||
nonce: Optional[bytes] = None,
|
||||
nonce: bytes | None = None,
|
||||
) -> str:
|
||||
"""Encrypt `plaintext` from the sender (holding the privkey) to the recipient
|
||||
(identified by pubkey). The recipient can decrypt with `decrypt_from(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue