From b067e328d019b4ad22ae2545c1d6bf7dc3fa7ba9 Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Tue, 23 May 2023 17:28:39 +0200 Subject: [PATCH] t0114: implement the ipns fixtures + related tests --- ...XSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record | Bin 0 -> 394 bytes ...8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record | Bin 0 -> 1082 bytes fixtures/t0114/README.md | 111 +++++++ fixtures/t0114/fixtures.car | Bin 0 -> 1518 bytes tests/t0114_gateway_subdomains_test.go | 290 ++++++++++-------- ...XSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record | Bin 0 -> 394 bytes ...8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record | Bin 0 -> 1082 bytes tooling/ipns/ipns_test.go | 29 ++ tooling/ipns/record.go | 54 +++- 9 files changed, 360 insertions(+), 124 deletions(-) create mode 100644 fixtures/t0114/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record create mode 100644 fixtures/t0114/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record create mode 100644 fixtures/t0114/README.md create mode 100644 fixtures/t0114/fixtures.car create mode 100644 tooling/ipns/_fixtures/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record create mode 100644 tooling/ipns/_fixtures/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record diff --git a/fixtures/t0114/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record b/fixtures/t0114/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record new file mode 100644 index 0000000000000000000000000000000000000000..39b2f41a40866132588557e1be7beb97f50b79d4 GIT binary patch literal 394 zcmd;b)XywPE7ng+Ov^4x%}lN=PB${n&MYr8Hc3r4N--}iPt7c-D9<^J}Yul1#e?Les=qsP9*TpHppd@W%Xk@HwV4`bi6k=#> zWnyAwYN=;oU}$b+5v9Rk(9qDcxZ%Nrr`k>qKjaU!b6-4rYi;`fm-}a{vCo?xRu}4g z^l|FihwZAz%U!lw{rY|+(EGO7p=OmC>knNP>?`)U^*Whrs^fvF0qEJ$Sl0Mn+K ATmS$7 literal 0 HcmV?d00001 diff --git a/fixtures/t0114/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record b/fixtures/t0114/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record new file mode 100644 index 0000000000000000000000000000000000000000..b37d9b75b50ce3baa472e0c790c63cc4476c8631 GIT binary patch literal 1082 zcmd;b)XywPE7ng+Ov^4x%}lN=PB${n&MYr8Hc3r4N--}iPt7c-D92(*IMXR5Go)>GsSynodq(GRGFw`JL;^nAdmmZe7@< z?;9u0)~oe;B6n8l#B-O4jHLznwHFfawsGeD^WdI5dD6CW_D`?(IR6u4yS}n>0Xs|C zV|Deu10TJ;+15H9y#1%w)-Pu|{~C5NEh+2ohgE%4GcFi^=!o1|c=mvclzM~Aq?sH1 zV;9|>pJ(C4b;k1K_pY`7N=jcyC2D2fRy9#Bx;b;nX--YmkL>f5|4X=(dm6Aa@2=jn zPF^r?@jIi2gJJgHoU|F^9$YA16dbkmCI8(bi=coUk?re*CGPIOm;0ZgQ?hD>F0X=C zL#OarR>@Lloz*!)FR?K>|cBO@yVa}y&! z15licsfm%1;pVJGT^wtTb=KA$^<13Nv3!=^X2&xt9)0ASbyDGP?WdlXx7q)`d@Z+h z!6|`%_KMwXk1o8Mo?{-MVA*x}^cm9=t?8#{Bqsazy{TE_Y}T4V{h&^m3)r^)bGv-5U2WMvuSX z7vtkGPzgn;O5JiMe~&<38&ZhUC?flR8gS@+~<#_0!o~ z@AZ8}8?WuOn%~@gsOVv8C3nV1oCd(eK6PTncvj@)S}Wr`}S-X)$F5@;ne3PMT?z z=NIb*B<2n+zLRAc6lAY~eeG%iDJwNZBx`P>1GC& uWCn)RutZ?qi=aH?W(21e0yA-PDnka)$jp??lFA5t$v6k5Dx|U?l>q?Oq1V#@ literal 0 HcmV?d00001 diff --git a/fixtures/t0114/README.md b/fixtures/t0114/README.md new file mode 100644 index 000000000..005a7f0c5 --- /dev/null +++ b/fixtures/t0114/README.md @@ -0,0 +1,111 @@ +# Dataset description/sources + +- fixtures.car + - raw CARv1 + +- QmUKd....ipns-record + - ipns record, encoded with protocol buffer + +- 12D3K....ipns-record + - ipns record, encoded with protocol buffer + +Generated with: + +```sh +# using ipfs version 0.21.0-dev (03a98280e3e642774776cd3d0435ab53e5dfa867) + +# CIDv0to1 is necessary because raw-leaves are enabled by default during +# "ipfs add" with CIDv1 and disabled with CIDv0 +CID_VAL="hello" +CIDv1=$(echo $CID_VAL | ipfs add --cid-version 1 -Q) +CIDv0=$(echo $CID_VAL | ipfs add --cid-version 0 -Q) +CIDv0to1=$(echo "$CIDv0" | ipfs cid base32) +# sha512 will be over 63char limit, even when represented in Base36 +CIDv1_TOO_LONG=$(echo $CID_VAL | ipfs add --cid-version 1 --hash sha2-512 -Q) + +echo CID_VAL=${CID_VAL} +echo CIDv1=${CIDv1} +echo CIDv0=${CIDv0} +echo CIDv0to1=${CIDv0to1} +echo CIDv1_TOO_LONG=${CIDv1_TOO_LONG} + +# Directory tree crafted to test for edge cases like "/ipfs/ipfs/ipns/bar" +mkdir -p testdirlisting/ipfs/ipns && +echo "hello" > testdirlisting/hello && +echo "text-file-content" > testdirlisting/ipfs/ipns/bar && +mkdir -p testdirlisting/api && +mkdir -p testdirlisting/ipfs && +echo "I am a txt file" > testdirlisting/api/file.txt && +echo "I am a txt file" > testdirlisting/ipfs/file.txt && +DIR_CID=$(ipfs add -Qr --cid-version 1 testdirlisting) + +echo DIR_CID=${DIR_CID} # ./testdirlisting + +ipfs files mkdir /t0114/ +ipfs files cp /ipfs/${CIDv1} /t0114/ +ipfs files cp /ipfs/${CIDv0} /t0114/ +ipfs files cp /ipfs/${CIDv0to1} /t0114/ +ipfs files cp /ipfs/${DIR_CID} /t0114/ +ipfs files cp /ipfs/${CIDv1_TOO_LONG} /t0114/ + +ROOT=`ipfs files stat /t0114/ --hash` + +ipfs dag export ${ROOT} > ./fixtures.car + +# Then the keys + +KEY_NAME=test_key_rsa_$RANDOM +RSA_KEY=$(ipfs key gen --ipns-base=b58mh --type=rsa --size=2048 ${KEY_NAME} | head -n1 | tr -d "\n") +RSA_IPNS_IDv0=$(echo "$RSA_KEY" | ipfs cid format -v 0) +RSA_IPNS_IDv1=$(echo "$RSA_KEY" | ipfs cid format -v 1 --mc libp2p-key -b base36) +RSA_IPNS_IDv1_DAGPB=$(echo "$RSA_IPNS_IDv0" | ipfs cid format -v 1 -b base36) + +# publish a record valid for a 100 years +ipfs name publish --key ${KEY_NAME} --allow-offline -Q --ttl=876600h --lifetime=876600h "/ipfs/$CIDv1" +ipfs routing get /ipns/${RSA_KEY} > ${RSA_KEY}.ipns-record + +echo RSA_KEY=${RSA_KEY} +echo RSA_IPNS_IDv0=${RSA_IPNS_IDv0} +echo RSA_IPNS_IDv1=${RSA_IPNS_IDv1} +echo RSA_IPNS_IDv1_DAGPB=${RSA_IPNS_IDv1_DAGPB} + +KEY_NAME=test_key_ed25519_$RANDOM +ED25519_KEY=$(ipfs key gen --ipns-base=b58mh --type=ed25519 ${KEY_NAME} | head -n1 | tr -d "\n") +ED25519_IPNS_IDv0=$ED25519_KEY +ED25519_IPNS_IDv1=$(ipfs key list -l --ipns-base=base36 | grep ${KEY_NAME} | cut -d " " -f1 | tr -d "\n") +ED25519_IPNS_IDv1_DAGPB=$(echo "$ED25519_IPNS_IDv1" | ipfs cid format -v 1 -b base36 --mc dag-pb) + +# ed25519 fits under 63 char limit when represented in base36 +IPNS_ED25519_B58MH=$(ipfs key list -l --ipns-base b58mh | grep $KEY_NAME | cut -d" " -f1 | tr -d "\n") +IPNS_ED25519_B36CID=$(ipfs key list -l --ipns-base base36 | grep $KEY_NAME | cut -d" " -f1 | tr -d "\n") + +# publish a record valid for a 100 years +ipfs name publish --key ${KEY_NAME} --allow-offline -Q --ttl=876600h --lifetime=876600h "/ipfs/$CIDv1" +ipfs routing get /ipns/${ED25519_KEY} > ${ED25519_KEY}.ipns-record + +echo ED25519_KEY=${ED25519_KEY} +echo ED25519_IPNS_IDv0=${ED25519_IPNS_IDv0} +echo ED25519_IPNS_IDv1=${ED25519_IPNS_IDv1} +echo ED25519_IPNS_IDv1_DAGPB=${ED25519_IPNS_IDv1_DAGPB} +echo IPNS_ED25519_B58MH=${IPNS_ED25519_B58MH} +echo IPNS_ED25519_B36CID=${IPNS_ED25519_B36CID} + +# CID_VAL=hello +# CIDv1=bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am +# CIDv0=QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN +# CIDv0to1=bafybeiffndsajwhk3lwjewwdxqntmjm4b5wxaaanokonsggenkbw6slwk4 +# CIDv1_TOO_LONG=bafkrgqhhyivzstcz3hhswshfjgy6ertgmnqeleynhwt4dlfsthi4hn7zgh4uvlsb5xncykzapi3ocd4lzogukir6ksdy6wzrnz6ohnv4aglcs +# DIR_CID=bafybeiht6dtwk3les7vqm6ibpvz6qpohidvlshsfyr7l5mpysdw2vmbbhe # ./testdirlisting + +# RSA_KEY=QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3 +# RSA_IPNS_IDv0=QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3 +# RSA_IPNS_IDv1=k2k4r8m7xvggw5pxxk3abrkwyer625hg01hfyggrai7lk1m63fuihi7w +# RSA_IPNS_IDv1_DAGPB=k2jmtxu61bnhrtj301lw7zizknztocdbeqhxgv76l2q9t36fn9jbzipo + +# ED25519_KEY=12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d +# ED25519_IPNS_IDv0=12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d +# ED25519_IPNS_IDv1=k51qzi5uqu5dk3v4rmjber23h16xnr23bsggmqqil9z2gduiis5se8dht36dam +# ED25519_IPNS_IDv1_DAGPB=k50rm9yjlt0jey4fqg6wafvqprktgbkpgkqdg27tpqje6iimzxewnhvtin9hhq +# IPNS_ED25519_B58MH=12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d +# IPNS_ED25519_B36CID=k51qzi5uqu5dk3v4rmjber23h16xnr23bsggmqqil9z2gduiis5se8dht36dam +``` diff --git a/fixtures/t0114/fixtures.car b/fixtures/t0114/fixtures.car new file mode 100644 index 0000000000000000000000000000000000000000..bc7b913dfa27573c76673744a7d15df6a885e891 GIT binary patch literal 1518 zcmb`GeQXnD9LKqJF0;ypXM$%)qznuxqXXLO6<<(B>E0+~lC3KP)VtnuFTJ<6&-Jc% zAZ8emC~AekvSdRu6%$2pDmVyKbW4oUh*Ouak!YMEFO$(kV@4F?-TIe*wK4wxe1E_1 z_w)Tds|P?zQB>G{VOezX9MmN~(GT9Z{qdnmvbArh-#syZWbfg+Tan$T4@h55eY@f; ztAP~c6&blvUi>i{an_)&H@Tn7FI=1Wb${3JnFYlCebrK8&fHYrI5rZ0MrqbM(YnW^ zu8yz}42300@JCyjAlohnjRv+pl3BNTUDR0L)Y!N&qJ$g5d^FUGRiVJS1nEFs(N|8K zs2TgAQmW1m&iixxn*|^Km5d$7zuvuP;7Y?EIS2X>MKVGP@G%3jUZ240nhyu8mkuO# zz$Y@g0%^sYFmRF9aIZ{}X*MmUf$Y}^Qo<_GA;h^J>9~9C_)FH>jS%Uy6m6hZq5P>0cx{A{x167X4IXPgm9G=!hNcl5z z%n(d6!TXdLjfVQ>ldKqnmUWv@q6GFfA%g-u!^kuw<2on! zL_H34oz5g>Rf_#$dF}$EKoWDMP0zHBACLO-}0A%ME6Wp7|2ub%9_vC zUORPPXk=Gza3*{G?e`WvFk6JZhEoYz)vX->2DGF^@Ki!GiDW|Ic-o4|LB>c0M8A|U zAgy~fiJ~}wz2-oNnG5tU7n~W9Hr?-NQS^b33-9l?*R}IyIwW^X%ccU0^X$ zvx}5mq{|YyY_)UWEX<-I{(~j7t^mm0H@&Is{G{{mu_pNH>0R@m?J@7lwGC|;xu>Q5 zokxEewE@Wx3)vAmZ9YW>cC%L0g@>Q_W*sNTZUpY|gtsF3{I*8<`0M+oyE~6==;=-O cqYjEpVW>TqDCNBhGOEXh;)yA;3S`y!570JmG5`Po literal 0 HcmV?d00001 diff --git a/tests/t0114_gateway_subdomains_test.go b/tests/t0114_gateway_subdomains_test.go index 1bec50ed6..89c440597 100644 --- a/tests/t0114_gateway_subdomains_test.go +++ b/tests/t0114_gateway_subdomains_test.go @@ -7,8 +7,11 @@ import ( "github.com/ipfs/gateway-conformance/tooling/car" . "github.com/ipfs/gateway-conformance/tooling/check" "github.com/ipfs/gateway-conformance/tooling/helpers" + "github.com/ipfs/gateway-conformance/tooling/ipns" "github.com/ipfs/gateway-conformance/tooling/specs" . "github.com/ipfs/gateway-conformance/tooling/test" + "github.com/multiformats/go-multibase" + "github.com/multiformats/go-multicodec" ) func TestGatewaySubdomains(t *testing.T) { @@ -278,153 +281,200 @@ func TestGatewaySubdomains(t *testing.T) { func TestGatewaySubdomainAndIPNS(t *testing.T) { tests := SugarTests{} + rsaFixture := ipns.MustOpenIPNSRecordWithKey("t0114/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record") + ed25519Fixture := ipns.MustOpenIPNSRecordWithKey("t0114/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record") + + car := car.MustOpenUnixfsCar("t0114/fixtures.car") + helloCID := "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am" + payload := string(car.MustGetRawData(helloCID)) + // We're going to run the same test against multiple gateways (localhost, and a subdomain gateway) gatewayURLs := []string{ SubdomainGatewayURL, SubdomainLocalhostGatewayURL, } + ipnsRecords := []*ipns.IpnsRecord{ + rsaFixture, + ed25519Fixture, + } + for _, gatewayURL := range gatewayURLs { - _, err := url.Parse(gatewayURL) + u, err := url.Parse(gatewayURL) if err != nil { t.Fatal(err) } - tests = append(tests, SugarTests{ - // # /ipns/ - - // test_localhost_gateway_response_should_contain \ - // "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ - // "http://localhost:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ - // "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" - - // test_localhost_gateway_response_should_contain \ - // "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ - // "http://localhost:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ - // "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" - - // # *.ipns.localhost - - // # .ipns.localhost - - // test_localhost_gateway_response_should_contain \ - // "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ - // "http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ - // "$CID_VAL" - - // test_localhost_gateway_response_should_contain \ - // "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ - // "http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ - // "$CID_VAL" - - // test_localhost_gateway_response_should_contain \ - // "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ - // "http://${RSA_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ - // "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" - - // test_localhost_gateway_response_should_contain \ - // "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ - // "http://${ED25519_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ - // "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" - - // # example.com/ipns/ - - // test_hostname_gateway_response_should_contain \ - // "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ - // "example.com" \ - // "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ - // "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" - - // test_hostname_gateway_response_should_contain \ - // "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ - // "example.com" \ - // "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ - // "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" - - // # *.ipns.example.com - // # ============================================================================ - - // # .ipns.example.com - - // test_hostname_gateway_response_should_contain \ - // "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ - // "${RSA_IPNS_IDv1}.ipns.example.com" \ - // "http://127.0.0.1:$GWAY_PORT" \ - // "$CID_VAL" - - // test_hostname_gateway_response_should_contain \ - // "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ - // "${ED25519_IPNS_IDv1}.ipns.example.com" \ - // "http://127.0.0.1:$GWAY_PORT" \ - // "$CID_VAL" - - // test_hostname_gateway_response_should_contain \ - // "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ - // "${RSA_IPNS_IDv1_DAGPB}.ipns.example.com" \ - // "http://127.0.0.1:$GWAY_PORT" \ - // "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" - - // test_hostname_gateway_response_should_contain \ - // "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ - // "${ED25519_IPNS_IDv1_DAGPB}.ipns.example.com" \ - // "http://127.0.0.1:$GWAY_PORT" \ - // "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" + for _, record := range ipnsRecords { + tests = append(tests, SugarTests{ + // # /ipns/ + // test_localhost_gateway_response_should_contain \ + // "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "http://localhost:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + // test_localhost_gateway_response_should_contain \ + // "request for localhost/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "http://localhost:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + { + Name: "request for /ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain", + Request: Request(). + DoNotFollowRedirects(). + URL("{{url}}/ipns/{{cid}}", gatewayURL, record.IdV0()), + Response: Expect(). + Status(301). + Headers( + Header("Location"). + Equals("{{scheme}}://{{cid}}.ipns.{{host}}/", u.Scheme, record.IdV1(), u.Host), + ), + }, + // # *.ipns.localhost + // # .ipns.localhost + // test_localhost_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ + // "http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ + // "$CID_VAL" + // test_localhost_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.localhost returns expected payload" \ + // "http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT" \ + // "$CID_VAL" + { + Name: "request for {CIDv1-libp2p-key}.ipns.{gateway} returns expected payload", + Request: Request(). + URL("{{scheme}}://{{cid}}.ipns.{{host}}/", u.Scheme, record.IdV1(), u.Host), + Response: Expect(). + Status(200). + BodyWithHint("Request for {{cid}}.ipns.{{host}} returns expected payload", payload), + }, + // test_localhost_gateway_response_should_contain \ + // "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "http://${RSA_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + // test_localhost_gateway_response_should_contain \ + // "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "http://${ED25519_IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.localhost:$GWAY_PORT/" + { + Name: "request for {CIDv1-dag-pb}.ipns.{gateway} redirects to CID with libp2p-key multicodec", + Request: Request(). + DoNotFollowRedirects(). + URL("{{scheme}}://{{cid}}.ipns.{{host}}/", u.Scheme, record.IntoCID(multicodec.DagPb, multibase.Base36), u.Host), + Response: Expect(). + Status(301). + Headers( + Header("Location"). + Equals("{{scheme}}://{{cid}}.ipns.{{host}}/", u.Scheme, record.IdV1(), u.Host), + ), + }, + // # example.com/ipns/ + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv0" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/{CIDv0} redirects to CIDv1 with libp2p-key multicodec in subdomain" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv0" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" + // Done above, thanks to the loop + // + // # *.ipns.example.com + // # ============================================================================ + + // # .ipns.example.com + + // test_hostname_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ + // "${RSA_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "$CID_VAL" + + // test_hostname_gateway_response_should_contain \ + // "request for {CIDv1-libp2p-key}.ipns.example.com returns expected payload" \ + // "${ED25519_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "$CID_VAL" + + // test_hostname_gateway_response_should_contain \ + // "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "${RSA_IPNS_IDv1_DAGPB}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "Location: http://${RSA_IPNS_IDv1}.ipns.example.com/" + + // test_hostname_gateway_response_should_contain \ + // "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \ + // "${ED25519_IPNS_IDv1_DAGPB}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "Location: http://${ED25519_IPNS_IDv1}.ipns.example.com/" + // # disable /ipns for the hostname by not whitelisting it + // ipfs config --json Gateway.PublicGateways '{ + // "example.com": { + // "UseSubdomains": true, + // "Paths": ["/ipfs"] + // } + // }' || exit 1 + // # restart daemon to apply config changes + // test_kill_ipfs_daemon + // test_launch_ipfs_daemon_without_network + + // TODO: what to do with these? + // # refuse requests to Paths that were not explicitly whitelisted for the hostname + // test_hostname_gateway_response_should_contain \ + // "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "${RSA_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "404 Not Found" + + // test_hostname_gateway_response_should_contain \ + // "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "${ED25519_IPNS_IDv1}.ipns.example.com" \ + // "http://127.0.0.1:$GWAY_PORT" \ + // "404 Not Found" + + // # refuse requests to Paths that were not explicitly whitelisted for the hostname + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv1" \ + // "404 Not Found" + + // test_hostname_gateway_response_should_contain \ + // "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ + // "example.com" \ + // "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv1" \ + // "404 Not Found" + }...) + } + tests = append(tests, SugarTests{ // ## Test subdomain handling of CIDs that do not fit in a single DNS Label (>63chars) // ## https://github.com/ipfs/go-ipfs/issues/7318 // ## ============================================================================ - // # local: *.localhost // test_localhost_gateway_response_should_contain \ // "request for a ED25519 libp2p-key at localhost/ipns/{b58mh} returns Location HTTP header for DNS-safe subdomain redirect in browsers" \ // "http://localhost:$GWAY_PORT/ipns/$IPNS_ED25519_B58MH" \ // "Location: http://${IPNS_ED25519_B36CID}.ipns.localhost:$GWAY_PORT/" - // # public subdomain gateway: *.example.com - // test_hostname_gateway_response_should_contain \ // "request for a ED25519 libp2p-key at example.com/ipns/{b58mh} returns Location HTTP header for DNS-safe subdomain redirect in browsers" \ // "example.com" \ // "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_ED25519_B58MH" \ // "Location: http://${IPNS_ED25519_B36CID}.ipns.example.com" - - // # disable /ipns for the hostname by not whitelisting it - // ipfs config --json Gateway.PublicGateways '{ - // "example.com": { - // "UseSubdomains": true, - // "Paths": ["/ipfs"] - // } - // }' || exit 1 - // # restart daemon to apply config changes - // test_kill_ipfs_daemon - // test_launch_ipfs_daemon_without_network - - // # refuse requests to Paths that were not explicitly whitelisted for the hostname - // test_hostname_gateway_response_should_contain \ - // "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ - // "${RSA_IPNS_IDv1}.ipns.example.com" \ - // "http://127.0.0.1:$GWAY_PORT" \ - // "404 Not Found" - - // test_hostname_gateway_response_should_contain \ - // "request for *.ipns.example.com returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ - // "${ED25519_IPNS_IDv1}.ipns.example.com" \ - // "http://127.0.0.1:$GWAY_PORT" \ - // "404 Not Found" - - // # refuse requests to Paths that were not explicitly whitelisted for the hostname - // test_hostname_gateway_response_should_contain \ - // "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ - // "example.com" \ - // "http://127.0.0.1:$GWAY_PORT/ipns/$RSA_IPNS_IDv1" \ - // "404 Not Found" - - // test_hostname_gateway_response_should_contain \ - // "request for example.com/ipns/ returns HTTP 404 Not Found when /ipns is not on Paths whitelist" \ - // "example.com" \ - // "http://127.0.0.1:$GWAY_PORT/ipns/$ED25519_IPNS_IDv1" \ - // "404 Not Found" + { + Name: "request for a ED25519 libp2p-key at example.com/ipns/{b58mh} returns Location HTTP header for DNS-safe subdomain redirect in browsers", + Request: Request(). + DoNotFollowRedirects(). + URL("{{url}}/ipns/{{cid}}", gatewayURL, ed25519Fixture.B58MH()), + Response: Expect(). + Headers( + Header("Location"). + Equals("{{scheme}}://{{cid}}.ipns.{{host}}/", u.Scheme, ed25519Fixture.IntoCID(multicodec.Libp2pKey, multibase.Base36), u.Host), + ), + }, }...) + } RunIfSpecsAreEnabled(t, helpers.UnwrapSubdomainTests(t, tests), specs.SubdomainGateway, specs.IPNSResolver) diff --git a/tooling/ipns/_fixtures/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record b/tooling/ipns/_fixtures/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record new file mode 100644 index 0000000000000000000000000000000000000000..39b2f41a40866132588557e1be7beb97f50b79d4 GIT binary patch literal 394 zcmd;b)XywPE7ng+Ov^4x%}lN=PB${n&MYr8Hc3r4N--}iPt7c-D9<^J}Yul1#e?Les=qsP9*TpHppd@W%Xk@HwV4`bi6k=#> zWnyAwYN=;oU}$b+5v9Rk(9qDcxZ%Nrr`k>qKjaU!b6-4rYi;`fm-}a{vCo?xRu}4g z^l|FihwZAz%U!lw{rY|+(EGO7p=OmC>knNP>?`)U^*Whrs^fvF0qEJ$Sl0Mn+K ATmS$7 literal 0 HcmV?d00001 diff --git a/tooling/ipns/_fixtures/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record b/tooling/ipns/_fixtures/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record new file mode 100644 index 0000000000000000000000000000000000000000..b37d9b75b50ce3baa472e0c790c63cc4476c8631 GIT binary patch literal 1082 zcmd;b)XywPE7ng+Ov^4x%}lN=PB${n&MYr8Hc3r4N--}iPt7c-D92(*IMXR5Go)>GsSynodq(GRGFw`JL;^nAdmmZe7@< z?;9u0)~oe;B6n8l#B-O4jHLznwHFfawsGeD^WdI5dD6CW_D`?(IR6u4yS}n>0Xs|C zV|Deu10TJ;+15H9y#1%w)-Pu|{~C5NEh+2ohgE%4GcFi^=!o1|c=mvclzM~Aq?sH1 zV;9|>pJ(C4b;k1K_pY`7N=jcyC2D2fRy9#Bx;b;nX--YmkL>f5|4X=(dm6Aa@2=jn zPF^r?@jIi2gJJgHoU|F^9$YA16dbkmCI8(bi=coUk?re*CGPIOm;0ZgQ?hD>F0X=C zL#OarR>@Lloz*!)FR?K>|cBO@yVa}y&! z15licsfm%1;pVJGT^wtTb=KA$^<13Nv3!=^X2&xt9)0ASbyDGP?WdlXx7q)`d@Z+h z!6|`%_KMwXk1o8Mo?{-MVA*x}^cm9=t?8#{Bqsazy{TE_Y}T4V{h&^m3)r^)bGv-5U2WMvuSX z7vtkGPzgn;O5JiMe~&<38&ZhUC?flR8gS@+~<#_0!o~ z@AZ8}8?WuOn%~@gsOVv8C3nV1oCd(eK6PTncvj@)S}Wr`}S-X)$F5@;ne3PMT?z z=NIb*B<2n+zLRAc6lAY~eeG%iDJwNZBx`P>1GC& uWCn)RutZ?qi=aH?W(21e0yA-PDnka)$jp??lFA5t$v6k5Dx|U?l>q?Oq1V#@ literal 0 HcmV?d00001 diff --git a/tooling/ipns/ipns_test.go b/tooling/ipns/ipns_test.go index c1b33f73a..bdec11c35 100644 --- a/tooling/ipns/ipns_test.go +++ b/tooling/ipns/ipns_test.go @@ -4,6 +4,8 @@ import ( "testing" "time" + mbase "github.com/multiformats/go-multibase" + "github.com/multiformats/go-multicodec" "github.com/stretchr/testify/assert" ) @@ -62,3 +64,30 @@ func TestLoadTestRecord(t *testing.T) { err = ipns.Valid() assert.NoError(t, err) } + +func TestIPNSFixtureVersionsConversion(t *testing.T) { + path := "./_fixtures/12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d.ipns-record" + record, err := OpenIPNSRecordWithKey(path) + + assert.Nil(t, err) + + // 12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d is a ED25519 key, which is using the identity hash. + assert.Equal(t, "12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d", record.Key()) + assert.Equal(t, "12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d", record.IdV0()) // TODO: confirm with @lidel this makes sense. + assert.Equal(t, "k51qzi5uqu5dk3v4rmjber23h16xnr23bsggmqqil9z2gduiis5se8dht36dam", record.IdV1()) + assert.Equal(t, "k50rm9yjlt0jey4fqg6wafvqprktgbkpgkqdg27tpqje6iimzxewnhvtin9hhq", record.IntoCID(multicodec.DagPb, mbase.Base36)) + assert.Equal(t, "12D3KooWLQzUv2FHWGVPXTXSZpdHs7oHbXub2G5WC8Tx4NQhyd2d", record.B58MH()) + assert.Equal(t, "k51qzi5uqu5dk3v4rmjber23h16xnr23bsggmqqil9z2gduiis5se8dht36dam", record.IntoCID(multicodec.Libp2pKey, mbase.Base36)) + + path = "./_fixtures/QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3.ipns-record" + record, err = OpenIPNSRecordWithKey(path) + + assert.Nil(t, err) + + // QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3 is a RSA key, which is using sha256 hash. + assert.Equal(t, "QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3", record.Key()) + assert.Equal(t, "QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3", record.IdV0()) + assert.Equal(t, "k2k4r8m7xvggw5pxxk3abrkwyer625hg01hfyggrai7lk1m63fuihi7w", record.IdV1()) + assert.Equal(t, "k2jmtxu61bnhrtj301lw7zizknztocdbeqhxgv76l2q9t36fn9jbzipo", record.IntoCID(multicodec.DagPb, mbase.Base36)) + assert.Equal(t, "QmVujd5Vb7moysJj8itnGufN7MEtPRCNHkKpNuA4onsRa3", record.B58MH()) +} diff --git a/tooling/ipns/record.go b/tooling/ipns/record.go index 4132711ab..2e4c7a379 100644 --- a/tooling/ipns/record.go +++ b/tooling/ipns/record.go @@ -1,16 +1,21 @@ package ipns import ( + "strings" "time" "github.com/ipfs/boxo/ipns" ipns_pb "github.com/ipfs/boxo/ipns/pb" + "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p/core/peer" + mbase "github.com/multiformats/go-multibase" + "github.com/multiformats/go-multicodec" ) type IpnsRecord struct { pb *ipns_pb.IpnsEntry key string + id peer.ID validity time.Time } @@ -25,7 +30,12 @@ func UnmarshalIpnsRecord(data []byte, pubKey string) (*IpnsRecord, error) { return nil, err } - return &IpnsRecord{pb: pb, key: pubKey, validity: validity}, nil + id, err := peer.Decode(pubKey) + if err != nil { + return nil, err + } + + return &IpnsRecord{pb: pb, key: pubKey, id: id, validity: validity}, nil } func (i *IpnsRecord) Value() string { @@ -41,10 +51,46 @@ func (i *IpnsRecord) Validity() time.Time { } func (i *IpnsRecord) Valid() error { - id, err := peer.Decode(i.key) + return ipns.ValidateWithPeerID(i.id, i.pb) +} + +func (i *IpnsRecord) idV1(codec multicodec.Code, base mbase.Encoding) (string, error) { + c := peer.ToCid(i.id) + c = cid.NewCidV1(uint64(codec), c.Hash()) + s, err := c.StringOfBase(base) + if err != nil { + return "", err + } + return s, nil +} + +func (i *IpnsRecord) IntoCID(codec multicodec.Code, base mbase.Encoding) string { + s, err := i.idV1(codec, base) if err != nil { - return err + panic(err) + } + return s +} + +func (i *IpnsRecord) IdV0() string { + if strings.HasPrefix(i.key, "Qm") || strings.HasPrefix(i.key, "1") { + return i.key } + panic("not a v0 id") + // This code won't work if key starts with "1", this is an identity multihash, which + // makes `NewCidV0` panic. + // c := peer.ToCid(i.id) + // s, err := cid.NewCidV0(c.Hash()).StringOfBase(mbase.Base58BTC) + // if err != nil { + // panic(err) + // } + // return s +} + +func (i *IpnsRecord) IdV1() string { + return i.IntoCID(cid.Libp2pKey, mbase.Base36) +} - return ipns.ValidateWithPeerID(id, i.pb) +func (i *IpnsRecord) B58MH() string { + return i.id.String() }