betterwithage commited on
Commit
085560d
·
verified ·
1 Parent(s): 5e0b102

chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)

Browse files

Automated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): szl_connectors/base.py, szl_connectors/oauth.py
Deleted (gone from the repo + Dockerfile COPY set): (none)

Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.

Files changed (2) hide show
  1. szl_connectors/base.py +20 -2
  2. szl_connectors/oauth.py +16 -1
szl_connectors/base.py CHANGED
@@ -154,9 +154,27 @@ def http_text(url: str, headers: dict | None = None, timeout: float = _TIMEOUT)
154
  return 0, str(e)
155
 
156
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  def cred_fingerprint(value: str) -> str:
158
- """SHA-256 fingerprint of a credential — what a receipt may carry. NEVER the value."""
159
- return "sha256:" + hashlib.sha256(value.encode("utf-8")).hexdigest()[:32]
 
 
 
 
 
 
160
 
161
 
162
  # ── the honesty core — resolve_state() ─────────────────────────────────────
 
154
  return 0, str(e)
155
 
156
 
157
+ # Credential fingerprints are derived with PBKDF2-HMAC-SHA256, not a single
158
+ # SHA-256 pass. A bare hash of a (possibly low-entropy) credential is cheap to
159
+ # brute-force / rainbow-table from the fingerprint alone (CodeQL
160
+ # py/weak-sensitive-data-hashing). The fixed domain-separation salt keeps the
161
+ # fingerprint DETERMINISTIC — the same credential always maps to the same
162
+ # fingerprint, which is the whole point of a correlation fingerprint — while the
163
+ # work factor makes recovery expensive. An optional deployment pepper
164
+ # (SZL_FINGERPRINT_PEPPER) adds a keyed secret an attacker cannot precompute.
165
+ _CRED_FP_SALT = b"szl.killinchu.cred-fingerprint.v1"
166
+ _CRED_FP_ITERATIONS = 200_000
167
+
168
+
169
  def cred_fingerprint(value: str) -> str:
170
+ """Brute-force-resistant fingerprint of a credential — what a receipt may
171
+ carry. NEVER the value. PBKDF2-HMAC-SHA256 over a deterministic salt (+ the
172
+ optional SZL_FINGERPRINT_PEPPER) so a low-entropy credential cannot be
173
+ recovered from its fingerprint, yet the same credential always maps to the
174
+ same fingerprint."""
175
+ salt = _CRED_FP_SALT + os.environ.get("SZL_FINGERPRINT_PEPPER", "").encode("utf-8")
176
+ dk = hashlib.pbkdf2_hmac("sha256", value.encode("utf-8"), salt, _CRED_FP_ITERATIONS)
177
+ return "pbkdf2-sha256:" + dk.hex()[:32]
178
 
179
 
180
  # ── the honesty core — resolve_state() ─────────────────────────────────────
szl_connectors/oauth.py CHANGED
@@ -92,11 +92,26 @@ PROVIDER_OAUTH: dict[str, dict[str, str]] = {
92
  }
93
 
94
 
 
 
 
 
 
 
95
  def _state_secret() -> bytes:
96
  # signed-state nonce key: reuse the cosign-adjacent secret if present, else a
97
  # per-process ephemeral key (state still verifiable within the process).
 
 
 
 
 
98
  s = os.environ.get("SZL_OAUTH_STATE_SECRET") or os.environ.get("SZL_COSIGN_PRIVATE_PEM") or "szl-oauth-ephemeral"
99
- return hashlib.sha256(s.encode()).digest()
 
 
 
 
100
 
101
 
102
  def _b64u(b: bytes) -> str:
 
92
  }
93
 
94
 
95
+ # Domain-separation salt + work factor for deriving the state-signing key.
96
+ _STATE_KDF_SALT = b"szl.killinchu.oauth-state.v1"
97
+ _STATE_KDF_ITERATIONS = 200_000
98
+ _STATE_KEY_CACHE: dict[str, bytes] = {}
99
+
100
+
101
  def _state_secret() -> bytes:
102
  # signed-state nonce key: reuse the cosign-adjacent secret if present, else a
103
  # per-process ephemeral key (state still verifiable within the process).
104
+ # Stretched with PBKDF2-HMAC-SHA256 rather than a single SHA-256 pass so a
105
+ # low-entropy secret (e.g. the ephemeral fallback) cannot be cheaply
106
+ # brute-forced from a leaked state signature (CodeQL
107
+ # py/weak-sensitive-data-hashing). Cached per secret so the stretch is a
108
+ # one-time cost while still honouring a changed secret.
109
  s = os.environ.get("SZL_OAUTH_STATE_SECRET") or os.environ.get("SZL_COSIGN_PRIVATE_PEM") or "szl-oauth-ephemeral"
110
+ key = _STATE_KEY_CACHE.get(s)
111
+ if key is None:
112
+ key = hashlib.pbkdf2_hmac("sha256", s.encode(), _STATE_KDF_SALT, _STATE_KDF_ITERATIONS)
113
+ _STATE_KEY_CACHE[s] = key
114
+ return key
115
 
116
 
117
  def _b64u(b: bytes) -> str: