11'use strict'
22
3- const PermissionSet = require ( 'solid-permissions' ) . PermissionSet
3+ // const PermissionSet = require('solid-permissions').PermissionSet
44const rdf = require ( 'rdflib' )
55const debug = require ( './debug' ) . ACL
66const HTTPError = require ( './http-error' )
@@ -14,32 +14,29 @@ class ACLChecker {
1414 constructor ( resource , options = { } ) {
1515 this . resource = resource
1616 this . host = options . host
17- this . origin = options . origin
17+ this . agentOrigin = options . origin
1818 this . fetch = options . fetch
1919 this . fetchGraph = options . fetchGraph
2020 this . strictOrigin = options . strictOrigin
2121 this . trustedOrigins = options . trustedOrigins
2222 this . suffix = options . suffix || DEFAULT_ACL_SUFFIX
23+ this . aclCached = { }
24+ this . messagesCached = { }
2325 }
2426
2527 // Returns a fulfilled promise when the user can access the resource
2628 // in the given mode, or rejects with an HTTP error otherwise
2729 async can ( user , mode ) {
30+ const cacheKey = `${ mode } -${ user } `
31+ if ( this . aclCached [ cacheKey ] ) {
32+ return this . aclCached [ cacheKey ]
33+ }
34+ this . messagesCached [ cacheKey ] = this . messagesCached [ cacheKey ] || [ ]
2835 // If this is an ACL, Control mode must be present for any operations
2936 if ( this . isAcl ( this . resource ) ) {
3037 mode = 'Control'
3138 }
3239
33- // Obtain the permission set for the resource
34- // this.acl.graph
35- // this.resource
36- // this.acl.isContainer ? this.resource : null
37- // this.acl.acl
38- // user
39- // ACL(mode)
40- // this.origin
41- // this.trustedOrigins
42-
4340 // console.log('ACL', this.origin, this.trustedOrigins)
4441 // console.log(aclCheck.accessDenied)
4542 // if (!this._permissionSet) {
@@ -50,30 +47,56 @@ class ACLChecker {
5047 // aclCheck.checkAccess(acl.graph, this.resource)
5148
5249 // Check the resource's permissions
50+ < << << << 2740 f8873bfe7d7edcf0c2c31f927a106dc0abc7
5351 this . acl = this . acl || await this . getNearestACL ( ) . catch ( err => {
5452 throw new HTTPError ( 500 , `Found no ACL file:\n${ err } ` )
5553 } )
54+ === = ===
55+ const acl = await this . getNearestACL ( )
56+ . catch ( err => {
57+ this . messagesCached [ cacheKey ] . push ( new HTTPError ( 500 , err ) )
58+ } )
59+ if ( ! acl ) {
60+ this . aclCached [ cacheKey ] = Promise . resolve ( false )
61+ return this . aclCached [ cacheKey ]
62+ }
63+ > >>> >>> Trying another approach to acl . can
5664 // console.log('TEST', this.acl)
5765 const resource = rdf . sym ( this . resource )
58- // const directory = this. acl.isContainer ? this.resource : null
59- const directory = this . acl . isContainer ? rdf . sym ( ACLChecker . getDirectory ( this . acl . acl ) ) : null
60- // console.log(ACLChecker.getDirectory(this. acl.acl))
61- const aclFile = rdf . sym ( this . acl . acl )
66+ // const directory = acl.isContainer ? this.resource : null
67+ const directory = acl . isContainer ? rdf . sym ( ACLChecker . getDirectory ( acl . acl ) ) : null
68+ // console.log(ACLChecker.getDirectory(acl.acl))
69+ const aclFile = rdf . sym ( acl . acl )
6270 // const agent = rdf.sym(user)
6371 const agent = user ? rdf . sym ( user ) : null
6472 // console.log('ACL agent', agent)
65- // console.log('ACL FILE', this.resource, this. acl.acl)
73+ // console.log('ACL FILE', this.resource, acl.acl)
6674 const modes = [ ACL ( mode ) ]
67- const origin = this . origin ? rdf . sym ( this . origin ) : null
75+ const agentOrigin = this . agentOrigin ? rdf . sym ( this . agentOrigin ) : null
6876 const trustedOrigins = this . trustedOrigins ? this . trustedOrigins . map ( trustedOrigin => rdf . sym ( trustedOrigin ) ) : null
69- const accessDenied = aclCheck . accessDenied ( this . acl . graph , resource , directory , aclFile , agent , modes , origin , trustedOrigins )
70- console . log ( 'ACCESS DENIED ' , accessDenied , '\n\n' )
77+ const accessDenied = aclCheck . accessDenied ( acl . graph , resource , directory , aclFile , agent , modes , agentOrigin , trustedOrigins )
78+ console . log ( 'BAR ' , accessDenied )
7179 if ( accessDenied && user ) {
80+ < << << << 2740 f8873bfe7d7edcf0c2c31f927a106dc0abc7
7281 throw new HTTPError ( 403 , accessDenied )
7382 } else if ( accessDenied ) {
7483 throw new HTTPError ( 401 , 'Unauthenticated' )
84+ === = ===
85+ this . messagesCached [ cacheKey ] . push ( new HTTPError ( 403 , `Access to ${ this . resource } denied for ${ user } : ${ accessDenied } ` ) )
86+ } else if ( accessDenied ) {
87+ this . messagesCached [ cacheKey ] . push ( new HTTPError ( 401 , `Access to ${ this . resource } requires authorization: ${ accessDenied } ` ) )
88+ >>> > >>> Trying another approach to acl . can
7589 }
76- return Promise . resolve ( true )
90+ console . log ( 'ACCESS ALLOWED' , ! accessDenied , user , '\n\n' )
91+ this . aclCached [ cacheKey ] = Promise . resolve ( ! accessDenied )
92+ return this . aclCached
93+ }
94+
95+ async getError ( mode , user ) {
96+ const cacheKey = `${ mode } -${ user } `
97+ this . aclCached [ cacheKey ] = this . aclCached [ cacheKey ] || this . can ( user , mode )
98+ const isAllowed = await this . aclCached [ cacheKey ]
99+ return isAllowed ? null : this . messagesCached [ cacheKey ] . reduce ( ( prevMsg , msg ) => msg . status > prevMsg . status ? msg : prevMsg , { status : 0 } )
77100 }
78101
79102 // return Promise.resolve(true)
@@ -93,13 +116,14 @@ class ACLChecker {
93116 return `${ parts . join ( '/' ) } /`
94117 }
95118
96- // Gets the ACL that applies to the resource
119+ // Gets the ACL that applies to the resource
97120 async getNearestACL ( ) {
98121 const { resource } = this
99122 let isContainer = false
100123 // let directory = null
101124 // Create a cascade of reject handlers (one for each possible ACL)
102125 const possibleACLs = this . getPossibleACLs ( )
126+ << < << << 2740 f8873bfe7d7edcf0c2c31f927a106dc0abc7
103127 const nearestACL = possibleACLs . reduce ( ( prevACL , acl ) => {
104128 return prevACL . catch ( ( ) => new Promise ( ( resolve , reject ) => {
105129 this . fetch ( acl , ( err , graph ) => {
@@ -118,6 +142,47 @@ class ACLChecker {
118142 } ) )
119143 } , Promise . reject ( ) )
120144 return nearestACL . catch ( e => { throw new Error ( `No ACL resource found, searched in \n- ${ possibleACLs . join ( '\n- ' ) } ` ) } )
145+ === = ===
146+ const acls = [ ...possibleACLs ]
147+ let returnAcl = null
148+ while ( possibleACLs . length > 0 && ! returnAcl ) {
149+ const acl = possibleACLs . shift ( )
150+ try {
151+ const graph = await this . fetch ( acl )
152+ const relative = resource . replace ( acl . replace ( / [ ^ / ] + $ / , '' ) , './' )
153+ debug ( `Using ACL ${ acl } for ${ relative } ` )
154+ returnAcl = { acl, graph, isContainer }
155+ } catch ( err ) {
156+ if ( err && err . code === 'ENOENT' ) {
157+ isContainer = true
158+ return
159+ } else if ( err ) {
160+ console . error ( 'ERROR IN getNearestACL' , err )
161+ debug ( err )
162+ throw err
163+ }
164+ }
165+ }
166+ if ( ! returnAcl ) {
167+ throw new Error ( `No ACL found for ${ resource } , searched in \n- ${ acls . join ( '\n- ' ) } ` )
168+ }
169+ return returnAcl
170+ // const nearestACL = possibleACLs.reduce((prevACL, acl) => {
171+ // return prevACL.catch(() => new Promise((resolve, reject) => {
172+ // this.fetch(acl, (err, graph) => {
173+ // if (err && err.code !== 'ENOENT') {
174+ // isContainer = true
175+ // reject(err)
176+ // } else {
177+ // const relative = resource.replace(acl.replace(/[^/]+$/, ''), './')
178+ // debug(`Using ACL ${acl} for ${relative}`)
179+ // resolve({ acl, graph, isContainer })
180+ // }
181+ // })
182+ // }))
183+ // }, Promise.reject())
184+ // return nearestACL.catch(e => { throw new Error(`No ACL resource found, searched in \n- ${possibleACLs.join('\n- ')}`) })
185+ >>> > >>> Trying another approach to acl . can
121186 }
122187
123188// Gets all possible ACL paths that apply to the resource
@@ -140,41 +205,41 @@ class ACLChecker {
140205 }
141206
142207// Tests whether the permissions allow a given operation
143- checkAccess ( permissionSet , user , mode ) {
144- const options = { fetchGraph : this . fetchGraph }
145- return permissionSet . checkAccess ( this . resource , user , mode , options )
146- . then ( hasAccess => {
147- if ( hasAccess ) {
148- return true
149- } else {
150- throw new Error ( 'ACL file found but no matching policy found' )
151- }
152- } )
153- }
208+ // checkAccess (permissionSet, user, mode) {
209+ // const options = { fetchGraph: this.fetchGraph }
210+ // return permissionSet.checkAccess(this.resource, user, mode, options)
211+ // .then(hasAccess => {
212+ // if (hasAccess) {
213+ // return true
214+ // } else {
215+ // throw new Error('ACL file found but no matching policy found')
216+ // }
217+ // })
218+ // }
154219
155220// Gets the permission set for the given ACL
156- getPermissionSet ( { acl, graph, isContainer } ) {
157- if ( ! graph || graph . length === 0 ) {
158- debug ( 'ACL ' + acl + ' is empty' )
159- throw new Error ( 'No policy found - empty ACL' )
160- }
161- const aclOptions = {
162- aclSuffix : this . suffix ,
163- graph : graph ,
164- host : this . host ,
165- origin : this . origin ,
166- rdf : rdf ,
167- strictOrigin : this . strictOrigin ,
168- trustedOrigins : this . trustedOrigins ,
169- isAcl : uri => this . isAcl ( uri ) ,
170- aclUrlFor : uri => this . aclUrlFor ( uri )
171- }
172- return new PermissionSet ( this . resource , acl , isContainer , aclOptions )
173- }
174-
175- aclUrlFor ( uri ) {
176- return this . isAcl ( uri ) ? uri : uri + this . suffix
177- }
221+ // getPermissionSet ({ acl, graph, isContainer }) {
222+ // if (!graph || graph.length === 0) {
223+ // debug('ACL ' + acl + ' is empty')
224+ // throw new Error('No policy found - empty ACL')
225+ // }
226+ // const aclOptions = {
227+ // aclSuffix: this.suffix,
228+ // graph: graph,
229+ // host: this.host,
230+ // origin: this.origin,
231+ // rdf: rdf,
232+ // strictOrigin: this.strictOrigin,
233+ // trustedOrigins: this.trustedOrigins,
234+ // isAcl: uri => this.isAcl(uri),
235+ // aclUrlFor: uri => this.aclUrlFor(uri)
236+ // }
237+ // return new PermissionSet(this.resource, acl, isContainer, aclOptions)
238+ // }
239+
240+ // aclUrlFor (uri) {
241+ // return this.isAcl(uri) ? uri : uri + this.suffix
242+ // }
178243
179244 isAcl ( resource ) {
180245 return resource . endsWith ( this . suffix )
0 commit comments