@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
105 lines (93 loc) • 4.33 kB
text/typescript
// Copyright 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 type { Thing, UrlString } from "../..";
import { getSourceIri } from "../../resource/resource";
import { getIriAll } from "../../thing/get";
import { asIri, getThing } from "../../thing/thing";
import type { WithAccessibleAcr } from "../acp";
import { ACP } from "../constants";
import { internal_getAcr } from "../control.internal";
import { getAccessControlResourceThing } from "../internal/getAccessControlResourceThing";
import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing";
import { getModes } from "../internal/getModes";
import type { AccessModes } from "../../interfaces";
import { DEFAULT_VC_MATCHER_NAME, DEFAULT_VC_POLICY_NAME } from "./setVcAccess";
const DEFAULT_NO_ACCESS: AccessModes = {
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
};
const linkExists = (
subject: Thing,
predicate: UrlString,
object: Thing,
): boolean => getIriAll(subject, predicate).includes(asIri(object));
// TODO: It should be possible to write a `chainExists` function, taking in a chain
// of Thing, predicate, Thing, predicate... and checks whether such chain exists
// in a given dataset. It would make the following function much easier to read,
// instead of checking at each link that it isn't null and it is connected to the
// next link.
/**
* ```{note}
* The ACP specification is a draft. As such, this function is experimental and
* subject to change, even in a non-major release.
* See also: https://solid.github.io/authorization-panel/acp-specification/
* ```
*
* Get the maximum access modes that are allowed for a VC holder for a given resource.
* If the resource owner issued an Access Grant for the resource, the agent that
* has been granted access will have at most the permissions returned by this function.
* The Access Grant may be more restrictive.
*
* Note that only the modes set using [[setVcAccess]] will be returned by this function.
* Additional access may have been set if the ACR has been manipulated not using this
* library, which is currently out of scope.
*
* @param resourceWithAcr The resource for which the VC access modes are looked up.
* @returns The access modes available to a VC holder.
* @since 1.17.0
*/
export function getVcAccess(resourceWithAcr: WithAccessibleAcr): AccessModes {
const acr = internal_getAcr(resourceWithAcr);
const accessControl = getDefaultAccessControlThing(
resourceWithAcr,
"defaultAccessControl",
);
const acrThing = getAccessControlResourceThing(resourceWithAcr);
if (
acrThing === null ||
!linkExists(acrThing, ACP.accessControl, accessControl)
) {
return DEFAULT_NO_ACCESS;
}
const defaultVcPolicyIri = `${getSourceIri(acr)}#${DEFAULT_VC_POLICY_NAME}`;
const vcPolicy = getThing(acr, defaultVcPolicyIri);
if (vcPolicy === null || !linkExists(accessControl, ACP.apply, vcPolicy)) {
return DEFAULT_NO_ACCESS;
}
const defaultVcMatcherIri = `${getSourceIri(acr)}#${DEFAULT_VC_MATCHER_NAME}`;
const vcMatcher = getThing(acr, defaultVcMatcherIri);
if (vcMatcher === null || !linkExists(vcPolicy, ACP.anyOf, vcMatcher)) {
return DEFAULT_NO_ACCESS;
}
return getModes(vcPolicy, ACP.allow);
}