@@ -12,7 +12,9 @@ import (
12
12
"strings"
13
13
"testing"
14
14
15
+ "github.com/ipfs/go-cid"
15
16
"github.com/ipfs/kubo/test/cli/harness"
17
+ carstore "github.com/ipld/go-car/v2/blockstore"
16
18
"github.com/libp2p/go-libp2p"
17
19
"github.com/libp2p/go-libp2p/core/peer"
18
20
libp2phttp "github.com/libp2p/go-libp2p/p2p/http"
@@ -34,8 +36,10 @@ func TestContentBlocking(t *testing.T) {
34
36
node := h .NewNode ().Init ("--empty-repo" , "--profile=test" )
35
37
36
38
// Create CIDs we use in test
37
- h .WriteFile ("blocked-dir/subdir/indirectly-blocked-file.txt" , "indirectly blocked file content" )
38
- parentDirCID := node .IPFS ("add" , "--raw-leaves" , "-Q" , "-r" , filepath .Join (h .Dir , "blocked-dir" )).Stdout .Trimmed ()
39
+ h .WriteFile ("parent-dir/blocked-subdir/indirectly-blocked-file.txt" , "indirectly blocked file content" )
40
+ allowedParentDirCID := node .IPFS ("add" , "--raw-leaves" , "-Q" , "-r" , "--pin=false" , filepath .Join (h .Dir , "parent-dir" )).Stdout .Trimmed ()
41
+ blockedSubDirCID := node .IPFS ("add" , "--raw-leaves" , "-Q" , "-r" , "--pin=false" , filepath .Join (h .Dir , "parent-dir" , "blocked-subdir" )).Stdout .Trimmed ()
42
+ node .IPFS ("block" , "rm" , blockedSubDirCID )
39
43
40
44
h .WriteFile ("directly-blocked-file.txt" , "directly blocked file content" )
41
45
blockedCID := node .IPFS ("add" , "--raw-leaves" , "-Q" , filepath .Join (h .Dir , "directly-blocked-file.txt" )).Stdout .Trimmed ()
@@ -50,7 +54,7 @@ func TestContentBlocking(t *testing.T) {
50
54
"//8526ba05eec55e28f8db5974cc891d0d92c8af69d386fc6464f1e9f372caf549\n " + // Legacy CID double-hash block: sha256(bafkqahtcnrxwg23fmqqgi33vmjwgk2dbonuca3dfm5qwg6jamnuwicq/)
51
55
"//e5b7d2ce2594e2e09901596d8e1f29fa249b74c8c9e32ea01eda5111e4d33f07\n " + // Legacy Path double-hash block: sha256(bafyaagyscufaqalqaacauaqiaejao43vmjygc5didacauaqiae/subpath)
52
56
"/ipfs/" + blockedCID + "\n " + // block specific CID
53
- "/ipfs/" + parentDirCID + "/subdir*\n " + // block only specific subpath
57
+ "/ipfs/" + allowedParentDirCID + "/blocked- subdir*\n " + // block only specific subpath
54
58
"/ipns/blocked-cid.example.com\n " +
55
59
"/ipns/blocked-dnslink.example.com\n " )
56
60
@@ -94,22 +98,63 @@ func TestContentBlocking(t *testing.T) {
94
98
// Confirm parent of blocked subpath is not blocked
95
99
t .Run ("Gateway Allows parent Path that is not blocked" , func (t * testing.T ) {
96
100
t .Parallel ()
97
- resp := client .Get ("/ipfs/" + parentDirCID )
101
+ resp := client .Get ("/ipfs/" + allowedParentDirCID )
98
102
assert .Equal (t , http .StatusOK , resp .StatusCode )
99
103
})
100
104
105
+ // Confirm CAR responses skip blocked subpaths
106
+ t .Run ("Gateway returns CAR without blocked subpath" , func (t * testing.T ) {
107
+ resp := client .Get ("/ipfs/" + allowedParentDirCID + "/subdir?format=car" )
108
+ assert .Equal (t , http .StatusOK , resp .StatusCode )
109
+
110
+ bs , err := carstore .NewReadOnly (strings .NewReader (resp .Body ), nil )
111
+ assert .NoError (t , err )
112
+
113
+ has , err := bs .Has (context .Background (), cid .MustParse (blockedSubDirCID ))
114
+ assert .NoError (t , err )
115
+ assert .False (t , has )
116
+ })
117
+
118
+ /* TODO: this was already broken in 0.26, but we should fix it
119
+ t.Run("Gateway returns CAR without directly blocked CID", func(t *testing.T) {
120
+ allowedDirWithDirectlyBlockedCID := node.IPFS("add", "--raw-leaves", "-Q", "-rw", filepath.Join(h.Dir, "directly-blocked-file.txt")).Stdout.Trimmed()
121
+ resp := client.Get("/ipfs/" + allowedDirWithDirectlyBlockedCID + "?format=car")
122
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
123
+
124
+ bs, err := carstore.NewReadOnly(strings.NewReader(resp.Body), nil)
125
+ assert.NoError(t, err)
126
+
127
+ has, err := bs.Has(context.Background(), cid.MustParse(blockedCID))
128
+ assert.NoError(t, err)
129
+ assert.False(t, has, "Returned CAR should not include blockedCID")
130
+ })
131
+ */
132
+
133
+ // Confirm CAR responses skip blocked subpaths
134
+ t .Run ("Gateway returns CAR without blocked subpath" , func (t * testing.T ) {
135
+ resp := client .Get ("/ipfs/" + allowedParentDirCID + "/subdir?format=car" )
136
+ assert .Equal (t , http .StatusOK , resp .StatusCode )
137
+
138
+ bs , err := carstore .NewReadOnly (strings .NewReader (resp .Body ), nil )
139
+ assert .NoError (t , err )
140
+
141
+ has , err := bs .Has (context .Background (), cid .MustParse (blockedSubDirCID ))
142
+ assert .NoError (t , err )
143
+ assert .False (t , has , "Returned CAR should not include blockedSubDirCID" )
144
+ })
145
+
101
146
// Ok, now the full list of test cases we want to cover in both CLI and Gateway
102
147
testCases := []struct {
103
148
name string
104
149
path string
105
150
}{
106
151
{
107
- name : "directly blocked CID" ,
152
+ name : "directly blocked file CID" ,
108
153
path : "/ipfs/" + blockedCID ,
109
154
},
110
155
{
111
156
name : "indirectly blocked file (on a blocked subpath)" ,
112
- path : "/ipfs/" + parentDirCID + "/subdir/indirectly-blocked-file.txt" ,
157
+ path : "/ipfs/" + allowedParentDirCID + "/blocked- subdir/indirectly-blocked-file.txt" ,
113
158
},
114
159
{
115
160
name : "/ipns path that resolves to a blocked CID" ,
@@ -161,9 +206,14 @@ func TestContentBlocking(t *testing.T) {
161
206
t .Run (cliTestName , func (t * testing.T ) {
162
207
t .Parallel ()
163
208
args := append (cmd , testCase .path )
164
- errMsg := node .RunIPFS (args ... ).Stderr .Trimmed ()
165
- if ! strings .Contains (errMsg , expectedMsg ) {
166
- t .Errorf ("Expected STDERR error message %q, but got: %q" , expectedMsg , errMsg )
209
+ cmd := node .RunIPFS (args ... )
210
+ stdout := cmd .Stdout .Trimmed ()
211
+ stderr := cmd .Stderr .Trimmed ()
212
+ if ! strings .Contains (stderr , expectedMsg ) {
213
+ t .Errorf ("Expected STDERR error message %q, but got: %q" , expectedMsg , stderr )
214
+ if stdout != "" {
215
+ t .Errorf ("Expected STDOUT to be empty, but got: %q" , stdout )
216
+ }
167
217
}
168
218
})
169
219
}
@@ -299,5 +349,17 @@ func TestContentBlocking(t *testing.T) {
299
349
assert .NotEqual (t , string (body ), "directly blocked file content" )
300
350
assert .Contains (t , string (body ), blockedMsg , bodyExpl )
301
351
})
352
+
353
+ t .Run ("Denies Blocked CID as CAR" , func (t * testing.T ) {
354
+ t .Parallel ()
355
+ resp , err := libp2pClient .Get (fmt .Sprintf ("/ipfs/%s?format=car" , blockedCID ))
356
+ require .NoError (t , err )
357
+ defer resp .Body .Close ()
358
+ assert .Equal (t , http .StatusGone , resp .StatusCode , statusExpl )
359
+ body , err := io .ReadAll (resp .Body )
360
+ require .NoError (t , err )
361
+ assert .NotContains (t , string (body ), "directly blocked file content" )
362
+ assert .Contains (t , string (body ), blockedMsg , bodyExpl )
363
+ })
302
364
})
303
365
}
0 commit comments