Repository navigation
Virtual resource for account resource and visualizing that data on frontpage #1060
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fd43a24
671031e
91aa445
0f0fa9e
4353125
803de27
8ebda5d
8720f9b
7766793
ee1a116
b79bd56
86a33e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,8 @@ const debug = require('./debug').ACL | |
| const HTTPError = require('./http-error') | ||
| const aclCheck = require('@solid/acl-check') | ||
| const { URL } = require('url') | ||
| const { promisify } = require('util') | ||
| const fs = require('fs') | ||
|
|
||
| const DEFAULT_ACL_SUFFIX = '.acl' | ||
| const ACL = rdf.Namespace('http://www.w3.org/ns/auth/acl#') | ||
|
|
@@ -144,6 +146,49 @@ class ACLChecker { | |
| isAcl (resource) { | ||
| return resource.endsWith(this.suffix) | ||
| } | ||
|
|
||
| static createFromLDPAndRequest (resource, ldp, req) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be moved as a method to
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's fine to keep it here, but not strong opinion. |
||
| const trustedOrigins = ldp.getTrustedOrigins(req) | ||
| return new ACLChecker(resource, { | ||
| agentOrigin: req.get('origin'), | ||
| // host: req.get('host'), | ||
| fetch: fetchFromLdp(ldp.resourceMapper), | ||
| fetchGraph: (uri, options) => { | ||
| // first try loading from local fs | ||
| return ldp.getGraph(uri, options.contentType) | ||
| // failing that, fetch remote graph | ||
| .catch(() => ldp.fetchGraph(uri, options)) | ||
| }, | ||
| suffix: ldp.suffixAcl, | ||
| strictOrigin: ldp.strictOrigin, | ||
| trustedOrigins | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns a fetch document handler used by the ACLChecker to fetch .acl | ||
| * resources up the inheritance chain. | ||
| * The `fetch(uri, callback)` results in the callback, with either: | ||
| * - `callback(err, graph)` if any error is encountered, or | ||
| * - `callback(null, graph)` with the parsed RDF graph of the fetched resource | ||
| * @return {Function} Returns a `fetch(uri, callback)` handler | ||
| */ | ||
| function fetchFromLdp (mapper) { | ||
| return async function fetch (url, graph = rdf.graph()) { | ||
| // Convert the URL into a filename | ||
| let path, contentType | ||
| try { | ||
| ({ path, contentType } = await mapper.mapUrlToFile({ url })) | ||
| } catch (err) { | ||
| throw new HTTPError(404, err) | ||
| } | ||
| // Read the file from disk | ||
| const body = await promisify(fs.readFile)(path, {'encoding': 'utf8'}) | ||
| // Parse the file as Turtle | ||
| rdf.parse(body, graph, url, contentType) | ||
| return graph | ||
| } | ||
| } | ||
|
|
||
| // Returns the index of the last slash before the given position | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| 'use strict' | ||
|
|
||
| const ACLChecker = require('../acl-checker') | ||
| const AuthRequest = require('./auth-request') | ||
| const { actualSize } = require('../utils') | ||
| const $rdf = require('rdflib') | ||
| const HTTPError = require('../http-error') | ||
|
|
||
| const PIM = $rdf.Namespace('http://www.w3.org/ns/pim/space#') | ||
| const SOLID = $rdf.Namespace('http://www.w3.org/ns/solid/terms#') | ||
|
|
||
| class GetAccountInfoRequest extends AuthRequest { | ||
| static async get (req, res) { | ||
| const contentType = req.get('content-type') || 'text/turtle' | ||
| const body = await getBody(req, contentType) | ||
| if (body.status && body.status >= 400) { | ||
| return res.status(body.status).send(body.message) | ||
| } | ||
| return res.status(200).set('Content-Type', contentType).send(body) | ||
| } | ||
| } | ||
|
|
||
| async function getBody (req, contentType) { | ||
| const userId = req.session.userId | ||
| if (!userId) { | ||
| return new HTTPError(401, 'Requires authentication') | ||
| } | ||
| const ldp = req.app.locals.ldp | ||
| const rootUrl = `${ldp.resourceMapper.resolveUrl(req.hostname)}/` | ||
| const acl = ACLChecker.createFromLDPAndRequest(rootUrl, ldp, req) | ||
| const isAllowed = await acl.can(userId, 'Control') | ||
| if (!isAllowed) { | ||
| return await req.acl.getError(userId, 'Control') | ||
| } | ||
|
|
||
| // Dereference graph for webId | ||
| let userIdGraph | ||
| try { | ||
| userIdGraph = await ldp.getGraph(userId) | ||
| } catch (err) { | ||
| return err | ||
| } | ||
|
|
||
| // Get object value for pim:storage | ||
| const storageUrlNode = userIdGraph.any($rdf.sym(userId), PIM('storage')) | ||
| if (!storageUrlNode) { | ||
| return new HTTPError(404, 'Unable to find pim:storage for webId') | ||
| } | ||
|
|
||
| // Dereference graph for serverSide.ttl | ||
| const serverSideUrl = `${storageUrlNode.value}settings/serverSide.ttl` // needs to be hardcoded for now | ||
| let serverSideGraph | ||
| try { | ||
| serverSideGraph = await ldp.getGraph(serverSideUrl) | ||
| } catch (err) { | ||
| return err | ||
| } | ||
|
|
||
| // Get object value for solid:storageQuota | ||
| const quotaNode = serverSideGraph.any(storageUrlNode, SOLID('storageQuota'), null) | ||
| if (!quotaNode) { | ||
| return new HTTPError(404, 'Unable to find solid:storageQuota') | ||
| } | ||
|
|
||
| // Get size of user's POD | ||
| const root = ldp.resourceMapper.getFullPath(rootUrl) | ||
| const size = await actualSize(root) | ||
|
|
||
| // Add triples to graph | ||
| const store = $rdf.graph() | ||
| store.add(storageUrlNode, SOLID('storageUsage'), $rdf.lit(size)) | ||
| store.add(storageUrlNode, SOLID('storageQuota'), quotaNode) | ||
| return await new Promise((resolve, reject) => { | ||
| $rdf.serialize(null, store, storageUrlNode.value, contentType, (err, result) => { | ||
| if (err) { | ||
| return reject(err) | ||
| } | ||
| resolve(result) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| module.exports = GetAccountInfoRequest |
Uh oh!
There was an error while loading. Please reload this page.