|
| 1 | +'use strict' |
| 2 | + |
| 3 | +const LdpRequest = require('./ldp-request') |
| 4 | +const AclChecker = require('../acl-checker') |
| 5 | +const LdpFileStore = require('../storage/ldp-file-store') |
| 6 | + |
| 7 | +class LdpApi { |
| 8 | + /** |
| 9 | + * @param options.host {SolidHost} server host / config object |
| 10 | + * |
| 11 | + * @param options.store {LdpFileStore|LdpMemoryStore|LdpQuadStore} storage backend |
| 12 | + * (either file system based, or in-memory, or SPARQL based quad store, etc) |
| 13 | + * |
| 14 | + * @param options.fetch {fetch} whatwg fetch, possibly with delegation in the |
| 15 | + * future. Needed for COPY operations, etc. |
| 16 | + * |
| 17 | + * @param options.acl {AclChecker} ACL checker component |
| 18 | + */ |
| 19 | + constructor (options) { |
| 20 | + this.host = options.host |
| 21 | + this.fetch = options.fetch |
| 22 | + this.store = options.store || new LdpFileStore(options) |
| 23 | + this.acl = options.acl || |
| 24 | + new AclChecker({host: this.host, store: this.store, fetch: this.fetch}) |
| 25 | + } |
| 26 | + |
| 27 | + /** |
| 28 | + * Provides an Express handler for LDP API requests. |
| 29 | + * Authentication has already happened earlier in the middleware stack, stored |
| 30 | + * in session. |
| 31 | + * Usage: |
| 32 | + * ``` |
| 33 | + * app.use('/', ldp.middleware) |
| 34 | + * ``` |
| 35 | + * |
| 36 | + * @see https://github.com/solid/solid-architecture/blob/master/server/request-flow.md |
| 37 | + * |
| 38 | + * @throws {Error} 401 If request not authenticated but resource is non-public |
| 39 | + * |
| 40 | + * @throws {Error} 404 If resource is not found, OR if found and request |
| 41 | + * is not authorized to access it (default behavior, can be overridden by |
| 42 | + * owner of resource) |
| 43 | + * |
| 44 | + * @throws {Error} 403 If request is not authorized to access resource and |
| 45 | + * user has enabled "Request permission" action |
| 46 | + * |
| 47 | + * @throws {Error} 400 If invalid parameters (or error parsing request body, |
| 48 | + * for cases like PATCH requests) |
| 49 | + * |
| 50 | + * @throws {Error} 409 If PATCH operation results in conflict |
| 51 | + * |
| 52 | + * @throws {Error} 406 If no appropriate representation found (for content type) |
| 53 | + * |
| 54 | + * @throws {Error} 405 If HTTP method not allowed / not implemented |
| 55 | + */ |
| 56 | + async middleware (req, res, next) { |
| 57 | + try { |
| 58 | + // parse target, operation, (optionally) body, preferences, store authn |
| 59 | + const request = await LdpRequest.from({req, host: this.host}) |
| 60 | + |
| 61 | + // check that operation is permitted (throws error if not) |
| 62 | + const permissions = await this.acl.allow(request) |
| 63 | + |
| 64 | + // perform the operation and return a response |
| 65 | + await request |
| 66 | + .handle({res, permissions, store: this.store, fetch: this.fetch}) |
| 67 | + } catch (error) { |
| 68 | + next(error) |
| 69 | + } |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +module.exports = LdpApi |
0 commit comments