@@ -9,6 +9,11 @@ const fs_utils = require('../../util/fs_utils');
9
9
const nb_native = require ( '../../util/nb_native' ) ;
10
10
const test_utils = require ( '../system_tests/test_utils' ) ;
11
11
const fs = require ( 'fs' ) ;
12
+ const { TMP_PATH } = require ( '../system_tests/test_utils' ) ;
13
+ const NamespaceFS = require ( '../../sdk/namespace_fs' ) ;
14
+ const buffer_utils = require ( '../../util/buffer_utils' ) ;
15
+ const endpoint_stats_collector = require ( '../../sdk/endpoint_stats_collector' ) ;
16
+ const SensitiveString = require ( '../../util/sensitive_string' ) ;
12
17
13
18
const new_umask = process . env . NOOBAA_ENDPOINT_UMASK || 0o000 ;
14
19
const old_umask = process . umask ( new_umask ) ;
@@ -175,5 +180,145 @@ mocha.describe('new tests check', async function() {
175
180
} ) ;
176
181
} ) ;
177
182
183
+ mocha . describe ( 'list object access check' , function ( ) {
184
+ this . timeout ( 10 * 60 * 1000 ) ; // eslint-disable-line no-invalid-this
178
185
186
+ const key_files_set_first = make_keys ( 10 , i => `small_key_files_set_first${ i } ` ) ;
187
+ const key_files_set_second = make_keys ( 10 , i => `small_key_files_set_second${ i } ` ) ;
188
+ const max_keys_files_set = make_keys ( 981 , i => `max_keys_files_set${ i } ` ) ;
189
+ const access_src_bkt = 'access_src' ;
190
+ const tmp_fs_path = path . join ( TMP_PATH , 'test_namespace_access_fs' ) ;
191
+ const ns_tmp_bucket_path = path . join ( tmp_fs_path , access_src_bkt ) ;
192
+ const first_file_path = path . join ( ns_tmp_bucket_path , 'small_key_files_set_first1' ) ;
193
+ const bucket1 = 'access_bucket1' ;
194
+ const ns_src = new NamespaceFS ( {
195
+ bucket_path : ns_tmp_bucket_path ,
196
+ bucket_id : '5' ,
197
+ namespace_resource_id : undefined ,
198
+ access_mode : undefined ,
199
+ versioning : undefined ,
200
+ force_md5_etag : false ,
201
+ stats : endpoint_stats_collector . instance ( ) ,
202
+ } ) ;
203
+ const custom_dummy_object_sdk1 = make_custom_dummy_object_sdk ( 200 , 200 ) ;
204
+ const custom_dummy_object_sdk2 = make_custom_dummy_object_sdk ( 300 , 200 ) ;
205
+ const custom_dummy_object_sdk3 = make_custom_dummy_object_sdk ( 400 , 400 ) ;
206
+ mocha . before ( async function ( ) {
207
+ await fs_utils . create_fresh_path ( tmp_fs_path , 0o777 ) ;
208
+ await fs_utils . file_must_exist ( tmp_fs_path ) ;
209
+ await fs_utils . create_fresh_path ( ns_tmp_bucket_path , 0o770 ) ;
210
+ await fs_utils . file_must_exist ( ns_tmp_bucket_path ) ;
211
+ await fs . promises . chmod ( tmp_fs_path , 0o777 ) ;
212
+ await fs . promises . chmod ( ns_tmp_bucket_path , 0o770 ) ;
213
+ await fs . promises . chown ( ns_tmp_bucket_path , custom_dummy_object_sdk1 . requesting_account . nsfs_account_config . uid ,
214
+ custom_dummy_object_sdk1 . requesting_account . nsfs_account_config . gid ) ;
215
+ } ) ;
216
+ mocha . after ( async function ( ) {
217
+ fs_utils . folder_delete ( ns_tmp_bucket_path ) ;
218
+ fs_utils . folder_delete ( tmp_fs_path ) ;
219
+ } ) ;
220
+
221
+ mocha . it ( 'list object with inaccessible item, smae UI and GID' , async function ( ) {
222
+ await upload_objects ( key_files_set_first , custom_dummy_object_sdk1 , bucket1 , ns_src ) ;
223
+ // change ownership for one file, and account can not access this file
224
+ await fs . promises . chown ( first_file_path , 999 , 999 ) ;
225
+ const r = await ns_src . list_objects ( {
226
+ bucket : bucket1 ,
227
+ } , custom_dummy_object_sdk1 ) ;
228
+ // skipping inaccessible file, list rest of the files
229
+ assert_list_items ( r , [ ...key_files_set_first ] , 9 ) ;
230
+ } ) ;
231
+
232
+ mocha . it ( 'list object with different account and same GID' , async function ( ) {
233
+ await upload_objects ( key_files_set_second , custom_dummy_object_sdk2 , bucket1 , ns_src ) ;
234
+ const r = await ns_src . list_objects ( {
235
+ bucket : bucket1 ,
236
+ } , custom_dummy_object_sdk2 ) ;
237
+ assert_list_items ( r , [ ...key_files_set_first , ...key_files_set_second ] , 19 ) ;
238
+ } ) ;
239
+
240
+ mocha . it ( 'list object with different account and different GID' , async function ( ) {
241
+ try {
242
+ await upload_objects ( [ "Banana" ] , custom_dummy_object_sdk3 , bucket1 , ns_src ) ;
243
+ } catch ( err ) {
244
+ assert . strictEqual ( err instanceof Error , true ) ;
245
+ assert . strictEqual ( err . code , 'EACCES' ) ;
246
+ }
247
+ const r = await ns_src . list_objects ( {
248
+ bucket : bucket1 ,
249
+ } , custom_dummy_object_sdk2 ) ;
250
+ assert_list_items ( r , [ ...key_files_set_first , ...key_files_set_second ] , 19 ) ;
251
+ } ) ;
252
+
253
+ mocha . it ( 'max - list object with different account and same GID' , async function ( ) {
254
+ await upload_objects ( max_keys_files_set , custom_dummy_object_sdk1 , bucket1 , ns_src ) ;
255
+ const r = await ns_src . list_objects ( {
256
+ bucket : bucket1 ,
257
+ } , custom_dummy_object_sdk1 ) ;
258
+ // Total number of object would be 9+10+981 = 1000
259
+ assert_list_items ( r , [ ...key_files_set_first , ...key_files_set_second , ...max_keys_files_set ] , 1000 ) ;
260
+ } ) ;
261
+ } ) ;
262
+
263
+ async function upload_objects ( keys , custom_object_sdk , user_bucket , user_ns ) {
264
+ return Promise . all ( keys . map ( async key => {
265
+ await user_ns . upload_object ( {
266
+ bucket : user_bucket ,
267
+ key,
268
+ content_type : 'application/octet-stream' ,
269
+ source_stream : buffer_utils . buffer_to_read_stream ( null ) ,
270
+ size : 0
271
+ } , custom_object_sdk ) ;
272
+ } ) ) ;
273
+ }
274
+
275
+ function make_custom_dummy_object_sdk ( uid , gid ) {
276
+ return {
277
+ requesting_account : {
278
+ force_md5_etag : false ,
279
+ nsfs_account_config : {
280
+ uid : uid ,
281
+ gid : gid ,
282
+ }
283
+ } ,
284
+ abort_controller : new AbortController ( ) ,
285
+ throw_if_aborted ( ) {
286
+ if ( this . abort_controller . signal . aborted ) throw new Error ( 'request aborted signal' ) ;
287
+ } ,
288
+
289
+ read_bucket_sdk_config_info ( name ) {
290
+ return {
291
+ bucket_owner : new SensitiveString ( 'dummy-owner' ) ,
292
+ owner_account : {
293
+ id : 'dummy-id-123' ,
294
+ }
295
+ } ;
296
+ }
297
+ } ;
298
+ }
299
+
300
+ /**
301
+ * validate list objects counts and items
302
+ * @param {Object } r
303
+ * @param {string[] } splice_array
304
+ * @param {number } object_items_count
305
+ */
306
+ function assert_list_items ( r , splice_array , object_items_count ) {
307
+ assert . equal ( r . objects . length , object_items_count ) ;
308
+ const index = splice_array . indexOf ( 'small_key_files_set_first1' ) ;
309
+ splice_array . splice ( index , 1 ) ;
310
+ assert . deepStrictEqual ( r . objects . map ( it => it . key ) , splice_array . sort ( ) ) ;
311
+ }
179
312
313
+ /**
314
+ * @param {number } count
315
+ * @param {(i:number)=>string } gen
316
+ * @returns {string[] }
317
+ */
318
+ function make_keys ( count , gen ) {
319
+ const arr = new Array ( count ) ;
320
+ for ( let i = 0 ; i < count ; ++ i ) arr [ i ] = gen ( i ) ;
321
+ arr . sort ( ) ;
322
+ Object . freeze ( arr ) ;
323
+ return arr ;
324
+ }
0 commit comments