xftp server: support storage time and BBS proofs of badge credential to extend it - #1856
xftp server: support storage time and BBS proofs of badge credential to extend it#1856epoberezkin wants to merge 14 commits into
Conversation
408679e to
4989bd8
Compare
66a325a to
add6542
Compare
8f2984c to
0df161a
Compare
There was a problem hiding this comment.
Summary
Adds per-file storage time to XFTP (new protocol version 4) plus BBS-based entitlement proofs that raise the server's maximum storage time. The change is careful and internally consistent: version gating on FNEW/SIDS is symmetric between encode and decode, the STM and Postgres expiredFiles predicates agree (stored expires_at < now; legacy rows via created_at + fileTimePrecision < old / created_at < old - fileTimePrecision), the store-log format stays backward compatible (absent expires_at parses to Nothing), and the CSV export/import column order matches the new schema. The proof is bound to sessionId <> sndKey <> digest, reconstructed server-side from the FNEW fields, which structurally prevents replay across sessions or chunks. Verification failure, unknown issuer key, and an entitlement expired past the 24h grace all fall back to the default maximum — fail-safe. The server storage bound is preserved even under hours * 3600 overflow because min (…) maxSeconds caps it regardless.
No blocking defects found. Notes below.
Privacy: disclosed entitlement attributes bound the anonymity set
BBS proofs are unlinkable by construction (testBBSUnlinkable), which is why they were chosen over a plain signature. But that unlinkability is only as strong as the disclosed attributes are coarse. The proof discloses expiresAt, entitlementName, and extraInfo (indexes 1–3), and expiresAt is encoded at full ISO8601 precision. If the issuer sets expiresAt per-user (e.g. purchase instant + 1 year, to the second), then the disclosed (name, expiresAt, extraInfo) tuple is identical across all of that user's uploads and effectively re-links them — defeating the proof unlinkability at the application layer. The XFTP server only needs expiresAt to evaluate the 24h grace, so day-granularity would suffice. This is issuer policy (scoped out of the RFC), not a code fix in simplexmq, but worth stating explicitly: the entitlement service must issue coarse expiresAt and avoid per-user extraInfo, or the anonymity set collapses to one. extraInfo is disclosed for peer-badge verification (chat), so the XFTP server receives it even though it ignores it — extra disclosure to the file server.
Minor
- RFC wording:
entExpires = shortString ; expiration, encoded as signeddoes not match the implementation, which encodesexpiresAt :: UTCTimeas an ISO8601 string viastrEncode. Inline suggestion below. Note this is also inconsistent withgrantedExpires, which uses Int64 epoch seconds. iniEntitlementssilently drops a malformedexpire_files_hours_for_*value (readMaybe → Nothing → entitlement absent → default max at runtime). Safe (default is the floor) but a silent config error; consider failing startup as the below-default check already does.createFiledoes not reject a negative or zero requestedstorageTime; the result expires immediately or at the next hour. Self-harming only, server bound intact — no action needed.
| entName = shortString ; e.g. "supporter", "legend" | ||
| entExpires = shortString ; expiration, encoded as signed | ||
| entExtra = shortString ; opaque, interpretation out of scope |
There was a problem hiding this comment.
The disclosed expiresAt message and the Entitlement Encoding both use strEncode on a UTCTime, which is iso8601Show (an ISO8601 string), not a signed integer. The RFC comment "encoded as signed" would mislead anyone implementing an interoperating issuer or verifier. Fixed to describe the actual encoding.
| entName = shortString ; e.g. "supporter", "legend" | |
| entExpires = shortString ; expiration, encoded as signed | |
| entExtra = shortString ; opaque, interpretation out of scope | |
| entName = shortString ; e.g. "supporter", "legend" | |
| entExpires = shortString ; expiration, ISO8601 UTC string | |
| entExtra = shortString ; opaque, interpretation out of scope |
No description provided.