Adamant-im / Adamant-im/ipfs-node
[Composite] Let the uploader delete their file with a signed request + AIP
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 301
- Forks
- 3
- Avg merge
- 23h 4m
- Merged PRs (30d)
- 6
Description
Summary
Let the user who uploaded a file delete it, proven by a signature from their own ADAMANT key, and let any node verify portable content authority without confusing that authority with counted cluster membership.
Details
A node currently has no idea who uploaded a file. Upload is anonymous, so the only way to release content is an operator action with the administrative key. That makes "the uploader may delete their file" impossible to express. Replication intake also relies on a fixed peer list because the request carries no portable content authority.
A signature lets the requester prove content authority and lets every node verify that authority independently, with no shared secret. It does not prove that a node is an accepted member, a counted replica holder, or a checkpoint attester; those remain separate membership-policy decisions in #28 and #23.
Key format, confirmed from the client code
Taken from adamant-api-jsclient, src/helpers/keys.ts and src/helpers/transactions/hash.ts:
- The keypair is Ed25519, derived with
crypto_sign_seed_keypairfromsha256(bip39.mnemonicToSeedSync(passphrase).toString('hex')). The public key is 32 bytes, the secret key 64. - The client signs with
crypto_sign_detached(hash, privateKey), wherehashis the SHA-256 digest of a canonical byte serialisation — not the message itself. The result is a detached 64-byte signature. - Public keys and signatures travel as hex strings, the way
senderPublicKeyandsignaturealready do on transactions. - The account address is
Ufollowed by the big-endian number formed from the first eight bytes ofsha256(publicKey), reversed.
Two consequences for this node:
- Verification must treat the 32-byte digest as the signed message. Passing the original bytes to an Ed25519 verifier fails, because the client never signed them directly.
- No new dependency is needed:
node:cryptoverifies Ed25519 from a raw 32-byte public key imported as a JWKOKPkey.
The AIP still has to define the canonical serialisation for upload and deletion requests, since the transaction serialisation in getBytes is transaction-shaped and does not fit these messages.
Binding an owner at upload
The client already knows the file bytes and the chunking parameters are fixed and covered by test/cidCompatibility.test.ts, so it can compute the CID locally before uploading. It signs the CID with a timestamp and sends the public key and the signature with the file. The node imports the content, checks that the CID it produced is the one that was signed, and records the owner.
Deleting
The client sends the CID, a timestamp, a nonce, its public key, and a signature. The node verifies the signature, checks the key against the recorded owners, and rejects a stale or replayed request. It then releases the file locally.
The node forwards the original signed request to its peers rather than asking them to trust it. Each peer verifies the same signature itself, so no node has to be trusted by another to propagate a deletion. A node that has already deleted a file must remember that fact for a while, otherwise a peer that has not processed the request yet will replicate the file back.
Shared content
Content addressing means two users who upload identical bytes produce one CID. Ownership must therefore be a set of claims, and a deletion must remove only the requester's claim; the content is reclaimed when the set becomes empty. ADAMANT encrypts files on the client, so identical plaintext usually yields different CIDs, but the node must not depend on a property of the client protocol.
What deletion means
Deletion means the ADAMANT nodes stop serving the file and reclaim their space. Anyone who already downloaded it still has it. This limit is inherent to content-addressed storage and must be stated in the AIP rather than implied away.
Checklist
- Write the AIP: message formats, canonical signing payload, timestamp and nonce rules, ownership claims, deletion semantics, and the explicit limits of deletion
- Define the canonical byte serialisation that upload and deletion requests hash before signing
- Bind an owner at upload and verify the signed CID against the imported content
- Store ownership claims in the file registry and expose them to the lifecycle rules
- Add a signed deletion request that releases the file locally
- Propagate the original signed request to peers, so each verifies it independently
- Remember deletions long enough that a lagging peer cannot replicate the file back
- Reject replayed and stale requests
- Authorize content replication requests by owner signature while keeping counted node membership governed separately by #28
- Rate-limit and quota signed requests per key, so a valid signature cannot be used to fill a node
- Document the client-side flow and the operator-facing behaviour
Notes
Depends on the storage lifecycle and the libp2p replication control plane added in #22 and #26.
Until this lands, a node accepts replication only from the peers listed in nodes, and only an operator can release content. Both are placeholders for the signature.
Verification
- Upload with a valid signature and confirm the owner is recorded
- Upload with a signature over a different CID and confirm it is refused
- Delete with the owner key and confirm the file is released on every node, each having verified the signature itself
- Delete with a different key and confirm it is refused
- Replay a captured deletion request and confirm it is refused
- Delete content claimed by two owners and confirm it survives until the last claim is gone
- Confirm a node that was offline during a deletion does not replicate the file back when it returns
Coordination with membership and health
An owner signature authorizes a content action. It does not by itself make the submitting or storing node an accepted cluster member, a counted replica holder, or a health-check attester.
Until #28 defines versioned membership, only the configured controlled peer set may count towards placement, durability, and checkpoint coverage. After #28, those decisions must use its accepted membership version. An unknown node may verify a signed request and may serve an uncounted extra copy under policy, but it must not satisfy the required copy count or the freshness quorum merely because the content request is valid.
Coordinate this with #23: the public health checkpoint must count only accepted members for its declared membership version. Signed deletion propagation also needs a bounded delivery and reconciliation rule; health must not claim a fresh cycle while a known accepted holder has not applied an authoritative deletion.
Additional checklist
- Keep content-owner authorization separate from node membership, counted placement, and health quorum
- Define how signed deletions enter repair/reconciliation state so stale replicas cannot be silently counted as fresh
Additional verification
- Submit a valid owner-signed request through an unknown node and confirm that the request can be verified without making that node a counted holder or checkpoint attester
- Leave one accepted holder behind on a signed deletion and confirm health does not report a falsely complete reconciliation cycle
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the AIP requirements, test/cidCompatibility.test.ts, and the client references to src/helpers/keys.ts and src/helpers/transactions/hash.ts. Then inspect the storage lifecycle and libp2p replication control plane from #22 and #26, coordinating membership and health constraints with #28 and #23. Done means the checklist and verification cases pass, including independent signature verification, ownership claims, replay protection, deletion propagation, and reconciliation behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cryptography, node.js, typescript
- Domain
- api, backend-api-design, distributed-systems, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100