@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
1,719 lines (1,573 loc) • 246 kB
text/typescript
/**
* 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 { describe, it } from "@jest/globals";
import * as fc from "fast-check";
import { WithAccessibleAcr } from "../acp/acp";
import {
AccessControlResource,
addPolicyUrl,
getAcrPolicyUrlAll,
getPolicyUrlAll,
} from "../acp/control";
import {
internal_createControl,
internal_getAcr,
} from "../acp/control.internal";
import { addMockAcrTo } from "../acp/mock";
import {
createPolicy,
getPolicy,
removePolicy,
setAllowModes,
setDenyModes,
setPolicy,
} from "../acp/policy";
import {
addNoneOfRuleUrl,
addAnyOfRuleUrl,
addAllOfRuleUrl,
createRule,
getRule,
Rule,
} from "../acp/rule";
import { acp } from "../constants";
import {
IriString,
ThingPersisted,
UrlString,
WithResourceInfo,
WithServerResourceInfo,
} from "../interfaces";
import { mockSolidDatasetFrom } from "../resource/mock";
import { addIri, addUrl } from "../thing/add";
import { getIri, getIriAll, getUrl, getUrlAll } from "../thing/get";
import { asIri, getThing, getThingAll, setThing } from "../thing/thing";
import {
internal_getActorAccessAll,
internal_getActorAccess,
internal_getAgentAccess,
internal_getAuthenticatedAccess,
internal_getGroupAccess,
internal_getPublicAccess,
internal_hasInaccessiblePolicies,
internal_getGroupAccessAll,
internal_getAgentAccessAll,
internal_setActorAccess,
internal_setAgentAccess,
internal_setGroupAccess,
internal_setPublicAccess,
internal_setAuthenticatedAccess,
} from "./acp";
// Key: actor relation (e.g. agent), value: actor (e.g. a WebID)
type MockRule = Partial<
Record<typeof acp.agent | typeof acp.group, UrlString[]>
>;
interface MockAccess {
read: boolean;
append: boolean;
write: boolean;
}
type MockPolicy = {
allOf: Record<UrlString, MockRule>;
anyOf: Record<UrlString, MockRule>;
noneOf: Record<UrlString, MockRule>;
allow: Partial<MockAccess>;
deny: Partial<MockAccess>;
};
type MockPolicies = {
policies: Record<UrlString, Partial<MockPolicy>>;
memberPolicies: Record<UrlString, Partial<MockPolicy>>;
acrPolicies: Record<UrlString, Partial<MockPolicy>>;
memberAcrPolicies: Record<UrlString, Partial<MockPolicy>>;
};
const defaultAcrUrl = "https://some.pod/policies";
const defaultMockPolicy: MockPolicy = {
allOf: {},
anyOf: {},
noneOf: {},
allow: {},
deny: {},
};
const defaultMockPolicies: MockPolicies = {
policies: { [`${defaultAcrUrl}"#policy`]: defaultMockPolicy },
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
};
function mockAcr(
accessTo: UrlString,
mockAcrUrl = defaultAcrUrl,
mockPolicies: Partial<MockPolicies> = {}
): AccessControlResource {
const allMockPolicies = {
...defaultMockPolicies,
...mockPolicies,
};
let acr: AccessControlResource & WithServerResourceInfo = Object.assign(
mockSolidDatasetFrom(mockAcrUrl),
{
accessTo: accessTo,
}
);
let control = internal_createControl({ url: mockAcrUrl });
function getRule(mockRuleUrl: UrlString, mockRule: MockRule): Rule {
let rule = createRule(mockRuleUrl);
Object.entries(mockRule).forEach(([mockActorRelation, mockActors]) => {
mockActors?.forEach((mockActor) => {
rule = addIri(rule, mockActorRelation, mockActor);
});
});
return rule;
}
function addPolicy(
policyType: IriString,
policyUrl: UrlString,
mockPolicy: Partial<MockPolicy>
) {
let policy = createPolicy(policyUrl);
const allOfRules = mockPolicy.allOf
? Object.entries(mockPolicy.allOf).map(([mockRuleUrl, mockRule]) =>
getRule(mockRuleUrl, mockRule)
)
: [];
const anyOfRules = mockPolicy.anyOf
? Object.entries(mockPolicy.anyOf).map(([mockRuleUrl, mockRule]) =>
getRule(mockRuleUrl, mockRule)
)
: [];
const noneOfRules = mockPolicy.noneOf
? Object.entries(mockPolicy.noneOf).map(([mockRuleUrl, mockRule]) =>
getRule(mockRuleUrl, mockRule)
)
: [];
acr = allOfRules.reduce(setThing, acr);
acr = anyOfRules.reduce(setThing, acr);
acr = noneOfRules.reduce(setThing, acr);
if (mockPolicy.allow) {
policy = setAllowModes(policy, {
read: mockPolicy.allow.read === true,
append: mockPolicy.allow.append === true,
write: mockPolicy.allow.write === true,
});
}
if (mockPolicy.deny) {
policy = setDenyModes(policy, {
read: mockPolicy.deny.read === true,
append: mockPolicy.deny.append === true,
write: mockPolicy.deny.write === true,
});
}
policy = allOfRules.reduce(
(policy, rule) => addIri(policy, acp.allOf, rule),
policy
);
policy = anyOfRules.reduce(
(policy, rule) => addIri(policy, acp.anyOf, rule),
policy
);
policy = noneOfRules.reduce(
(policy, rule) => addIri(policy, acp.noneOf, rule),
policy
);
acr = setThing(acr, policy);
control = addUrl(control, policyType, policy);
}
Object.entries(allMockPolicies.policies).forEach(
([policyUrl, mockPolicy]) => {
addPolicy(acp.apply, policyUrl, mockPolicy);
}
);
Object.entries(allMockPolicies.memberPolicies).forEach(
([policyUrl, mockPolicy]) => {
addPolicy(acp.applyMembers, policyUrl, mockPolicy);
}
);
Object.entries(allMockPolicies.acrPolicies).forEach(
([policyUrl, mockPolicy]) => {
addPolicy(acp.access, policyUrl, mockPolicy);
}
);
Object.entries(allMockPolicies.memberAcrPolicies).forEach(
([policyUrl, mockPolicy]) => {
addPolicy(acp.accessMembers, policyUrl, mockPolicy);
}
);
acr = setThing(acr, control);
return acr;
}
function mockResourceWithAcr(
accessTo: UrlString,
mockAcrUrl = defaultAcrUrl,
mockPolicies: Partial<MockPolicies> = {}
): WithResourceInfo & WithAccessibleAcr {
const acr = mockAcr(accessTo, mockAcrUrl, mockPolicies);
const plainResource = mockSolidDatasetFrom(accessTo);
return addMockAcrTo(plainResource, acr);
}
describe("hasInaccessiblePolicies", () => {
it("returns false if the ACR contains no reference to either Policies or Rules", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/policies",
{
policies: {},
memberAcrPolicies: {},
acrPolicies: {},
memberPolicies: {},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(false);
});
it("returns false if the ACR only contains references to Policies within the ACR", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: { "https://some.pod/resource?ext=acr#policy": {} },
memberAcrPolicies: {},
acrPolicies: {},
memberPolicies: {},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(false);
});
it("returns true if the ACR references a Policy in a different Resource", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: { "https://some.pod/another-resource?ext=acr#policy": {} },
memberAcrPolicies: {},
acrPolicies: {},
memberPolicies: {},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(true);
});
it("returns true if the ACR references a Policy in a different Resource, and the Policy is not defined in the ACR itself too", () => {
const plainResource = mockSolidDatasetFrom("https://some.pod/resource");
let mockedAcr = mockAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: { "https://some.pod/another-resource?ext=acr#policy": {} },
memberAcrPolicies: {},
acrPolicies: {},
memberPolicies: {},
}
);
mockedAcr = removePolicy(
mockedAcr,
"https://some.pod/another-resource?ext=acr#policy"
);
const resourceWithAcr = addMockAcrTo(plainResource, mockedAcr);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(true);
});
it("returns true if the ACR references an ACR Policy in a different Resource", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberAcrPolicies: {},
acrPolicies: { "https://some.pod/another-resource?ext=acr#policy": {} },
memberPolicies: {},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(true);
});
it("returns false if the ACR includes an unreferenced Policy with a different Resource's URL", () => {
const plainResource = mockSolidDatasetFrom("https://some.pod/resource");
const policyInOtherResource = createPolicy(
"https://some.pod/some-other-resource?ext=acr#inactive-policy"
);
let mockedAcr = mockAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{ policies: {} }
);
mockedAcr = setPolicy(mockedAcr, policyInOtherResource);
const resourceWithAcr = addMockAcrTo(plainResource, mockedAcr);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(false);
});
it("returns false if the ACR only references Rules in the same Resource", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/resource?ext=acr#rule": {},
},
},
},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(false);
});
it("returns true if the ACR references an allOf Rule in a different Resource", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberAcrPolicies: {},
acrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/other-rule-resource#rule": {},
},
},
},
memberPolicies: {},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(true);
});
it("returns true if the ACR references an anyOf Rule in a different Resource", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberAcrPolicies: {},
acrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
anyOf: {
"https://some.pod/other-rule-resource#rule": {},
},
},
},
memberPolicies: {},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(true);
});
it("returns true if the ACR references an active noneOf Rule in a different Resource", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberAcrPolicies: {},
acrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
noneOf: {
"https://some.pod/other-rule-resource#rule": {},
},
},
},
memberPolicies: {},
}
);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(true);
});
it("returns false if the ACR includes an unreferenced Policy that references an allOf Rule in a different Resource", () => {
let policyReferencingRuleInDifferentResource = createPolicy(
"https://some.pod/resource?ext=acr#policy"
);
policyReferencingRuleInDifferentResource = addAllOfRuleUrl(
policyReferencingRuleInDifferentResource,
"https://some.pod/other-resource#rule"
);
const mockedAcr = setPolicy(
mockAcr("https://some.pod/resource", "https://some.pod/resource", {
policies: {},
}),
policyReferencingRuleInDifferentResource
);
const plainResource = mockSolidDatasetFrom("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(plainResource, mockedAcr);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(false);
});
it("returns false if the ACR includes an unreferenced Policy that references an anyOf Rule in a different Resource", () => {
let policyReferencingRuleInDifferentResource = createPolicy(
"https://some.pod/resource?ext=acr#policy"
);
policyReferencingRuleInDifferentResource = addAnyOfRuleUrl(
policyReferencingRuleInDifferentResource,
"https://some.pod/other-resource#rule"
);
const mockedAcr = setPolicy(
mockAcr("https://some.pod/resource", "https://some.pod/resource", {
policies: {},
}),
policyReferencingRuleInDifferentResource
);
const plainResource = mockSolidDatasetFrom("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(plainResource, mockedAcr);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(false);
});
it("returns false if the ACR includes an unreferenced Policy that references a noneOf Rule in a different Resource", () => {
let policyReferencingRuleInDifferentResource = createPolicy(
"https://some.pod/resource?ext=acr#policy"
);
policyReferencingRuleInDifferentResource = addNoneOfRuleUrl(
policyReferencingRuleInDifferentResource,
"https://some.pod/other-resource#rule"
);
const mockedAcr = setPolicy(
mockAcr("https://some.pod/resource", "https://some.pod/resource", {
policies: {},
}),
policyReferencingRuleInDifferentResource
);
const plainResource = mockSolidDatasetFrom("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(plainResource, mockedAcr);
expect(internal_hasInaccessiblePolicies(resourceWithAcr)).toBe(false);
});
});
describe("getActorAccess", () => {
const webId = "https://some.pod/profile#me";
it("returns false for all access if no access was granted to the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://arbitrary.pod/resource",
"https://arbitrary.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns true for Read access if that was granted to the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns true for Append access if that was granted to the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { append: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: true,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns true for Write access if that was granted to the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: true,
controlRead: false,
controlWrite: false,
});
});
it("returns true for ControlRead access if that was granted to the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: true,
controlWrite: false,
});
});
it("returns true for ControlWrite access if that was granted to the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: true,
});
});
it("returns false for Read access if that was denied for the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Append access if that was denied for the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { append: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Write access if that was denied for the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for ControlRead access if that was denied for the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for ControlWrite access if that was denied for the given actor", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Read access if that was granted to the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Append access if that was granted to the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { append: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Write access if that was granted to the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for ControlRead access if that was granted to the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for ControlWrite access if that was granted to the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Read access if that was denied for the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Append access if that was denied for the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { append: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for Write access if that was denied for the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for ControlRead access if that was denied for the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns false for ControlWrite access if that was denied for the given actor for child Resources only", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {
"https://some.pod/resource?ext=acr#policy": {
deny: { write: true },
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does not apply a Policy that does not specify any access modes", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("applies a Policy that does not specify any Rules at all", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("applies a Policy that also specifies empty Rules", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#emptyRule": {},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("applies a Policy that only specifies non-existent Rules", () => {
let mockedAcr = mockAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allow: { read: true },
allOf: {
"https://some.pod/resource?ext=acr#emptyRule": {},
},
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
let policyReferencingNonExistentRules = getPolicy(
mockedAcr,
"https://some.pod/resource?ext=acr#policy"
)!;
policyReferencingNonExistentRules = addIri(
policyReferencingNonExistentRules,
acp.allOf,
"https://some.pod/resource?ext=acr#emptyRule"
);
mockedAcr = setPolicy(mockedAcr, policyReferencingNonExistentRules);
const plainResource = mockSolidDatasetFrom("https://some.pod/resource");
const resourceWithAcr = addPolicyUrl(
addMockAcrTo(plainResource, mockedAcr),
"https://some.pod/resource?ext=acr#policy"
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("returns null if some access is defined in separate Resources", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/other-resource?ext=acr#policy": {
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toBeNull();
});
describe("A Policy that references just the given actor in a single Rule", () => {
it("applies for an allOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("applies for an anyOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
anyOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
allow: { append: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: true,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does not apply for a noneOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
noneOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.agent]: [webId],
},
},
allow: { append: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
});
describe("A Policy that references a Rule that applies to multiple actors, including the given one", () => {
it("does apply for an allOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/resource?ext=acr#applicable-rule": {
[acp.agent]: [webId, "https://some.pod/other-profile#me"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does apply for an anyOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
anyOf: {
"https://some.pod/resource?ext=acr#applicable-rule": {
[acp.agent]: [webId, "https://some.pod/other-profile#me"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does not apply for a noneOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
noneOf: {
"https://some.pod/resource?ext=acr#applicable-rule": {
[acp.agent]: [webId, "https://some.pod/other-profile#me"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
});
describe("A Policy that references a Rule that does not include the given actor", () => {
it("does not apply for an allOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/resource?ext=acr#unapplicable-rule": {
[acp.group]: ["https://some.pod/groups#group"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does not apply for an anyOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
anyOf: {
"https://some.pod/resource?ext=acr#unapplicable-rule": {
[acp.group]: ["https://some.pod/groups#group"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does not apply for a noneOf Rule", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
noneOf: {
"https://some.pod/resource?ext=acr#rule": {
[acp.group]: ["https://some.pod/groups#group"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
});
describe("A Policy that references multiple of the same type of Rules, not all of which reference the given actor", () => {
it("does not apply for allOf Rules", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/resource?ext=acr#applicable-rule": {
[acp.agent]: [webId],
},
"https://some.pod/resource?ext=acr#unapplicable-rule": {
[acp.group]: ["https://some.pod/groups#group"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does apply for anyOf Rules", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
anyOf: {
"https://some.pod/resource?ext=acr#applicable-rule": {
[acp.agent]: [webId],
},
"https://some.pod/resource?ext=acr#unapplicable-rule": {
[acp.group]: ["https://some.pod/groups#group"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
it("does not apply for noneOf Rules", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
noneOf: {
"https://some.pod/resource?ext=acr#applicable-rule": {
[acp.agent]: [webId],
},
"https://some.pod/resource?ext=acr#unapplicable-rule": {
[acp.group]: ["https://some.pod/groups#group"],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: false,
append: false,
write: false,
controlRead: false,
controlWrite: false,
});
});
});
describe("A Policy that references multiple of the same type of Rules, all of which reference the given actor", () => {
it("does apply for allOf Rules", () => {
const resourceWithAcr = mockResourceWithAcr(
"https://some.pod/resource",
"https://some.pod/resource?ext=acr",
{
policies: {
"https://some.pod/resource?ext=acr#policy": {
allOf: {
"https://some.pod/resource?ext=acr#applicable-rule": {
[acp.agent]: [webId],
},
"https://some.pod/resource?ext=acr#non-applicable-rule": {
[acp.agent]: [webId],
},
},
allow: { read: true },
},
},
memberPolicies: {},
acrPolicies: {},
memberAcrPolicies: {},
}
);
const access = internal_getActorAccess(resourceWithAcr, acp.agent, webId);
expect(access).toStrictEqual({
read: true,
append: false,
write: f