Skip to content

xftp server: support storage time and BBS proofs of badge credential to extend it - #1856

Open
epoberezkin wants to merge 14 commits into
masterfrom
ep/badges-xftp
Open

xftp server: support storage time and BBS proofs of badge credential to extend it#1856
epoberezkin wants to merge 14 commits into
masterfrom
ep/badges-xftp

Conversation

@epoberezkin

Copy link
Copy Markdown
Member

No description provided.

@simplex-chat-agent simplex-chat-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 signed does not match the implementation, which encodes expiresAt :: UTCTime as an ISO8601 string via strEncode. Inline suggestion below. Note this is also inconsistent with grantedExpires, which uses Int64 epoch seconds.
  • iniEntitlements silently drops a malformed expire_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.
  • createFile does not reject a negative or zero requested storageTime; the result expires immediately or at the next hour. Self-harming only, server bound intact — no action needed.

Comment on lines +15 to +17
entName = shortString ; e.g. "supporter", "legend"
entExpires = shortString ; expiration, encoded as signed
entExtra = shortString ; opaque, interpretation out of scope

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants