storacha / w3name

IPNS client and service for generating, updating, and tracking immutable names with signed updates
Other
45 stars 12 forks source link

Create an example of w3name using the HTTP API with Kubo CLI. #91

Open joshJarr opened 2 years ago

joshJarr commented 2 years ago

We currently have little tangible documentation on how to use the w3name HTTP API in tandem with the Kubo CLI. This would be useful for builds that cannot use the Node client library.

mbommerez commented 2 years ago

Need to investigate whether this is a regular request & it warrants looking into.

mbommerez commented 2 years ago

There are a few options:

mbommerez commented 2 years ago

The five steps we currently use to explain this to users:

When creating a new record:

  1. Generate a key pair (we use libp2p-crypto to do this, but any way to make a Ed25519 pair will work). Sounds like you’ve done this!
  2. Next we need to create the IPNS entry, assigning the public key, IPFS content path, sequence number, and validity date. The client uses the IPNS package to do this on publish (see the JS client implementation for more on this) - sounds like you have done this too!
  3. Format the data: In the JS client, the entry is formatted and returned for us from the IPNS package (see IPNS.create). IPNS should return the entry for you in this format:
{
  value: Uint8Array,
  signature: Uint8Array,
  validityType: 0,
  validity: Uint8Array,
  sequence: 2
}
  1. Now the data should be good, you’ll need to marshal the entry with proto buffer. in the JS client we use ipns.marshal.
  2. Finally you should be able to POST this entry to /name/{public_key} as a string, to do this stringify the marshalled entry to a base64paded string (see JS client for how we do this)
mbommerez commented 2 years ago

Let's start with updating the YAML file with all the necessary steps https://web3.storage/docs/reference/w3name-http-api/

francois-potato commented 2 years ago

Testing manual IPNS creation with CLI tools:

Create a name and copy the outputted k5 key

ipfs key gen test

Export the private key to a file

ipfs key export --format pem-pkcs8-cleartext --output test.key test

Create an Protobuf definition ipns.proto file with the following content

syntax = "proto2";

message IpnsEntry {
 enum ValidityType {
  // setting an EOL says "this record is valid until..."
  EOL = 0;
 }

 // deserialized copy of data[value]
 optional bytes value = 1;

 // legacy field, verify 'signatureV2' instead
 optional bytes signatureV1 = 2;

 // deserialized copies of data[validityType] and data[validity]
 optional ValidityType validityType = 3;
 optional bytes validity = 4;

 // deserialized copy of data[sequence]
 optional uint64 sequence = 5;

 // record TTL in nanoseconds, a deserialized copy of data[ttl]
 optional uint64 ttl = 6;

 // in order for nodes to properly validate a record upon receipt, they need the public
 // key associated with it. For old RSA keys, its easiest if we just send this as part of
 // the record itself. For newer Ed25519 keys, the public key can be embedded in the
 // IPNS Name itself, making this field unnecessary.
 optional bytes pubKey = 7;

 // the signature of the IPNS record
 optional bytes signatureV2 = 8;

 // extensible record data in DAG-CBOR format
 optional bytes data = 9;
}

Create a example.json

{
  "value": "bafybeic7zrcqvhanfwl4o7ei3565o55ovu7bnrqdocumj6pg6s6dfskpvy",
  "validity": "2023-01-01T00:00:00.000000001Z",
  "validityType": 0,
  "sequence": 1,
  "ttl": 999
}

Install npm install cbor-cli and protobuf

Serialize example.json to CBOR

echo "69706e732d7369676e61747572653a"$(npx json2cbor example.json) > signatureV2

Sign, this is the value of signatureV2

openssl pkeyutl -sign -inkey test.key -rawin -in signatureV2 | openssl enc -base64

Create an example.data file. The data field is the serialised CBOR from example.json

validity: "2023-01-01T00:00:00.000000001Z",
value: "bafybeic7zrcqvhanfwl4o7ei3565o55ovu7bnrqdocumj6pg6s6dfskpvy"
signatureV2: "NnxTpcQW94FMuDeRN088vmlewEw0kNGRHRydBEEft4VnIUMa/mB+2iaGjvUy4/1n\nYq86BxTAn4GL8U7qpzPzCA=="
sequence: 1
ttl: 999
pubKey: "k51qzi5uqu5dh4ui598wd8hnuqck51hoqld4ojqoq6j6keun25p6s2t7lro78a"
data: "69706e732d7369676e61747572653aa56576616c7565783b6261667962656963377a7263717668616e66776c346f376569333536356f35356f767537626e7271646f63756d6a3670673673366466736b7076796876616c6964697479781e323032332d30312d30315430303a30303a30302e3030303030303030315a6c76616c696469747954797065006873657175656e6365016374746c1903e7"

Encode example.data with ProtoBuf

cat example.data | protoc ipns.proto --encode=IpnsEntry | basenc --base64url > entry.serialised.base64  

POST to w3name

curl -X POST --data '@entry.serialised.base64' https://name.web3.storage/name/k51qzi5uqu5dh4ui598wd8hnuqck51hoqld4ojqoq6j6keun25p6s2t7lro78a