11'use strict'
22/* eslint-disable node/no-deprecated-api */
33
4- const { dirname } = require ( 'path' )
4+ // const { dirname } = require('path')
55const rdf = require ( 'rdflib' )
66const debug = require ( './debug' ) . ACL
7- const debugCache = require ( './debug' ) . cache
7+ // const debugCache = require('./debug').cache
88const HTTPError = require ( './http-error' )
99const aclCheck = require ( '@solid/acl-check' )
1010const { URL } = require ( 'url' )
@@ -63,59 +63,62 @@ class ACLChecker {
6363 return this . aclCached [ cacheKey ]
6464 }
6565 let resource = rdf . sym ( this . resource )
66+ let parentResource = resource
67+ if ( ! this . resource . endsWith ( '/' ) ) { parentResource = rdf . sym ( ACLChecker . getDirectory ( this . resource ) ) }
6668 if ( this . resource . endsWith ( '/' + this . suffix ) ) {
6769 resource = rdf . sym ( ACLChecker . getDirectory ( this . resource ) )
70+ parentResource = resource
6871 }
6972 // If this is an ACL, Control mode must be present for any operations
7073 if ( this . isAcl ( this . resource ) ) {
7174 mode = 'Control'
72- resource = rdf . sym ( this . resource . substring ( 0 , this . resource . length - this . suffix . length ) )
75+ const thisResource = this . resource . substring ( 0 , this . resource . length - this . suffix . length )
76+ resource = rdf . sym ( thisResource )
77+ parentResource = resource
78+ if ( ! thisResource . endsWith ( '/' ) ) parentResource = rdf . sym ( ACLChecker . getDirectory ( thisResource ) )
7379 }
7480 // If the slug is an acl, reject
7581 /* if (this.isAcl(this.slug)) {
7682 this.aclCached[cacheKey] = Promise.resolve(false)
7783 return this.aclCached[cacheKey]
7884 } */
79- const directory = acl . isContainer ? rdf . sym ( ACLChecker . getDirectory ( acl . acl ) ) : null
80- const aclFile = rdf . sym ( acl . acl )
85+ const directory = acl . isContainer ? rdf . sym ( ACLChecker . getDirectory ( acl . docAcl ) ) : null
86+ const aclFile = rdf . sym ( acl . docAcl )
87+ const aclGraph = acl . docGraph
8188 const agent = user ? rdf . sym ( user ) : null
8289 const modes = [ ACL ( mode ) ]
8390 const agentOrigin = this . agentOrigin
8491 const trustedOrigins = this . trustedOrigins
8592 let originTrustedModes = [ ]
8693 try {
8794 this . fetch ( aclFile . doc ( ) . value )
88- originTrustedModes = await aclCheck . getTrustedModesForOrigin ( acl . graph , resource , directory , aclFile , agentOrigin , ( uriNode ) => {
89- return this . fetch ( uriNode . doc ( ) . value , acl . graph )
95+ originTrustedModes = await aclCheck . getTrustedModesForOrigin ( aclGraph , resource , directory , aclFile , agentOrigin , ( uriNode ) => {
96+ return this . fetch ( uriNode . doc ( ) . value , aclGraph )
9097 } )
9198 } catch ( e ) {
9299 // FIXME: https://github.com/solid/acl-check/issues/23
93100 // console.error(e.message)
94101 }
95- let accessDenied = aclCheck . accessDenied ( acl . graph , resource , directory , aclFile , agent , modes , agentOrigin , trustedOrigins , originTrustedModes )
102+ let accessDenied = aclCheck . accessDenied ( aclGraph , resource , directory , aclFile , agent , modes , agentOrigin , trustedOrigins , originTrustedModes )
96103
97104 function accessDeniedForAccessTo ( mode ) {
98- const accessDeniedAccessTo = aclCheck . accessDenied ( acl . graph , directory , null , aclFile , agent , [ ACL ( mode ) ] , agentOrigin , trustedOrigins , originTrustedModes )
105+ const parentAclDirectory = ACLChecker . getDirectory ( acl . parentAcl )
106+ const parentDirectory = parentResource === parentAclDirectory ? null : rdf . sym ( parentAclDirectory )
107+ const accessDeniedAccessTo = aclCheck . accessDenied ( acl . parentGraph , parentResource , parentDirectory , rdf . sym ( acl . parentAcl ) , agent , [ ACL ( mode ) ] , agentOrigin , trustedOrigins , originTrustedModes )
99108 const accessResult = ! accessDenied && ! accessDeniedAccessTo
100109 accessDenied = accessResult ? false : accessDenied || accessDeniedAccessTo
101110 // debugCache('accessDenied result ' + accessDenied)
102111 }
103112 // For create and update HTTP methods
104- if ( ( method === 'PUT' || method === 'PATCH' || method === 'COPY' ) && directory ) {
105- // if resource and acl have same parent container,
106- // and resource does not exist, then accessTo Append from parent is required
107- if ( directory . value === dirname ( aclFile . value ) + '/' && ! resourceExists ) {
108- accessDeniedForAccessTo ( 'Append' )
109- }
113+ if ( ( method === 'PUT' || method === 'PATCH' || method === 'COPY' ) ) { // && !aclFile.value.endsWith('/.acl')) {
114+ // accessTo Append from parent is required
115+ accessDeniedForAccessTo ( 'Append' )
110116 }
111117
112118 // For delete HTTP method
113- if ( ( method === 'DELETE' ) && directory ) {
114- // if resource and acl have same parent container,
115- // then accessTo Write from parent is required
116- if ( directory . value === dirname ( aclFile . value ) + '/' ) {
117- accessDeniedForAccessTo ( 'Write' )
118- }
119+ if ( ( method === 'DELETE' ) ) { // } && !aclFile.value.endsWith('/.acl')) {
120+ // accessTo Write from parent is required
121+ accessDeniedForAccessTo ( 'Write' )
119122 }
120123 if ( accessDenied && user ) {
121124 this . messagesCached [ cacheKey ] . push ( HTTPError ( 403 , accessDenied ) )
@@ -147,7 +150,12 @@ class ACLChecker {
147150 const possibleACLs = this . getPossibleACLs ( )
148151 const acls = [ ...possibleACLs ]
149152 let returnAcl = null
150- while ( possibleACLs . length > 0 && ! returnAcl ) {
153+ let returnParentAcl = null
154+ let parentAcl = null
155+ let parentGraph = null
156+ let docAcl = null
157+ let docGraph = null
158+ while ( possibleACLs . length > 0 && ! returnParentAcl ) {
151159 const acl = possibleACLs . shift ( )
152160 let graph
153161 try {
@@ -161,19 +169,32 @@ class ACLChecker {
161169 debug ( err )
162170 throw err
163171 }
164- const relative = resource . replace ( acl . replace ( / [ ^ / ] + $ / , '' ) , './' )
165- debug ( `Using ACL ${ acl } for ${ relative } ` )
166- returnAcl = { acl, graph, isContainer }
172+ // const relative = resource.replace(acl.replace(/[^/]+$/, ''), './')
173+ // debug(`Using ACL ${acl} for ${relative}`)
174+ if ( ! docAcl ) {
175+ docAcl = acl
176+ docGraph = graph
177+ if ( ( possibleACLs . length === 0 ) || docAcl . endsWith ( '/.acl' ) ) {
178+ parentAcl = acl // alain
179+ parentGraph = graph // alain
180+ returnParentAcl = true
181+ }
182+ } else {
183+ parentAcl = acl
184+ parentGraph = graph
185+ returnParentAcl = true
186+ }
187+ returnAcl = { docAcl, docGraph, isContainer, parentAcl, parentGraph }
167188 }
168- if ( ! returnAcl ) {
189+ if ( ! returnParentAcl ) {
169190 throw new HTTPError ( 500 , `No ACL found for ${ resource } , searched in \n- ${ acls . join ( '\n- ' ) } ` )
170191 }
171- const groupNodes = returnAcl . graph . statementsMatching ( null , ACL ( 'agentGroup' ) , null )
192+ const groupNodes = returnAcl . docGraph . statementsMatching ( null , ACL ( 'agentGroup' ) , null )
172193 const groupUrls = groupNodes . map ( node => node . object . value . split ( '#' ) [ 0 ] )
173194 await Promise . all ( groupUrls . map ( async groupUrl => {
174195 try {
175- const graph = await this . fetch ( groupUrl , returnAcl . graph )
176- this . requests [ groupUrl ] = this . requests [ groupUrl ] || graph
196+ const docGraph = await this . fetch ( groupUrl , returnAcl . docGraph )
197+ this . requests [ groupUrl ] = this . requests [ groupUrl ] || docGraph
177198 } catch ( e ) { } // failed to fetch groupUrl
178199 } ) )
179200
@@ -264,7 +285,7 @@ function fetchLocalOrRemote (mapper, serverUri) {
264285 // debugCache('Expunging from cache', url)
265286 delete temporaryCache [ url ]
266287 if ( Object . keys ( temporaryCache ) . length === 0 ) {
267- debugCache ( 'Cache is empty again' )
288+ // debugCache('Cache is empty again')
268289 }
269290 } , EXPIRY_MS ) ,
270291 promise : doFetch ( url )
0 commit comments