├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── audit.yml │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── e2e-browser.yml │ ├── e2e-node.yml │ └── release.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── .prettierignore ├── ARCHITECTURE.md ├── CHANGELOG.md ├── CODE-OF-CONDUCT.md ├── CODEOWNERS ├── LICENSE ├── README.md ├── SECURITY.md ├── docs ├── README.md └── api │ ├── Makefile │ ├── conf.py │ ├── redirects.txt │ ├── source │ └── index.rst │ └── themes │ └── inrupt │ └── theme.conf ├── e2e ├── browser │ ├── test-app │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── components │ │ │ └── solidClient │ │ │ │ └── index.tsx │ │ ├── next-env.d.ts │ │ ├── next.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ └── tsconfig.json │ └── test │ │ ├── README.md │ │ ├── e2e.playwright.ts │ │ └── globalSetup.ts ├── bundle │ ├── import.js │ └── webpack.config.js ├── env │ ├── .env │ ├── .env.dev │ ├── .env.legacy │ └── .env.prod └── node │ ├── README.md │ ├── acp.test.ts │ ├── jest.setup.ts │ ├── request-metadata.test.ts │ ├── resource.test.ts │ └── wac.test.ts ├── jest.config.ts ├── jest.environment-apac.js ├── jest.environment-utc.js ├── jest.setup.ts ├── package-lock.json ├── package.json ├── playwright.config.ts ├── rollup.config.mjs ├── sonar-project.properties ├── src ├── access │ ├── wac.test.ts │ └── wac.ts ├── acl │ ├── acl.internal.ts │ ├── acl.test.ts │ ├── acl.ts │ ├── agent.test.ts │ ├── agent.ts │ ├── class.test.ts │ ├── class.ts │ ├── group.test.ts │ ├── group.ts │ ├── mock.internal.ts │ ├── mock.test.ts │ └── mock.ts ├── acp │ ├── accessControl │ │ ├── getAccessControlUrlAll.test.ts │ │ ├── getAccessControlUrlAll.ts │ │ ├── getMemberAccessControlUrlAll.test.ts │ │ └── getMemberAccessControlUrlAll.ts │ ├── acp.internal.ts │ ├── acp.test.ts │ ├── acp.ts │ ├── constants.ts │ ├── control.internal.ts │ ├── control.test.ts │ ├── control.ts │ ├── ess2.test.ts │ ├── ess2.ts │ ├── internal │ │ ├── getAccessControlResourceThing.ts │ │ ├── getDefaultAccessControlThing.ts │ │ ├── getDefaultAccessControlUrl.ts │ │ ├── getDefaultAgentMatcherPolicyMatcherUrl.ts │ │ ├── getDefaultAgentMatcherPolicyUrl.ts │ │ ├── getModes.ts │ │ ├── getPolicyUrls.ts │ │ ├── setAccessControlResourceThing.ts │ │ ├── setAcr.ts │ │ ├── setDefaultAccessControlThingIfNotExist.ts │ │ ├── setDefaultAgentMatcherPolicyMatcherThingIfNotExist.ts │ │ ├── setDefaultAgentMatcherPolicyThingIfNotExist.ts │ │ └── setModes.ts │ ├── matcher.test.ts │ ├── matcher.ts │ ├── mock.test.ts │ ├── mock.ts │ ├── mock │ │ ├── constants.ts │ │ ├── dataset.ts │ │ └── mockAccessControlledResource.ts │ ├── policy.test.ts │ ├── policy.ts │ ├── policy │ │ ├── addAcrPolicyUrl.test.ts │ │ ├── addAcrPolicyUrl.ts │ │ ├── addMemberAcrPolicyUrl.test.ts │ │ ├── addMemberAcrPolicyUrl.ts │ │ ├── addMemberPolicyUrl.test.ts │ │ ├── addMemberPolicyUrl.ts │ │ ├── addPolicyUrl.test.ts │ │ ├── addPolicyUrl.ts │ │ ├── getAcrPolicyUrlAll.test.ts │ │ ├── getAcrPolicyUrlAll.ts │ │ ├── getAllowModes.ts │ │ ├── getDenyModes.ts │ │ ├── getMemberAcrPolicyUrlAll.test.ts │ │ ├── getMemberAcrPolicyUrlAll.ts │ │ ├── getMemberPolicyUrlAll.test.ts │ │ ├── getMemberPolicyUrlAll.ts │ │ ├── getPolicyUrlAll.test.ts │ │ ├── getPolicyUrlAll.ts │ │ ├── removeAcrPolicyUrl.test.ts │ │ ├── removeAcrPolicyUrl.ts │ │ ├── removeMemberAcrPolicyUrl.test.ts │ │ ├── removeMemberAcrPolicyUrl.ts │ │ ├── removeMemberPolicyUrl.test.ts │ │ ├── removeMemberPolicyUrl.ts │ │ ├── removePolicyUrl.test.ts │ │ ├── removePolicyUrl.ts │ │ ├── setAllowModes.ts │ │ ├── setDenyModes.ts │ │ ├── setResourcePolicy.test.ts │ │ └── setResourcePolicy.ts │ ├── rule.test.ts │ ├── rule.ts │ ├── type │ │ ├── AccessControlResource.ts │ │ └── DefaultOptions.ts │ └── util │ │ ├── getAcrUrl.test.ts │ │ ├── getAcrUrl.ts │ │ ├── getAgentAccess.test.ts │ │ ├── getAgentAccess.ts │ │ ├── getAgentAccessAll.test.ts │ │ ├── getAgentAccessAll.ts │ │ ├── getAgentUrlAll.test.ts │ │ ├── getAgentUrlAll.ts │ │ ├── getPublicAccess.test.ts │ │ ├── getPublicAccess.ts │ │ ├── getResourceAcr.test.ts │ │ ├── getResourceAcr.ts │ │ ├── getVcAccess.test.ts │ │ ├── getVcAccess.ts │ │ ├── setAgentAccess.test.ts │ │ ├── setAgentAccess.ts │ │ ├── setPublicAccess.test.ts │ │ ├── setPublicAccess.ts │ │ ├── setVcAccess.test.ts │ │ └── setVcAccess.ts ├── constants.ts ├── datatypes.test.ts ├── datatypes.ts ├── formats │ ├── index.ts │ ├── jsonLd.test.ts │ ├── jsonLd.ts │ ├── prefixes.ts │ ├── solidDatasetAsTurtle.test.ts │ ├── solidDatasetAsTurtle.ts │ ├── turtle.test.ts │ └── turtle.ts ├── index.test.ts ├── index.ts ├── interfaces.internal.ts ├── interfaces.ts ├── profile │ ├── jwks.test.ts │ ├── jwks.ts │ ├── webid.test.ts │ └── webid.ts ├── rdf.internal.ts ├── rdf.test.ts ├── rdfjs.internal.ts ├── rdfjs.ts ├── resource │ ├── __snapshots__ │ │ └── solidDataset.test.ts.snap │ ├── file.test.ts │ ├── file.ts │ ├── iri.internal.ts │ ├── mock.test.ts │ ├── mock.ts │ ├── resource.internal.ts │ ├── resource.test.ts │ ├── resource.ts │ ├── solidDataset.test.ts │ └── solidDataset.ts ├── tests.internal.ts ├── thing │ ├── add.test.ts │ ├── add.ts │ ├── build.test.ts │ ├── build.ts │ ├── get.test.ts │ ├── get.ts │ ├── mock.test.ts │ ├── mock.ts │ ├── remove.test.ts │ ├── remove.ts │ ├── set.test.ts │ ├── set.ts │ ├── thing.internal.ts │ ├── thing.test.ts │ └── thing.ts └── universal │ ├── getAclServerResourceInfo.test.ts │ ├── getAclServerResourceInfo.ts │ ├── getAgentAccess.test.ts │ ├── getAgentAccess.ts │ ├── getAgentAccessAll.test.ts │ ├── getAgentAccessAll.ts │ ├── getPublicAccess.test.ts │ ├── getPublicAccess.ts │ ├── index.test.ts │ ├── index.ts │ ├── setAgentAccess.test.ts │ ├── setAgentAccess.ts │ ├── setPublicAccess.test.ts │ └── setPublicAccess.ts ├── tsconfig.eslint.json ├── tsconfig.json └── tsconfig.test.json /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.ts.snap 2 | jest.config.js 3 | jest.setup.js 4 | jest.e2e.config.js 5 | .eslintrc.js 6 | rollup.config.js 7 | tsconfig.json 8 | # these files are generated by next.js 9 | next-env.d.ts 10 | next.config.js 11 | 12 | # Eslint is not properly configured to work 13 | # with the following files 14 | e2e/bundle/*.js 15 | e2e/bundle/dist/*.js 16 | e2e/browser/test-app 17 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | require("@rushstack/eslint-patch/modern-module-resolution"); 2 | 3 | module.exports = { 4 | extends: ["@inrupt/eslint-config-lib"], 5 | parserOptions: { 6 | project: "./tsconfig.eslint.json", 7 | }, 8 | rules: { 9 | camelcase: [ 10 | "error", 11 | { 12 | allow: [ 13 | "^internal_", 14 | "^acp_ess_", 15 | "^acp_v*", 16 | "^access_v*", 17 | "^Quad_*", 18 | "^reexport_*", 19 | "^latest_*", 20 | "^legacy_*", 21 | ], 22 | }, 23 | ], 24 | 25 | // Temporarily fix the Jest shadowing warnings 26 | "no-shadow": [ 27 | "warn", 28 | { 29 | allow: ["describe", "it", "jest", "expect"], 30 | }, 31 | ], 32 | 33 | // We use a lot of named exports: 34 | "import/prefer-default-export": "off", 35 | // Made warning due to src/thing/thing.ts 36 | "max-classes-per-file": "warn", 37 | 38 | "no-underscore-dangle": "warn", 39 | "no-param-reassign": "warn", 40 | 41 | // Currently the typings for the Object type in src/rdfjs.internal.js specs 42 | // the property of it's object as partial, though it may not be: 43 | "@typescript-eslint/no-non-null-assertion": "off", 44 | "@typescript-eslint/ban-ts-comment": "error", 45 | "@typescript-eslint/no-use-before-define": "off", 46 | "@typescript-eslint/no-explicit-any": "error", 47 | }, 48 | overrides: [ 49 | { 50 | files: "*.test.ts", 51 | rules: { 52 | "no-nested-ternary": "warn", 53 | "@typescript-eslint/no-explicit-any": "off", 54 | 55 | // TODO: Refactor to https://github.com/SamVerschueren/tsd 56 | "@typescript-eslint/ban-ts-comment": "off", 57 | "no-param-reassign": "off", 58 | "no-shadow": "off" 59 | }, 60 | }, 61 | ], 62 | }; 63 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to help us improve 4 | title: "" 5 | labels: "bug" 6 | assignees: "" 7 | --- 8 | 9 | 14 | 15 | ### Search terms you've used 16 | 17 | 18 | 19 | ### Bug description 20 | 21 | 22 | 23 | ### To Reproduce 24 | 25 | 1. 26 | 2. 27 | 3. 28 | 4. 29 | 30 | **Minimal reproduction** 31 | 32 | 39 | 40 | ### Expected result 41 | 42 | 43 | 44 | ### Actual result 45 | 46 | 47 | 48 | ### Environment 49 | 50 | 57 | 58 | ``` 59 | $ npx envinfo --system --npmPackages --binaries --npmGlobalPackages --browsers 60 | ``` 61 | 62 | ## Additional information 63 | 64 | 65 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Question 4 | url: https://forum.solidproject.org/c/build-a-solid-app/24 5 | about: Ask the Solid community for help with solid-client 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for a new feature 4 | title: "" 5 | labels: "enhancement" 6 | assignees: "" 7 | --- 8 | 9 | 14 | 15 | ### Search terms you've used 16 | 17 | 18 | 19 | ### Feature suggestion 20 | 21 | 22 | 23 | ### Expected functionality/enhancement 24 | 25 | 26 | 27 | ### Actual functionality/enhancement 28 | 29 | 30 | 31 | ### Use Cases 32 | 33 | 37 | 38 | ### Additional information 39 | 40 | 41 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable dependency updates 4 | - package-ecosystem: "npm" 5 | directory: "/" 6 | # Check the npm registry for updates once a week 7 | schedule: 8 | interval: "weekly" 9 | labels: 10 | - "dependencies" 11 | - "npm" 12 | ignore: 13 | - dependency-name: "eslint" 14 | update-types: ["version-update:semver-major"] 15 | - dependency-name: "typedoc-plugin-markdown" 16 | update-types: ["version-update:semver-major"] 17 | groups: 18 | internal-tooling: 19 | patterns: 20 | - "@inrupt/internal-*" 21 | - "@inrupt/base-*" 22 | - "@inrupt/jest-*" 23 | - "@inrupt/eslint-*" 24 | external-types: 25 | patterns: 26 | - "@types/*" 27 | 28 | # Enable weekly version updates for the test application 29 | - package-ecosystem: "npm" 30 | directory: "/e2e/browser/test-app" 31 | schedule: 32 | interval: "weekly" 33 | ignore: 34 | - dependency-name: "eslint" 35 | update-types: ["version-update:semver-major"] 36 | groups: 37 | internal-tooling: 38 | patterns: 39 | - "@inrupt/internal-*" 40 | - "@inrupt/base-*" 41 | - "@inrupt/jest-*" 42 | - "@inrupt/eslint-*" 43 | external-types: 44 | patterns: 45 | - "@types/*" 46 | 47 | # Enable version updates for the website tooling 48 | - package-ecosystem: "pip" 49 | directory: "/docs" 50 | # Check the npm registry for updates once a week 51 | schedule: 52 | interval: "weekly" 53 | labels: 54 | - "dependencies" 55 | - "pip" 56 | # Enable version updates for our CI tooling 57 | - package-ecosystem: "github-actions" 58 | directory: "/" 59 | # Check the npm registry for updates once a week 60 | schedule: 61 | interval: "weekly" 62 | labels: 63 | - "dependencies" 64 | - "github-actions" 65 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | This PR fixes #. 4 | 5 | - [ ] I've added a unit test to test for potential regressions of this bug. 6 | - [ ] The changelog has been updated, if applicable. 7 | - [ ] Commits in this PR are minimal and [have descriptive commit messages](https://chris.beams.io/posts/git-commit/). 8 | 9 | 10 | 11 | # New feature description 12 | 13 | # Checklist 14 | 15 | - [ ] All acceptance criteria are met. 16 | - [ ] Relevant documentation, if any, has been written/updated. 17 | - [ ] The changelog has been updated, if applicable. 18 | - [ ] New functions/types have been exported in `index.ts`, if applicable. 19 | - [ ] New modules (i.e. new `.ts` files) are listed in the `exports` field in `package.json`, if applicable. 20 | - [ ] New modules (i.e. new `.ts` files) are listed in the `typedocOptions.entryPoints` field in `tsconfig.json`, if applicable. 21 | - [ ] Commits in this PR are minimal and [have descriptive commit messages](https://chris.beams.io/posts/git-commit/). 22 | 23 | 24 | 25 | This PR bumps the version to . 26 | 27 | # Checklist 28 | 29 | - [ ] I inspected the changelog to determine if the release was major, minor or patch. I then used the command `npm version ` to update the `package.json` and `package-lock.json` (and locally create a tag). 30 | - [ ] The CHANGELOG has been updated to show version and release date - https://keepachangelog.com/en/1.0.0/. 31 | - [ ] `@since X.Y.Z` annotations have been added to new APIs. 32 | - [ ] The **only** commits in this PR are: 33 | - the CHANGELOG update. 34 | - the version update. 35 | - `@since` annotations. 36 | - [ ] I will make sure **not** to squash these commits, but **rebase** instead. 37 | - [ ] Once this PR is merged, I will push the tag created by `npm version ...` (e.g. `git push origin vX.Y.Z`). 38 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Audit 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | schedule: 9 | - cron: "40 10 * * *" 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | jobs: 14 | audit: 15 | uses: inrupt/typescript-sdk-tools/.github/workflows/reusable-audit.yml@v3 16 | secrets: 17 | WEBHOOK_E2E_FAILURE: ${{ secrets.WEBHOOK_E2E_FAILURE }} 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | env: 6 | CI: true 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | jobs: 11 | lint: 12 | uses: inrupt/typescript-sdk-tools/.github/workflows/reusable-lint.yml@v3 13 | 14 | unit-tests: 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | matrix: 18 | os: [ubuntu-latest, windows-latest] 19 | node-version: ["22.x", "20.x", "18.x"] 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: actions/setup-node@v4 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | cache: "npm" 26 | - run: npm ci --ignore-scripts 27 | # Unit tests are separate because running both at the same time causes issues 28 | # to the CI runner. 29 | - run: npm run test:unit:browser 30 | - run: npm run test:unit:node 31 | - run: npm run test:webpack 32 | # Upload coverage for sonarcube (only matching OS and one node version required) 33 | - uses: actions/upload-artifact@v4 34 | if: ${{ matrix.os == 'ubuntu-latest' && matrix.node-version == '22.x' }} 35 | with: 36 | name: code-coverage-${{matrix.os}}-${{matrix.node-version}} 37 | path: coverage/ 38 | 39 | sonar-scan: 40 | if: ${{ github.actor != 'dependabot[bot]' }} 41 | needs: [unit-tests] 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@v4 45 | with: 46 | # Sonar analysis needs the full history for features like automatic assignment of bugs. If the following step 47 | # is not included the project will show a warning about incomplete information. 48 | fetch-depth: 0 49 | - uses: actions/download-artifact@v4 50 | with: 51 | name: code-coverage-ubuntu-latest-22.x 52 | path: coverage/ 53 | - uses: SonarSource/sonarcloud-github-action@ffc3010689be73b8e5ae0c57ce35968afd7909e8 # v5 54 | env: 55 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 57 | 58 | check: 59 | if: always() 60 | needs: 61 | - lint 62 | - sonar-scan 63 | - unit-tests 64 | runs-on: ubuntu-latest 65 | steps: 66 | - name: Decide whether the needed jobs succeeded or failed 67 | uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # release/v1 68 | with: 69 | jobs: ${{ toJSON(needs) }} 70 | allowed-skips: sonar-scan 71 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "Static Application security Testing (CodeQL)" 7 | 8 | on: 9 | pull_request: 10 | # The branches below must be a subset of the branches above 11 | branches: 12 | - main 13 | schedule: 14 | - cron: "0 12 * * 6" 15 | 16 | jobs: 17 | analyze: 18 | name: Analyze 19 | runs-on: ubuntu-latest 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | # Override automatic language detection by changing the below list 25 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 26 | language: ["javascript"] 27 | # Learn more... 28 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 29 | 30 | steps: 31 | - name: Checkout repository 32 | uses: actions/checkout@v4 33 | with: 34 | # We must fetch at least the immediate parents so that if this is 35 | # a pull request then we can checkout the head. 36 | fetch-depth: 2 37 | 38 | # Initializes the CodeQL tools for scanning. 39 | - name: Initialize CodeQL 40 | uses: github/codeql-action/init@v3 41 | with: 42 | languages: ${{ matrix.language }} 43 | # If you wish to specify custom queries, you can do so here or in a config file. 44 | # By default, queries listed here will override any specified in a config file. 45 | # Prefix the list here with "+" to use these queries and those in the config file. 46 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 47 | 48 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 49 | # If this step fails, then you should remove it and run the build manually (see below) 50 | #- name: Autobuild 51 | # uses: github/codeql-action/autobuild@v1 52 | 53 | # ℹ️ Command-line programs to run using the OS shell. 54 | # 📚 https://git.io/JvXDl 55 | 56 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 57 | # and modify them (or add more) to build your code if your project 58 | # uses a compiled language 59 | 60 | #- run: | 61 | # make bootstrap 62 | # make release 63 | 64 | - name: Perform CodeQL Analysis 65 | uses: github/codeql-action/analyze@v3 66 | -------------------------------------------------------------------------------- /.github/workflows/e2e-browser.yml: -------------------------------------------------------------------------------- 1 | name: End-to-end Tests (Browser) 2 | 3 | on: 4 | push: 5 | 6 | concurrency: 7 | group: ${{ github.workflow }}-${{ github.ref }} 8 | cancel-in-progress: true 9 | jobs: 10 | e2e-browser: 11 | # Ensure we timeout reasonably quickly: 12 | timeout-minutes: 30 13 | runs-on: ${{ matrix.os }} 14 | environment: 15 | name: ${{ matrix.environment-name }} 16 | continue-on-error: ${{ matrix.experimental }} 17 | strategy: 18 | matrix: 19 | # Available OS's: https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners 20 | os: [ubuntu-latest, windows-latest] 21 | environment-name: ["ESS PodSpaces", "ESS Release-2-3", "ESS Dev-2-4"] 22 | experimental: [false] 23 | include: 24 | - environment-name: "ESS Dev-2-3" 25 | experimental: true 26 | os: ubuntu-latest 27 | 28 | steps: 29 | - uses: actions/checkout@v4 30 | - uses: actions/setup-node@v4 31 | with: 32 | node-version-file: ".nvmrc" 33 | cache: "npm" 34 | cache-dependency-path: "**/package-lock.json" 35 | # install 36 | - run: npm ci --ignore-scripts 37 | - run: npx playwright install --with-deps 38 | # build 39 | - run: npm run build 40 | # setup 41 | - run: npm run test:e2e:browser:build 42 | # test 43 | - # Dependabot cannot access secrets, so it doesn't have a token to authenticate to ESS. 44 | # We want jobs in this workflow to be gating PRs, so the whole matrix must 45 | # run even for dependabot so that the matrixed jobs are skipped, instead 46 | # of the whole pipeline. 47 | if: ${{ github.actor != 'dependabot[bot]' }} 48 | run: npm run test:e2e:browser 49 | env: 50 | E2E_TEST_ENVIRONMENT: ${{ matrix.environment-name }} 51 | E2E_TEST_POD: ${{ secrets.E2E_TEST_POD }} 52 | E2E_TEST_IDP: ${{ secrets.E2E_TEST_IDP }} 53 | E2E_TEST_USER: ${{ secrets.E2E_TEST_USER }} 54 | E2E_TEST_PASSWORD: ${{ secrets.E2E_TEST_PASSWORD }} 55 | - name: Archive browser-based end-to-end test request logs 56 | uses: actions/upload-artifact@v4 57 | if: failure() 58 | continue-on-error: true 59 | with: 60 | name: playwright-output 61 | path: test-results/ 62 | 63 | check: 64 | if: always() 65 | needs: 66 | - e2e-browser 67 | runs-on: ubuntu-latest 68 | steps: 69 | - name: Decide whether the needed jobs succeeded or failed 70 | uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # release/v1 71 | with: 72 | allowed-skips: e2e-browser 73 | jobs: ${{ toJSON(needs) }} 74 | -------------------------------------------------------------------------------- /.github/workflows/e2e-node.yml: -------------------------------------------------------------------------------- 1 | name: End-to-end Tests (Node) 2 | 3 | on: 4 | push: 5 | # Allow manual triggering, e.g. to run end-to-end tests against Dependabot PRs: 6 | workflow_dispatch: 7 | 8 | env: 9 | CI: true 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | jobs: 14 | e2e-node: 15 | runs-on: ${{ matrix.os }} 16 | environment: 17 | name: ${{ matrix.environment-name }} 18 | continue-on-error: ${{ matrix.experimental }} 19 | strategy: 20 | matrix: 21 | os: [ubuntu-latest] 22 | node-version: [22.x, 20.x, 18.x] 23 | environment-name: ["ESS PodSpaces", "ESS Release-2-3", "ESS Dev-2-4"] 24 | experimental: [false] 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: actions/setup-node@v4 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | cache: "npm" 31 | cache-dependency-path: "**/package-lock.json" 32 | 33 | - name: Install dependencies 34 | # FIXME: setup-node's caching seems to not restore correctly: https://github.com/actions/setup-node/pull/323/files 35 | # if: steps.setup-node.outputs.cache-hit != 'true' 36 | run: npm ci --ignore-scripts 37 | 38 | - # Dependabot cannot access secrets, so it doesn't have a token to authenticate to ESS. 39 | # We want jobs in this workflow to be gating PRs, so the whole matrix must 40 | # run even for dependabot so that the matrixed jobs are skipped, instead 41 | # of the whole pipeline. 42 | if: ${{ github.actor != 'dependabot[bot]' }} 43 | run: npm run test:e2e:node 44 | env: 45 | E2E_TEST_POD: ${{ secrets.E2E_TEST_POD }} 46 | E2E_TEST_IDP: ${{ secrets.E2E_TEST_IDP }} 47 | E2E_TEST_ENVIRONMENT: ${{ matrix.environment-name }} 48 | E2E_TEST_OWNER_CLIENT_ID: ${{ secrets.E2E_TEST_OWNER_CLIENT_ID }} 49 | E2E_TEST_OWNER_CLIENT_SECRET: ${{ secrets.E2E_TEST_OWNER_CLIENT_SECRET }} 50 | E2E_TEST_FEATURE_ACP: ${{ secrets.E2E_TEST_FEATURE_ACP }} 51 | E2E_TEST_FEATURE_ACP_V3: ${{ secrets.E2E_TEST_FEATURE_ACP_V3 }} 52 | E2E_TEST_FEATURE_WAC: ${{ secrets.E2E_TEST_FEATURE_WAC }} 53 | E2E_TEST_FEATURE_PROBLEM_DETAILS: ${{ secrets.E2E_TEST_FEATURE_PROBLEM_DETAILS }} 54 | 55 | check: 56 | if: always() 57 | needs: 58 | - e2e-node 59 | runs-on: ubuntu-latest 60 | steps: 61 | - name: Decide whether the needed jobs succeeded or failed 62 | uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # release/v1 63 | with: 64 | allowed-skips: e2e-node 65 | jobs: ${{ toJSON(needs) }} 66 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v[0-9]+.[0-9]+.[0-9]+ 7 | 8 | env: 9 | CI: true 10 | jobs: 11 | publish-npm: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Prepare for publication to npm 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version-file: ".nvmrc" 19 | registry-url: "https://registry.npmjs.org" 20 | cache: "npm" 21 | 22 | - run: npm ci 23 | - run: npm publish --access public 24 | env: 25 | NODE_AUTH_TOKEN: ${{ secrets.INRUPT_NPM_TOKEN }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | umd 4 | .DS_Store 5 | .eslintcache 6 | whitesource/ 7 | LICENSE_DEPENDENCIES 8 | LICENSE_DEPENDENCIES_ALL 9 | docs/api/build/ 10 | docs/api/source/api/ 11 | docs/api/docs-assets/ 12 | docs/dist/ 13 | .env*.local 14 | .codesandbox/sandbox/.parcel-cache/ 15 | test-results/ 16 | .vercel 17 | .virtualenv 18 | .parcel-cache/ 19 | .vscode/settings.json 20 | coverage 21 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # We want to ignore compiled Javascript in .gitignore, but not when publishing to npm. Hence this file. 2 | *.test.js 3 | *.test.ts 4 | coverage 5 | whitesource 6 | docs 7 | # Resources should contain files useful at build time only, and should not 8 | # be required as part of the package (like devDependencies) 9 | resources 10 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | e2e/browser/testapp 2 | docs/api/build/source 3 | docs/api/docs-assets 4 | docs/api/source/api 5 | *.snap 6 | *.env 7 | *.env.* 8 | **/.next/ -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @inrupt/engineering 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Inrupt Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to use, 6 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 7 | Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 15 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 16 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 17 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 18 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security policy 2 | 3 | This library intends supporting the development of Solid applications reading and 4 | writing data in Solid servers. Data should always be considered sensitive and 5 | be processed with care and regards to access restrictions and personal information. 6 | 7 | For a better separation of concerns, this library does not deal directly with 8 | authentication. In order to make authenticated requests, one should inject a `fetch` 9 | function compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters) 10 | dealing with authentication. This may be done using Inrupt's authentication libraries 11 | [for Node](https://www.npmjs.com/package/@inrupt/solid-client-authn-node) or [for 12 | the browser](https://www.npmjs.com/package/@inrupt/solid-client-authn-browser). 13 | The security policy for these libraries is available in the associated [GitHub repository](https://github.com/inrupt/solid-client-authn-js/blob/main/SECURITY.md). 14 | 15 | This library also exposes functions to modify data access permissions. We 16 | strive to make the API and [documentation](https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/manage-access/) 17 | as clear and intuitive as possible, because misuse of these functions may result 18 | in exposing data beyond what is intended. Please do open an 19 | [issue](https://github.com/inrupt/solid-client-js/issues) if you face difficulties 20 | with our access control APIs. 21 | 22 | # Reporting a vulnerability 23 | 24 | If you discover a vulnerability in our code, or experience a bug related to security, 25 | please report it following the instructions provided on [Inrupt’s security page](https://inrupt.com/security/). 26 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # apidocs 2 | 3 | Builds the API docs site from generated api \*.md files. 4 | 5 | ## To Build 6 | 7 | To build: 8 | 9 | 0. Prereq: [python3](https://www.python.org/downloads/), [Node.js](https://nodejs.org/). 10 | 11 | 1. Optional but recommended. Create a virtual env: 12 | 13 | ```sh 14 | python3 -m venv 15 | source /bin/activate 16 | ``` 17 | 18 | 2. Install the dependencies: 19 | 20 | ```sh 21 | npm ci 22 | npm run docs:install 23 | ``` 24 | 25 | 3. Generate the docs source files and build the site: 26 | 27 | ```sh 28 | npm run docs:build 29 | ``` 30 | 31 | 4. If you want to preview the docs site, you can use: 32 | 33 | ```sh 34 | npm run docs:preview 35 | ``` 36 | 37 | 5. If you'd like to clean the generated docs and start fresh, you can use: 38 | 39 | ```sh 40 | npm run docs:clean 41 | ``` 42 | 43 | When finished, can deactivate your virtual env. 44 | 45 | ## Third Party Licenses 46 | 47 | The `requirements.txt` lists the 3rd party libraries used for the docs. 48 | For the licenses, see the shared 49 | [inrupt/docs-assets](https://github.com/inrupt/docs-assets#readme). 50 | -------------------------------------------------------------------------------- /docs/api/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXBUILD ?= sphinx-build 7 | SOURCEDIR = source 8 | GIT_BRANCH :=$(shell git rev-parse --abbrev-ref HEAD) 9 | BUILDDIR = build 10 | SPHINXOPTS = -d $(BUILDDIR)/doctrees -W 11 | SOURCECOPYDIR = $(BUILDDIR)/source 12 | 13 | # Will need later for scrubbing generated .md files 14 | MY_OS :=$(shell uname) 15 | # In Makefile, spaces and everything count inside if parens() 16 | ifeq ($(MY_OS),Darwin) 17 | IS_MAC="DEFINED" 18 | endif 19 | 20 | .PHONY: Makefile help check clean clean-all prepare html dist 21 | 22 | check: 23 | $(if $(shell command -v $(SPHINXBUILD) 2> /dev/null),$(info Found `$(SPHINXBUILD)`),$(error sphinx-build is not available, please follow the instructions in ./docs/api/README.md)) 24 | 25 | # Put it first so that "make" without argument is like "make help". 26 | help: check 27 | @$(SPHINXBUILD) -M help "$(SOURCECOPYDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 28 | 29 | clean: 30 | if [ -d $(BUILDDIR) ]; then rm -rf $(BUILDDIR) ; fi; 31 | if [ -d ../dist ]; then rm -rf ../dist ; fi; 32 | 33 | # clean-all has to be separate from clean as prepare depends on clean, 34 | # but prepare also expects the typedoc build output to exist in source/api 35 | clean-all: clean 36 | if [ -d docs-assets ]; then rm -rf docs-assets ; fi; 37 | if [ -d source/api ]; then rm -rf source/api ; fi; 38 | 39 | prepare: clean 40 | if [ ! -d docs-assets ]; then git clone https://github.com/inrupt/docs-assets.git docs-assets; fi; 41 | # Copying to SOURCECOPYDIR instead of copying source dir to BUILDDIR 42 | # in case someone forgets to backslash after build/ 43 | # Copying source/api/* to BUILDDIR. 44 | 45 | mkdir -p $(SOURCECOPYDIR) 46 | cp -R $(SOURCEDIR)/api/* $(SOURCECOPYDIR) 47 | # Note: remove the typedoc generated `index.rst` (see tsconfig.json) since we use a custom index.rst instead 48 | rm $(SOURCECOPYDIR)/index.rst 49 | 50 | # Use our custom index.rst 51 | cp -R $(SOURCEDIR)/index.rst $(SOURCECOPYDIR) 52 | 53 | html: Makefile check prepare 54 | @$(SPHINXBUILD) -M $@ "$(SOURCECOPYDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -c . --keep-going 55 | 56 | dist: html 57 | if [ -d ../dist ]; then rm -r ../dist; fi; 58 | mkdir -p ../dist 59 | cp -R $(BUILDDIR)/html/. ../dist/ 60 | 61 | # Catch-all target: route all unknown targets to Sphinx using the new 62 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 63 | %: Makefile check prepare 64 | @$(SPHINXBUILD) -M $@ "$(SOURCECOPYDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -c . --keep-going 65 | -------------------------------------------------------------------------------- /docs/api/themes/inrupt/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = pydata_sphinx_theme 3 | pygments_style = sphinx 4 | 5 | [options] 6 | project_title = 7 | banner = 8 | banner_msg = 9 | github_editable = 10 | github_org = inrupt 11 | github_repo = 12 | github_branch = 13 | robots_index = 14 | ess_docs = 15 | clientlibjs_docs = 16 | reactsdk_docs = 17 | docs_project = developer-tools/api/javascript/solid-client 18 | -------------------------------------------------------------------------------- /e2e/browser/test-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["../../../.eslintrc.js", "next/core-web-vitals"], 3 | parserOptions: { 4 | project: "./tsconfig.json", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /e2e/browser/test-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /e2e/browser/test-app/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, in the root of the project, run: 6 | 7 | ```bash 8 | npm run build 9 | ``` 10 | 11 | Then, on the `test-app` directory, run: 12 | 13 | ```bash 14 | npm ci 15 | ``` 16 | 17 | Then run the development server: 18 | 19 | ```bash 20 | npm run dev 21 | # or 22 | yarn dev 23 | ``` 24 | 25 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 26 | 27 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 28 | 29 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 30 | 31 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 32 | 33 | ## Learn More 34 | 35 | To learn more about Next.js, take a look at the following resources: 36 | 37 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 38 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 39 | 40 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 41 | 42 | ## Deploy on Vercel 43 | 44 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 45 | 46 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 47 | -------------------------------------------------------------------------------- /e2e/browser/test-app/app/layout.tsx: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | export default function TestAppLayout({ 22 | children, 23 | }: { 24 | children: React.ReactNode; 25 | }) { 26 | return ( 27 | 28 | 29 |
{children}
30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /e2e/browser/test-app/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /e2e/browser/test-app/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | }; 5 | 6 | module.exports = nextConfig; 7 | -------------------------------------------------------------------------------- /e2e/browser/test-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@inrupt/solid-client": "file:../../../", 13 | "@inrupt/solid-client-authn-browser": "^2.5.0", 14 | "next": "^15.3.2", 15 | "react": "^19.1.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^22.15.29", 19 | "@types/react": "^19.1.6", 20 | "eslint": "^8.12.0", 21 | "typescript": "^4.7.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /e2e/browser/test-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules", ".next"] 20 | } 21 | -------------------------------------------------------------------------------- /e2e/browser/test/README.md: -------------------------------------------------------------------------------- 1 | # End-to-end tests for solid-client in the browser 2 | 3 | This directory contains our browser-based end-to-end tests. The interaction 4 | between the test script, which runs on the command line in Node, and the system 5 | under test, which runs in the browser, is a bit involved, so here's a short 6 | description of our setup. 7 | 8 | There are two main parts: 9 | 10 | - The system under test, which you can find under ../test-app in the 11 | root of this repository. 12 | - The test code, which you can find in this directory. 13 | 14 | ## The system under test 15 | 16 | The system under test is a small NextJS app enabling basic interactions with the Pod. 17 | One thing to note is that its dependency on solid-client should be on the code 18 | _inside this repository_, rather than fetched from npm. This means that you will 19 | first need to run `npm run build` at the root of this repository, followed by 20 | `npm run test:e2e:browser:build`. You may run the app manually with `npm run dev` 21 | from the `../test-app` directory. 22 | 23 | ## The test code 24 | 25 | We use [Playwright](https://playwright.dev) to run our 26 | browser-based end-to-end tests. It is configured in `playwright.config.ts` in 27 | the `e2e/browser/test`. It also points to `e2e/browser/test/globalSetup.ts`, where 28 | it is told how to setup the environment before running the test. 29 | 30 | Essentially, the tests open the system under test in a browser, go through the 31 | login procedure if they intend to make authenticated requests, and then interact 32 | with elements on the page. 33 | 34 | Note that the tests need the URL of an OIDC Provider and user credentials to log 35 | in to it. These can be set via environment variables, or by creating a file 36 | `.env.*.local` in this directory - see `e2e/env/` for examples. 37 | 38 | ## Running the tests 39 | 40 | To run the tests, run at the root: 41 | 42 | 1. `npm ci` to install the test runner and the dependencies of the local code. 43 | 2. `npm run build` to build the local code for the tests to depend on. 44 | 3. `npx playwright install` to download the latest versions of all browsers the 45 | tests run in. 46 | 4. `npm run test:e2e:browser:build` to install the dependencies of the 47 | application under test. 48 | 5. `npm run test:e2e:browser` to run the tests. 49 | 50 | If you want to actually see the interactive parts, set `headless: false` in 51 | `e2e/browser/test/playwright.config.ts`. 52 | 53 | To only run tests in a specific browser, run one of: 54 | 55 | npm run test:e2e:browser -- --project=firefox 56 | npm run test:e2e:browser -- --project=chromium 57 | npm run test:e2e:browser -- --project=webkit 58 | -------------------------------------------------------------------------------- /e2e/browser/test/e2e.playwright.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | /* eslint-disable jest/no-done-callback */ 23 | 24 | import { test, expect } from "@inrupt/internal-playwright-helpers"; 25 | 26 | test("creating and removing empty Containers", async ({ page, auth }) => { 27 | await auth.login({ allow: true }); 28 | 29 | // The button is only shown once the app is ready. 30 | await page.waitForSelector("button[data-testid=createContainer]"); 31 | 32 | // A root container should have been found. 33 | await expect(page.getByTestId("parentContainerUrl")).toContainText( 34 | /https:\/\//, 35 | ); 36 | // No child container should be available yet. 37 | await expect(page.getByTestId("childContainerUrl")).toContainText("None"); 38 | 39 | await Promise.all([ 40 | page.waitForRequest((request) => request.method() === "POST"), 41 | page.waitForResponse((response) => response.status() === 201), 42 | page.click("button[data-testid=createContainer]"), 43 | ]); 44 | 45 | // The delete button is only shown once the state has been updated after creation. 46 | await page.waitForSelector("button[data-testid=deleteContainer]"); 47 | 48 | // The child container should have been created under the parent 49 | await expect( 50 | page.locator("span[data-testid=childContainerUrl]"), 51 | ).toContainText( 52 | await page.locator("span[data-testid=childContainerUrl]").allInnerTexts(), 53 | ); 54 | 55 | await Promise.all([ 56 | page.waitForRequest((request) => request.method() === "DELETE"), 57 | page.waitForResponse((response) => response.status() === 204), 58 | page.click("button[data-testid=deleteContainer]"), 59 | ]); 60 | 61 | await page.waitForSelector("button[data-testid=createContainer]"); 62 | 63 | // The child container should have been deleted. 64 | await expect( 65 | page.locator("span[data-testid=childContainerUrl]"), 66 | ).toContainText("None"); 67 | }); 68 | -------------------------------------------------------------------------------- /e2e/browser/test/globalSetup.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { setupEnv } from "@inrupt/internal-test-env"; 23 | 24 | async function globalSetup() { 25 | setupEnv(); 26 | // Return the teardown function. 27 | return async () => {}; 28 | } 29 | 30 | export default globalSetup; 31 | -------------------------------------------------------------------------------- /e2e/bundle/import.js: -------------------------------------------------------------------------------- 1 | import * as all from "../../dist"; 2 | -------------------------------------------------------------------------------- /e2e/bundle/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | module.exports = { 3 | mode: "development", 4 | entry: path.resolve(__dirname, "import.js"), 5 | output: { 6 | path: path.resolve(__dirname, "dist"), 7 | filename: "import.js", 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /e2e/env/.env: -------------------------------------------------------------------------------- 1 | # Select environment (see @inrupt/internal-test-env for a list of available environments) 2 | E2E_TEST_ENVIRONMENT=Inrupt Production 3 | E2E_TEST_IDP=https://login.inrupt.com 4 | # Mark the features you want to test 5 | E2E_TEST_FEATURE_ACP=true 6 | E2E_TEST_FEATURE_ACP_V3=false 7 | E2E_TEST_FEATURE_WAC=false 8 | 9 | # The following environment variables should be kept in a .env.test.local file 10 | # Obtain credentials via https://login.inrupt.com/registration.html 11 | E2E_TEST_CLIENT_ID= 12 | E2E_TEST_CLIENT_SECRET= 13 | E2E_TEST_USER= 14 | E2E_TEST_PASSWORD= 15 | -------------------------------------------------------------------------------- /e2e/env/.env.dev: -------------------------------------------------------------------------------- 1 | # To run tests loading the Inrupt Dev environment, run: 2 | # NODE_ENV=dev npm run test:e2e:node 3 | 4 | # Select environment (see @inrupt/internal-test-env for a list of available environments) 5 | E2E_TEST_ENVIRONMENT=ESS Dev-Next 6 | E2E_TEST_IDP=https://openid.dev-next.inrupt.com 7 | 8 | # Mark the features you want to test 9 | E2E_TEST_FEATURE_ACP=true 10 | E2E_TEST_FEATURE_ACP_V3=false 11 | E2E_TEST_FEATURE_WAC=false 12 | 13 | # Secrets: the following environment variables should be kept in a .env.dev.local file (ignored by git) 14 | # Obtain credentials via https://openid.dev-next.inrupt.com/registration.html 15 | E2E_TEST_OWNER_CLIENT_ID= 16 | E2E_TEST_OWNER_CLIENT_SECRET= 17 | E2E_TEST_USER= 18 | E2E_TEST_PASSWORD= 19 | 20 | # Obtain pod id via https://provision.dev-next.inrupt.com 21 | E2E_TEST_POD=https://storage.dev-next.inrupt.com// 22 | -------------------------------------------------------------------------------- /e2e/env/.env.legacy: -------------------------------------------------------------------------------- 1 | # To run tests loading the Inrupt ESS 1.1 environment, run: 2 | # NODE_ENV=legacy npm run test:e2e:node 3 | 4 | # Select environment (see @inrupt/internal-test-env for a list of available environments) 5 | E2E_TEST_ENVIRONMENT=Inrupt 1.1 6 | E2E_TEST_IDP=https://broker.pod.inrupt.com 7 | 8 | # Mark the features you want to test 9 | E2E_TEST_FEATURE_ACP=false 10 | E2E_TEST_FEATURE_ACP_V3=true 11 | E2E_TEST_FEATURE_WAC=false 12 | 13 | # Secrets: the following environment variables should be kept in a .env.dev.local file (ignored by git) 14 | # Obtain credentials via https://broker.pod.inrupt.com/registration.html 15 | E2E_TEST_CLIENT_ID= 16 | E2E_TEST_CLIENT_SECRET= 17 | E2E_TEST_USER= 18 | E2E_TEST_PASSWORD= 19 | 20 | # Obtain pod id via https://provision.broker.pod.inrupt.com 21 | E2E_TEST_POD=https://pod.inrupt.com// 22 | -------------------------------------------------------------------------------- /e2e/env/.env.prod: -------------------------------------------------------------------------------- 1 | # To run tests loading the Inrupt Prod environment, run: 2 | # NODE_ENV=prod npm run test:e2e:node 3 | 4 | # Select environment (see @inrupt/internal-test-env for a list of available environments) 5 | E2E_TEST_ENVIRONMENT=ESS PodSpaces 6 | E2E_TEST_IDP=https://login.inrupt.com 7 | 8 | # Mark the features you want to test 9 | E2E_TEST_FEATURE_ACP=true 10 | E2E_TEST_FEATURE_ACP_V3=false 11 | E2E_TEST_FEATURE_WAC=false 12 | 13 | # Secrets: the following environment variables should be kept in a .env.dev.local file (ignored by git) 14 | # Obtain credentials via https://login.inrupt.com/registration.html 15 | E2E_TEST_OWNER_CLIENT_ID= 16 | E2E_TEST_OWNER_CLIENT_SECRET= 17 | E2E_TEST_USER= 18 | E2E_TEST_PASSWORD= 19 | 20 | # Obtain pod id via https://provision.inrupt.com 21 | E2E_TEST_POD=https://storage.inrupt.com// 22 | -------------------------------------------------------------------------------- /e2e/node/README.md: -------------------------------------------------------------------------------- 1 | # End-to-end tests for solid-client in Node 2 | 3 | ## Running the tests 4 | 5 | To run the tests locally: 6 | 7 | 1. At the root, run `npm install`. 8 | 2. Copy the relevant `.env.*` file for your environment to `.env.test.local`. 9 | 3. Add the client credentials of the Pod you want the test to run against 10 | into `.env.test.local`. 11 | For example, for pod.inrupt.com, you can obtain them via 12 | https://broker.pod.inrupt.com/catalog.html. 13 | 4. You can now run `npm run test:e2e:node` from the root. 14 | 15 | ## Running these End-to-End-specific tests from an IDE 16 | 17 | To run these tests from your IDE, you may need to setup your test configuration 18 | to pick up the End-2-End-specific Jest configuration file from the root folder 19 | of this mono-repo. 20 | 21 | For example, in IntelliJ you may need to add `--config=jest.e2e.config.js` to 22 | the Jest options of the 'Run/Debug Configurations' modal dialog box. 23 | -------------------------------------------------------------------------------- /e2e/node/jest.setup.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { setupEnv } from "@inrupt/internal-test-env"; 23 | import { jest } from "@jest/globals"; 24 | 25 | // In jest, we immediately invoke this: 26 | setupEnv(); 27 | 28 | if (process.env.CI === "true") { 29 | // Tests running in the CI runners tend to be more flaky. 30 | jest.retryTimes(5, { logErrorsBeforeRetry: true }); 31 | } 32 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2022 Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | 21 | import type { Config } from "jest"; 22 | 23 | type ArrayElement = MyArray extends Array ? T : never; 24 | 25 | const baseConfig: ArrayElement> = { 26 | modulePathIgnorePatterns: ["dist/", "/examples/"], 27 | setupFilesAfterEnv: ["/jest.setup.ts"], 28 | testRegex: "/src/.*\\.test\\.ts$", 29 | clearMocks: true, 30 | injectGlobals: false, 31 | preset: "ts-jest", 32 | }; 33 | 34 | export default { 35 | collectCoverage: true, 36 | coverageReporters: process.env.CI ? ["text", "lcov"] : ["text"], 37 | coverageThreshold: { 38 | global: { 39 | branches: 100, 40 | functions: 100, 41 | lines: 100, 42 | statements: 100, 43 | }, 44 | }, 45 | projects: [ 46 | { 47 | ...baseConfig, 48 | displayName: "browser-utc", 49 | testEnvironment: "./jest.environment-utc.js", 50 | testPathIgnorePatterns: ["e2e", "node.test.ts"], 51 | }, 52 | { 53 | ...baseConfig, 54 | displayName: "browser-apac", 55 | testEnvironment: "./jest.environment-apac.js", 56 | testPathIgnorePatterns: ["e2e", "node.test.ts"], 57 | }, 58 | { 59 | ...baseConfig, 60 | displayName: "node", 61 | testEnvironment: "node", 62 | testPathIgnorePatterns: ["e2e", "browser.test.ts"], 63 | }, 64 | { 65 | ...baseConfig, 66 | testEnvironment: "node", 67 | displayName: "e2e-node", 68 | testRegex: "e2e/node/.*.test.ts", 69 | setupFiles: ["/e2e/node/jest.setup.ts"], 70 | // don't load the polyfills 71 | setupFilesAfterEnv: [], 72 | slowTestThreshold: 30, 73 | }, 74 | ], 75 | } as Config; 76 | -------------------------------------------------------------------------------- /jest.environment-apac.js: -------------------------------------------------------------------------------- 1 | const Environment = require("jest-environment-jsdom"); 2 | 3 | module.exports = class CustomTestEnvironment extends Environment.default { 4 | async setup() { 5 | await super.setup(); 6 | process.env.TZ = 'Australia/Melbourne'; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /jest.environment-utc.js: -------------------------------------------------------------------------------- 1 | const Environment = require("jest-environment-jsdom"); 2 | 3 | module.exports = class CustomTestEnvironment extends Environment.default { 4 | async setup() { 5 | await super.setup(); 6 | process.env.TZ = 'UTC'; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /jest.setup.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2022 Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import "@inrupt/jest-jsdom-polyfills"; 23 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2022 Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { PlaywrightTestConfig } from "@playwright/test"; 23 | 24 | const config: PlaywrightTestConfig = { 25 | testMatch: "*.playwright.ts", 26 | // Configure dotenv in local: 27 | globalSetup: "./e2e/browser/test/globalSetup.ts", 28 | retries: process.env.CI ? 3 : 1, 29 | // Extends from the default 30s 30 | timeout: 120000, 31 | use: { 32 | baseURL: "http://localhost:3000/", 33 | headless: true, 34 | screenshot: "only-on-failure", 35 | trace: "on", 36 | video: "on-first-retry", 37 | }, 38 | webServer: { 39 | command: "cd ./e2e/browser/test-app/ && npm run dev", 40 | port: 3000, 41 | timeout: 120 * 1000, 42 | reuseExistingServer: !process.env.CI, 43 | }, 44 | projects: [ 45 | { 46 | name: "Firefox", 47 | use: { 48 | browserName: "firefox", 49 | userAgent: `Browser-based solid-client end-to-end tests running ${ 50 | process.env.CI === "true" ? "in CI" : "locally" 51 | }. Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0`, 52 | }, 53 | }, 54 | { 55 | name: "Chromium", 56 | use: { 57 | browserName: "chromium", 58 | userAgent: `Browser-based solid-client end-to-end tests running ${ 59 | process.env.CI === "true" ? "in CI" : "locally" 60 | }. Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36`, 61 | }, 62 | }, 63 | // There are currently issues making the Webkit tests flaky on playwright, even using version 1.37.X. 64 | // { 65 | // name: "WebKit", 66 | // use: { 67 | // browserName: "webkit", 68 | // userAgent: `Browser-based solid-client end-to-end tests running ${ 69 | // process.env.CI === "true" ? "in CI" : "locally" 70 | // }. Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1`, 71 | // }, 72 | // }, 73 | ], 74 | }; 75 | 76 | export default config; 77 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | // The following is only possible from Node 18 onwards 2 | import pkg from "./package.json" with { type: "json" }; 3 | import sharedConfig from "@inrupt/base-rollup-config"; 4 | import typescript from '@rollup/plugin-typescript'; 5 | 6 | const config = sharedConfig(pkg); 7 | 8 | config[0].output.push( 9 | { 10 | dir: "dist", 11 | entryFileNames: "[name].mjs", 12 | format: "esm", 13 | preserveModules: true, 14 | }, 15 | { 16 | dir: "dist", 17 | entryFileNames: "[name].umd.js", 18 | format: "umd", 19 | name: "SolidClient", 20 | } 21 | ) 22 | 23 | export default config; 24 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=inrupt_solid-client-js 2 | sonar.organization=inrupt 3 | 4 | # Path is relative to the sonar-project.properties file. Defaults to . 5 | sonar.sources=src 6 | 7 | # Path to Tests and coverage results 8 | #sonar.tests=test 9 | 10 | # Typescript tsconfigPath JSON file 11 | sonar.typescript.tsconfigPath=. 12 | 13 | # Comma-delimited list of paths to LCOV coverage report files. Paths may be absolute or relative to the project root. 14 | sonar.javascript.lcov.reportPaths=./coverage/lcov.info 15 | 16 | sonar.exclusions=**/*.test.ts 17 | -------------------------------------------------------------------------------- /src/acp/accessControl/getAccessControlUrlAll.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, it, expect } from "@jest/globals"; 23 | import { ACP } from "../constants"; 24 | import { 25 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 26 | TEST_URL, 27 | } from "../mock/constants"; 28 | import { mockAccessControlledResource } from "../mock/mockAccessControlledResource"; 29 | import { createDatasetFromSubjects } from "../mock/dataset"; 30 | import { getAccessControlUrlAll } from "./getAccessControlUrlAll"; 31 | 32 | describe("getAccessControlUrlAll()", () => { 33 | it("returns an empty array for empty Access Control Resource", async () => { 34 | const resource = mockAccessControlledResource(); 35 | 36 | expect(getAccessControlUrlAll(resource)).toStrictEqual([]); 37 | }); 38 | 39 | it("returns an access control URL when present", async () => { 40 | const resource = mockAccessControlledResource( 41 | createDatasetFromSubjects([ 42 | [ 43 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 44 | [[ACP.accessControl, [TEST_URL.accessControl1]]], 45 | ], 46 | ]), 47 | ); 48 | 49 | expect(getAccessControlUrlAll(resource)).toStrictEqual([ 50 | TEST_URL.accessControl1, 51 | ]); 52 | }); 53 | 54 | it("returns all access control URLs when present", async () => { 55 | const resource = mockAccessControlledResource( 56 | createDatasetFromSubjects([ 57 | [ 58 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 59 | [ 60 | [ 61 | ACP.accessControl, 62 | [TEST_URL.accessControl1, TEST_URL.accessControl2], 63 | ], 64 | ], 65 | ], 66 | ]), 67 | ); 68 | 69 | expect(getAccessControlUrlAll(resource)).toStrictEqual([ 70 | TEST_URL.accessControl1, 71 | TEST_URL.accessControl2, 72 | ]); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /src/acp/accessControl/getAccessControlUrlAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { ACP } from "../constants"; 23 | import type { UrlString } from "../../interfaces"; 24 | import { getIriAll } from "../../thing/get"; 25 | import type { WithAccessibleAcr } from "../acp"; 26 | import { getAccessControlResourceThing } from "../internal/getAccessControlResourceThing"; 27 | 28 | /** 29 | * ```{note} 30 | * The ACP specification is a draft. As such, this function is experimental and 31 | * subject to change, even in a non-major release. 32 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 33 | * ``` 34 | * 35 | * Get the URL of all access controls linked to the given resource's ACR. 36 | * 37 | * @param resourceWithAcr The resource for which to retrieve URLs of access 38 | * controls applying to it. 39 | * @returns Access Control URL array 40 | * @since 1.6.0 41 | */ 42 | export function getAccessControlUrlAll( 43 | resourceWithAcr: WithAccessibleAcr, 44 | ): UrlString[] { 45 | const acrThing = getAccessControlResourceThing(resourceWithAcr); 46 | 47 | if (acrThing === null) { 48 | return []; 49 | } 50 | 51 | return getIriAll(acrThing, ACP.accessControl); 52 | } 53 | -------------------------------------------------------------------------------- /src/acp/accessControl/getMemberAccessControlUrlAll.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, it, expect } from "@jest/globals"; 23 | import { ACP } from "../constants"; 24 | import { 25 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 26 | TEST_URL, 27 | } from "../mock/constants"; 28 | import { mockAccessControlledResource } from "../mock/mockAccessControlledResource"; 29 | import { createDatasetFromSubjects } from "../mock/dataset"; 30 | import { getMemberAccessControlUrlAll } from "./getMemberAccessControlUrlAll"; 31 | 32 | describe("getMemberAccessControlUrlAll()", () => { 33 | it("returns an empty array for empty Access Control Resource", async () => { 34 | const resource = mockAccessControlledResource(); 35 | 36 | expect(getMemberAccessControlUrlAll(resource)).toStrictEqual([]); 37 | }); 38 | 39 | it("returns a member access control URL when present", async () => { 40 | const resource = mockAccessControlledResource( 41 | createDatasetFromSubjects([ 42 | [ 43 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 44 | [[ACP.memberAccessControl, [TEST_URL.memberAccessControl1]]], 45 | ], 46 | ]), 47 | ); 48 | 49 | expect(getMemberAccessControlUrlAll(resource)).toStrictEqual([ 50 | TEST_URL.memberAccessControl1, 51 | ]); 52 | }); 53 | 54 | it("returns all member access control URLs when present", async () => { 55 | const resource = mockAccessControlledResource( 56 | createDatasetFromSubjects([ 57 | [ 58 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 59 | [ 60 | [ 61 | ACP.memberAccessControl, 62 | [TEST_URL.memberAccessControl1, TEST_URL.memberAccessControl2], 63 | ], 64 | ], 65 | ], 66 | ]), 67 | ); 68 | 69 | expect(getMemberAccessControlUrlAll(resource)).toStrictEqual([ 70 | TEST_URL.memberAccessControl1, 71 | TEST_URL.memberAccessControl2, 72 | ]); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /src/acp/accessControl/getMemberAccessControlUrlAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { ACP } from "../constants"; 23 | import type { UrlString } from "../../interfaces"; 24 | import { getIriAll } from "../../thing/get"; 25 | import type { WithAccessibleAcr } from "../acp"; 26 | import { getAccessControlResourceThing } from "../internal/getAccessControlResourceThing"; 27 | 28 | /** 29 | * ```{note} 30 | * The ACP specification is a draft. As such, this function is experimental and 31 | * subject to change, even in a non-major release. 32 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 33 | * ``` 34 | * 35 | * Get the URL of all member access controls linked to the given resource's ACR. 36 | * 37 | * @param resourceWithAcr The resource for which to retrieve URLs of access 38 | * controls inherited by its children. 39 | * @returns Access Control URL array 40 | * @since 1.6.0 41 | */ 42 | export function getMemberAccessControlUrlAll( 43 | resourceWithAcr: WithAccessibleAcr, 44 | ): UrlString[] { 45 | const acrThing = getAccessControlResourceThing(resourceWithAcr); 46 | 47 | if (acrThing === null) { 48 | return []; 49 | } 50 | 51 | return getIriAll(acrThing, ACP.memberAccessControl); 52 | } 53 | -------------------------------------------------------------------------------- /src/acp/acp.internal.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { acp } from "../constants"; 23 | import type { WithServerResourceInfo } from "../interfaces"; 24 | import { getLinkedResourceUrlAll } from "../resource/resource"; 25 | 26 | /** 27 | * @param linkedAccessResource A Resource exposed via the Link header of another Resource with rel="acl". 28 | * @returns Whether that Resource is an ACP ACR or not (in which case it's likely a WAC ACL). 29 | */ 30 | export function isAcr(linkedAccessResource: WithServerResourceInfo): boolean { 31 | const relTypeLinks = getLinkedResourceUrlAll(linkedAccessResource).type; 32 | return ( 33 | Array.isArray(relTypeLinks) && 34 | relTypeLinks.includes(acp.AccessControlResource) 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/acp/constants.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | /** @hidden */ 23 | export const ACP_NAMESPACE = "http://www.w3.org/ns/solid/acp#"; 24 | 25 | /** @hidden */ 26 | export const ACP = { 27 | AccessControl: ACP_NAMESPACE.concat("AccessControl"), 28 | AccessControlResource: ACP_NAMESPACE.concat("AccessControlResource"), 29 | AuthenticatedAgent: ACP_NAMESPACE.concat("AuthenticatedAgent"), 30 | CreatorAgent: ACP_NAMESPACE.concat("CreatorAgent"), 31 | Matcher: ACP_NAMESPACE.concat("Matcher"), 32 | Policy: ACP_NAMESPACE.concat("Policy"), 33 | PublicAgent: ACP_NAMESPACE.concat("PublicAgent"), 34 | access: ACP_NAMESPACE.concat("access"), 35 | accessControl: ACP_NAMESPACE.concat("accessControl"), 36 | agent: ACP_NAMESPACE.concat("agent"), 37 | allOf: ACP_NAMESPACE.concat("allOf"), 38 | allow: ACP_NAMESPACE.concat("allow"), 39 | anyOf: ACP_NAMESPACE.concat("anyOf"), 40 | apply: ACP_NAMESPACE.concat("apply"), 41 | client: ACP_NAMESPACE.concat("client"), 42 | deny: ACP_NAMESPACE.concat("deny"), 43 | memberAccessControl: ACP_NAMESPACE.concat("memberAccessControl"), 44 | noneOf: ACP_NAMESPACE.concat("noneOf"), 45 | vc: ACP_NAMESPACE.concat("vc"), 46 | }; 47 | 48 | /** @hidden */ 49 | export const ACL_NAMESPACE = "http://www.w3.org/ns/auth/acl#"; 50 | 51 | /** @hidden */ 52 | export const ACL = { 53 | Append: ACL_NAMESPACE.concat("Append"), 54 | Control: ACL_NAMESPACE.concat("Control"), 55 | Read: ACL_NAMESPACE.concat("Read"), 56 | Write: ACL_NAMESPACE.concat("Write"), 57 | }; 58 | 59 | /** @hidden */ 60 | export const VC_ACCESS_GRANT = "http://www.w3.org/ns/solid/vc#SolidAccessGrant"; 61 | -------------------------------------------------------------------------------- /src/acp/internal/getAccessControlResourceThing.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { ThingPersisted } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { getSourceUrl } from "../../resource/resource"; 25 | import { getThing } from "../../thing/thing"; 26 | import { internal_getAcr as getAccessControlResource } from "../control.internal"; 27 | 28 | /** @hidden */ 29 | export function getAccessControlResourceThing( 30 | resource: WithAccessibleAcr, 31 | ): ThingPersisted | null { 32 | const acr = getAccessControlResource(resource); 33 | const acrUrl = getSourceUrl(acr); 34 | 35 | return getThing(acr, acrUrl); 36 | } 37 | -------------------------------------------------------------------------------- /src/acp/internal/getDefaultAccessControlThing.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { ThingPersisted } from "../.."; 23 | import { createThing, getThing } from "../.."; 24 | import type { WithAccessibleAcr } from "../acp"; 25 | import { internal_getAcr as getAccessControlResource } from "../control.internal"; 26 | import type { DefaultAccessControlName } from "./getDefaultAccessControlUrl"; 27 | import { getDefaultAccessControlUrl } from "./getDefaultAccessControlUrl"; 28 | 29 | /** @hidden */ 30 | export function getDefaultAccessControlThing( 31 | resource: WithAccessibleAcr, 32 | name: DefaultAccessControlName, 33 | ): ThingPersisted { 34 | const acr = getAccessControlResource(resource); 35 | const defaultAccessControlUrl = getDefaultAccessControlUrl(resource, name); 36 | 37 | const accessControlThing = getThing(acr, defaultAccessControlUrl); 38 | 39 | if ( 40 | accessControlThing === null || 41 | typeof accessControlThing === "undefined" 42 | ) { 43 | return createThing({ url: defaultAccessControlUrl }); 44 | } 45 | 46 | return accessControlThing; 47 | } 48 | -------------------------------------------------------------------------------- /src/acp/internal/getDefaultAccessControlUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { WithAccessibleAcr } from "../acp"; 23 | import { getSourceUrl } from "../.."; 24 | import { internal_getAcr as getAccessControlResource } from "../control.internal"; 25 | 26 | /** @hidden */ 27 | export type DefaultAccessControlName = 28 | | typeof DEFAULT_ACCESS_CONTROL 29 | | typeof DEFAULT_ACR_ACCESS_CONTROL 30 | | typeof DEFAULT_MEMBER_ACCESS_CONTROL 31 | | typeof DEFAULT_MEMBER_ACR_ACCESS_CONTROL; 32 | 33 | /** @hidden */ 34 | export const DEFAULT_ACCESS_CONTROL = "defaultAccessControl"; 35 | 36 | /** @hidden */ 37 | export const DEFAULT_ACR_ACCESS_CONTROL = "defaultAcrAccessControl"; 38 | 39 | /** @hidden */ 40 | export const DEFAULT_MEMBER_ACCESS_CONTROL = "defaultMemberAccessControl"; 41 | 42 | /** @hidden */ 43 | export const DEFAULT_MEMBER_ACR_ACCESS_CONTROL = 44 | "defaultMemberAcrAccessControl"; 45 | 46 | /** @hidden */ 47 | export function getDefaultAccessControlUrl( 48 | resource: WithAccessibleAcr, 49 | name: DefaultAccessControlName, 50 | ): string { 51 | const acr = getAccessControlResource(resource); 52 | const acrUrl = getSourceUrl(acr); 53 | return acrUrl.concat("#").concat(name); 54 | } 55 | -------------------------------------------------------------------------------- /src/acp/internal/getDefaultAgentMatcherPolicyMatcherUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { WithAccessibleAcr } from "../acp"; 23 | import type { AccessModes } from "../../interfaces"; 24 | import type { DefaultAccessControlName } from "./getDefaultAccessControlUrl"; 25 | import { getDefaultAgentMatcherPolicyUrl } from "./getDefaultAgentMatcherPolicyUrl"; 26 | 27 | /** @hidden */ 28 | export function getDefaultAgentMatcherPolicyMatcherUrl( 29 | resource: WithAccessibleAcr, 30 | name: DefaultAccessControlName, 31 | mode: keyof AccessModes, 32 | ): string { 33 | return getDefaultAgentMatcherPolicyUrl(resource, name, mode).concat( 34 | "Matcher", 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/acp/internal/getDefaultAgentMatcherPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { WithAccessibleAcr } from "../acp"; 23 | import type { AccessModes } from "../../interfaces"; 24 | import type { DefaultAccessControlName } from "./getDefaultAccessControlUrl"; 25 | import { getDefaultAccessControlUrl } from "./getDefaultAccessControlUrl"; 26 | 27 | /** @hidden */ 28 | export function getDefaultAgentMatcherPolicyUrl( 29 | resource: WithAccessibleAcr, 30 | name: DefaultAccessControlName, 31 | mode: keyof AccessModes, 32 | ): string { 33 | return getDefaultAccessControlUrl(resource, name) 34 | .concat("AgentMatcher") 35 | .concat(mode.charAt(0).toUpperCase() + mode.slice(1)) 36 | .concat("Policy"); 37 | } 38 | -------------------------------------------------------------------------------- /src/acp/internal/getModes.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, ThingPersisted } from "../../interfaces"; 23 | import type { ACP } from "../constants"; 24 | import { ACL } from "../constants"; 25 | import { getIriAll } from "../../thing/get"; 26 | 27 | /** @hidden */ 28 | export type ModeType = typeof ACP.allow | typeof ACP.deny; 29 | 30 | /** @hidden */ 31 | export function getModes( 32 | policy: T, 33 | type: ModeType, 34 | ): AccessModes { 35 | const modes = getIriAll(policy, type); 36 | 37 | return { 38 | read: modes.includes(ACL.Read), 39 | append: modes.includes(ACL.Append), 40 | write: modes.includes(ACL.Write), 41 | controlRead: false, 42 | controlWrite: false, 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/acp/internal/getPolicyUrls.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import type { ACP } from "../constants"; 25 | import { getIriAll } from "../../thing/get"; 26 | import { getThing } from "../../thing/thing"; 27 | import { internal_getAcr as getAccessControlResource } from "../control.internal"; 28 | 29 | /** @hidden */ 30 | type PolicyType = typeof ACP.apply | typeof ACP.access; 31 | 32 | /** @hidden */ 33 | export function getPolicyUrls( 34 | resource: WithAccessibleAcr, 35 | accessControlUrls: UrlString[], 36 | type: PolicyType, 37 | ): string[] { 38 | const acr = getAccessControlResource(resource); 39 | 40 | return Array.from( 41 | new Set( 42 | accessControlUrls 43 | .map((accessControlUrl) => { 44 | const accessControlThing = getThing(acr, accessControlUrl); 45 | // istanbul ignore next 46 | if (accessControlThing !== null) { 47 | return getIriAll(accessControlThing, type); 48 | } 49 | // istanbul ignore next 50 | return []; 51 | }) 52 | .reduce( 53 | (previousValue, currentValue) => previousValue.concat(currentValue), 54 | [], 55 | ), 56 | ), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/acp/internal/setAccessControlResourceThing.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { WithAccessibleAcr } from "../acp"; 23 | import type { ThingPersisted } from "../.."; 24 | import { setThing } from "../.."; 25 | import { internal_cloneResource as cloneResource } from "../../resource/resource.internal"; 26 | 27 | /** @hidden */ 28 | export function setAccessControlResourceThing( 29 | resource: T, 30 | thing: ThingPersisted, 31 | ): T { 32 | return Object.assign(cloneResource(resource), { 33 | internal_acp: { 34 | ...resource.internal_acp, 35 | acr: setThing(resource.internal_acp.acr, thing), 36 | }, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/acp/internal/setAcr.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { internal_cloneResource } from "../../resource/resource.internal"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import type { AccessControlResource } from "../type/AccessControlResource"; 25 | 26 | /** 27 | * @hidden 28 | * 29 | * Internal function that attaches an ACR to a Resource. Prefer using this than 30 | * setting the internal values manually (easier to refactor when changing the internals). 31 | */ 32 | export function setAcr( 33 | resource: T, 34 | acr: AccessControlResource, 35 | ): T { 36 | return Object.assign(internal_cloneResource(resource), { 37 | internal_acp: { 38 | acr, 39 | }, 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /src/acp/internal/setDefaultAgentMatcherPolicyThingIfNotExist.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { WithAccessibleAcr } from "../acp"; 23 | import type { AccessModes } from "../../interfaces"; 24 | import type { DefaultAccessControlName } from "./getDefaultAccessControlUrl"; 25 | import { getDefaultAgentMatcherPolicyUrl } from "./getDefaultAgentMatcherPolicyUrl"; 26 | import { addAcrPolicyUrl } from "../policy/addAcrPolicyUrl"; 27 | import { addPolicyUrl } from "../policy/addPolicyUrl"; 28 | 29 | /** @hidden */ 30 | export function setDefaultAgentMatcherPolicyThingIfNotExist< 31 | T extends WithAccessibleAcr, 32 | >(resource: T, name: DefaultAccessControlName, mode: keyof AccessModes): T { 33 | const policyUrl = getDefaultAgentMatcherPolicyUrl(resource, name, mode); 34 | 35 | // TODO: Re-enable when we support setting agent access on member resources 36 | // if (policyUrl.includes("Member") && policyUrl.includes("Acr")) { 37 | // return addMemberAcrPolicyUrl(resource, policyUrl); 38 | // } 39 | 40 | // if (policyUrl.includes("Member")) { 41 | // return addMemberPolicyUrl(resource, policyUrl); 42 | // } 43 | 44 | if (policyUrl.includes("Acr")) { 45 | return addAcrPolicyUrl(resource, policyUrl); 46 | } 47 | 48 | return addPolicyUrl(resource, policyUrl); 49 | } 50 | -------------------------------------------------------------------------------- /src/acp/internal/setModes.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, ThingPersisted } from "../../interfaces"; 23 | import { removeAll } from "../../thing/remove"; 24 | import { addIri } from "../../thing/add"; 25 | import { ACL } from "../constants"; 26 | import type { ModeType } from "./getModes"; 27 | 28 | /** @hidden */ 29 | export function setModes( 30 | policy: T, 31 | modes: AccessModes, 32 | type: ModeType, 33 | ): T { 34 | let newPolicy = removeAll(policy, type); 35 | 36 | if (modes.read || modes.controlRead) { 37 | newPolicy = addIri(newPolicy, type, ACL.Read); 38 | } 39 | 40 | if (modes.append) { 41 | newPolicy = addIri(newPolicy, type, ACL.Append); 42 | } 43 | 44 | if (modes.write || modes.controlWrite) { 45 | newPolicy = addIri(newPolicy, type, ACL.Write); 46 | } 47 | 48 | return newPolicy; 49 | } 50 | -------------------------------------------------------------------------------- /src/acp/mock.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, it, expect } from "@jest/globals"; 23 | import { mockSolidDatasetFrom } from "../resource/mock"; 24 | import { addMockAcrTo, mockAcrFor } from "./mock"; 25 | 26 | describe("mockAcrFor", () => { 27 | it("should attach the URL of the Resource it applies to", () => { 28 | const mockedAcr = mockAcrFor("https://some.pod/resource"); 29 | 30 | expect(mockedAcr.accessTo).toBe("https://some.pod/resource"); 31 | }); 32 | }); 33 | 34 | describe("addMockAcrTo", () => { 35 | it("attaches the given ACR to the given Resource", () => { 36 | const resource = mockSolidDatasetFrom("https://some.pod/resource"); 37 | const acr = mockAcrFor("https://some.pod/resource?ext=acr"); 38 | 39 | const withMockAcr = addMockAcrTo(resource, acr); 40 | 41 | expect(withMockAcr.internal_acp.acr).toEqual(acr); 42 | }); 43 | 44 | it("generates a mock ACR if none is provided", () => { 45 | const resource = mockSolidDatasetFrom("https://some.pod/resource"); 46 | 47 | const withMockAcr = addMockAcrTo(resource); 48 | 49 | expect(withMockAcr.internal_acp.acr).not.toBeNull(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /src/acp/mock/dataset.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { SolidDataset, ThingPersisted } from "../../interfaces"; 23 | import { 24 | buildThing, 25 | createSolidDataset, 26 | createThing, 27 | getThing, 28 | setThing, 29 | } from "../.."; 30 | 31 | /** @hidden */ 32 | export type SubjectPredicateObjectTuple = [string, [string, string[]][]]; 33 | 34 | /** @hidden */ 35 | export function addSubject( 36 | dataset: SolidDataset, 37 | subject: SubjectPredicateObjectTuple, 38 | ): SolidDataset { 39 | let thing = getThing(dataset, subject[0]); 40 | // istanbul ignore next 41 | if (thing === null || typeof thing === "undefined") { 42 | thing = createThing({ url: subject[0] }); 43 | } 44 | for (const predicate of subject[1]) { 45 | let thingBuilder = buildThing(thing); 46 | for (const object of predicate[1]) { 47 | thingBuilder = thingBuilder.addUrl(predicate[0], object); 48 | } 49 | thing = thingBuilder.build() as ThingPersisted; 50 | } 51 | return setThing(dataset, thing); 52 | } 53 | 54 | /** @hidden */ 55 | export function addSubjects( 56 | dataset: SolidDataset, 57 | subjects: SubjectPredicateObjectTuple[], 58 | ): SolidDataset { 59 | return subjects.reduce(addSubject, dataset); 60 | } 61 | 62 | /** @hidden */ 63 | export function createDatasetFromSubjects( 64 | data: SubjectPredicateObjectTuple[], 65 | ): SolidDataset { 66 | return addSubjects(createSolidDataset(), data); 67 | } 68 | -------------------------------------------------------------------------------- /src/acp/mock/mockAccessControlledResource.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { SolidDataset } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { createSolidDataset } from "../../resource/solidDataset"; 25 | import { 26 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 27 | DEFAULT_RESOURCE_URL, 28 | } from "./constants"; 29 | 30 | /** @hidden */ 31 | export function mockAccessControlledResource( 32 | dataset: SolidDataset = createSolidDataset(), 33 | ): WithAccessibleAcr { 34 | return { 35 | ...createSolidDataset(), 36 | internal_acp: { 37 | acr: { 38 | ...dataset, 39 | internal_resourceInfo: { 40 | isRawData: false, 41 | sourceIri: DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 42 | }, 43 | accessTo: DEFAULT_RESOURCE_URL, 44 | }, 45 | }, 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/acp/policy/addAcrPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { buildThing } from "../../thing/build"; 26 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 27 | import { DEFAULT_ACR_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 28 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 29 | import { setDefaultAccessControlThingIfNotExist } from "../internal/setDefaultAccessControlThingIfNotExist"; 30 | 31 | /** 32 | * ```{note} 33 | * The ACP specification is a draft. As such, this function is experimental and 34 | * subject to change, even in a non-major release. 35 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 36 | * ``` 37 | * 38 | * Add a policy applying to the ACR of the given resource. 39 | * 40 | * @param resourceWithAcr The resource for which to add the URL of a policy 41 | * applying to its access control resource. 42 | * @param policyUrl A Policy URL. 43 | * @returns The resource with its ammended access control resource. 44 | * @since 1.16.1 45 | */ 46 | export function addAcrPolicyUrl( 47 | resourceWithAcr: T, 48 | policyUrl: Url | UrlString, 49 | ): T { 50 | const resourceWithAcrContainingDefaultAccessControl = 51 | setDefaultAccessControlThingIfNotExist( 52 | resourceWithAcr, 53 | DEFAULT_ACR_ACCESS_CONTROL, 54 | ); 55 | 56 | const defaultAccessControlThing = getDefaultAccessControlThing( 57 | resourceWithAcrContainingDefaultAccessControl, 58 | DEFAULT_ACR_ACCESS_CONTROL, 59 | ); 60 | 61 | return setAccessControlResourceThing( 62 | resourceWithAcrContainingDefaultAccessControl, 63 | buildThing(defaultAccessControlThing).addUrl(ACP.access, policyUrl).build(), 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /src/acp/policy/addMemberAcrPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { buildThing } from "../../thing/build"; 26 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 27 | import { DEFAULT_MEMBER_ACR_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 28 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 29 | import { setDefaultAccessControlThingIfNotExist } from "../internal/setDefaultAccessControlThingIfNotExist"; 30 | 31 | /** 32 | * ```{note} 33 | * The ACP specification is a draft. As such, this function is experimental and 34 | * subject to change, even in a non-major release. 35 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 36 | * ``` 37 | * 38 | * Add a policy applying to the ACRs of the given resource's children. 39 | * 40 | * @param resourceWithAcr The resource for which to add the URL of a policy 41 | * applying to its children's access control resources. 42 | * @param policyUrl A Policy URL. 43 | * @returns The resource with its ammended access control resource. 44 | * @since 1.16.1 45 | */ 46 | export function addMemberAcrPolicyUrl( 47 | resourceWithAcr: T, 48 | policyUrl: Url | UrlString, 49 | ): T { 50 | const resourceWithAcrContainingDefaultAccessControl = 51 | setDefaultAccessControlThingIfNotExist( 52 | resourceWithAcr, 53 | DEFAULT_MEMBER_ACR_ACCESS_CONTROL, 54 | ); 55 | 56 | const defaultAccessControlThing = getDefaultAccessControlThing( 57 | resourceWithAcrContainingDefaultAccessControl, 58 | DEFAULT_MEMBER_ACR_ACCESS_CONTROL, 59 | ); 60 | 61 | return setAccessControlResourceThing( 62 | resourceWithAcrContainingDefaultAccessControl, 63 | buildThing(defaultAccessControlThing).addUrl(ACP.access, policyUrl).build(), 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /src/acp/policy/addMemberPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { buildThing } from "../../thing/build"; 26 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 27 | import { DEFAULT_MEMBER_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 28 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 29 | import { setDefaultAccessControlThingIfNotExist } from "../internal/setDefaultAccessControlThingIfNotExist"; 30 | 31 | /** 32 | * ```{note} 33 | * The ACP specification is a draft. As such, this function is experimental and 34 | * subject to change, even in a non-major release. 35 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 36 | * ``` 37 | * 38 | * Add a policy applying to the given resource's children. 39 | * 40 | * @param resourceWithAcr The resource for which to add the URL of a policy 41 | * applying to its children. 42 | * @param policyUrl A Policy URL. 43 | * @returns The resource with its ammended access control resource. 44 | * @since 1.16.1 45 | */ 46 | export function addMemberPolicyUrl( 47 | resourceWithAcr: T, 48 | policyUrl: Url | UrlString, 49 | ): T { 50 | const resourceWithAcrContainingDefaultMemberAccessControl = 51 | setDefaultAccessControlThingIfNotExist( 52 | resourceWithAcr, 53 | DEFAULT_MEMBER_ACCESS_CONTROL, 54 | ); 55 | const defaultMemberAccessControlThing = getDefaultAccessControlThing( 56 | resourceWithAcrContainingDefaultMemberAccessControl, 57 | DEFAULT_MEMBER_ACCESS_CONTROL, 58 | ); 59 | 60 | return setAccessControlResourceThing( 61 | resourceWithAcrContainingDefaultMemberAccessControl, 62 | buildThing(defaultMemberAccessControlThing) 63 | .addUrl(ACP.apply, policyUrl) 64 | .build(), 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /src/acp/policy/addPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { buildThing } from "../../thing/build"; 26 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 27 | import { DEFAULT_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 28 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 29 | import { setDefaultAccessControlThingIfNotExist } from "../internal/setDefaultAccessControlThingIfNotExist"; 30 | 31 | /** 32 | * ```{note} 33 | * The ACP specification is a draft. As such, this function is experimental and 34 | * subject to change, even in a non-major release. 35 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 36 | * ``` 37 | * 38 | * Add a policy applying to the given resource. 39 | * 40 | * @param resourceWithAcr The resource for which to add the URL of a policy 41 | * applying to it. 42 | * @param policyUrl A Policy URL. 43 | * @returns The resource with its ammended access control resource. 44 | * @since 1.16.1 45 | */ 46 | export function addPolicyUrl( 47 | resourceWithAcr: T, 48 | policyUrl: Url | UrlString, 49 | ): T { 50 | const resourceWithAcrContainingDefaultAccessControl = 51 | setDefaultAccessControlThingIfNotExist( 52 | resourceWithAcr, 53 | DEFAULT_ACCESS_CONTROL, 54 | ); 55 | 56 | const defaultAccessControlThing = getDefaultAccessControlThing( 57 | resourceWithAcrContainingDefaultAccessControl, 58 | DEFAULT_ACCESS_CONTROL, 59 | ); 60 | 61 | return setAccessControlResourceThing( 62 | resourceWithAcrContainingDefaultAccessControl, 63 | buildThing(defaultAccessControlThing).addUrl(ACP.apply, policyUrl).build(), 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /src/acp/policy/getAcrPolicyUrlAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getAccessControlUrlAll } from "../accessControl/getAccessControlUrlAll"; 26 | import { getPolicyUrls } from "../internal/getPolicyUrls"; 27 | 28 | /** 29 | * ```{note} 30 | * The ACP specification is a draft. As such, this function is experimental and 31 | * subject to change, even in a non-major release. 32 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 33 | * ``` 34 | * 35 | * Get the URLs of policies applying to the ACR of the given resource. 36 | * 37 | * @param resourceWithAcr The resource for which to retrieve URLs of policies 38 | * applying to its access control resource. 39 | * @returns Policy URL array. 40 | * @since 1.16.1 41 | */ 42 | export function getAcrPolicyUrlAll( 43 | resourceWithAcr: T, 44 | ): UrlString[] { 45 | return getPolicyUrls( 46 | resourceWithAcr, 47 | getAccessControlUrlAll(resourceWithAcr), 48 | ACP.access, 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/acp/policy/getAllowModes.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, ThingPersisted } from "../../interfaces"; 23 | import { ACP } from "../constants"; 24 | import { getModes } from "../internal/getModes"; 25 | 26 | /** 27 | * ```{note} 28 | * The ACP specification is a draft. As such, this function is experimental and 29 | * subject to change, even in a non-major release. 30 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 31 | * ``` 32 | * 33 | * Policies allow or deny access modes over resources and their associated 34 | * access control resource. 35 | * 36 | * @param policy The Policy Thing which allows retrieved access modes. 37 | * @returns Policy URL array. 38 | * @since 1.16.1 39 | */ 40 | export function getAllowModes( 41 | policy: T, 42 | ): AccessModes { 43 | return getModes(policy, ACP.allow); 44 | } 45 | -------------------------------------------------------------------------------- /src/acp/policy/getDenyModes.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, ThingPersisted } from "../../interfaces"; 23 | import { ACP } from "../constants"; 24 | import { getModes } from "../internal/getModes"; 25 | 26 | /** 27 | * ```{note} 28 | * The ACP specification is a draft. As such, this function is experimental and 29 | * subject to change, even in a non-major release. 30 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 31 | * ``` 32 | * 33 | * Policies allow or deny access modes over resources and their associated 34 | * access control resource. 35 | * 36 | * @param policy The Policy Thing which denies retrieved access modes. 37 | * @returns Policy URL array. 38 | * @since 1.16.1 39 | */ 40 | export function getDenyModes(policy: T): AccessModes { 41 | return getModes(policy, ACP.deny); 42 | } 43 | -------------------------------------------------------------------------------- /src/acp/policy/getMemberAcrPolicyUrlAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getMemberAccessControlUrlAll } from "../accessControl/getMemberAccessControlUrlAll"; 26 | import { getPolicyUrls } from "../internal/getPolicyUrls"; 27 | 28 | /** 29 | * ```{note} 30 | * The ACP specification is a draft. As such, this function is experimental and 31 | * subject to change, even in a non-major release. 32 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 33 | * ``` 34 | * 35 | * Get the URLs of policies applying to the ACRs of the given resource's 36 | * children. 37 | * 38 | * @param resourceWithAcr The resource for which to retrieve URLs of policies 39 | * applying to its children's access control resources. 40 | * @returns Policy URL array. 41 | * @since 1.16.1 42 | */ 43 | export function getMemberAcrPolicyUrlAll( 44 | resourceWithAcr: T, 45 | ): UrlString[] { 46 | return getPolicyUrls( 47 | resourceWithAcr, 48 | getMemberAccessControlUrlAll(resourceWithAcr), 49 | ACP.access, 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /src/acp/policy/getMemberPolicyUrlAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getMemberAccessControlUrlAll } from "../accessControl/getMemberAccessControlUrlAll"; 26 | import { getPolicyUrls } from "../internal/getPolicyUrls"; 27 | 28 | /** 29 | * ```{note} 30 | * The ACP specification is a draft. As such, this function is experimental and 31 | * subject to change, even in a non-major release. 32 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 33 | * ``` 34 | * 35 | * Get the URLs of policies applying to the given resource's children. 36 | * 37 | * @param resourceWithAcr The resource for which to retrieve URLs policies 38 | * applying to its children. 39 | * @returns Policy URL array. 40 | * @since 1.16.1 41 | */ 42 | export function getMemberPolicyUrlAll( 43 | resourceWithAcr: T, 44 | ): UrlString[] { 45 | return getPolicyUrls( 46 | resourceWithAcr, 47 | getMemberAccessControlUrlAll(resourceWithAcr), 48 | ACP.apply, 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/acp/policy/getPolicyUrlAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getAccessControlUrlAll } from "../accessControl/getAccessControlUrlAll"; 26 | import { getPolicyUrls } from "../internal/getPolicyUrls"; 27 | 28 | /** 29 | * ```{note} 30 | * The ACP specification is a draft. As such, this function is experimental and 31 | * subject to change, even in a non-major release. 32 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 33 | * ``` 34 | * 35 | * Get the URLs of policies applying to the given resource. 36 | * 37 | * @param resourceWithAcr The resource for which to retrieve URLs of policies 38 | * applying to it. 39 | * @returns Policy URL array. 40 | * @since 1.16.1 41 | */ 42 | export function getPolicyUrlAll( 43 | resourceWithAcr: WithAccessibleAcr, 44 | ): UrlString[] { 45 | return getPolicyUrls( 46 | resourceWithAcr, 47 | getAccessControlUrlAll(resourceWithAcr), 48 | ACP.apply, 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/acp/policy/removeAcrPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 26 | import { DEFAULT_ACR_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 27 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 28 | import { removeIri } from "../../thing/remove"; 29 | 30 | /** 31 | * ```{note} 32 | * The ACP specification is a draft. As such, this function is experimental and 33 | * subject to change, even in a non-major release. 34 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 35 | * ``` 36 | * 37 | * Remove a policy applying to the ACR of the given resource. 38 | * 39 | * @param resourceWithAcr The resource for which to remove the URL of a policy 40 | * applying to its access control resource. 41 | * @param policyUrl A Policy URL. 42 | * @returns The resource with its ammended access control resource. 43 | * @since 1.16.1 44 | */ 45 | export function removeAcrPolicyUrl( 46 | resourceWithAcr: T, 47 | policyUrl: Url | UrlString, 48 | ): T { 49 | const defaultAccessControlThing = getDefaultAccessControlThing( 50 | resourceWithAcr, 51 | DEFAULT_ACR_ACCESS_CONTROL, 52 | ); 53 | 54 | return setAccessControlResourceThing( 55 | resourceWithAcr, 56 | removeIri(defaultAccessControlThing, ACP.access, policyUrl), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/acp/policy/removeMemberAcrPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 26 | import { DEFAULT_MEMBER_ACR_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 27 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 28 | import { removeIri } from "../../thing/remove"; 29 | 30 | /** 31 | * ```{note} 32 | * The ACP specification is a draft. As such, this function is experimental and 33 | * subject to change, even in a non-major release. 34 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 35 | * ``` 36 | * 37 | * Remove a policy applying to the ACRs of the given resource's children. 38 | * 39 | * @param resourceWithAcr The resource for which to remove the URL of a policy 40 | * applying to its children's access control resources. 41 | * @param policyUrl A Policy URL. 42 | * @returns The resource with its ammended access control resource. 43 | * @since 1.16.1 44 | */ 45 | export function removeMemberAcrPolicyUrl( 46 | resourceWithAcr: T, 47 | policyUrl: Url | UrlString, 48 | ): T { 49 | const defaultAccessControlThing = getDefaultAccessControlThing( 50 | resourceWithAcr, 51 | DEFAULT_MEMBER_ACR_ACCESS_CONTROL, 52 | ); 53 | 54 | return setAccessControlResourceThing( 55 | resourceWithAcr, 56 | removeIri(defaultAccessControlThing, ACP.access, policyUrl), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/acp/policy/removeMemberPolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 26 | import { DEFAULT_MEMBER_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 27 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 28 | import { removeIri } from "../../thing/remove"; 29 | 30 | /** 31 | * ```{note} 32 | * The ACP specification is a draft. As such, this function is experimental and 33 | * subject to change, even in a non-major release. 34 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 35 | * ``` 36 | * 37 | * Remove a policy applying to the given resource's children. 38 | * 39 | * @param resourceWithAcr The resource for which to remove the URL of a policy 40 | * applying to its children. 41 | * @param policyUrl A Policy URL. 42 | * @returns The resource with its ammended access control resource. 43 | * @since 1.16.1 44 | */ 45 | export function removeMemberPolicyUrl( 46 | resourceWithAcr: T, 47 | policyUrl: Url | UrlString, 48 | ): T { 49 | const defaultAccessControlThing = getDefaultAccessControlThing( 50 | resourceWithAcr, 51 | DEFAULT_MEMBER_ACCESS_CONTROL, 52 | ); 53 | 54 | return setAccessControlResourceThing( 55 | resourceWithAcr, 56 | removeIri(defaultAccessControlThing, ACP.apply, policyUrl), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/acp/policy/removePolicyUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getDefaultAccessControlThing } from "../internal/getDefaultAccessControlThing"; 26 | import { DEFAULT_ACCESS_CONTROL } from "../internal/getDefaultAccessControlUrl"; 27 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 28 | import { removeIri } from "../../thing/remove"; 29 | 30 | /** 31 | * ```{note} 32 | * The ACP specification is a draft. As such, this function is experimental and 33 | * subject to change, even in a non-major release. 34 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 35 | * ``` 36 | * 37 | * Remove a policy applying to the given resource. 38 | * 39 | * @param resourceWithAcr The resource for which to remove the URL of a policy 40 | * applying to it. 41 | * @param policyUrl A Policy URL. 42 | * @returns The resource with its ammended access control resource. 43 | * @since 1.16.1 44 | */ 45 | export function removePolicyUrl( 46 | resourceWithAcr: T, 47 | policyUrl: Url | UrlString, 48 | ): T { 49 | const defaultAccessControlThing = getDefaultAccessControlThing( 50 | resourceWithAcr, 51 | DEFAULT_ACCESS_CONTROL, 52 | ); 53 | 54 | return setAccessControlResourceThing( 55 | resourceWithAcr, 56 | removeIri(defaultAccessControlThing, ACP.apply, policyUrl), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/acp/policy/setAllowModes.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, ThingPersisted } from "../../interfaces"; 23 | import { ACP } from "../constants"; 24 | import { setModes } from "../internal/setModes"; 25 | 26 | /** 27 | * ```{note} 28 | * The ACP specification is a draft. As such, this function is experimental and 29 | * subject to change, even in a non-major release. 30 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 31 | * ``` 32 | * 33 | * Policies allow or deny access modes over resources and their associated 34 | * access control resource. 35 | * 36 | * @param policy The Policy on which to set the modes to allow. 37 | * @param modes Modes to allow for this Policy. 38 | * @since 1.16.1 39 | */ 40 | export function setAllowModes( 41 | policy: T, 42 | modes: AccessModes, 43 | ): T { 44 | return setModes(policy, modes, ACP.allow); 45 | } 46 | -------------------------------------------------------------------------------- /src/acp/policy/setDenyModes.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, ThingPersisted } from "../../interfaces"; 23 | import { ACP } from "../constants"; 24 | import { setModes } from "../internal/setModes"; 25 | 26 | /** 27 | * ```{note} 28 | * The ACP specification is a draft. As such, this function is experimental and 29 | * subject to change, even in a non-major release. 30 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 31 | * ``` 32 | * 33 | * Policies allow or deny access modes over resources and their associated 34 | * access control resource. 35 | * 36 | * @param policy The Policy on which to set the modes to allow. 37 | * @param modes Modes to allow for this Policy. 38 | * @since 1.16.1 39 | */ 40 | export function setDenyModes( 41 | policy: T, 42 | modes: AccessModes, 43 | ): T { 44 | return setModes(policy, modes, ACP.deny); 45 | } 46 | -------------------------------------------------------------------------------- /src/acp/policy/setResourcePolicy.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { ThingPersisted } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { setAccessControlResourceThing } from "../internal/setAccessControlResourceThing"; 25 | 26 | /** 27 | * ```{note} 28 | * The ACP specification is a draft. As such, this function is experimental and 29 | * subject to change, even in a non-major release. 30 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 31 | * ``` 32 | * 33 | * Insert the given [[ResourcePolicy]] into the given Resource's Acccess Control 34 | * Resource, replacing previous instances of that Policy. 35 | * 36 | * @param resourceWithAcr The Resource whose Access Control Resource contains Access Policies. 37 | * @param policy The Policy to insert into the Resource's Access Control Resource. 38 | * @returns A new Resource equal to the given Resource, but with the given Policy in its Access Control Resource. 39 | * @since 1.18.0 40 | */ 41 | export function setResourcePolicy( 42 | resourceWithAcr: T, 43 | policy: ThingPersisted, 44 | ): T { 45 | return setAccessControlResourceThing(resourceWithAcr, policy); 46 | } 47 | -------------------------------------------------------------------------------- /src/acp/type/AccessControlResource.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { 23 | SolidDataset, 24 | UrlString, 25 | WithResourceInfo, 26 | } from "../../interfaces"; 27 | 28 | /** 29 | * ```{note} 30 | * The ACP specification is a draft. As such, this function is experimental and 31 | * subject to change, even in a non-major release. 32 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 33 | * ``` 34 | */ 35 | export interface AccessControlResource extends SolidDataset, WithResourceInfo { 36 | accessTo: UrlString; 37 | } 38 | -------------------------------------------------------------------------------- /src/acp/type/DefaultOptions.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | /** 23 | * ```{note} 24 | * The ACP specification is a draft. As such, this function is experimental and 25 | * subject to change, even in a non-major release. 26 | * See also: https://solid.github.io/authorization-panel/acp-specification/ 27 | * ``` 28 | */ 29 | export interface DefaultOptions { 30 | fetch?: typeof fetch; 31 | } 32 | -------------------------------------------------------------------------------- /src/acp/util/getAcrUrl.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { jest, describe, it, expect } from "@jest/globals"; 23 | import { getAcrUrl } from "./getAcrUrl"; 24 | import { getLinkedResourceUrlAll } from "../../resource/resource"; 25 | import { getAclServerResourceInfo } from "../../universal/getAclServerResourceInfo"; 26 | 27 | jest.mock("../../universal/getAclServerResourceInfo"); 28 | 29 | jest.mock("../../resource/resource", () => ({ 30 | getLinkedResourceUrlAll: jest.fn().mockImplementation(() => ({ 31 | type: ["http://www.w3.org/ns/solid/acp#AccessControlResource"], 32 | })), 33 | getSourceUrl: jest.fn().mockImplementation(() => "x"), 34 | })); 35 | 36 | describe("getAcrUrl", () => { 37 | it("returns null if the ACL resource info can't be fetched", async () => { 38 | ( 39 | getAclServerResourceInfo as jest.Mocked 40 | ).mockResolvedValueOnce(null); 41 | const x = await getAcrUrl({} as any); 42 | expect(x).toBeNull(); 43 | }); 44 | 45 | it("returns the ACR URL if info is fetched and the correct link type is present", async () => { 46 | const x = await getAcrUrl({} as any); 47 | expect(x).toBe("x"); 48 | }); 49 | 50 | it("returns null if the correct link type is not present", async () => { 51 | ( 52 | getLinkedResourceUrlAll as jest.Mocked 53 | ).mockReturnValueOnce({ type: ["y"] }); 54 | const x = await getAcrUrl({} as any); 55 | expect(x).toBeNull(); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/acp/util/getAcrUrl.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { UrlString, WithServerResourceInfo } from "../../interfaces"; 23 | import type { DefaultOptions } from "../type/DefaultOptions"; 24 | import { ACP } from "../constants"; 25 | import { getLinkedResourceUrlAll, getSourceUrl } from "../../resource/resource"; 26 | import { getAclServerResourceInfo } from "../../universal/getAclServerResourceInfo"; 27 | 28 | /** 29 | * Retrieve the URL of an Access Control Resource as per the ACP Draft 30 | * specification. 31 | * 32 | * @param resource The Resource for which to retrieve the URL of the Access 33 | * Control Resource if it is accessible. 34 | * @returns The URL of the ACR or null. 35 | */ 36 | export async function getAcrUrl( 37 | resource: WithServerResourceInfo, 38 | options?: DefaultOptions, 39 | ): Promise { 40 | // The ACP Draft mandates a link rel="type" header identifies Access Control Resources 41 | const aclServerResourceInfo = await getAclServerResourceInfo( 42 | resource, 43 | options, 44 | ); 45 | 46 | if (aclServerResourceInfo === null) { 47 | return null; 48 | } 49 | 50 | const relTypeLinks = getLinkedResourceUrlAll(aclServerResourceInfo).type; 51 | if ( 52 | Array.isArray(relTypeLinks) && 53 | relTypeLinks.includes(ACP.AccessControlResource) 54 | ) { 55 | return getSourceUrl(aclServerResourceInfo); 56 | } 57 | 58 | return null; 59 | } 60 | -------------------------------------------------------------------------------- /src/acp/util/getAgentAccessAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes } from "../../interfaces"; 23 | import { getAgentAccess } from "./getAgentAccess"; 24 | import { getAgentUrlAll } from "./getAgentUrlAll"; 25 | import type { WithAccessibleAcr } from "../acp"; 26 | 27 | /** 28 | * Get an overview of what access is defined for agents. 29 | * 30 | * This function works with Solid Pods that implement either the Web Access 31 | * Control spec or the Access Control Policies proposal, with some caveats: 32 | * 33 | * - If access to the given Resource has been set using anything other than the 34 | * functions in this module, it is possible that it has been set in a way that 35 | * prevents this function from reliably reading access. 36 | * - It will only return access specified explicitly for the given Agent within 37 | * the ACL linked to the resource. If additional restrictions or external 38 | * resources are used, those will not be reflected in the return value of this 39 | * function. 40 | * - It will only return access specified explicitly for the given Resource. 41 | * In other words, if the Resource is a Container, the returned Access may not 42 | * apply to contained Resources. 43 | * - If the current user does not have permission to view access for the given 44 | * Resource, this function will resolve to `null`. 45 | * 46 | * @param resourceUrl URL of the Resource you want to read the access for. 47 | * @param options Default Options such as a fetch function. 48 | * @since 1.21.0 49 | */ 50 | export async function getAgentAccessAll( 51 | resourceWithAcr: T, 52 | ): Promise | null> { 53 | return ( 54 | await Promise.all( 55 | getAgentUrlAll(resourceWithAcr).map(async (agent) => ({ 56 | [agent]: await getAgentAccess(resourceWithAcr, agent), 57 | })), 58 | ) 59 | ).reduce( 60 | (agentAccessAll, currentAgentAccess) => ({ 61 | ...agentAccessAll, 62 | ...currentAgentAccess, 63 | }), 64 | {}, 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /src/acp/util/getAgentUrlAll.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, expect, it } from "@jest/globals"; 23 | import { ACP } from "../constants"; 24 | import { createDatasetFromSubjects } from "../mock/dataset"; 25 | import { mockAccessControlledResource } from "../mock/mockAccessControlledResource"; 26 | import { getAgentUrlAll } from "./getAgentUrlAll"; 27 | 28 | describe("getAgentUrlAll", () => { 29 | it("returns an empty array if the ACR is empty", () => { 30 | expect(getAgentUrlAll(mockAccessControlledResource())).toStrictEqual([]); 31 | }); 32 | 33 | it("returns agents defined in a matcher", () => { 34 | expect( 35 | getAgentUrlAll( 36 | mockAccessControlledResource( 37 | createDatasetFromSubjects([ 38 | [ 39 | "https://example.org/subject_resource", 40 | [ 41 | [ 42 | ACP.agent, 43 | [ 44 | "https://example.org/x", 45 | "https://example.org/y", 46 | "https://example.org/z", 47 | ], 48 | ], 49 | ], 50 | ], 51 | ]), 52 | ), 53 | ), 54 | ).toStrictEqual([ 55 | "https://example.org/x", 56 | "https://example.org/y", 57 | "https://example.org/z", 58 | ]); 59 | }); 60 | 61 | it("returns agents defined in a matcher only once", () => { 62 | expect( 63 | getAgentUrlAll( 64 | mockAccessControlledResource( 65 | createDatasetFromSubjects([ 66 | [ 67 | "https://example.org/subject_resource_1", 68 | [ 69 | [ 70 | ACP.agent, 71 | [ 72 | "https://example.org/x", 73 | "https://example.org/y", 74 | "https://example.org/z", 75 | ], 76 | ], 77 | ], 78 | ], 79 | [ 80 | "https://example.org/subject_resource_2", 81 | [[ACP.agent, ["https://example.org/x"]]], 82 | ], 83 | ]), 84 | ), 85 | ), 86 | ).toStrictEqual([ 87 | "https://example.org/x", 88 | "https://example.org/y", 89 | "https://example.org/z", 90 | ]); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /src/acp/util/getAgentUrlAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { WithAccessibleAcr } from "../acp"; 23 | import { internal_getAcr } from "../control.internal"; 24 | import { ACP } from "../constants"; 25 | import { getThingAll, getUrlAll } from "../.."; 26 | 27 | /** @hidden */ 28 | export function getAgentUrlAll(acr: WithAccessibleAcr): string[] { 29 | return Array.from( 30 | new Set( 31 | getThingAll(internal_getAcr(acr)) 32 | .map((thing) => { 33 | return getUrlAll(thing, ACP.agent); 34 | }) 35 | .reduce((flatArray, agentArray) => { 36 | return flatArray.concat(agentArray); 37 | }, []), 38 | ), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/acp/util/getPublicAccess.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, it, expect } from "@jest/globals"; 23 | import { ACL, ACP } from "../constants"; 24 | import { 25 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 26 | DEFAULT_DOMAIN, 27 | } from "../mock/constants"; 28 | import { createDatasetFromSubjects } from "../mock/dataset"; 29 | import { mockAccessControlledResource } from "../mock/mockAccessControlledResource"; 30 | import { getPublicAccess } from "./getPublicAccess"; 31 | 32 | describe("getPublicAccess()", () => { 33 | it("returns the default access modes for an empty ACR", async () => { 34 | const resource = mockAccessControlledResource(); 35 | 36 | expect(resource.internal_acp.acr.graphs).toStrictEqual({ default: {} }); 37 | expect(await getPublicAccess(resource)).toStrictEqual({ 38 | read: false, 39 | append: false, 40 | write: false, 41 | controlRead: false, 42 | controlWrite: false, 43 | }); 44 | }); 45 | 46 | it("returns public access modes for a simple ACR", async () => { 47 | const resource = mockAccessControlledResource( 48 | createDatasetFromSubjects([ 49 | [ 50 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 51 | [[ACP.accessControl, [DEFAULT_DOMAIN.concat("ac1")]]], 52 | ], 53 | [ 54 | DEFAULT_DOMAIN.concat("ac1"), 55 | [[ACP.apply, [DEFAULT_DOMAIN.concat("p1")]]], 56 | ], 57 | [ 58 | DEFAULT_DOMAIN.concat("p1"), 59 | [ 60 | [ACP.anyOf, [DEFAULT_DOMAIN.concat("m1")]], 61 | [ACP.allow, [ACL.Read]], 62 | ], 63 | ], 64 | [DEFAULT_DOMAIN.concat("m1"), [[ACP.agent, [ACP.PublicAgent]]]], 65 | ]), 66 | ); 67 | 68 | expect(await getPublicAccess(resource)).toStrictEqual({ 69 | read: true, 70 | append: false, 71 | write: false, 72 | controlRead: false, 73 | controlWrite: false, 74 | }); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /src/acp/util/getPublicAccess.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { getAgentAccess } from "./getAgentAccess"; 26 | 27 | /** 28 | * Get an overview of what access is given to the public. 29 | * 30 | * @param resourceWithAcr URL of the Resource you want to read the access for. 31 | * @since 1.16.0 32 | */ 33 | export async function getPublicAccess( 34 | resourceWithAcr: T, 35 | ): Promise { 36 | return getAgentAccess(resourceWithAcr, ACP.PublicAgent); 37 | } 38 | -------------------------------------------------------------------------------- /src/acp/util/getResourceAcr.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { jest, describe, it, expect } from "@jest/globals"; 23 | import { getResourceAcr } from "./getResourceAcr"; 24 | import { getAcrUrl } from "./getAcrUrl"; 25 | import { getSolidDataset } from "../../resource/solidDataset"; 26 | 27 | jest.mock("./getAcrUrl"); 28 | jest.mock("../../resource/solidDataset"); 29 | jest.mock("../../resource/resource"); 30 | 31 | describe("getResourceAcr", () => { 32 | it("returns null if the ACR URL can't be retrieved", async () => { 33 | (getAcrUrl as jest.Mocked).mockResolvedValueOnce(null); 34 | const x = await getResourceAcr({} as any); 35 | expect(getAcrUrl).toHaveBeenCalledTimes(1); 36 | expect(getAcrUrl).toHaveBeenCalledWith({}, undefined); 37 | expect(x).toBeNull(); 38 | }); 39 | 40 | it("returns null if the ACR can't be retrieved", async () => { 41 | ( 42 | getSolidDataset as jest.Mocked 43 | ).mockRejectedValueOnce("reject"); 44 | const x = await getResourceAcr({} as any); 45 | expect(getAcrUrl).toHaveBeenCalledTimes(1); 46 | expect(getAcrUrl).toHaveBeenCalledWith({}, undefined); 47 | expect(getSolidDataset).toHaveBeenCalledTimes(1); 48 | expect(x).toBeNull(); 49 | }); 50 | 51 | it("returns the resource with ACR", async () => { 52 | await getResourceAcr({} as any); 53 | expect(getAcrUrl).toHaveBeenCalledTimes(1); 54 | expect(getAcrUrl).toHaveBeenCalledWith({}, undefined); 55 | expect(getSolidDataset).toHaveBeenCalledTimes(1); 56 | // FIXME this tests too much internals 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /src/acp/util/getResourceAcr.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { SolidDataset, WithServerResourceInfo } from "../../interfaces"; 23 | import type { DefaultOptions } from "../type/DefaultOptions"; 24 | import type { WithAccessibleAcr } from "../acp"; 25 | import { getAcrUrl } from "./getAcrUrl"; 26 | import { getSolidDataset } from "../../resource/solidDataset"; 27 | import { getSourceUrl } from "../../resource/resource"; 28 | 29 | /** 30 | * Retrieve the Access Control Resource of a Resource as per the ACP Draft 31 | * specification. 32 | * 33 | * @param resource The Resource for which to retrieve the URL of the Access 34 | * Control Resource if it is accessible. 35 | * @param options Default Options such as a fetch function. 36 | * @returns The URL of the ACR or null. 37 | */ 38 | export async function getResourceAcr( 39 | resource: T, 40 | options?: DefaultOptions, 41 | ): Promise<(T & WithAccessibleAcr) | null> { 42 | const acrUrl = await getAcrUrl(resource, options); 43 | if (acrUrl === null) { 44 | return null; 45 | } 46 | 47 | let acr: SolidDataset & WithServerResourceInfo; 48 | try { 49 | acr = await getSolidDataset(acrUrl, options); 50 | } catch { 51 | return null; 52 | } 53 | 54 | return { 55 | ...resource, 56 | internal_acp: { 57 | acr: { 58 | ...acr, 59 | accessTo: getSourceUrl(resource), 60 | }, 61 | }, 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /src/acp/util/setPublicAccess.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, it, expect } from "@jest/globals"; 23 | import { ACL, ACP } from "../constants"; 24 | import { 25 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 26 | TEST_URL, 27 | } from "../mock/constants"; 28 | import { createDatasetFromSubjects } from "../mock/dataset"; 29 | import { mockAccessControlledResource } from "../mock/mockAccessControlledResource"; 30 | import { setPublicAccess } from "./setPublicAccess"; 31 | 32 | describe("setPublicAccess()", () => { 33 | it("sets an access mode for the Public", async () => { 34 | const resource = mockAccessControlledResource(); 35 | 36 | expect(resource.internal_acp.acr.graphs).toStrictEqual({ default: {} }); 37 | 38 | expect( 39 | (await setPublicAccess(resource, { read: true })).internal_acp.acr.graphs 40 | .default, 41 | ).toStrictEqual( 42 | createDatasetFromSubjects([ 43 | [ 44 | DEFAULT_ACCESS_CONTROL_RESOURCE_URL, 45 | [[ACP.accessControl, [TEST_URL.defaultAccessControl]]], 46 | ], 47 | [ 48 | TEST_URL.defaultAccessControl, 49 | [[ACP.apply, [TEST_URL.defaultAccessControlAgentMatcherReadPolicy]]], 50 | ], 51 | [ 52 | TEST_URL.defaultAccessControlAgentMatcherReadPolicy, 53 | [ 54 | [ 55 | ACP.anyOf, 56 | [TEST_URL.defaultAccessControlAgentMatcherReadPolicyMatcher], 57 | ], 58 | [ACP.allow, [ACL.Read]], 59 | ], 60 | ], 61 | [ 62 | TEST_URL.defaultAccessControlAgentMatcherReadPolicyMatcher, 63 | [[ACP.agent, [ACP.PublicAgent]]], 64 | ], 65 | ]).graphs.default, 66 | ); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /src/acp/util/setPublicAccess.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes } from "../../interfaces"; 23 | import type { WithAccessibleAcr } from "../acp"; 24 | import { ACP } from "../constants"; 25 | import { setAgentAccess } from "./setAgentAccess"; 26 | 27 | /** 28 | * Set access for the public. 29 | * 30 | * @param resourceWithAcr URL of the Resource you want to read the access for. 31 | * @param access Access Modes you want to set for the agent. 32 | * @since 1.16.0 33 | */ 34 | export async function setPublicAccess( 35 | resourceWithAcr: T, 36 | access: Partial, 37 | ): Promise { 38 | return setAgentAccess(resourceWithAcr, ACP.PublicAgent, access); 39 | } 40 | -------------------------------------------------------------------------------- /src/formats/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | export { getJsonLdParser } from "./jsonLd"; 23 | export { getTurtleParser } from "./turtle"; 24 | export { solidDatasetAsTurtle } from "./solidDatasetAsTurtle"; 25 | -------------------------------------------------------------------------------- /src/formats/jsonLd.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | import { JsonLdParser } from "jsonld-streaming-parser"; 22 | import { FetchDocumentLoader } from "jsonld-context-parser"; 23 | import { getSourceUrl } from "../resource/resource"; 24 | import type { Parser } from "../resource/solidDataset"; 25 | 26 | /** 27 | * ```{note} This function is still experimental and subject to change, even 28 | * in a non-major release. 29 | * ``` 30 | * This returns a parser that transforms a JSON-LD string into a set of RDFJS quads. 31 | * 32 | * @returns A Parser object. 33 | * @since 1.15.0 34 | */ 35 | export const getJsonLdParser = (): Parser => { 36 | const onQuadCallbacks: Array[0]> = []; 37 | const onCompleteCallbacks: Array[0]> = []; 38 | const onErrorCallbacks: Array[0]> = []; 39 | 40 | return { 41 | onQuad: (callback) => { 42 | onQuadCallbacks.push(callback); 43 | }, 44 | onError: (callback) => { 45 | onErrorCallbacks.push(callback); 46 | }, 47 | onComplete: (callback) => { 48 | onCompleteCallbacks.push(callback); 49 | }, 50 | // The following returns a Promise that can be awaited, which is undocumented 51 | // behavior that doesn't match the type signature. It prevents a potentially 52 | // breaking change, and will be updated on the next major release. 53 | parse: (source, resourceInfo) => 54 | new Promise((res) => { 55 | const parser = new JsonLdParser({ 56 | baseIRI: getSourceUrl(resourceInfo), 57 | documentLoader: new FetchDocumentLoader((...args) => fetch(...args)), 58 | }); 59 | 60 | let endCalled = false; 61 | function end() { 62 | if (!endCalled) { 63 | endCalled = true; 64 | onCompleteCallbacks.forEach((callback) => callback()); 65 | res(); 66 | } 67 | } 68 | 69 | parser.on("end", end); 70 | parser.on("error", (err) => { 71 | onErrorCallbacks.forEach((callback) => callback(err)); 72 | end(); 73 | }); 74 | onQuadCallbacks.forEach((callback) => parser.on("data", callback)); 75 | 76 | parser.write(source); 77 | parser.end(); 78 | }), 79 | }; 80 | }; 81 | -------------------------------------------------------------------------------- /src/formats/prefixes.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | export const prefixes = { 23 | acl: "http://www.w3.org/ns/auth/acl#", 24 | acp: "http://www.w3.org/ns/solid/acp#", 25 | cc: "http://creativecommons.org/ns#", 26 | cert: "http://www.w3.org/ns/auth/cert#", 27 | csvw: "http://www.w3.org/ns/csvw#", 28 | current: "#", 29 | dc: "http://purl.org/dc/terms/", 30 | dcam: "http://purl.org/dc/dcam/", 31 | dcat: "http://www.w3.org/ns/dcat#", 32 | dctype: "http://purl.org/dc/dcmitype/", 33 | foaf: "http://xmlns.com/foaf/0.1/", 34 | ldp: "http://www.w3.org/ns/ldp#", 35 | owl: "http://www.w3.org/2002/07/owl#", 36 | posixstat: "http://www.w3.org/ns/posix/stat#", 37 | rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", 38 | rdfs: "http://www.w3.org/2000/01/rdf-schema#", 39 | schema: "https://schema.org/", 40 | shacl: "http://www.w3.org/ns/shacl#", 41 | skos: "http://www.w3.org/2004/02/skos/core#", 42 | skosxl: "http://www.w3.org/2008/05/skos-xl#", 43 | solid: "http://www.w3.org/ns/solid/terms#", 44 | swapdoc: "http://www.w3.org/2000/10/swap/pim/doc#", 45 | ui: "http://www.w3.org/ns/ui#", 46 | vann: "http://purl.org/vocab/vann/", 47 | vcard: "http://www.w3.org/2006/vcard/ns#", 48 | ws: "http://www.w3.org/ns/pim/space#", 49 | xsd: "http://www.w3.org/2001/XMLSchema#", 50 | }; 51 | -------------------------------------------------------------------------------- /src/formats/solidDatasetAsTurtle.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { NamedNode, Writer } from "n3"; 23 | import type { SolidDataset } from "../interfaces"; 24 | import { prefixes as defaultPrefixes } from "./prefixes"; 25 | import { toRdfJsDataset } from "../rdfjs"; 26 | 27 | /** 28 | * A function to serialise a Solid Dataset as Turtle 29 | * 30 | * @param dataset The Dataset to serialize as Turtle 31 | * @param options.prefixes The Prefixes to use for Turtle serialisation (defaulting to a set of well known prefixes) 32 | * @param options.thing Restricts serialisation to the part of a dataset related to the thing 33 | * @returns RDF serialised as Turtle 34 | * @since 1.20.0 35 | */ 36 | export async function solidDatasetAsTurtle( 37 | dataset: SolidDataset, 38 | options?: { 39 | prefixes?: Record; 40 | thing?: string; 41 | }, 42 | ): Promise { 43 | const { prefixes = defaultPrefixes, thing } = { ...options }; 44 | const writer = new Writer({ format: "application/turtle", prefixes }); 45 | const subject = thing ? new NamedNode(thing) : undefined; 46 | 47 | // If the subject is undefined, all the triples match. 48 | for (const quad of toRdfJsDataset(dataset).match(subject)) { 49 | writer.addQuad(quad); 50 | } 51 | 52 | return new Promise((resolve, reject) => { 53 | writer.end((error, result) => { 54 | /* istanbul ignore next */ 55 | if (error) { 56 | reject(error); 57 | } else { 58 | resolve(result); 59 | } 60 | }); 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /src/interfaces.internal.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Iri, IriString } from "./interfaces"; 23 | 24 | /** @internal */ 25 | export function internal_toIriString(iri: Iri | IriString): IriString { 26 | return typeof iri === "string" ? iri : iri.value; 27 | } 28 | 29 | /** 30 | * @hidden 31 | * @param inputUrl The URL to normalize 32 | * @param options If trailingSlash is set, a trailing slash will be respectively added/removed. 33 | * The input URL trailing slash is left unchanged if trailingSlash is undefined. 34 | * @returns the normalized URL, without relative components, slash sequences, and proper trailing slash. 35 | */ 36 | export function normalizeUrl( 37 | inputUrl: IriString, 38 | options: { trailingSlash?: boolean } = {}, 39 | ): IriString { 40 | // Normalize relative components. 41 | const normalizedUrl = new URL(inputUrl); 42 | 43 | // Collapse slash sequences. 44 | normalizedUrl.pathname = normalizedUrl.pathname.replace(/\/\/+/g, "/"); 45 | 46 | // Enforce a trailing slash is present/absent. 47 | if ( 48 | options.trailingSlash === false && 49 | normalizedUrl.pathname.slice(-1) === "/" 50 | ) { 51 | normalizedUrl.pathname = normalizedUrl.pathname.slice( 52 | 0, 53 | normalizedUrl.pathname.length - 1, 54 | ); 55 | } 56 | if ( 57 | options.trailingSlash === true && 58 | normalizedUrl.pathname.slice(-1) !== "/" 59 | ) { 60 | normalizedUrl.pathname = `${normalizedUrl.pathname}/`; 61 | } 62 | 63 | return normalizedUrl.href; 64 | } 65 | -------------------------------------------------------------------------------- /src/resource/iri.internal.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { IriString } from "../interfaces"; 23 | 24 | /** 25 | * This function normalizes IRIs as managed by the server to ease accurate comparison. 26 | * @param iri 27 | * @hidden 28 | */ 29 | export function normalizeServerSideIri(iri: IriString): IriString { 30 | const iriObj = new URL(iri); 31 | iriObj.hash = ""; 32 | return iriObj.href; 33 | } 34 | -------------------------------------------------------------------------------- /src/tests.internal.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | import { jest } from "@jest/globals"; 22 | 23 | /** 24 | * This function is intended to be extracted into a shared package, as it is used 25 | * across multiple repositories. It receiving a callback allows the shared package 26 | * to have no dependency on jest, the need for peer dependencies and version alignment. 27 | */ 28 | const buildResponseMocker = 29 | (urlMock: (sourceUrl: string, response: Response) => void) => 30 | (body?: BodyInit | null, init?: ResponseInit, sourceUrl?: string) => { 31 | const response = new Response(body, init); 32 | if (sourceUrl !== undefined) { 33 | urlMock(sourceUrl, response); 34 | } 35 | return response; 36 | }; 37 | 38 | /** 39 | * The `url` property of a Response is read-only, and using the default constructor 40 | * doesn't allow to set it. Our library requires `response.url` to be set in order 41 | * to track the resource's URL, so we use jest to mock this call. 42 | */ 43 | export const mockResponse = buildResponseMocker( 44 | (sourceUrl: string, response: Response) => { 45 | jest.spyOn(response, "url", "get").mockReturnValue(sourceUrl); 46 | }, 47 | ); 48 | -------------------------------------------------------------------------------- /src/thing/mock.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, it, expect } from "@jest/globals"; 23 | 24 | import { mockThingFrom } from "./mock"; 25 | import { asIri, isThing } from "./thing"; 26 | 27 | describe("mockThingFrom", () => { 28 | it("is identified by the given IRI", async () => { 29 | const mockedThing = mockThingFrom("https://some.pod/resource#thing"); 30 | 31 | expect(asIri(mockedThing)).toBe("https://some.pod/resource#thing"); 32 | }); 33 | 34 | it("is recognised as a Thing", async () => { 35 | const mockedThing = mockThingFrom("https://arbitrary.pod/resource#thing"); 36 | 37 | expect(isThing(mockedThing)).toBe(true); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/thing/mock.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { Url, UrlString, ThingPersisted } from "../interfaces"; 23 | import { internal_toIriString } from "../interfaces.internal"; 24 | 25 | /** 26 | * Function for use in unit tests to mock a [[Thing]] with a given URL. 27 | * 28 | * Warning: do not use this function in actual production code. 29 | * This function initialises a new empty Thing and sets its URL to a given URL. 30 | * This is useful to mock a Thing in tests of code that call e.g. 31 | * [[asUrl]]. 32 | * 33 | * @param url The URL that the mocked Thing pretends identifies it. 34 | * @returns A new Thing, pretending to be identified by the given URL. 35 | * @since 0.2.0 36 | */ 37 | export function mockThingFrom(url: Url | UrlString): ThingPersisted { 38 | const iri = internal_toIriString(url); 39 | const thing: ThingPersisted = { 40 | type: "Subject", 41 | predicates: {}, 42 | url: iri, 43 | }; 44 | 45 | return thing; 46 | } 47 | -------------------------------------------------------------------------------- /src/universal/getAclServerResourceInfo.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { WithServerResourceInfo } from "../interfaces"; 23 | import type { DefaultOptions } from "../acp/type/DefaultOptions"; 24 | import { getResourceInfo } from "../resource/resource"; 25 | 26 | /** 27 | * Retrieve the Server Resource Info of Resource expressing access control over 28 | * another resource it is linked to. It applies in both ACP and WAC contexts: 29 | * the Access Control Resource is discovered consistently using a Link header 30 | * with `rel=acl`. 31 | * 32 | * @param {WithServerResourceInfo} resource The Resource for which ACL we want 33 | * to retrieve the Server Resource Info. 34 | * @param {DefaultOptions} options 35 | * @returns The Server Resource Info if available, null otherwise. 36 | * @since 1.19.0 37 | */ 38 | export async function getAclServerResourceInfo( 39 | resource: WithServerResourceInfo, 40 | options?: DefaultOptions, 41 | ): Promise { 42 | if (typeof resource.internal_resourceInfo.aclUrl !== "string") { 43 | return null; 44 | } 45 | try { 46 | return await getResourceInfo( 47 | resource.internal_resourceInfo.aclUrl, 48 | options, 49 | ); 50 | } catch { 51 | // A WAC-governed resource may have a link to a non-existant ACL (by design). 52 | // The absence of an ACL at the target URL is a useful information that is 53 | // used by the universal API to pick between ACR and WAC. 54 | return null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/universal/getAgentAccess.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, UrlString, WebId } from "../interfaces"; 23 | import type { DefaultOptions } from "../acp/type/DefaultOptions"; 24 | import { getResourceInfo } from "../resource/resource"; 25 | import { getAgentAccess as getAgentAccessAcp } from "../acp/util/getAgentAccess"; 26 | import { getAgentAccess as getAgentAccessWac } from "../access/wac"; 27 | import { getResourceAcr } from "../acp/util/getResourceAcr"; 28 | 29 | /** 30 | * Get an overview of what access is defined for a given Agent. 31 | * 32 | * This function works with Solid Pods that implement either the Web Access 33 | * Control spec or the Access Control Policies proposal, with some caveats: 34 | * 35 | * - If access to the given Resource has been set using anything other than the 36 | * functions in this module, it is possible that it has been set in a way that 37 | * prevents this function from reliably reading access. 38 | * - It will only return access specified explicitly for the given Agent within 39 | * the ACL linked to the resource. If additional restrictions or external 40 | * resources are used, those will not be reflected in the return value of this 41 | * function. 42 | * - It will only return access specified explicitly for the given Resource. 43 | * In other words, if the Resource is a Container, the returned Access may not 44 | * apply to contained Resources. 45 | * - If the current user does not have permission to view access for the given 46 | * Resource, this function will resolve to `null`. 47 | * 48 | * @param resourceUrl URL of the Resource you want to read the access for. 49 | * @param webId WebID of the Agent you want to get the access for. 50 | * @param options Default Options such as a fetch function. 51 | * @since 1.19.0 52 | */ 53 | export async function getAgentAccess( 54 | resourceUrl: UrlString, 55 | webId: WebId, 56 | options?: DefaultOptions, 57 | ): Promise { 58 | const resourceInfo = await getResourceInfo(resourceUrl, options); 59 | const acr = await getResourceAcr(resourceInfo, options); 60 | 61 | if (acr === null) { 62 | return getAgentAccessWac(resourceInfo, webId, options); 63 | } 64 | 65 | return getAgentAccessAcp(acr, webId); 66 | } 67 | -------------------------------------------------------------------------------- /src/universal/getAgentAccessAll.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, UrlString } from "../interfaces"; 23 | import type { DefaultOptions } from "../acp/type/DefaultOptions"; 24 | import { getResourceInfo } from "../resource/resource"; 25 | import { getAgentAccessAll as getAgentAccessAllAcp } from "../acp/util/getAgentAccessAll"; 26 | import { getAgentAccessAll as getAgentAccessAllWac } from "../access/wac"; 27 | import { getResourceAcr } from "../acp/util/getResourceAcr"; 28 | 29 | /** 30 | * Get an overview of what access is defined for agents. 31 | * 32 | * This function works with Solid Pods that implement either the Web Access 33 | * Control spec or the Access Control Policies proposal, with some caveats: 34 | * 35 | * - If access to the given Resource has been set using anything other than the 36 | * functions in this module, it is possible that it has been set in a way that 37 | * prevents this function from reliably reading access. 38 | * - It will only return access specified explicitly for the given Agent within 39 | * the ACL linked to the resource. If additional restrictions or external 40 | * resources are used, those will not be reflected in the return value of this 41 | * function. 42 | * - It will only return access specified explicitly for the given Resource. 43 | * In other words, if the Resource is a Container, the returned Access may not 44 | * apply to contained Resources. 45 | * - If the current user does not have permission to view access for the given 46 | * Resource, this function will resolve to `null`. 47 | * 48 | * @param resourceUrl URL of the Resource you want to read the access for. 49 | * @param options Default Options such as a fetch function. 50 | * @since 1.21.0 51 | */ 52 | export async function getAgentAccessAll( 53 | resourceUrl: UrlString, 54 | options?: DefaultOptions, 55 | ): Promise | null> { 56 | const resourceInfo = await getResourceInfo(resourceUrl, options); 57 | const acr = await getResourceAcr(resourceInfo, options); 58 | 59 | if (acr === null) { 60 | return getAgentAccessAllWac(resourceInfo, options); 61 | } 62 | 63 | return getAgentAccessAllAcp(acr); 64 | } 65 | -------------------------------------------------------------------------------- /src/universal/getPublicAccess.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import type { AccessModes, UrlString } from "../interfaces"; 23 | import type { DefaultOptions } from "../acp/type/DefaultOptions"; 24 | import { getResourceInfo } from "../resource/resource"; 25 | import { getPublicAccess as getPublicAccessAcp } from "../acp/util/getPublicAccess"; 26 | import { getPublicAccess as getPublicAccessWac } from "../access/wac"; 27 | import { getResourceAcr } from "../acp/util/getResourceAcr"; 28 | 29 | /** 30 | * Get an overview of what access is defined for the Public. 31 | * 32 | * This function works with Solid Pods that implement either the Web Access 33 | * Control spec or the Access Control Policies proposal, with some caveats: 34 | * 35 | * - If access to the given Resource has been set using anything other than the 36 | * functions in this module, it is possible that it has been set in a way that 37 | * prevents this function from reliably reading access. 38 | * - It will only return access specified explicitly for the given Agent within 39 | * the ACL linked to the resource. If additional restrictions or external 40 | * resources are used, those will not be reflected in the return value of this 41 | * function. 42 | * - It will only return access specified explicitly for the given Resource. 43 | * In other words, if the Resource is a Container, the returned Access may not 44 | * apply to contained Resources. 45 | * - If the current user does not have permission to view access for the given 46 | * Resource, this function will resolve to `null`. 47 | * 48 | * @param resourceUrl URL of the Resource you want to read the access for. 49 | * @param options Default Options such as a fetch function. 50 | * @since 1.19.0 51 | */ 52 | export async function getPublicAccess( 53 | resourceUrl: UrlString, 54 | options?: DefaultOptions, 55 | ): Promise { 56 | const resourceInfo = await getResourceInfo(resourceUrl, options); 57 | const acr = await getResourceAcr(resourceInfo, options); 58 | 59 | if (acr === null) { 60 | return getPublicAccessWac(resourceInfo, options); 61 | } 62 | 63 | return getPublicAccessAcp(acr); 64 | } 65 | -------------------------------------------------------------------------------- /src/universal/index.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | import { describe, it, expect } from "@jest/globals"; 23 | import * as universal from "./index"; 24 | 25 | describe("universal", () => { 26 | it("exports getAclServerResourceInfo", () => { 27 | expect(universal.getAclServerResourceInfo).toBeDefined(); 28 | }); 29 | 30 | it("exports getAgentAccess", () => { 31 | expect(universal.getAgentAccess).toBeDefined(); 32 | }); 33 | 34 | it("exports getAgentAccessAll", () => { 35 | expect(universal.getAgentAccessAll).toBeDefined(); 36 | }); 37 | 38 | it("exports getPublicAccess", () => { 39 | expect(universal.getPublicAccess).toBeDefined(); 40 | }); 41 | 42 | it("exports setAgentAccess", () => { 43 | expect(universal.setAgentAccess).toBeDefined(); 44 | }); 45 | 46 | it("exports setPublicAccess", () => { 47 | expect(universal.setPublicAccess).toBeDefined(); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/universal/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright Inrupt Inc. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal in 6 | // the Software without restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | // Software, and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | // 21 | 22 | /** 23 | * :::{admonition} Experimental API 24 | * :class: important 25 | * 26 | * This API is still experimental, and subject to change. It builds on top of 27 | * both ACP and WAC, aiming at being adaptable to any Access Control system that 28 | * may be implemented in Solid. That is why it is purely Resource-centric: the 29 | * library discovers metadata associated with the Resource itself, and calls the 30 | * appropriate underlying API to deal with the Access Control in place for the 31 | * target Resource. 32 | * 33 | * As it is still under development, the following export is *only* intended for 34 | * experimentation by early adopters, and is not recommended for production 35 | * applications. 36 | * 37 | * For more information see: [Tutorial: Managing 38 | * Access](https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/manage-access/) 39 | * ::: 40 | * 41 | * This module can be imported as an object from the main package, which results 42 | * in tree-shaking not being supported (so all the exported APIs will likely end 43 | * up in your bundle). This import style is used for environments such as nextjs 44 | * or create-react-app. 45 | * 46 | * ```typescript 47 | * import { universalAccess } from "@inrupt/solid-client"; 48 | * ``` 49 | * 50 | * Alternatively, if your environment supports [export 51 | * maps](https://nodejs.org/dist/latest-v16.x/docs/api/packages.html#exports), 52 | * then you can import directly: 53 | * 54 | * ```typescript 55 | * import * as universalAccess from "@inrupt/solid-client/universal"; 56 | * ``` 57 | * 58 | * If you're using Typescript, and receive errors about type definitions not 59 | * being found, please see this 60 | * [documentation](https://www.typescriptlang.org/docs/handbook/esm-node.html) 61 | * 62 | * @packageDocumentation 63 | * @module universalAccess 64 | */ 65 | 66 | export { getAclServerResourceInfo } from "./getAclServerResourceInfo"; 67 | export { getAgentAccess } from "./getAgentAccess"; 68 | export { getAgentAccessAll } from "./getAgentAccessAll"; 69 | export { getPublicAccess } from "./getPublicAccess"; 70 | export { setAgentAccess } from "./setAgentAccess"; 71 | export { setPublicAccess } from "./setPublicAccess"; 72 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*.ts", "e2e/**/*.ts*"], 4 | // Although we do not want our browser-based end-to-end tests from /e2e/browser 5 | // to be compiled as part of solid-client, we do want to run ESLint over them. 6 | // Thus, we override the `exclude` property of the tsconfig.json that we extend. 7 | "exclude": ["**/node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "lib": ["es6", "dom"], 6 | "declaration": true, 7 | "outDir": "dist", 8 | "rootDir": "src", 9 | "strict": true, 10 | // https://github.com/microsoft/TypeScript/wiki/Performance#controlling-types-inclusion: 11 | "types": ["jest"], 12 | "esModuleInterop": true, 13 | // Prevent developers on different OSes from running into problems: 14 | "forceConsistentCasingInFileNames": true, 15 | // Advanced Options 16 | "stripInternal": true 17 | }, 18 | "typedocOptions": { 19 | "out": "docs/api/source/api", 20 | "hideInPageTOC": true, 21 | "entryPoints": [ 22 | // The source files of everything listed under `exports` in our package.json 23 | // (i.e. public API's that should be documented) should be listed here: 24 | "src/interfaces.ts", 25 | "src/resource/resource.ts", 26 | "src/resource/solidDataset.ts", 27 | "src/resource/file.ts", 28 | "src/resource/mock.ts", 29 | "src/thing/thing.ts", 30 | "src/thing/get.ts", 31 | "src/thing/set.ts", 32 | "src/thing/add.ts", 33 | "src/thing/remove.ts", 34 | "src/thing/build.ts", 35 | "src/thing/mock.ts", 36 | "src/acl/acl.ts", 37 | "src/acl/agent.ts", 38 | "src/acl/group.ts", 39 | "src/acl/class.ts", 40 | "src/acl/mock.ts", 41 | "src/universal/index.ts", 42 | "src/acp/ess2.ts", 43 | "src/acp/ess1.ts", 44 | "src/rdfjs.ts", 45 | "src/profile/jwks.ts", 46 | "src/profile/webid.ts", 47 | "src/formats/index.ts" 48 | ], 49 | "exclude": [ 50 | "node_modules/**", 51 | "**/*.test.ts", 52 | // Internal helpers: 53 | "**/*.internal.ts", 54 | // End-to-end tests: 55 | "e2e/**", 56 | // Re-exported functions are already documented in their own modules: 57 | "src/index.ts", 58 | // Constants are only used internally: 59 | "src/constants.ts", 60 | // Helper methods for working with raw RDF internally: 61 | "src/datatypes.ts", 62 | // Behind-the-scenes auto-detection of the right fetcher to use: 63 | "src/fetcher.ts", 64 | // Helper methods for working with raw Turtle internally: 65 | "src/formats/turtle.ts", 66 | "src/formats/jsonLd.ts" 67 | ], 68 | "theme": "markdown", 69 | "readme": "none", 70 | "entryDocument": "index.rst", 71 | "plugin": ["typedoc-plugin-markdown"] 72 | }, 73 | "include": ["src/**/*.ts"], 74 | "exclude": [ 75 | "**/node_modules", 76 | // These end-to-end tests reference code in `.codesandbox`, 77 | // which is not part of this project and should not be compiled together with it. 78 | // Not excluding this will lead to the root of the repository being used 79 | // as the root directory for compilation (instead of /src), 80 | // meaning that files that would otherwise be included in /dist directly 81 | // (e.g. dist/index.d.ts) will then be built to /dist/src. 82 | "e2e", 83 | "**/*.test.ts", 84 | "src/tests.internal.ts" 85 | ] 86 | } 87 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*.test.ts", "e2e/**/*.test.ts"] 4 | } 5 | --------------------------------------------------------------------------------