diff --git a/src/demo/App.js b/src/demo/App.js index d07fbd74..751817d0 100644 --- a/src/demo/App.js +++ b/src/demo/App.js @@ -79,11 +79,11 @@ const App = () => { const createAcl = async () => { if (webId) { const uri = new URL(webId); - const documentURI = `${uri.origin}/public/test`; + const documentURI = `${uri.origin}/public/container`; const { MODES } = AccessControlList; const permissions = [{ modes: [MODES.CONTROL], agents: [webId] }]; const aclInstance = new AccessControlList(webId, documentURI); - await aclInstance.createACLFile(permissions); + await aclInstance.createACL(permissions); } }; diff --git a/src/lib/classes/access-control-list.js b/src/lib/classes/access-control-list.js index 840a5118..6db85b12 100644 --- a/src/lib/classes/access-control-list.js +++ b/src/lib/classes/access-control-list.js @@ -11,7 +11,7 @@ type Permissions = { modes: Array }; -class AccessControlList { +export default class AccessControlList { constructor(owner, documentUri) { this.owner = owner; this.documentUri = documentUri; @@ -105,18 +105,21 @@ class AccessControlList { }; /** - * @function createACLFile Creates a file or container with a specific set of acls. Assigns READ, WRITE and CONTROL permissions to the owner by default + * @function createACL Creates a file or container with a specific set of acls. Assigns READ, WRITE and CONTROL permissions to the owner by default * @param {Array | null} permissions Array of permissions to be added in the acl file */ - createACLFile = async (permissions = null) => { - await this.createSolidFile(this.documentUri); - if (permissions) { - const permissionList = [ - { agents: this.owner, modes: [PERMISSIONS.READ, PERMISSIONS.WRITE, PERMISSIONS.CONTROL] }, - ...permissions - ]; - const body = this.createPermissionsTurtle(permissionList); - await this.createSolidFile(this.aclUri, { body }); + createACL = async (permissions = null) => { + try { + if (permissions) { + const permissionList = [ + { agents: this.owner, modes: [PERMISSIONS.READ, PERMISSIONS.WRITE, PERMISSIONS.CONTROL] }, + ...permissions + ]; + const body = this.createPermissionsTurtle(permissionList); + return await this.createSolidResource(this.aclUri, { body }); + } + } catch (error) { + throw error; } }; @@ -125,7 +128,7 @@ class AccessControlList { * @param {String} url Url where the solid file has to be created * @param {Object} options Options to add as part of the native fetch options object */ - createSolidFile = async (url: String, options: Object = {}) => + createSolidResource = async (url: String, options: Object = {}) => solid.fetch(url, { method: 'PUT', headers: { @@ -306,19 +309,21 @@ class AccessControlList { * @param {Array | null | String} permissionss An array of permissions to be removed */ removePermissions = async permissions => { - const aclPermissions = await this.getPermissions(); - for await (const permission of permissions) { - const { modes, agents } = permission; - const modeExists = aclPermissions.filter(per => this.isSameMode(per.modes, modes)); - if (modeExists.length > 0) { - const mode = modeExists[0]; - const agentsExists = mode.agents.filter(agent => agents.includes(agent)); - for await (const agent of agentsExists) { - await this.removePermissionsFromMode(mode, agent); + try { + const aclPermissions = await this.getPermissions(); + for await (const permission of permissions) { + const { modes, agents } = permission; + const modeExists = aclPermissions.filter(per => this.isSameMode(per.modes, modes)); + if (modeExists.length > 0) { + const mode = modeExists[0]; + const agentsExists = mode.agents.filter(agent => agents.includes(agent)); + for await (const agent of agentsExists) { + await this.removePermissionsFromMode(mode, agent); + } } } + } catch (e) { + throw e; } }; } - -export default AccessControlList; diff --git a/src/lib/classes/notification.js b/src/lib/classes/notification.js index af58dca2..35d199c9 100644 --- a/src/lib/classes/notification.js +++ b/src/lib/classes/notification.js @@ -3,6 +3,7 @@ import N3 from 'n3'; import solidLDflex from '@solid/query-ldflex'; import { solidResponse, SolidError, getBasicPod } from '@utils'; import defaultShape from '../shapes/notification.json'; +import AccessControlList from './access-control-list'; const PREFIXES = { terms: 'https://www.w3.org/ns/solid/terms#', @@ -115,15 +116,16 @@ export class Notification { * @param owner * @returns {Promise<*>} */ - createInbox = async (inboxPath, appPath, settingFileName = 'settings.ttl') => { try { + const newInboxPath = inboxPath.endsWith('/') ? inboxPath : `${inboxPath}/`; + const newAppPath = appPath.endsWith('/') ? appPath : `${appPath}/`; /** * Check if inbox already exists or not in the target path. * @type {*|boolean} */ - const hasInbox = await this.hasInbox(inboxPath); - const appSettingPat = `${appPath}${settingFileName}`; + const hasInbox = await this.hasInbox(newInboxPath); + const appSettingPath = `${newAppPath}${settingFileName}`; /** * if container exist will return message without changes. */ @@ -132,119 +134,35 @@ export class Notification { if (!this.owner) throw new SolidError('Owner is undefined', 'Inbox', 500); /** - * Start to build ACL file to add access to owner and users to inbox container - * To know more about ACL please go to: https://github.com/solid/web-access-control-spec - */ - const termFactory = N3.DataFactory; - const { namedNode } = termFactory; - const writer = new N3.Writer({ - prefixes: { - ns: PREFIXES.ns, - foaf: PREFIXES.foaf, - acl: PREFIXES.acl - }, - format: 'text/turtle' - }); - - /** - * Add Quad type Authorization - */ - writer.addQuad(namedNode('#owner'), namedNode('ns:type'), namedNode('acl:Authorization')); - /** - * Add agent permission to owner - */ - writer.addQuad(namedNode('#owner'), namedNode('acl:agent'), namedNode(this.owner)); - /** - * Add access reference to the container folder + * Create inbox reference to be discovered in the pod into settings.ttl */ - writer.addQuad(namedNode('#owner'), namedNode('acl:accessTo'), namedNode('./')); - writer.addQuad(namedNode('#owner'), namedNode('acl:defaultForNew'), namedNode('./')); + const settingsResult = await this.settingsTurtle(appSettingPath, newInboxPath); /** - * Add roles to owner Read, Write and Control + * Check if settings reference was created it if not we will try one time more. */ - writer.addQuad( - namedNode('#owner'), - namedNode('acl:mode'), - namedNode('acl:Read, acl:Write, acl:Control') - ); + if (!settingsResult.ok) await this.settingsTurtle(appSettingPath, newInboxPath); /** - * Add permissions to public users + * Create inbox container */ - writer.addQuad(namedNode('#public'), namedNode('ns:type'), namedNode('acl:Authorization')); - - writer.addQuad( - namedNode('#public'), - namedNode('acl:agentClass'), - namedNode('http://xmlns.com/foaf/0.1/Agent') - ); - /** - * Add access reference to the container folder - */ - writer.addQuad(namedNode('#public'), namedNode('acl:accessTo'), namedNode('./')); + const resultInbox = await solid.fetch(`${newInboxPath}.dummy`, { + method: 'PUT', + headers: { + 'Content-Type': 'text/turtle' + } + }); - writer.addQuad(namedNode('#public'), namedNode('acl:defaultForNew'), namedNode('./')); /** - * Add roles to public Append + * If create inbox fail we return an error message */ - writer.addQuad(namedNode('#public'), namedNode('acl:mode'), namedNode('acl:Append')); - - await writer.end(async (error, result) => { - if (error) { - throw error; - } + if (!resultInbox.ok) + throw new SolidError('Error when tried to create an inbox', 'Error', resultInbox.status); - /** - * Create inbox container - */ - const resultInbox = await solid.fetch(`${inboxPath}.dummy`, { - method: 'PUT', - headers: { - 'Content-Type': 'text/turtle' - } - }); - - /** - * If create inbox fail we return an error message - */ - if (!resultInbox.ok) - throw new SolidError( - result.message || 'Error when tried to create an inbox', - 'Error', - resultInbox.status - ); - - await solid.fetch(`${inboxPath}.dummy`, { method: 'DELETE' }); - - /** - * Create inbox reference to be discovered in the pod into settings.ttl - */ - const settingsResult = await this.settingsTurtle(appSettingPat, inboxPath); - - /** - * Check if settings reference was created it if not we will try one time more. - */ - if (!settingsResult.ok) await this.settingsTurtle(appSettingPat, inboxPath); - - /** - * Create a default ACL for inbox container - */ - const resultAcl = await solid.fetch(`${inboxPath}.acl`, { - method: 'PUT', - body: result, - headers: { - 'Content-Type': 'text/turtle' - } - }); - - if (!resultAcl.ok) - throw new SolidError( - result.message || 'An error when tried to assign permissions', - 'Error', - resultAcl.status - ); - }); + await solid.fetch(`${newInboxPath}.dummy`, { method: 'DELETE' }); + const permissions = [{ agents: null, modes: [AccessControlList.MODES.APPEND] }]; + const aclContainer = new AccessControlList(this.owner, newInboxPath); + await aclContainer.createACL(permissions); return solidResponse(200, 'Inbox was created'); } catch (error) { diff --git a/src/lib/index.js b/src/lib/index.js index 7b4c2413..38209b88 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -20,6 +20,8 @@ import { import { useNotification } from '@hooks'; +import { AccessControlList } from '@classes'; + export { ProviderLogin, PrivateRoute, @@ -36,5 +38,6 @@ export { useLatestUpdate, ShexForm, ShexFormBuilder, - useNotification + useNotification, + AccessControlList };