@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
1,304 lines (1,162 loc) • 42.5 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 { jest, describe, it, expect } from "@jest/globals";
jest.mock("../fetcher.ts", () => ({
fetch: jest.fn().mockImplementation(() =>
Promise.resolve(
new Response(undefined, {
headers: { Location: "https://arbitrary.pod/resource" },
})
)
),
}));
import { Response } from "cross-fetch";
import { DataFactory } from "n3";
import { rdf, acp } from "../constants";
import { mockSolidDatasetFrom } from "../resource/mock";
import { getSourceUrl } from "../resource/resource";
import { createSolidDataset } from "../resource/solidDataset";
import { addIri } from "../thing/add";
import { getIriAll, getUrl } from "../thing/get";
import { mockThingFrom } from "../thing/mock";
import { removeUrl } from "../thing/remove";
import { setUrl } from "../thing/set";
import {
asUrl,
createThing,
getThing,
getThingAll,
setThing,
} from "../thing/thing";
import {
addAcrPolicyUrl,
addPolicyUrl,
getAcrPolicyUrlAll,
getPolicyUrlAll,
} from "./control";
import { internal_getAcr } from "./control.internal";
import { addMockAcrTo, mockAcrFor } from "./mock";
import {
createPolicy,
createResourcePolicyFor,
getAllowModes,
getDenyModes,
getPolicy,
getPolicyAll,
getResourceAcrPolicy,
getResourceAcrPolicyAll,
getResourcePolicy,
getResourcePolicyAll,
policyAsMarkdown,
removePolicy,
removeResourceAcrPolicy,
removeResourcePolicy,
setAllowModes,
setDenyModes,
setPolicy,
setResourceAcrPolicy,
setResourcePolicy,
} from "./policy";
import { addNoneOfRuleUrl, addAnyOfRuleUrl, addAllOfRuleUrl } from "./rule";
describe("createPolicy", () => {
it("creates a Thing of type acp:AccessPolicy", () => {
const newPolicy = createPolicy("https://some.pod/policy-resource#policy");
expect(getUrl(newPolicy, rdf.type)).toBe(acp.Policy);
expect(asUrl(newPolicy)).toBe("https://some.pod/policy-resource#policy");
});
});
describe("getPolicy", () => {
it("returns the Policy with the given URL", () => {
let mockPolicy = createThing({
url: "https://some.pod/policy-resource#policy",
});
mockPolicy = setUrl(mockPolicy, rdf.type, acp.Policy);
const policyDataset = setThing(createSolidDataset(), mockPolicy);
expect(
getPolicy(policyDataset, "https://some.pod/policy-resource#policy")
).not.toBeNull();
});
it("returns null if the given URL identifies something that is not an Access Policy", () => {
let notAPolicy = createThing({
url: "https://some.pod/policy-resource#not-a-policy",
});
notAPolicy = setUrl(
notAPolicy,
rdf.type,
"https://arbitrary.vocab/not-a-policy"
);
const policyDataset = setThing(createSolidDataset(), notAPolicy);
expect(
getPolicy(policyDataset, "https://some.pod/policy-resource#not-a-policy")
).toBeNull();
});
it("returns null if there is no Thing at the given URL", () => {
expect(
getPolicy(createSolidDataset(), "https://some.pod/policy-resource#policy")
).toBeNull();
});
});
describe("getPolicyAll", () => {
it("returns included Policies", () => {
let mockPolicy = createThing({
url: "https://some.pod/policy-resource#policy",
});
mockPolicy = setUrl(mockPolicy, rdf.type, acp.Policy);
const policyDataset = setThing(createSolidDataset(), mockPolicy);
expect(getPolicyAll(policyDataset)).toHaveLength(1);
});
it("returns only those Things whose type is of acp:AccessPolicy", () => {
let mockPolicy = createThing({
url: "https://some.pod/policy-resource#policy",
});
mockPolicy = setUrl(mockPolicy, rdf.type, acp.Policy);
let notAPolicy = createThing({
url: "https://some.pod/policy-resource#not-a-policy",
});
notAPolicy = setUrl(
notAPolicy,
rdf.type,
"https://arbitrary.vocab/not-a-policy"
);
let policyDataset = setThing(createSolidDataset(), mockPolicy);
policyDataset = setThing(policyDataset, notAPolicy);
expect(getPolicyAll(policyDataset)).toHaveLength(1);
});
it("returns an empty array if there are no Thing in the given PolicyDataset", () => {
expect(getPolicyAll(createSolidDataset())).toHaveLength(0);
});
});
describe("setPolicy", () => {
it("replaces existing instances of the set Access Policy", () => {
const somePredicate = "https://some.vocab/predicate";
let mockPolicy = createThing({
url: "https://some.pod/policy-resource#policy",
});
mockPolicy = setUrl(mockPolicy, rdf.type, acp.Policy);
mockPolicy = setUrl(mockPolicy, somePredicate, "https://example.test");
const policyDataset = setThing(createSolidDataset(), mockPolicy);
const updatedPolicy = removeUrl(
mockPolicy,
somePredicate,
"https://example.test"
);
const updatedPolicyDataset = setPolicy(policyDataset, updatedPolicy);
const policyAfterUpdate = getPolicy(
updatedPolicyDataset,
"https://some.pod/policy-resource#policy"
);
expect(getUrl(policyAfterUpdate!, somePredicate)).toBeNull();
});
});
describe("removePolicy", () => {
it("removes the given Access Policy from the Access Policy Resource", () => {
let mockPolicy = createThing({
url: "https://some.pod/policy-resource#policy",
});
mockPolicy = setUrl(mockPolicy, rdf.type, acp.Policy);
const policyDataset = setThing(createSolidDataset(), mockPolicy);
const updatedPolicyDataset = removePolicy(policyDataset, mockPolicy);
expect(getThingAll(updatedPolicyDataset)).toHaveLength(0);
});
it("accepts a plain URL to remove an Access Policy", () => {
let mockPolicy = createThing({
url: "https://some.pod/policy-resource#policy",
});
mockPolicy = setUrl(mockPolicy, rdf.type, acp.Policy);
const policyDataset = setThing(createSolidDataset(), mockPolicy);
const updatedPolicyDataset = removePolicy(
policyDataset,
"https://some.pod/policy-resource#policy"
);
expect(getThingAll(updatedPolicyDataset)).toHaveLength(0);
});
it("does not remove unrelated policies", () => {
let mockPolicy1 = createThing({
url: "https://some.pod/policy-resource#policy1",
});
mockPolicy1 = setUrl(mockPolicy1, rdf.type, acp.Policy);
let mockPolicy2 = createThing({
url: "https://some.pod/policy-resource#policy2",
});
mockPolicy2 = setUrl(mockPolicy2, rdf.type, acp.Policy);
let policyDataset = setThing(createSolidDataset(), mockPolicy1);
policyDataset = setThing(policyDataset, mockPolicy2);
const updatedPolicyDataset = removePolicy(policyDataset, mockPolicy1);
expect(getThingAll(updatedPolicyDataset)).toHaveLength(1);
});
});
describe("createResourcePolicyFor", () => {
it("creates a Thing of type acp:AccessPolicy", () => {
const mockedAcr = mockAcrFor("https://some.pod/resource");
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
const newPolicy = createResourcePolicyFor(mockedResourceWithAcr, "policy");
expect(getUrl(newPolicy, rdf.type)).toBe(acp.Policy);
expect(asUrl(newPolicy)).toBe(`${getSourceUrl(mockedAcr)}#policy`);
});
});
describe("getResourcePolicy", () => {
it("returns the Policy with the given name", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(getResourcePolicy(mockedResourceWithAcr, "policy")).not.toBeNull();
});
it("returns null if the Policy does not apply to the Resource", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
expect(getResourcePolicy(mockedResourceWithAcr, "policy")).toBeNull();
});
it("returns null if the Policy applies to the ACR itself", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(getResourcePolicy(mockedResourceWithAcr, "policy")).toBeNull();
});
it("returns null if the given URL identifies something that is not an Access Policy", () => {
let notAPolicy = createThing({
url: "https://some.pod/resource?ext=acr#not-a-policy",
});
notAPolicy = setUrl(
notAPolicy,
rdf.type,
"https://arbitrary.vocab/not-a-policy"
);
const mockedAcr = setThing(
mockAcrFor("https://some.pod/resource"),
notAPolicy
);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
"https://some.pod/resource?ext=acr#not-a-policy"
);
expect(getResourcePolicy(mockedResourceWithAcr, "not-a-policy")).toBeNull();
});
it("returns null if there is no Thing at the given URL", () => {
expect(
getResourcePolicy(
addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockAcrFor("https://some.pod/resource")
),
"policy"
)
).toBeNull();
});
});
describe("getResourceAcrPolicy", () => {
it("returns the Policy with the given name", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(
getResourceAcrPolicy(mockedResourceWithAcr, "policy")
).not.toBeNull();
});
it("returns null if the Policy does not apply to the Resource's ACR", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
expect(getResourceAcrPolicy(mockedResourceWithAcr, "policy")).toBeNull();
});
it("returns null if the Policy applies to the Resource itself", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(getResourceAcrPolicy(mockedResourceWithAcr, "policy")).toBeNull();
});
it("returns null if the given URL identifies something that is not an Access Policy", () => {
let notAPolicy = createThing({
url: "https://some.pod/resource?ext=acr#not-a-policy",
});
notAPolicy = setUrl(
notAPolicy,
rdf.type,
"https://arbitrary.vocab/not-a-policy"
);
const mockedAcr = setThing(
mockAcrFor("https://some.pod/resource"),
notAPolicy
);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
"https://some.pod/resource?ext=acr#not-a-policy"
);
expect(
getResourceAcrPolicy(mockedResourceWithAcr, "not-a-policy")
).toBeNull();
});
it("returns null if there is no Thing at the given URL", () => {
expect(
getResourceAcrPolicy(
addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockAcrFor("https://some.pod/resource")
),
"policy"
)
).toBeNull();
});
});
describe("getResourcePolicyAll", () => {
it("returns included Policies", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(getResourcePolicyAll(mockedResourceWithAcr)).toHaveLength(1);
});
it("returns only those Things whose type is of acp:AccessPolicy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
let notAPolicy = createThing({
url: "https://some.pod/policy-resource#not-a-policy",
});
notAPolicy = setUrl(
notAPolicy,
rdf.type,
"https://arbitrary.vocab/not-a-policy"
);
mockedAcr = setThing(mockedAcr, mockedPolicy);
mockedAcr = setThing(mockedAcr, notAPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
"https://some.pod/policy-resource#not-a-policy"
);
expect(getResourcePolicyAll(mockedResourceWithAcr)).toHaveLength(1);
});
it("returns only those Things that apply to the given Resource", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let applicablePolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#applicable-policy`,
});
applicablePolicy = setUrl(applicablePolicy, rdf.type, acp.Policy);
let unapplicablePolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#unapplicable-policy`,
});
unapplicablePolicy = setUrl(unapplicablePolicy, rdf.type, acp.Policy);
let acrPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#acr-policy`,
});
acrPolicy = setUrl(applicablePolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, applicablePolicy);
mockedAcr = setThing(mockedAcr, unapplicablePolicy);
mockedAcr = setThing(mockedAcr, acrPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#applicable-policy`
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#acr-policy`
);
expect(getResourcePolicyAll(mockedResourceWithAcr)).toHaveLength(1);
});
it("returns an empty array if there are no Things in the given Resource's ACR", () => {
expect(
getResourcePolicyAll(
addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockAcrFor("https://some.pod/resource")
)
)
).toHaveLength(0);
});
});
describe("getResourceAcrPolicyAll", () => {
it("returns included ACR Policies", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(getResourceAcrPolicyAll(mockedResourceWithAcr)).toHaveLength(1);
});
it("returns only those Things whose type is of acp:AccessPolicy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
let notAPolicy = createThing({
url: "https://some.pod/policy-resource#not-a-policy",
});
notAPolicy = setUrl(
notAPolicy,
rdf.type,
"https://arbitrary.vocab/not-a-policy"
);
mockedAcr = setThing(mockedAcr, mockedPolicy);
mockedAcr = setThing(mockedAcr, notAPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
"https://some.pod/policy-resource#not-a-policy"
);
expect(getResourceAcrPolicyAll(mockedResourceWithAcr)).toHaveLength(1);
});
it("returns only those Things that apply to the given Resource's ACR", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let applicablePolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#applicable-policy`,
});
applicablePolicy = setUrl(applicablePolicy, rdf.type, acp.Policy);
let unapplicablePolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#unapplicable-policy`,
});
unapplicablePolicy = setUrl(unapplicablePolicy, rdf.type, acp.Policy);
let regularPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#regular-policy`,
});
regularPolicy = setUrl(applicablePolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, applicablePolicy);
mockedAcr = setThing(mockedAcr, unapplicablePolicy);
mockedAcr = setThing(mockedAcr, regularPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#applicable-policy`
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#regular-policy`
);
expect(getResourceAcrPolicyAll(mockedResourceWithAcr)).toHaveLength(1);
});
it("returns an empty array if there are no Things in the given Resource's ACR", () => {
expect(
getResourceAcrPolicyAll(
addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockAcrFor("https://some.pod/resource")
)
)
).toHaveLength(0);
});
});
describe("setResourcePolicy", () => {
it("replaces existing instances of the set Access Policy", () => {
const somePredicate = "https://some.vocab/predicate";
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedPolicy = setUrl(mockedPolicy, somePredicate, "https://example.test");
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicy = removeUrl(
mockedPolicy,
somePredicate,
"https://example.test"
);
const updatedResourceWithAcr = setResourcePolicy(
mockedResourceWithAcr,
updatedPolicy
);
const policyAfterUpdate = getResourcePolicy(
updatedResourceWithAcr,
"policy"
);
expect(getUrl(policyAfterUpdate!, somePredicate)).toBeNull();
});
it("applies the Policy to the Resource", () => {
const mockedAcr = mockAcrFor("https://some.pod/resource");
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
const mockedPolicy = createResourcePolicyFor(
mockedResourceWithAcr,
"policy"
);
const updatedResourceWithAcr = setResourcePolicy(
mockedResourceWithAcr,
mockedPolicy
);
expect(getPolicyUrlAll(updatedResourceWithAcr)).toEqual([
`${getSourceUrl(mockedAcr)}#policy`,
]);
});
});
describe("setResourceAcrPolicy", () => {
it("replaces existing instances of the set Access Policy", () => {
const somePredicate = "https://some.vocab/predicate";
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedPolicy = setUrl(mockedPolicy, somePredicate, "https://example.test");
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicy = removeUrl(
mockedPolicy,
somePredicate,
"https://example.test"
);
const updatedResourceWithAcr = setResourceAcrPolicy(
mockedResourceWithAcr,
updatedPolicy
);
const policyAfterUpdate = getResourceAcrPolicy(
updatedResourceWithAcr,
"policy"
);
expect(getUrl(policyAfterUpdate!, somePredicate)).toBeNull();
});
it("applies the Policy to the Resource's ACR", () => {
const mockedAcr = mockAcrFor("https://some.pod/resource");
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
const mockedPolicy = createResourcePolicyFor(
mockedResourceWithAcr,
"policy"
);
const updatedResourceWithAcr = setResourceAcrPolicy(
mockedResourceWithAcr,
mockedPolicy
);
expect(getAcrPolicyUrlAll(updatedResourceWithAcr)).toEqual([
`${getSourceUrl(mockedAcr)}#policy`,
]);
});
});
describe("removeResourcePolicy", () => {
it("removes the given Access Policy from the Access Policy Resource", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourcePolicy(
mockedResourceWithAcr,
mockedPolicy
);
expect(getResourcePolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("unapplies the Policy from the Resource", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourcePolicy(
mockedResourceWithAcr,
mockedPolicy
);
expect(getPolicyUrlAll(updatedPolicyDataset)).toHaveLength(0);
});
it("accepts a plain name to remove an Access Policy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourcePolicy(
mockedResourceWithAcr,
"policy"
);
expect(getResourcePolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("accepts a full URL to remove an Access Policy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourcePolicy(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(getResourcePolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("accepts a Named Node to remove an Access Policy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourcePolicy(
mockedResourceWithAcr,
DataFactory.namedNode(`${getSourceUrl(mockedAcr)}#policy`)
);
expect(getResourcePolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("does not remove non-Policies", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(
mockedPolicy,
rdf.type,
"https://arbitrary.vocab/#not-a-policy"
);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourcePolicy(
mockedResourceWithAcr,
mockedPolicy
);
const updatedAcr = internal_getAcr(updatedPolicyDataset);
expect(
getThing(updatedAcr, `${getSourceUrl(mockedAcr)}#policy`)
).not.toBeNull();
});
it("does not remove unrelated policies", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy1 = createThing({
url: `${getSourceUrl(mockedAcr)}#policy1`,
});
mockedPolicy1 = setUrl(mockedPolicy1, rdf.type, acp.Policy);
let mockedPolicy2 = createThing({
url: `${getSourceUrl(mockedAcr)}#policy2`,
});
mockedPolicy2 = setUrl(mockedPolicy2, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy1);
mockedAcr = setThing(mockedAcr, mockedPolicy2);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy1`
);
mockedResourceWithAcr = addPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy2`
);
const updatedPolicyDataset = removeResourcePolicy(
mockedResourceWithAcr,
mockedPolicy1
);
expect(getResourcePolicyAll(updatedPolicyDataset)).toHaveLength(1);
});
});
describe("removeResourceAcrPolicy", () => {
it("removes the given Access Policy from the Access Policy Resource", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourceAcrPolicy(
mockedResourceWithAcr,
mockedPolicy
);
expect(getResourceAcrPolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("unapplies the Policy from the Resource", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourceAcrPolicy(
mockedResourceWithAcr,
mockedPolicy
);
expect(getAcrPolicyUrlAll(updatedPolicyDataset)).toHaveLength(0);
});
it("accepts a plain name to remove an Access Policy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourceAcrPolicy(
mockedResourceWithAcr,
"policy"
);
expect(getResourceAcrPolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("accepts a full URL to remove an Access Policy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourceAcrPolicy(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
expect(getResourceAcrPolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("accepts a Named Node to remove an Access Policy", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(mockedPolicy, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourceAcrPolicy(
mockedResourceWithAcr,
DataFactory.namedNode(`${getSourceUrl(mockedAcr)}#policy`)
);
expect(getResourceAcrPolicyAll(updatedPolicyDataset)).toHaveLength(0);
});
it("does not remove non-Policies", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy = createThing({
url: `${getSourceUrl(mockedAcr)}#policy`,
});
mockedPolicy = setUrl(
mockedPolicy,
rdf.type,
"https://arbitrary.vocab/#not-a-policy"
);
mockedAcr = setThing(mockedAcr, mockedPolicy);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy`
);
const updatedPolicyDataset = removeResourceAcrPolicy(
mockedResourceWithAcr,
mockedPolicy
);
const updatedAcr = internal_getAcr(updatedPolicyDataset);
expect(
getThing(updatedAcr, `${getSourceUrl(mockedAcr)}#policy`)
).not.toBeNull();
});
it("does not remove unrelated policies", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedPolicy1 = createThing({
url: `${getSourceUrl(mockedAcr)}#policy1`,
});
mockedPolicy1 = setUrl(mockedPolicy1, rdf.type, acp.Policy);
let mockedPolicy2 = createThing({
url: `${getSourceUrl(mockedAcr)}#policy2`,
});
mockedPolicy2 = setUrl(mockedPolicy2, rdf.type, acp.Policy);
mockedAcr = setThing(mockedAcr, mockedPolicy1);
mockedAcr = setThing(mockedAcr, mockedPolicy2);
let mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy1`
);
mockedResourceWithAcr = addAcrPolicyUrl(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#policy2`
);
const updatedPolicyDataset = removeResourceAcrPolicy(
mockedResourceWithAcr,
mockedPolicy1
);
expect(getResourceAcrPolicyAll(updatedPolicyDataset)).toHaveLength(1);
});
});
describe("setAllowModes", () => {
it("sets the given modes on the Policy", () => {
const policy = mockThingFrom(
"https://arbitrary.pod/policy-resource#policy"
);
const updatedPolicy = setAllowModes(policy, {
read: false,
append: true,
write: true,
});
expect(getIriAll(updatedPolicy, acp.allow)).toEqual([
acp.Append,
acp.Write,
]);
});
it("replaces existing modes set on the Policy", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.allow, acp.Append);
const updatedPolicy = setAllowModes(policy, {
read: true,
append: false,
write: false,
});
expect(getIriAll(updatedPolicy, acp.allow)).toEqual([acp.Read]);
});
it("does not affect denied modes", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.deny, acp.Append);
const updatedPolicy = setAllowModes(policy, {
read: true,
append: false,
write: false,
});
expect(getIriAll(updatedPolicy, acp.deny)).toEqual([acp.Append]);
});
});
describe("getAllowModes", () => {
it("returns all modes that are allowed on the Policy", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.allow, acp.Append);
const allowedModes = getAllowModes(policy);
expect(allowedModes).toEqual({ read: false, append: true, write: false });
});
it("does not return modes that are denied on the Policy", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.deny, acp.Append);
const allowedModes = getAllowModes(policy);
expect(allowedModes).toEqual({ read: false, append: false, write: false });
});
});
describe("setDenyModes", () => {
it("sets the given modes on the Policy", () => {
const policy = mockThingFrom(
"https://arbitrary.pod/policy-resource#policy"
);
const updatedPolicy = setDenyModes(policy, {
read: false,
append: true,
write: true,
});
expect(getIriAll(updatedPolicy, acp.deny)).toEqual([acp.Append, acp.Write]);
});
it("replaces existing modes set on the Policy", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.deny, acp.Append);
const updatedPolicy = setDenyModes(policy, {
read: true,
append: false,
write: false,
});
expect(getIriAll(updatedPolicy, acp.deny)).toEqual([acp.Read]);
});
it("does not affect allowed modes", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.allow, acp.Append);
const updatedPolicy = setDenyModes(policy, {
read: true,
append: false,
write: false,
});
expect(getIriAll(updatedPolicy, acp.allow)).toEqual([acp.Append]);
});
});
describe("getDenyModes", () => {
it("returns all modes that are denied on the Policy", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.deny, acp.Append);
const allowedModes = getDenyModes(policy);
expect(allowedModes).toEqual({ read: false, append: true, write: false });
});
it("does not return modes that are allowed on the Policy", () => {
let policy = mockThingFrom("https://arbitrary.pod/policy-resource#policy");
policy = addIri(policy, acp.allow, acp.Append);
const allowedModes = getDenyModes(policy);
expect(allowedModes).toEqual({ read: false, append: false, write: false });
});
});
describe("policyAsMarkdown", () => {
it("lists which access modes are allowed, denied or unspecified", () => {
let policy = createPolicy("https://some.pod/policyResource#policy");
policy = setAllowModes(policy, { read: true, append: false, write: false });
policy = setDenyModes(policy, { read: false, append: false, write: true });
expect(policyAsMarkdown(policy)).toBe(
"## Policy: https://some.pod/policyResource#policy\n" +
"\n" +
"- Read: allowed\n" +
"- Append: unspecified\n" +
"- Write: denied\n" +
"\n" +
"<no rules specified yet>\n"
);
});
it("can list individual rules without adding unused types of rules", () => {
let policy = createPolicy("https://some.pod/policyResource#policy");
policy = addAllOfRuleUrl(
policy,
"https://some.pod/policyResource#allOfRule"
);
expect(policyAsMarkdown(policy)).toBe(
"## Policy: https://some.pod/policyResource#policy\n" +
"\n" +
"- Read: unspecified\n" +
"- Append: unspecified\n" +
"- Write: unspecified\n" +
"\n" +
"All of these rules should match:\n" +
"- https://some.pod/policyResource#allOfRule\n"
);
});
it("can list all applicable rules", () => {
let policy = createPolicy("https://some.pod/policyResource#policy");
policy = addAllOfRuleUrl(
policy,
"https://some.pod/policyResource#allOfRule"
);
policy = addAnyOfRuleUrl(
policy,
"https://some.pod/policyResource#anyOfRule"
);
policy = addNoneOfRuleUrl(
policy,
"https://some.pod/policyResource#noneOfRule"
);
expect(policyAsMarkdown(policy)).toBe(
"## Policy: https://some.pod/policyResource#policy\n" +
"\n" +
"- Read: unspecified\n" +
"- Append: unspecified\n" +
"- Write: unspecified\n" +
"\n" +
"All of these rules should match:\n" +
"- https://some.pod/policyResource#allOfRule\n" +
"\n" +
"At least one of these rules should match:\n" +
"- https://some.pod/policyResource#anyOfRule\n" +
"\n" +
"None of these rules should match:\n" +
"- https://some.pod/policyResource#noneOfRule\n"
);
});
});