diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c89ad88f..9be778d18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -180,8 +180,20 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and export to docker + uses: docker/build-push-action@v3 + with: + context: . + load: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + - name: "Test docker image 'latest'" + run: | + docker run --rm solidproject/community-server:latest --version + - name: "Test docker image 'edge'" + run: | + docker run --rm solidproject/community-server:edge --version - name: Build and push - id: docker_build uses: docker/build-push-action@v3 with: context: . @@ -221,8 +233,17 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and export to docker + uses: docker/build-push-action@v3 + with: + context: . + load: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + - name: "Test docker image 'next'" + run: | + docker run --rm solidproject/community-server:next --version - name: Build and push - id: docker_build uses: docker/build-push-action@v3 with: context: . @@ -230,7 +251,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - docs: + typedocs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -238,7 +259,7 @@ jobs: with: node-version: '16.x' - run: npm ci --ignore-scripts - - run: npm run docs + - run: npm run typedocs - name: Save docs uses: actions/upload-artifact@v3 with: @@ -246,9 +267,28 @@ jobs: path: docs retention-days: 1 + mkdocs: + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + needs: + - typedocs + steps: + - uses: actions/checkout@v2 + - id: get_version + uses: battila7/get-version-action@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.x + - run: pip install mkdocs-material + - run: pip install mike + - run: git config user.name ci-bot + - run: git config user.email ci-bot@example.com + - run: git fetch origin gh-pages --depth=1 + - run: cd documentation && mike deploy --push --update-aliases ${{steps.get_version.outputs.major}}.${{steps.get_version.outputs.minor}} latest + publish-docs: needs: - - docs + - mkdocs - lint - test-unit - test-integration @@ -261,7 +301,10 @@ jobs: with: name: docs path: docs + - id: get_version + uses: battila7/get-version-action@v2 - uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: . + publish_dir: ./docs + destination_dir: ${{steps.get_version.outputs.major}}.${{steps.get_version.outputs.minor}}/docs diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..f84184f6a --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +We follow and adhere to the Solid [Code of Conduct](https://github.com/solid/process/blob/main/code-of-conduct.md). diff --git a/Dockerfile b/Dockerfile index 48c620bb0..5854bd132 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,9 @@ # Build stage -FROM node:lts AS build +FROM node:lts-alpine AS build ## Set current working directory WORKDIR /community-server -## Copy the package.json for audit -COPY package*.json ./ - ## Copy the dockerfile's context's community server files COPY . . @@ -15,12 +12,11 @@ RUN npm ci --unsafe-perm && npm run build - # Runtime stage FROM node:lts-alpine ## Add contact informations for questions about the container -LABEL maintainer="Solid Community Server Docker Image Maintainer " +LABEL maintainer="Solid Community Server Docker Image Maintainer " ## Container config & data dir for volume sharing ## Defaults to filestorage with /data directory (passed through CMD below) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index c540766f7..e1f5b44b8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -52,7 +52,7 @@ These changes are relevant if you wrote custom modules for the server that depen A new interface `SingleThreaded` has been added. This empty interface can be implemented to mark a component as not-threadsafe. When the CSS starts in multithreaded mode, it will error and halt if any SingleThreaded components are instantiated. -## V4.0.1 +## v4.0.1 Freezes the `oidc-provider` dependency to prevent a potential issue with the solid authn client as described in https://github.com/inrupt/solid-client-authn-js/issues/2103. diff --git a/config/identity/email/example.json b/config/identity/email/example.json index 03c428a7f..7466f4c6d 100644 --- a/config/identity/email/example.json +++ b/config/identity/email/example.json @@ -5,10 +5,10 @@ "comment": "This is an example of what an actual email sender configuration would look like.", "@id": "urn:solid-server:default:EmailSender", "@type": "BaseEmailSender", - "args_senderName": "Solid Server", + "args_senderName": "Community Solid Server ", "args_emailConfig_host": "smtp.example.email", "args_emailConfig_port": 587, - "args_emailConfig_auth_user": "alice@example.email", + "args_emailConfig_auth_user": "solid@example.email", "args_emailConfig_auth_pass": "NYEaCsqV7aVStRCbmC" } ] diff --git a/config/quota-file.json b/config/quota-file.json index 9a67fdabd..9e9463287 100644 --- a/config/quota-file.json +++ b/config/quota-file.json @@ -16,7 +16,7 @@ "css:config/identity/pod/static.json", "css:config/identity/registration/enabled.json", "css:config/ldp/authentication/dpop-bearer.json", - "css:config/ldp/authorization/allow-all.json", + "css:config/ldp/authorization/webacl.json", "css:config/ldp/handler/default.json", "css:config/ldp/metadata-parser/default.json", "css:config/ldp/metadata-writer/default.json", diff --git a/documentation/README.md b/documentation/markdown/README.md similarity index 97% rename from documentation/README.md rename to documentation/markdown/README.md index 452f7d26f..5f20da569 100644 --- a/documentation/README.md +++ b/documentation/markdown/README.md @@ -1,4 +1,9 @@ -# Documentation +--- +hide: + - navigation +--- + +# Welcome Welcome to the Community Solid Server! Here we will cover many aspects of the server, diff --git a/documentation/architecture.md b/documentation/markdown/architecture.md similarity index 97% rename from documentation/architecture.md rename to documentation/markdown/architecture.md index 9390d97f2..94d48edda 100644 --- a/documentation/architecture.md +++ b/documentation/markdown/architecture.md @@ -69,5 +69,5 @@ The `ErrorHandler` will convert the error to an HTTP response to be returned. Below are sections that go deeper into the specific steps. Not all steps are covered yet and will be added in the future. -[How authentication and authorization work](authorization.md) -[What the `ResourceStore` looks like](resource-store.md) +* [How authentication and authorization work](authorization.md) +* [What the `ResourceStore` looks like](resource-store.md) diff --git a/documentation/authorization.md b/documentation/markdown/authorization.md similarity index 100% rename from documentation/authorization.md rename to documentation/markdown/authorization.md diff --git a/documentation/client-credentials.md b/documentation/markdown/client-credentials.md similarity index 100% rename from documentation/client-credentials.md rename to documentation/markdown/client-credentials.md diff --git a/documentation/dependency-injection.md b/documentation/markdown/dependency-injection.md similarity index 100% rename from documentation/dependency-injection.md rename to documentation/markdown/dependency-injection.md diff --git a/documentation/example-requests.md b/documentation/markdown/example-requests.md similarity index 100% rename from documentation/example-requests.md rename to documentation/markdown/example-requests.md diff --git a/documentation/identity-provider.md b/documentation/markdown/identity-provider.md similarity index 100% rename from documentation/identity-provider.md rename to documentation/markdown/identity-provider.md diff --git a/documentation/making-changes.md b/documentation/markdown/making-changes.md similarity index 100% rename from documentation/making-changes.md rename to documentation/markdown/making-changes.md diff --git a/documentation/release.md b/documentation/markdown/release.md similarity index 100% rename from documentation/release.md rename to documentation/markdown/release.md diff --git a/documentation/resource-store.md b/documentation/markdown/resource-store.md similarity index 100% rename from documentation/resource-store.md rename to documentation/markdown/resource-store.md diff --git a/documentation/seeding-pods.md b/documentation/markdown/seeding-pods.md similarity index 100% rename from documentation/seeding-pods.md rename to documentation/markdown/seeding-pods.md diff --git a/documentation/mkdocs.yml b/documentation/mkdocs.yml new file mode 100644 index 000000000..bce1cb59a --- /dev/null +++ b/documentation/mkdocs.yml @@ -0,0 +1,89 @@ +docs_dir: markdown + +theme: + name: 'material' + custom_dir: overrides + icon: + repo: fontawesome/brands/github + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/weather-night + name: Switch to dark mode + primary: deep purple + accent: deep orange + + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/weather-sunny + name: Switch to light mode + primary: deep purple + accent: deep orange + features: + - navigation.instant + - navigation.tabs + - navigation.top + - navigation.indexes + +site_name: 'Community Solid Server' +site_url: https://communitysolidserver.github.io/CommunitySolidServer + +repo_url: https://github.com/CommunitySolidServer/CommunitySolidServer +repo_name: CommunitySolidServer +edit_uri: "" + +plugins: + - search + +markdown_extensions: + - admonition + - def_list + - footnotes + - meta + - tables + - toc: + permalink: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.caret + - pymdownx.tilde + - pymdownx.details + - pymdownx.highlight + - pymdownx.superfences + - pymdownx.smartsymbols + + +extra: + version: + provider: mike + social: + - icon: fontawesome/brands/github + link: https://github.com/CommunitySolidServer/CommunitySolidServer + - icon: fontawesome/brands/docker + link: https://hub.docker.com/r/solidproject/community-server + - icon: fontawesome/brands/npm + link: https://www.npmjs.com/package/@solid/community-server + - icon: fontawesome/brands/gitter + link: https://gitter.im/CommunitySolidServer/community + +nav: + - Welcome: + - README.md + - Usage: + - 'Example request': example-requests.md + - 'Identity provider': identity-provider.md + - 'Client credentials': client-credentials.md + - 'Seeding Pods': seeding-pods.md + - Architecture: + - Architecture: architecture.md + - Dependency injection: dependency-injection.md + - Contributing: + - Pull requests: making-changes.md + - Releases: release.md + - API: ./docs/" target="_blank + +# To write documentation locally, execute the next line and browse to http://localhost:8000 +# docker run --rm -it -p 8000:8000 -v ${PWD}/documentation:/docs squidfunk/mkdocs-material diff --git a/documentation/overrides/main.html b/documentation/overrides/main.html new file mode 100644 index 000000000..8d9f50509 --- /dev/null +++ b/documentation/overrides/main.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% block outdated %} + You're not viewing the latest version. + + Click here to go to latest. + +{% endblock %} diff --git a/documentation/typedoc.css b/documentation/typedoc.css new file mode 100644 index 000000000..24616e25d --- /dev/null +++ b/documentation/typedoc.css @@ -0,0 +1,4 @@ +.tsd-page-toolbar, +.tsd-page-title { + background-color: #7E56C2; +} diff --git a/package-lock.json b/package-lock.json index b190943c3..7bd466f36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13788,9 +13788,9 @@ } }, "node_modules/semver-regex": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.3.tgz", - "integrity": "sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz", + "integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==", "dev": true, "engines": { "node": ">=8" @@ -26756,9 +26756,9 @@ } }, "semver-regex": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.3.tgz", - "integrity": "sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz", + "integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==", "dev": true }, "set-blocking": { diff --git a/package.json b/package.json index e18c46582..71eb54e4b 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ ], "contributors": [ "Joachim Van Herwegen ", + "Thomas Dupont ", + "Wannes Kerckhove ", + "Jasper Vaneessen ", "Ruben Taelman (https://www.rubensworks.net/)", "Ruben Verborgh (https://ruben.verborgh.org/)" ], @@ -47,7 +50,7 @@ "docker:setup": "./test/docker/docker-setup.sh", "docker:start": "./test/docker/docker-start.sh", "docker:stop": "./test/docker/docker-stop.sh", - "docs": "typedoc", + "typedocs": "typedoc --customCss ./documentation/typedoc.css", "jest": "jest --coverageReporters text-summary --", "lint": "eslint . --cache --ignore-path .gitignore --max-warnings 0", "prepare": "npm run build", diff --git a/src/http/UnsecureWebSocketsProtocol.ts b/src/http/UnsecureWebSocketsProtocol.ts index e18e32a63..26921b842 100644 --- a/src/http/UnsecureWebSocketsProtocol.ts +++ b/src/http/UnsecureWebSocketsProtocol.ts @@ -1,4 +1,5 @@ import { EventEmitter } from 'events'; +import type { TLSSocket } from 'tls'; import type { WebSocket } from 'ws'; import { getLoggerFor } from '../logging/LogUtil'; import type { HttpRequest } from '../server/HttpRequest'; @@ -47,7 +48,7 @@ class WebSocketListener extends EventEmitter { // Store the HTTP host and protocol const forwarded = parseForwarded(headers); this.host = forwarded.host ?? headers.host ?? 'localhost'; - this.protocol = forwarded.proto === 'https' || (socket as any).secure ? 'https:' : 'http:'; + this.protocol = forwarded.proto === 'https' || (socket as TLSSocket).encrypted ? 'https:' : 'http:'; } private stop(): void { @@ -91,10 +92,10 @@ class WebSocketListener extends EventEmitter { // Resolve and verify the URL const resolved = new URL(path, `${this.protocol}${this.host}`); if (resolved.host !== this.host) { - throw new Error(`Mismatched host: ${resolved.host} instead of ${this.host}`); + throw new Error(`Mismatched host: expected ${this.host} but got ${resolved.host}`); } if (resolved.protocol !== this.protocol) { - throw new Error(`Mismatched protocol: ${resolved.protocol} instead of ${this.protocol}`); + throw new Error(`Mismatched protocol: expected ${this.protocol} but got ${resolved.protocol}`); } // Subscribe to the URL const url = resolved.href; diff --git a/src/storage/conversion/RdfToQuadConverter.ts b/src/storage/conversion/RdfToQuadConverter.ts index 07f8f3974..f807581c1 100644 --- a/src/storage/conversion/RdfToQuadConverter.ts +++ b/src/storage/conversion/RdfToQuadConverter.ts @@ -13,7 +13,10 @@ import type { RepresentationConverterArgs } from './RepresentationConverter'; */ export class RdfToQuadConverter extends BaseTypedRepresentationConverter { public constructor() { - super(rdfParser.getContentTypes(), INTERNAL_QUADS); + const inputTypes = rdfParser.getContentTypes() + // ContentType application/json MAY NOT be converted to Quad. + .then((types): string[] => types.filter((type): boolean => type !== 'application/json')); + super(inputTypes, INTERNAL_QUADS); } public async handle({ representation, identifier }: RepresentationConverterArgs): Promise { diff --git a/test/unit/http/UnsecureWebSocketsProtocol.test.ts b/test/unit/http/UnsecureWebSocketsProtocol.test.ts index 0d95c421e..d3320115e 100644 --- a/test/unit/http/UnsecureWebSocketsProtocol.test.ts +++ b/test/unit/http/UnsecureWebSocketsProtocol.test.ts @@ -25,7 +25,7 @@ describe('An UnsecureWebSocketsProtocol', (): void => { 'sec-websocket-protocol': 'solid-0.1, other/1.0.0', }, socket: { - secure: true, + encrypted: true, }, } as any as HttpRequest; await protocol.handle({ webSocket, upgradeRequest } as any); @@ -101,7 +101,7 @@ describe('An UnsecureWebSocketsProtocol', (): void => { it('send an error message.', (): void => { expect(webSocket.messages).toHaveLength(1); expect(webSocket.messages.shift()) - .toBe('error Mismatched host: wrong.example instead of mypod.example'); + .toBe('error Mismatched host: expected mypod.example but got wrong.example'); }); }); @@ -113,7 +113,7 @@ describe('An UnsecureWebSocketsProtocol', (): void => { it('send an error message.', (): void => { expect(webSocket.messages).toHaveLength(1); expect(webSocket.messages.shift()) - .toBe('error Mismatched protocol: http: instead of https:'); + .toBe('error Mismatched protocol: expected https: but got http:'); }); }); }); diff --git a/test/unit/storage/conversion/RdfToQuadConverter.test.ts b/test/unit/storage/conversion/RdfToQuadConverter.test.ts index a9a4be871..99736d1b7 100644 --- a/test/unit/storage/conversion/RdfToQuadConverter.test.ts +++ b/test/unit/storage/conversion/RdfToQuadConverter.test.ts @@ -18,12 +18,17 @@ describe('A RdfToQuadConverter', (): void => { const identifier: ResourceIdentifier = { path: 'path' }; it('supports serializing as quads.', async(): Promise => { - const types = await rdfParser.getContentTypes(); - for (const type of types) { + const types = rdfParser.getContentTypes() + .then((inputTypes): string[] => inputTypes.filter((type): boolean => type !== 'application/json')); + for (const type of await types) { await expect(converter.getOutputTypes(type)).resolves.toEqual({ [INTERNAL_QUADS]: 1 }); } }); + it('may not handle application/json to quad conversion.', async(): Promise => { + await expect(converter.getOutputTypes('application/json')).resolves.toEqual({ }); + }); + it('can handle turtle to quad conversions.', async(): Promise => { const metadata = new RepresentationMetadata('text/turtle'); const representation = { metadata } as Representation;