Skip to content

Commit 905e729

Browse files
comment
1 parent f60f221 commit 905e729

3 files changed

Lines changed: 28 additions & 7 deletions

File tree

plans/2026-08-22-xftp-file-storage-time.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ Testing:
141141

142142
- e2e test in `tests/XFTPAgent.hs`: generate a BBS keypair, sign a supporter credential (issuer key index 1), run the server with `entitlementKeys = {1: testPk}` and a supporter maximum above the default, run the sender agent with the same `entitlementKeys` and the credential for the user, send a file requesting a number of hours above the default and below that maximum, and assert `SFDONE`'s granted expiry rounds up `now + requested` (proof of the entitlement raising the max above the default)
143143
- the same upload without the credential is capped at the default maximum
144-
- store log round trip in `tests/CoreTests/StoreLogTests.hs`, in the shape of the SMP store log test: a file record survives a write, a read into the store, and compaction, including a file blocked with a notice, where the record has a field after the blocking info
144+
- the expiry is written before the status, because `BlockingInfo`'s notice parser is terminal (`A.takeByteString`), so any field after the blocking info makes the record unparseable and the file is dropped on restart. Every field added to `AddFile` must go before the status
145+
- store log round trip in `tests/CoreTests/StoreLogTests.hs`, in the shape of the SMP store log test: a file record survives a write, a read into the store, and compaction, with and without the expiry, including a file blocked with a notice in both cases
145146

146147
## simplex-chat
147148

protocol/xftp.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ This document describes XFTP protocol version 4. The version history:
5555
- v1: initial version
5656
- v2: authenticated commands - added basic auth support for commands
5757
- v3: blocked files - added BLOCKED error type for policy violations
58-
- v4: server public information in handshake
58+
- v4: server public information and entitlement proof in handshake, file storage time in FNEW and SIDS
5959

6060
The protocol describes the set of commands that senders and recipients can send to XFTP routers to create, upload, download and delete data packets of several pre-defined sizes. XFTP routers SHOULD support packets of 4 sizes: 64KB, 256KB, 1MB and 4MB (1KB = 1024 bytes, 1MB = 1024KB).
6161

@@ -330,7 +330,7 @@ Once TLS handshake is complete, client and router will exchange blocks of fixed
330330

331331
```abnf
332332
paddedRouterHello = <padded(routerHello, 16384)>
333-
routerHello = xftpVersionRange sessionIdentifier routerCerts signedRouterKey ignoredPart
333+
routerHello = xftpVersionRange sessionIdentifier routerCerts signedRouterKey webIdentityProof serverInfo ignoredPart
334334
xftpVersionRange = minXftpVersion maxXftpVersion
335335
minXftpVersion = xftpVersion
336336
maxXftpVersion = xftpVersion
@@ -339,15 +339,27 @@ sessionIdentifier = shortString
339339
routerCerts = length 1*routerCert ; NonEmpty list of certificates in chain
340340
routerCert = originalLength <x509encoded>
341341
signedRouterKey = originalLength <x509encoded> ; signed by router certificate
342+
webIdentityProof = shortString ; signature over the web client challenge and sessionIdentifier, empty when the client sent no challenge
343+
serverInfo = %s"0" / (%s"1" largeString) ; JSON server public information, sent when maxXftpVersion is 4 or above
342344
343345
paddedClientHello = <padded(clientHello, 16384)>
344-
clientHello = xftpVersion keyHash ignoredPart
346+
clientHello = xftpVersion keyHash entitlementProof ignoredPart
345347
; chosen XFTP protocol version - must be the maximum supported version
346348
; within the range offered by the router
347349
350+
entitlementProof = %s"0" / (%s"1" issuerKeyIndex bbsProof entitlement)
351+
; proof of the user entitlement, encoded from v4, bound to sessionIdentifier
352+
issuerKeyIndex = 2*2OCTET ; Word16 index of the issuer public key
353+
bbsProof = largeString
354+
entitlement = entExpires entName entExtra
355+
entExpires = shortString ; expiration as an ISO8601 UTC timestamp
356+
entName = shortString ; e.g. "supporter", "legend"
357+
entExtra = largeString ; opaque to the router
358+
348359
xftpVersion = 2*2OCTET ; Word16 version number
349360
keyHash = shortString
350361
shortString = length length*OCTET
362+
largeString = originalLength *OCTET
351363
length = 1*1OCTET
352364
originalLength = 2*2OCTET
353365
ignoredPart = *OCTET
@@ -433,27 +445,35 @@ Routers SHOULD support basic auth with this command, to allow only router owners
433445
The syntax is:
434446

435447
```abnf
436-
register = %s"FNEW " fileInfo rcvPublicAuthKeys basicAuth
448+
register = %s"FNEW " fileInfo rcvPublicAuthKeys basicAuth fileStorageTime
437449
fileInfo = sndKey size digest
438450
sndKey = length x509encoded
439451
size = 4*4 OCTET ; Word32 big-endian
440452
digest = length *OCTET
441453
rcvPublicAuthKeys = length 1*rcvPublicAuthKey
442454
rcvPublicAuthKey = length x509encoded
443455
basicAuth = "0" / "1" length *OCTET
456+
fileStorageTime = %s"0" / (%s"1" storageHours)
457+
; encoded from v4; absent or zero requests the maximum the router allows
458+
storageHours = 4*4 OCTET ; Word32 big-endian
444459
445460
x509encoded = <binary X509 key encoding>
446461
447462
length = 1*1 OCTET
448463
```
449464

465+
`fileStorageTime` requests how long the router stores the data packet. The router grants the smaller of the request and the maximum it allows for the entitlement presented in the handshake, and returns the granted expiration in `sndIds`.
466+
450467
If the data packet is registered successfully, the router must send `sndIds` response with the sender's and recipients' data packet IDs:
451468

452469
```abnf
453-
sndIds = %s"SIDS " senderId recipientIds
470+
sndIds = %s"SIDS " senderId recipientIds grantedStorageTime
454471
senderId = length *OCTET
455472
recipientIds = length 1*recipientId
456473
recipientId = length *OCTET
474+
grantedStorageTime = %s"0" / (%s"1" grantedExpires) ; encoded from v4
475+
grantedExpires = %s"T" expiresAt
476+
expiresAt = 8*8 OCTET ; Int64 big-endian, seconds since epoch
457477
```
458478

459479
#### Add data packet recipients

src/Simplex/FileTransfer/Transport.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ data XFTPServerHandshake = XFTPServerHandshake
129129
authPubKey :: CertChainPubKey,
130130
-- | signed identity challenge from XFTPClientHello
131131
webIdentityProof :: Maybe C.ASignature,
132-
-- | optional server public information (JSON-encoded ServerPublicInfo), sent when version >= serverInfoXFTPVersion
132+
-- | optional server public information (JSON-encoded ServerPublicInfo), sent when version >= fileStorageTimeXFTPVersion
133133
serverInfoBytes :: Maybe ByteString
134134
}
135135

0 commit comments

Comments
 (0)