diff --git a/src/common/constants.ts b/src/common/constants.ts index 96df0bce9..1de70d09c 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -20,7 +20,7 @@ // import type { Term, Quad, NamedNode, BlankNode, Literal } from "@rdfjs/types"; import { DataFactory } from "n3"; -import { rdf } from "rdf-namespaces"; +import { rdf, acl as _acl } from "rdf-namespaces"; const { namedNode } = DataFactory; @@ -40,15 +40,15 @@ export const gc = { hasConsent: namedNode(`${GC}hasConsent`), isProvidedTo: namedNode(`${GC}isProvidedTo`), isConsentForDataSubject: namedNode(`${GC}isConsentForDataSubject`), -} - - +}; +export const acl = { + Read: namedNode(_acl.Read), + Write: namedNode(_acl.Write), + Append: namedNode(_acl.Append), + mode: namedNode(_acl.mode), +}; -export const MODE = namedNode(`${ACL}mode`); -export const READ = namedNode(`${ACL}Read`); -export const WRITE = namedNode(`${ACL}Write`); -export const APPEND = namedNode(`${ACL}Append`); export const ISSUANCE_DATE = namedNode(`${CRED}issuanceDate`); export const EXPIRATION_DATE = namedNode(`${CRED}expirationDate`); export const ISSUER = namedNode(`${CRED}issuer`); diff --git a/src/common/getters.ts b/src/common/getters.ts index 80b26d01e..2c72d1876 100644 --- a/src/common/getters.ts +++ b/src/common/getters.ts @@ -30,21 +30,23 @@ import type { AccessGrantGConsent } from "../gConsent/type/AccessGrant"; import type { AccessRequestGConsent } from "../gConsent/type/AccessRequest"; import type { AccessModes } from "../type/AccessModes"; import { - APPEND, CREDENTIAL_SUBJECT, EXPIRATION_DATE, INHERIT, ISSUANCE_DATE, ISSUER, - MODE, - READ, - WRITE, XSD_BOOLEAN, assertTermType, getSingleQuad, - gc + gc, + acl, } from "./constants"; -import { GC_CONSENT_STATUS_DENIED, GC_CONSENT_STATUS_EXPLICITLY_GIVEN, GC_FOR_PERSONAL_DATA, GC_HAS_STATUS } from "../gConsent/constants"; +import { + GC_CONSENT_STATUS_DENIED, + GC_CONSENT_STATUS_EXPLICITLY_GIVEN, + GC_FOR_PERSONAL_DATA, + GC_HAS_STATUS, +} from "../gConsent/constants"; const { namedNode, defaultGraph, quad, literal } = DataFactory; @@ -65,9 +67,16 @@ export function getResources( ): string[] { const resources: string[] = []; - for (const { object } of vc.match(getConsent(vc), namedNode(GC_FOR_PERSONAL_DATA), null, defaultGraph())) { - if (object.termType !== 'NamedNode') { - throw new Error(`Expected resource to be a Named Node. Instead got [${object.value}] with term type [${object.termType}]`) + for (const { object } of vc.match( + getConsent(vc), + namedNode(GC_FOR_PERSONAL_DATA), + null, + defaultGraph(), + )) { + if (object.termType !== "NamedNode") { + throw new Error( + `Expected resource to be a Named Node. Instead got [${object.value}] with term type [${object.termType}]`, + ); } resources.push(object.value); } @@ -80,14 +89,30 @@ export function isGConsentAccessGrant( ): boolean { const credentialSubject = getCredentialSubject(vc); try { - const providedConsent = getSingleObject(vc, credentialSubject, gc.providedConsent, 'BlankNode'); + const providedConsent = getSingleObject( + vc, + credentialSubject, + gc.providedConsent, + "BlankNode", + ); return ( - ( - vc.has(quad(providedConsent, namedNode(GC_HAS_STATUS), namedNode(GC_CONSENT_STATUS_DENIED))) - || vc.has(quad(providedConsent, namedNode(GC_HAS_STATUS), namedNode(GC_CONSENT_STATUS_EXPLICITLY_GIVEN))) - // Because of the getSingleObject the try / catch is also needed to wrap this as well as getting the provided consent - ) && !!getSingleObject(vc, providedConsent, gc.isProvidedTo) - ) + (vc.has( + quad( + providedConsent, + namedNode(GC_HAS_STATUS), + namedNode(GC_CONSENT_STATUS_DENIED), + ), + ) || + vc.has( + quad( + providedConsent, + namedNode(GC_HAS_STATUS), + namedNode(GC_CONSENT_STATUS_EXPLICITLY_GIVEN), + ), + )) && + // Because of the getSingleObject the try / catch is also needed to wrap this as well as getting the provided consent + !!getSingleObject(vc, providedConsent, gc.isProvidedTo) + ); } catch (e) { return false; } @@ -120,9 +145,9 @@ export function getResourceOwner( return getSingleObject( vc, // We should probably allow this to be Blank or Named Node - getSingleObject(vc, credentialSubject, gc.hasConsent, 'BlankNode'), - gc.isConsentForDataSubject - ).value + getSingleObject(vc, credentialSubject, gc.hasConsent, "BlankNode"), + gc.isConsentForDataSubject, + ).value; } catch (e) { return undefined; } @@ -136,16 +161,20 @@ function getConsent(vc: AccessGrantGConsent | AccessRequestGConsent) { const credentialSubject = getCredentialSubject(vc); const consents = [ ...vc.match(credentialSubject, gc.providedConsent, null, defaultGraph()), - ...vc.match(credentialSubject, gc.hasConsent, null, defaultGraph()) + ...vc.match(credentialSubject, gc.hasConsent, null, defaultGraph()), ]; if (consents.length !== 1) { - throw new Error(`Expected exactly 1 consent value. Found ${consents.length}.`) + throw new Error( + `Expected exactly 1 consent value. Found ${consents.length}.`, + ); } const [{ object }] = consents; if (object.termType !== "BlankNode" && object.termType !== "NamedNode") { - throw new Error(`Expected consent to be a Named Node or Blank Node, instead got ${object.termType}`) + throw new Error( + `Expected consent to be a Named Node or Blank Node, instead got ${object.termType}`, + ); } - return object + return object; } /** @@ -226,9 +255,9 @@ export function getAccessModes( ): AccessModes { const consent = getConsent(vc); return { - read: vc.has(quad(consent, MODE, READ, defaultGraph())), - write: vc.has(quad(consent, MODE, WRITE, defaultGraph())), - append: vc.has(quad(consent, MODE, APPEND, defaultGraph())), + read: vc.has(quad(consent, acl.mode, acl.Read, defaultGraph())), + write: vc.has(quad(consent, acl.mode, acl.Write, defaultGraph())), + append: vc.has(quad(consent, acl.mode, acl.Append, defaultGraph())), }; } @@ -364,7 +393,14 @@ export function getIssuer( export function getInherit( vc: AccessGrantGConsent | AccessRequestGConsent, ): boolean { - return !vc.has(quad(getConsent(vc), INHERIT, literal("false", XSD_BOOLEAN), defaultGraph())); + return !vc.has( + quad( + getConsent(vc), + INHERIT, + literal("false", XSD_BOOLEAN), + defaultGraph(), + ), + ); } /** diff --git a/src/gConsent/guard/isAccessGrant.ts b/src/gConsent/guard/isAccessGrant.ts index df643ba4e..4128a161d 100644 --- a/src/gConsent/guard/isAccessGrant.ts +++ b/src/gConsent/guard/isAccessGrant.ts @@ -19,6 +19,12 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +import { ACCESS_GRANT_STATUS } from "../constants"; +import type { + AccessGrantBody, + BaseAccessVcBody, +} from "../type/AccessVerifiableCredential"; + export const GC_CONSENT_STATUS_DENIED = "https://w3id.org/GConsent#ConsentStatusDenied"; export const GC_CONSENT_STATUS_EXPLICITLY_GIVEN = @@ -26,13 +32,6 @@ export const GC_CONSENT_STATUS_EXPLICITLY_GIVEN = export const GC_CONSENT_STATUS_REQUESTED = "https://w3id.org/GConsent#ConsentStatusRequested"; - -import { ACCESS_GRANT_STATUS } from "../constants"; -import type { - AccessGrantBody, - BaseAccessVcBody, -} from "../type/AccessVerifiableCredential"; - export function isAccessGrant( vc: BaseAccessVcBody, ): vc is BaseAccessVcBody & AccessGrantBody {