UNPKG

@inrupt/solid-client

Version:
465 lines (453 loc) • 21 kB
/** * Copyright 2020 Inrupt Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import { hasAccessibleAcl } from "../acl/acl"; import { getResourceInfoWithAcr, hasAccessibleAcr, saveAcrFor, } from "../acp/acp"; import { UrlString, WebId } from "../interfaces"; import { getSourceIri, internal_defaultFetchOptions, } from "../resource/resource"; import { internal_getAgentAccess as getAgentAccessAcp, internal_getAgentAccessAll as getAgentAccessAllAcp, internal_setAgentAccess as setAgentAccessAcp, internal_getGroupAccess as getGroupAccessAcp, internal_getGroupAccessAll as getGroupAccessAllAcp, internal_setGroupAccess as setGroupAccessAcp, internal_getPublicAccess as getPublicAccessAcp, internal_setPublicAccess as setPublicAccessAcp, } from "./acp"; import { getAgentAccess as getAgentAccessWac, getAgentAccessAll as getAgentAccessAllWac, setAgentResourceAccess as setAgentAccessWac, getGroupAccess as getGroupAccessWac, getGroupAccessAll as getGroupAccessAllWac, setGroupResourceAccess as setGroupAccessWac, getPublicAccess as getPublicAccessWac, setPublicResourceAccess as setPublicAccessWac, WacAccess, } from "./wac"; /** * Each of the following access modes is in one of two states: * - true: this access mode is granted, or * - false: this access mode is not granted. * @since 1.5.0 */ export interface Access { read: boolean; append: boolean; write: boolean; controlRead: boolean; controlWrite: boolean; } /** * Get an overview of what access is defined for a given Agent. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably reading access, in which case it will * resolve to `null`. * - It will only return access specified explicitly for the given Agent. If * additional restrictions are set up to apply to the given Agent in a * particular situation, those will not be reflected in the return value of * this function. * - It will only return access specified explicitly for the given Resource. * In other words, if the Resource is a Container, the returned Access may not * apply to contained Resources. * - If the current user does not have permission to view access for the given * Resource, this function will resolve to `null`. * * @param resourceUrl URL of the Resource you want to read the access for. * @param webId WebID of the Agent you want to get the access for. * @since 1.5.0 */ export async function getAgentAccess( resourceUrl: UrlString, webId: WebId, options = internal_defaultFetchOptions ): Promise<Access | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { return getAgentAccessAcp(resourceInfo, webId); } if (hasAccessibleAcl(resourceInfo)) { return await getAgentAccessWac(resourceInfo, webId, options); } return null; } /** * Set access to a Resource for a specific Agent. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably setting access, in which case it will * resolve to `null`. * - It will only set access explicitly for the given Agent. In other words, * additional restrictions could be present that further restrict or loosen * what access the given Agent has in particular circumstances. * - The provided access will only apply to the given Resource. In other words, * if the Resource is a Container, the configured Access may not apply to * contained Resources. * - If the current user does not have permission to view or change access for * the given Resource, this function will resolve to `null`. * * Additionally, two caveats apply to users with a Pod server that uses WAC: * - If the Resource did not have an ACL yet, a new one will be initialised. * This means that changes to the ACL of a parent Container can no longer * affect access people have to this Resource, although existing access will * be preserved. * - Setting different values for `controlRead` and `controlWrite` is not * supported, and **will throw an error**. If you expect (some of) your users * to have Pods implementing WAC, be sure to pass the same value for both. * * @param resourceUrl URL of the Resource you want to change the Agent's access to. * @param webId WebID of the Agent you want to set access for. * @param access What access permissions you want to set for the given Agent to the given Resource. Possible properties are `read`, `append`, `write`, `controlRead` and `controlWrite`: set to `true` to allow, to `false` to stop allowing, or `undefined` to leave unchanged. Take note that `controlRead` and `controlWrite` can not have distinct values for a Pod server implementing Web Access Control; trying this will throw an error. * @returns What access has been set for the given Agent explicitly. * @since 1.5.0 */ export async function setAgentAccess( resourceUrl: UrlString, webId: WebId, access: Partial<Access>, options = internal_defaultFetchOptions ): Promise<Access | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { const updatedResource = setAgentAccessAcp(resourceInfo, webId, access); if (updatedResource) { try { await saveAcrFor(updatedResource, options); return getAgentAccessAcp(updatedResource, webId); } catch (e) { return null; } } return null; } if (hasAccessibleAcl(resourceInfo)) { if (access.controlRead != access.controlWrite) { throw new Error( `When setting access for a Resource in a Pod implementing Web Access Control (i.e. [${getSourceIri( resourceInfo )}]), ` + "`controlRead` and `controlWrite` should have the same value." ); } const wacAccess = access as WacAccess; await setAgentAccessWac(resourceInfo, webId, wacAccess, options); return await getAgentAccessWac(resourceInfo, webId, options); } return null; } /** * Get an overview of what access is defined for all Agents with respect to a given * Resource. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably reading access, in which case it will * resolve to `null`. * - It will only return access specified explicitly for the returned Agents. If * additional restrictions are set up to apply to the listed Agents in a * particular situation, those will not be reflected in the return value of * this function. * - It will only return access specified explicitly for the given Resource. * In other words, if the Resource is a Container, the returned Access may not * apply to contained Resources. * - If the current user does not have permission to view access for the given * Resource, this function will resolve to `null`. * * @param resourceUrl URL of the Resource you want to read the access for. * @returns The access information to the Resource, grouped by Agent. * @since 1.5.0 */ export async function getAgentAccessAll( resourceUrl: UrlString, options = internal_defaultFetchOptions ): Promise<Record<WebId, Access> | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { return getAgentAccessAllAcp(resourceInfo); } if (hasAccessibleAcl(resourceInfo)) { return await getAgentAccessAllWac(resourceInfo, options); } return null; } /** * Get an overview of what access is defined for a given Group. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably reading access, in which case it will * resolve to `null`. * - It will only return access specified explicitly for the given Group. If * additional restrictions are set up to apply to the given Group in a * particular situation, those will not be reflected in the return value of * this function. * - It will only return access specified explicitly for the given Resource. * In other words, if the Resource is a Container, the returned Access may not * apply to contained Resources. * - If the current user does not have permission to view access for the given * Resource, this function will resolve to `null`. * * @param resourceUrl URL of the Resource you want to read the access for. * @param webId WebID of the Group you want to get the access for. * @since 1.5.0 */ export async function getGroupAccess( resourceUrl: UrlString, webId: WebId, options = internal_defaultFetchOptions ): Promise<Access | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { return getGroupAccessAcp(resourceInfo, webId); } if (hasAccessibleAcl(resourceInfo)) { return await getGroupAccessWac(resourceInfo, webId, options); } return null; } /** * Get an overview of what access is defined for all Groups with respect to a given * Resource. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably reading access, in which case it will * resolve to `null`. * - It will only return access specified explicitly for the returned Groups. If * additional restrictions are set up to apply to the listed Groups in a * particular situation, those will not be reflected in the return value of * this function. * - It will only return access specified explicitly for the given Resource. * In other words, if the Resource is a Container, the returned Access may not * apply to contained Resources. * - If the current user does not have permission to view access for the given * Resource, this function will resolve to `null`. * * @param resourceUrl URL of the Resource you want to read the access for. * @returns The access information to the Resource, sorted by Group. * @since 1.5.0 */ export async function getGroupAccessAll( resourceUrl: UrlString, options = internal_defaultFetchOptions ): Promise<Record<UrlString, Access> | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { return getGroupAccessAllAcp(resourceInfo); } if (hasAccessibleAcl(resourceInfo)) { return await getGroupAccessAllWac(resourceInfo, options); } return null; } /** * Set access to a Resource for a specific Group. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably setting access, in which case it will * resolve to `null`. * - It will only set access explicitly for the given Group. In other words, * additional restrictions could be present that further restrict or loosen * what access the given Group has in particular circumstances. * - The provided access will only apply to the given Resource. In other words, * if the Resource is a Container, the configured Access may not apply to * contained Resources. * - If the current user does not have permission to view or change access for * the given Resource, this function will resolve to `null`. * * Additionally, two caveats apply to users with a Pod server that uses WAC: * - If the Resource did not have an ACL yet, a new one will be initialised. * This means that changes to the ACL of a parent Container can no longer * affect access people have to this Resource, although existing access will * be preserved. * - Setting different values for `controlRead` and `controlWrite` is not * supported, and **will throw an error**. If you expect (some of) your users * to have Pods implementing WAC, be sure to pass the same value for both. * * @param resourceUrl URL of the Resource you want to change the Group's access to. * @param groupUrl URL of the Group you want to set access for. * @param access What access permissions you want to set for the given Group to the given Resource. Possible properties are `read`, `append`, `write`, `controlRead` and `controlWrite`: set to `true` to allow, to `false` to stop allowing, or `undefined` to leave unchanged. Take note that `controlRead` and `controlWrite` can not have distinct values for a Pod server implementing Web Access Control; trying this will throw an error. * @returns What access has been set for the given Group explicitly. * @since 1.5.0 */ export async function setGroupAccess( resourceUrl: UrlString, groupUrl: UrlString, access: Partial<Access>, options = internal_defaultFetchOptions ): Promise<Access | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { const updatedResource = setGroupAccessAcp(resourceInfo, groupUrl, access); if (updatedResource) { try { await saveAcrFor(updatedResource, options); return getGroupAccessAcp(updatedResource, groupUrl); } catch (e) { return null; } } return null; } if (hasAccessibleAcl(resourceInfo)) { if (access.controlRead != access.controlWrite) { throw new Error( `When setting access for a Resource in a Pod implementing Web Access Control (i.e. [${getSourceIri( resourceInfo )}]), ` + "`controlRead` and `controlWrite` should have the same value." ); } const wacAccess = access as WacAccess; await setGroupAccessWac(resourceInfo, groupUrl, wacAccess, options); return await getGroupAccessWac(resourceInfo, groupUrl, options); } return null; } /** * Get an overview of what access is defined for everyone. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably reading access, in which case it will * resolve to `null`. * - It will only return access specified explicitly for everyone. If * additional restrictions are set up to apply to users in a particular * situation, those will not be reflected in the return value of this * function. * - It will only return access specified explicitly for the given Resource. * In other words, if the Resource is a Container, the returned Access may not * apply to contained Resources. * - If the current user does not have permission to view access for the given * Resource, this function will resolve to `null`. * * @param resourceUrl URL of the Resource you want to read the access for. * @since 1.5.0 */ export async function getPublicAccess( resourceUrl: UrlString, options = internal_defaultFetchOptions ): Promise<Access | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { return getPublicAccessAcp(resourceInfo); } if (hasAccessibleAcl(resourceInfo)) { return await getPublicAccessWac(resourceInfo, options); } return null; } /** * Set access to a Resource for everybody. * * This function works with Solid Pods that implement either the Web Access * Control spec or the Access Control Policies proposal, with some caveats: * * - If access to the given Resource has been set using anything other than the * functions in this module, it is possible that it has been set in a way that * prevents this function from reliably setting access, in which case it will * resolve to `null`. * - It will only set access explicitly for everybody. In other words, * additional restrictions could be present that further restrict or loosen * what access a user has in particular circumstances. * - The provided access will only apply to the given Resource. In other words, * if the Resource is a Container, the configured Access may not apply to * contained Resources. * - If the current user does not have permission to view or change access for * the given Resource, this function will resolve to `null`. * * Additionally, two caveats apply to users with a Pod server that uses WAC: * - If the Resource did not have an ACL yet, a new one will be initialised. * This means that changes to the ACL of a parent Container can no longer * affect access people have to this Resource, although existing access will * be preserved. * - Setting different values for `controlRead` and `controlWrite` is not * supported, and **will throw an error**. If you expect (some of) your users * to have Pods implementing WAC, be sure to pass the same value for both. * * @param resourceUrl URL of the Resource you want to change public access to. * @param access What access permissions you want to set for everybody to the given Resource. Possible properties are `read`, `append`, `write`, `controlRead` and `controlWrite`: set to `true` to allow, to `false` to stop allowing, or `undefined` to leave unchanged. Take note that `controlRead` and `controlWrite` can not have distinct values for a Pod server implementing Web Access Control; trying this will throw an error. * @returns What access has been set for everybody explicitly. * @since 1.5.0 */ export async function setPublicAccess( resourceUrl: UrlString, access: Partial<Access>, options = internal_defaultFetchOptions ): Promise<Access | null> { const resourceInfo = await getResourceInfoWithAcr(resourceUrl, options); if (hasAccessibleAcr(resourceInfo)) { const updatedResource = setPublicAccessAcp(resourceInfo, access); if (updatedResource) { try { await saveAcrFor(updatedResource, options); return getPublicAccessAcp(updatedResource); } catch (e) { return null; } } return null; } if (hasAccessibleAcl(resourceInfo)) { if (access.controlRead != access.controlWrite) { throw new Error( `When setting access for a Resource in a Pod implementing Web Access Control (i.e. [${getSourceIri( resourceInfo )}]), ` + "`controlRead` and `controlWrite` should have the same value." ); } const wacAccess = access as WacAccess; await setPublicAccessWac(resourceInfo, wacAccess, options); return await getPublicAccessWac(resourceInfo, options); } return null; } export { getAccessFor, getAccessForAll, setAccessFor } from "./for";