@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
1,451 lines (1,271 loc) • 82 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, expect } from "@jest/globals";
import { DataFactory } from "n3";
import {
AccessControlResource,
acrAsMarkdown,
addAcrPolicyUrl,
addMemberAcrPolicyUrl,
addMemberPolicyUrl,
addPolicyUrl,
getAcrPolicyUrlAll,
getMemberAcrPolicyUrlAll,
getMemberPolicyUrlAll,
getPolicyUrlAll,
hasLinkedAcr,
removeAcrPolicyUrl,
removeAcrPolicyUrlAll,
removeMemberAcrPolicyUrl,
removeMemberAcrPolicyUrlAll,
removeMemberPolicyUrl,
removeMemberPolicyUrlAll,
removePolicyUrl,
removePolicyUrlAll,
WithLinkedAcr,
} from "./control";
import {
internal_createControl,
internal_getControl,
internal_getControlAll,
internal_setControl,
internal_addMemberPolicyUrl,
internal_addPolicyUrl,
internal_getMemberPolicyUrlAll,
internal_getPolicyUrlAll,
internal_removeMemberPolicyUrl,
internal_removeMemberPolicyUrlAll,
internal_removePolicyUrl,
internal_removePolicyUrlAll,
} from "./control.internal";
import { acp, rdf } from "../constants";
import { WithServerResourceInfo } from "../interfaces";
import { getIri, getIriAll } from "../thing/get";
import { createThing, getThing, setThing } from "../thing/thing";
import { addMockAcrTo, mockAcrFor } from "./mock";
import { setIri, setUrl } from "../thing/set";
import { addIri } from "../thing/add";
import { mockSolidDatasetFrom } from "../resource/mock";
import { WithAccessibleAcl } from "../acl/acl";
import { getSourceUrl } from "../resource/resource";
import { removeControl } from "./v1";
describe("hasLinkedAcr", () => {
it("returns true if a Resource exposes a URL to an Access Control Resource", () => {
const withLinkedAcr: WithLinkedAcr = {
internal_resourceInfo: {
isRawData: false,
sourceIri: "https://some.pod/resource",
linkedResources: {
[acp.accessControl]: ["https://some.pod/access-control-resource"],
},
},
};
expect(hasLinkedAcr(withLinkedAcr)).toBe(true);
});
it("returns false if a Resource is governed by Web-Access-Control", () => {
const withLinkedAcr: WithAccessibleAcl = {
internal_resourceInfo: {
isRawData: false,
sourceIri: "https://some.pod/resource",
linkedResources: {
acl: ["https://some.pod/access-control-resource"],
},
aclUrl: "https://some.pod/access-control-resource",
},
};
expect(hasLinkedAcr(withLinkedAcr)).toBe(false);
});
it("returns false if a Resource does not expose anything Access Control-related", () => {
const withLinkedAcr: WithServerResourceInfo = {
internal_resourceInfo: {
isRawData: false,
sourceIri: "https://some.pod/resource",
linkedResources: {},
},
};
expect(hasLinkedAcr(withLinkedAcr)).toBe(false);
});
});
describe("createControl", () => {
it("sets the type of the new Access Control to acp:AccessControl", () => {
const newControl = internal_createControl();
expect(getIri(newControl, rdf.type)).toBe(acp.AccessControl);
});
});
describe("getControl", () => {
it("returns the Access Control if found", () => {
const controlUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const control = setUrl(
createThing({ url: controlUrl }),
rdf.type,
acp.AccessControl
);
const accessControlResource = setThing(
mockAcrFor("https://some.pod/resource"),
control
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const foundControl = internal_getControl(resourceWithAcr, controlUrl);
expect(foundControl).toEqual(control);
});
it("returns null if the specified Thing is not an Access Control", () => {
const controlUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const control = createThing({ url: controlUrl });
const accessControlResource = setThing(
mockAcrFor("https://some.pod/resource"),
control
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const foundControl = internal_getControl(resourceWithAcr, controlUrl);
expect(foundControl).toBeNull();
});
it("returns null if the Access Control could not be found", () => {
const controlUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const control = createThing({ url: controlUrl });
const accessControlResource = setThing(
mockAcrFor("https://some.pod/resource"),
control
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const foundControl = internal_getControl(
resourceWithAcr,
"https://some-other.pod/access-control-resource.ttl#access-control"
);
expect(foundControl).toBeNull();
});
it("throws an error if the given Resource does not have an Access Control Resource", () => {
const controlUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const withoutAcr = mockSolidDatasetFrom("https://some.pod/resource");
expect(() => internal_getControl(withoutAcr as any, controlUrl)).toThrow(
"An Access Control Resource for [https://some.pod/resource] is not available. This could be because the current user is not allowed to see it, or because their Pod Server does not support Access Control Resources."
);
});
});
describe("getControlAll", () => {
it("returns all included Access Controls", () => {
const control = setUrl(createThing(), rdf.type, acp.AccessControl);
const accessControlResource = setThing(
mockAcrFor("https://some.pod/resource"),
control
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const foundControls = internal_getControlAll(resourceWithAcr);
expect(foundControls).toEqual([control]);
});
it("ignores Things that are not Access Controls", () => {
const control = setUrl(createThing(), rdf.type, acp.AccessControl);
const notAControl = setUrl(
createThing(),
rdf.type,
"https://some.vocab/not-access-control"
);
let accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource = setThing(accessControlResource, control);
accessControlResource = setThing(accessControlResource, notAControl);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const foundControls = internal_getControlAll(resourceWithAcr);
expect(foundControls).toEqual([control]);
});
it("returns an empty array if no Access Controls could be found", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const foundControl = internal_getControlAll(resourceWithAcr);
expect(foundControl).toEqual([]);
});
it("throws an error if the given Resource does not have an Access Control Resource", () => {
const withoutAcr = mockSolidDatasetFrom("https://some.pod/resource");
expect(() => internal_getControlAll(withoutAcr as any)).toThrow(
"An Access Control Resource for [https://some.pod/resource] is not available. This could be because the current user is not allowed to see it, or because their Pod Server does not support Access Control Resources."
);
});
it("throws an error if the given Resource's ACR could not be fetched", () => {
const withoutAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
(null as unknown) as AccessControlResource
);
expect(() => internal_getControlAll(withoutAcr as any)).toThrow(
"An Access Control Resource for [https://some.pod/resource] is not available. This could be because the current user is not allowed to see it, or because their Pod Server does not support Access Control Resources."
);
});
});
describe("setControl", () => {
it("adds the given Access Control to the given Access Control Resource", () => {
const controlUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const control = setUrl(
createThing({ url: controlUrl }),
rdf.type,
acp.AccessControl
);
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const newWithAccessControlResource = internal_setControl(
resourceWithAcr,
control
);
expect(
getThing(newWithAccessControlResource.internal_acp.acr, controlUrl)
).toEqual(control);
});
it("throws an error if the given Resource does not have an Access Control Resource", () => {
const accessUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const control = setUrl(
createThing({ url: accessUrl }),
rdf.type,
acp.AccessControl
);
const withoutAcr = mockSolidDatasetFrom("https://some.pod/resource");
expect(() => internal_setControl(withoutAcr as any, control)).toThrow(
"An Access Control Resource for [https://some.pod/resource] is not available. This could be because the current user is not allowed to see it, or because their Pod Server does not support Access Control Resources."
);
});
});
describe("removeControl", () => {
it("removes the given Access Control from the given Access Control Resource", () => {
const controlUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const control = setUrl(
createThing({ url: controlUrl }),
rdf.type,
acp.AccessControl
);
const accessControlResource = setThing(
mockAcrFor("https://some.pod/resource"),
control
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://arbitrary.pod/resource"),
accessControlResource
);
const newWithAccessControlResource = removeControl(
resourceWithAcr,
control
);
expect(
getThing(newWithAccessControlResource.internal_acp.acr, controlUrl)
).toBeNull();
});
it("throws an error if the given Resource does not have an Access Control Resource", () => {
const controlUrl =
"https://some.pod/access-control-resource.ttl#access-control";
const control = setUrl(
createThing({ url: controlUrl }),
rdf.type,
acp.AccessControl
);
const withoutAcr = mockSolidDatasetFrom("https://some.pod/resource");
expect(() => removeControl(withoutAcr as any, control)).toThrow(
"An Access Control Resource for [https://some.pod/resource] is not available. This could be because the current user is not allowed to see it, or because their Pod Server does not support Access Control Resources."
);
});
});
describe("addAcrPolicyUrl", () => {
it("adds the given URL as a Policy for the given ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.access);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not remove existing Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(2);
expect(acrQuads[0].predicate.value).toBe(acp.access);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
expect(acrQuads[1].predicate.value).toBe(acp.access);
expect(acrQuads[1].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
addAcrPolicyUrl(resourceWithAcr, "https://some.pod/policy-resource#policy");
expect(accessControlResource.size).toBe(0);
});
});
describe("addMemberAcrPolicyUrl", () => {
it("adds the given URL as a Policy for the given ACR's children's ACRs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.accessMembers);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not remove existing Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(2);
expect(acrQuads[0].predicate.value).toBe(acp.accessMembers);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
expect(acrQuads[1].predicate.value).toBe(acp.accessMembers);
expect(acrQuads[1].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
addMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
expect(accessControlResource.size).toBe(0);
});
});
describe("getAcrPolicyUrlAll", () => {
it("returns an empty array if no Policy URLs are defined for the ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getAcrPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
it("returns all applicable Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getAcrPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual(["https://some.pod/policy-resource#policy"]);
});
it("does not return Member Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getAcrPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
});
describe("getMemberAcrPolicyUrlAll", () => {
it("returns an empty array if no Policy URLs are defined for the ACR's children's ACRs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getMemberAcrPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
it("returns all applicable Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getMemberAcrPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual(["https://some.pod/policy-resource#policy"]);
});
it("does not return own Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getMemberAcrPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
});
describe("removeAcrPolicyUrl", () => {
it("removes the given URL as a Policy from the given ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toEqual([]);
});
it("returns the input unchanged if there was nothing to remove", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
expect(updatedResourceWithAcr).toEqual(resourceWithAcr);
});
it("does not remove existing mismatching Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.access);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
});
it("does not remove Member Control Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.accessMembers);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
removeAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const oldAcrQuads = Array.from(accessControlResource);
expect(oldAcrQuads).toHaveLength(1);
expect(oldAcrQuads[0].predicate.value).toBe(acp.access);
expect(oldAcrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
});
describe("removeMemberAcrPolicyUrl", () => {
it("removes the given URL as a Policy from the given ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toEqual([]);
});
it("returns the input unchanged if there was nothing to remove", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
expect(updatedResourceWithAcr).toEqual(resourceWithAcr);
});
it("does not remove existing mismatching Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.accessMembers);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
});
it("does not remove own Control Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.access);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
removeMemberAcrPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const oldAcrQuads = Array.from(accessControlResource);
expect(oldAcrQuads).toHaveLength(1);
expect(oldAcrQuads[0].predicate.value).toBe(acp.accessMembers);
expect(oldAcrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
});
describe("removeAcrPolicyUrlAll", () => {
it("removes all URLs that served as its Policy from the given ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeAcrPolicyUrlAll(resourceWithAcr);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toEqual([]);
});
it("returns the input unchanged if there was nothing to remove", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeAcrPolicyUrlAll(resourceWithAcr);
expect(updatedResourceWithAcr).toEqual(resourceWithAcr);
});
it("does not remove Member Control Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeAcrPolicyUrlAll(resourceWithAcr);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.accessMembers);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
removeAcrPolicyUrlAll(resourceWithAcr);
const oldAcrQuads = Array.from(accessControlResource);
expect(oldAcrQuads).toHaveLength(1);
expect(oldAcrQuads[0].predicate.value).toBe(acp.access);
expect(oldAcrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
});
describe("removeMemberAcrPolicyUrlAll", () => {
it("removes all URLs that served as its Policy from the given ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeMemberAcrPolicyUrlAll(resourceWithAcr);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toEqual([]);
});
it("returns the input unchanged if there was nothing to remove", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeMemberAcrPolicyUrlAll(resourceWithAcr);
expect(updatedResourceWithAcr).toEqual(resourceWithAcr);
});
it("does not remove own Control Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.access),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removeMemberAcrPolicyUrlAll(resourceWithAcr);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
expect(acrQuads[0].predicate.value).toBe(acp.access);
expect(acrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.accessMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
removeMemberAcrPolicyUrlAll(resourceWithAcr);
const oldAcrQuads = Array.from(accessControlResource);
expect(oldAcrQuads).toHaveLength(1);
expect(oldAcrQuads[0].predicate.value).toBe(acp.accessMembers);
expect(oldAcrQuads[0].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
});
describe("addPolicyUrl", () => {
it("adds the given URL as a Policy for the given Resource", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(2);
expect(acrQuads[1].predicate.value).toBe(acp.apply);
expect(acrQuads[1].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not remove existing Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.apply),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(3);
expect(acrQuads[1].predicate.value).toBe(acp.apply);
expect(acrQuads[1].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
expect(acrQuads[2].predicate.value).toBe(acp.apply);
expect(acrQuads[2].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
addPolicyUrl(resourceWithAcr, "https://some.pod/policy-resource#policy");
const oldAcrQuads = Array.from(accessControlResource);
expect(oldAcrQuads).toEqual([]);
});
});
describe("addMemberPolicyUrl", () => {
it("adds the given URL as a Policy for the given Resource's children", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addMemberPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(2);
expect(acrQuads[1].predicate.value).toBe(acp.applyMembers);
expect(acrQuads[1].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not remove existing Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.applyMembers),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = addMemberPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(3);
expect(acrQuads[1].predicate.value).toBe(acp.applyMembers);
expect(acrQuads[1].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
expect(acrQuads[2].predicate.value).toBe(acp.applyMembers);
expect(acrQuads[2].object.value).toBe(
"https://some.pod/policy-resource#policy"
);
});
it("does not modify the input ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
addMemberPolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const oldAcrQuads = Array.from(accessControlResource);
expect(oldAcrQuads).toEqual([]);
});
});
describe("getPolicyUrlAll", () => {
it("returns an empty array if no Policy URLs are defined for the Resource", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
it("returns all applicable Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.apply),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual(["https://some.pod/policy-resource#policy"]);
});
it("does not return Member Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.applyMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
});
describe("getMemberPolicyUrlAll", () => {
it("returns an empty array if no Policy URLs are defined for the Resource's children", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getMemberPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
it("returns all applicable Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.applyMembers),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getMemberPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual(["https://some.pod/policy-resource#policy"]);
});
it("does not return own Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.apply),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const policyUrls = getMemberPolicyUrlAll(resourceWithAcr);
expect(policyUrls).toEqual([]);
});
});
describe("removePolicyUrl", () => {
it("removes the given URL as a Policy from the given ACR", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.apply),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removePolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(1);
});
it("returns the input unchanged if there was nothing to remove", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removePolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
expect(updatedResourceWithAcr).toEqual(resourceWithAcr);
});
it("does not remove existing mismatching Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.apply),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.apply),
DataFactory.namedNode("https://some.pod/policy-resource#other-policy")
)
);
const resourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
accessControlResource
);
const updatedResourceWithAcr = removePolicyUrl(
resourceWithAcr,
"https://some.pod/policy-resource#policy"
);
const acrQuads = Array.from(updatedResourceWithAcr.internal_acp.acr);
expect(acrQuads).toHaveLength(2);
expect(acrQuads[1].predicate.value).toBe(acp.apply);
expect(acrQuads[1].object.value).toBe(
"https://some.pod/policy-resource#other-policy"
);
});
it("does not remove Member Control Policy URLs", () => {
const accessControlResource = mockAcrFor("https://some.pod/resource");
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(acp.AccessControl)
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.namedNode(acp.apply),
DataFactory.namedNode("https://some.pod/policy-resource#policy")
)
);
accessControlResource.add(
DataFactory.quad(
DataFactory.namedNode(getSourceUrl(accessControlResource)),
DataFactory.