github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/vfs/permissions_test.go (about)

     1  package vfs_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/cozy/cozy-stack/model/permission"
     7  	"github.com/cozy/cozy-stack/model/vfs"
     8  	"github.com/cozy/cozy-stack/pkg/config/config"
     9  	"github.com/cozy/cozy-stack/pkg/consts"
    10  	"github.com/cozy/cozy-stack/pkg/couchdb"
    11  	"github.com/cozy/cozy-stack/tests/testutils"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestPermissions(t *testing.T) {
    17  	if testing.Short() {
    18  		t.Skip("an instance is required for this test: test skipped due to the use of --short flag")
    19  	}
    20  
    21  	config.UseTestFile(t)
    22  	testutils.NeedCouchdb(t)
    23  
    24  	aferoFS := makeAferoFS(t)
    25  	swiftFS := makeSwiftFS(t)
    26  
    27  	var tests = []struct {
    28  		name string
    29  		fs   vfs.VFS
    30  	}{
    31  		{"afero", aferoFS},
    32  		{"swift", swiftFS},
    33  	}
    34  
    35  	for _, tt := range tests {
    36  		fs := tt.fs
    37  		t.Run("Permissions", func(t *testing.T) {
    38  			origtree := H{
    39  				"O/": H{
    40  					"A/": H{
    41  						"a1/": H{},
    42  						"a2/": H{},
    43  					},
    44  					"B/": H{
    45  						"b1.txt": nil,
    46  						"c1.txt": nil,
    47  					},
    48  					"B2/": H{
    49  						"b1.txt": nil,
    50  						"c1.txt": nil,
    51  					},
    52  					"C/":    H{},
    53  					"d.txt": nil,
    54  				},
    55  			}
    56  			O := createTree(t, fs, origtree, consts.RootDirID)
    57  
    58  			A, err := fs.DirByPath("/O/A")
    59  			require.NoError(t, err)
    60  
    61  			B, err := fs.DirByPath("/O/B")
    62  			require.NoError(t, err)
    63  
    64  			_, err = vfs.ModifyDirMetadata(fs, B, &vfs.DocPatch{
    65  				Tags: &[]string{"testtagparent"},
    66  			})
    67  			assert.NoError(t, err)
    68  
    69  			B2, err := fs.DirByPath("/O/B2")
    70  			require.NoError(t, err)
    71  
    72  			f, err := fs.FileByPath("/O/B/b1.txt")
    73  			require.NoError(t, err)
    74  
    75  			_, err = vfs.ModifyFileMetadata(fs, f, &vfs.DocPatch{
    76  				Tags: &[]string{"testtag"},
    77  			})
    78  			assert.NoError(t, err)
    79  			// reload
    80  			f, err = fs.FileByPath("/O/B/b1.txt")
    81  			require.NoError(t, err)
    82  
    83  			// hack to have a Class attribute
    84  			f.Class = "superfile"
    85  
    86  			psetWholeType := permission.Set{
    87  				permission.Rule{
    88  					Type:  consts.Files,
    89  					Verbs: permission.ALL,
    90  				},
    91  			}
    92  			assert.NoError(t, vfs.Allows(fs, psetWholeType, permission.GET, f))
    93  
    94  			psetSelfID := permission.Set{
    95  				permission.Rule{
    96  					Type:   consts.Files,
    97  					Verbs:  permission.ALL,
    98  					Values: []string{f.ID()},
    99  				},
   100  			}
   101  			assert.NoError(t, vfs.Allows(fs, psetSelfID, permission.GET, f))
   102  
   103  			psetSelfAttributes := permission.Set{
   104  				permission.Rule{
   105  					Type:     consts.Files,
   106  					Verbs:    permission.ALL,
   107  					Selector: "class",
   108  					Values:   []string{"superfile"},
   109  				},
   110  			}
   111  			assert.NoError(t, vfs.Allows(fs, psetSelfAttributes, permission.GET, f))
   112  
   113  			psetOnlyFiles := permission.Set{
   114  				permission.Rule{
   115  					Type:     consts.Files,
   116  					Verbs:    permission.ALL,
   117  					Selector: "type",
   118  					Values:   []string{"file"},
   119  				},
   120  			}
   121  			assert.NoError(t, vfs.Allows(fs, psetOnlyFiles, permission.GET, f))
   122  
   123  			psetOnlyDirs := permission.Set{
   124  				permission.Rule{
   125  					Type:     consts.Files,
   126  					Verbs:    permission.ALL,
   127  					Selector: "type",
   128  					Values:   []string{"directory"},
   129  				},
   130  			}
   131  			assert.NoError(t, vfs.Allows(fs, psetOnlyDirs, permission.GET, B))
   132  
   133  			psetMime := permission.Set{
   134  				permission.Rule{
   135  					Type:     consts.Files,
   136  					Verbs:    permission.ALL,
   137  					Selector: "mime",
   138  					Values:   []string{"text/plain"},
   139  				},
   140  			}
   141  			f.Mime = "text/plain"
   142  			assert.NoError(t, vfs.Allows(fs, psetMime, permission.GET, f))
   143  
   144  			psetReferences := permission.Set{
   145  				permission.Rule{
   146  					Type:     consts.Files,
   147  					Verbs:    permission.ALL,
   148  					Selector: "referenced_by",
   149  					Values:   []string{"somealbumid"},
   150  				},
   151  			}
   152  			f.ReferencedBy = []couchdb.DocReference{{Type: "io.cozy.albums", ID: "somealbumid"}}
   153  			assert.NoError(t, vfs.Allows(fs, psetReferences, permission.GET, f))
   154  
   155  			psetBadReferences := permission.Set{
   156  				permission.Rule{
   157  					Type:     consts.Files,
   158  					Verbs:    permission.ALL,
   159  					Selector: "referenced_by",
   160  					Values:   []string{"anotheralbumid"},
   161  				},
   162  			}
   163  			assert.Error(t, vfs.Allows(fs, psetBadReferences, permission.GET, f))
   164  
   165  			psetName := permission.Set{
   166  				permission.Rule{
   167  					Type:     consts.Files,
   168  					Verbs:    permission.ALL,
   169  					Selector: "name",
   170  					Values:   []string{"b1.txt"},
   171  				},
   172  			}
   173  			assert.NoError(t, vfs.Allows(fs, psetName, permission.GET, f))
   174  
   175  			psetSelfTag := permission.Set{
   176  				permission.Rule{
   177  					Type:     consts.Files,
   178  					Verbs:    permission.ALL,
   179  					Selector: "tags",
   180  					Values:   []string{"testtag"},
   181  				},
   182  			}
   183  			assert.NoError(t, vfs.Allows(fs, psetSelfTag, permission.GET, f))
   184  
   185  			psetParentID := permission.Set{
   186  				permission.Rule{
   187  					Type:   consts.Files,
   188  					Verbs:  permission.ALL,
   189  					Values: []string{O.ID()},
   190  				},
   191  			}
   192  			assert.NoError(t, vfs.Allows(fs, psetParentID, permission.GET, f))
   193  
   194  			psetSelfParentTag := permission.Set{
   195  				permission.Rule{
   196  					Type:     consts.Files,
   197  					Verbs:    permission.ALL,
   198  					Selector: "tags",
   199  					Values:   []string{"testtagparent"},
   200  				},
   201  			}
   202  			assert.NoError(t, vfs.Allows(fs, psetSelfParentTag, permission.GET, f))
   203  
   204  			psetWrongType := permission.Set{
   205  				permission.Rule{
   206  					Type:   "io.cozy.not.files",
   207  					Verbs:  permission.ALL,
   208  					Values: []string{A.ID()},
   209  				},
   210  			}
   211  			assert.Error(t, vfs.Allows(fs, psetWrongType, permission.GET, f))
   212  
   213  			psetWrongVerb := permission.Set{
   214  				permission.Rule{
   215  					Type:   consts.Files,
   216  					Verbs:  permission.Verbs(permission.POST),
   217  					Values: []string{A.ID()},
   218  				},
   219  			}
   220  			assert.Error(t, vfs.Allows(fs, psetWrongVerb, permission.GET, f))
   221  
   222  			psetUncleID := permission.Set{
   223  				permission.Rule{
   224  					Type:   consts.Files,
   225  					Verbs:  permission.ALL,
   226  					Values: []string{B.ID()},
   227  				},
   228  			}
   229  			assert.Error(t, vfs.Allows(fs, psetUncleID, permission.GET, B2))
   230  
   231  			psetUnclePrefixID := permission.Set{
   232  				permission.Rule{
   233  					Type:   consts.Files,
   234  					Verbs:  permission.ALL,
   235  					Values: []string{A.ID()},
   236  				},
   237  			}
   238  			assert.Error(t, vfs.Allows(fs, psetUnclePrefixID, permission.GET, f))
   239  		})
   240  	}
   241  }