Verification Rules
Normative rules for validating EWP operations. Implementations MUST perform all listed checks before mutating any state.
CreateConnection
Target: POST /ewp/connections
typedDataandsignatureMUST be present and structurally validfollowerAddress,followeeAddress,followeeUrl,followerUrl, andtimestampMUST all be presentfollowerUrlandfolloweeUrlMUST be validhttps://URLs- Recover signer address from
signature; MUST equalfollowerAddress timestampMUST be within ±1 hour of the receiver's current time- Fetch
GET /ewp/profilefromfolloweeUrl; returnedaddressMUST equalfolloweeAddress - Fetch
GET /ewp/profilefromfollowerUrl; returnedaddressMUST equalfollowerAddress - A connection record with this
(followerAddress, followeeAddress)pair MUST NOT already exist - Create connection record
Without verifying followerUrl, an attacker could submit a valid follow request with an arbitrary target URL as followerUrl, causing the followee to direct all replication notifications at an unintended endpoint. This is both a misdirection attack and a DDoS amplification vector.
DestroyConnection
Target: DELETE /ewp/connections
typedDataandsignatureMUST be presentfollowerAddress,followeeAddress, andtimestampMUST be present- Recover signer address from
signature - Recovered signer MUST equal
followerAddressORfolloweeAddress; otherwise reject withINVALID_SIGNATURE timestampMUST be within ±1 hour of the receiver's current time- Locate the connection record matching
(followerAddress, followeeAddress); if not found, return404 CONNECTION_NOT_FOUND - If the connection record's
createdAt>message.timestamp, return409 STALE_REQUESTand stop - Delete the connection record
StatementOfSource (Inbound Publication)
Target: POST /ewp/publications
typedDataandsignatureMUST be present and structurally validcontentHash,publisherAddress, andtimestampMUST be presentpublisherAddressMUST correspond to a node in the receiver's follow list- Recover signer; MUST equal
publisherAddress - If a publication with
(contentHash, publisherAddress, timestamp)already exists locally, return409 REPLICATION_ALREADY_EXISTSand stop - Return
202 Accepted - Asynchronously: if
X-Epress-Node-Updatedis present and newer than locally cachedupdatedAt, refresh the publisher's profile before fetching content - Asynchronously: fetch
GET /ewp/contents/<contentHash>?timestamp=<timestamp>from the publisher's cached URL; if the fetch fails and no header was present, re-fetch profile and retry once - Asynchronously: compute SHA-256 of the fetched body; MUST equal
contentHash; if mismatch, discard and log error - Asynchronously: persist the Content Unit and publication record
NodeProfileUpdate
Target: PATCH /ewp/nodes/:address
typedDataandsignatureMUST be present- Path
:addressMUST equaltypedData.message.ownerAddress - Recover signer; MUST equal
ownerAddress - If
typedData.message.urldiffers from the locally cached URL:- Fetch
GET /ewp/profilefrom the new URL - Returned
addressMUST equalownerAddress - If this check fails, reject the
urlfield; other fields MAY still be applied
- Fetch
- Apply the update only if
timestamp> locally storedupdatedAt
Connection Staleness Check
DestroyConnection requests are rejected if the targeted connection was established after the termination was signed.
Rule: If connection.createdAt > message.timestamp, return 409 STALE_REQUEST.
This prevents delayed or replayed termination from destroying a connection that was re-established in the interim.
Content Hash Verification
For content integrity:
- Compute SHA-256 of UTF-8 encoded content body (POST) or raw bytes (FILE)
- Compare against
contentHashin the StatementOfSource - Verify match before accepting publication