mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
docs: Write initial user documentation
This commit is contained in:
parent
7d3320dea6
commit
a5a34f5071
20
README.md
20
README.md
@ -16,7 +16,7 @@ This Pod acts as your own personal storage space
|
|||||||
so you can share data with people and Solid applications.**
|
so you can share data with people and Solid applications.**
|
||||||
|
|
||||||
As an open and modular implementation of the
|
As an open and modular implementation of the
|
||||||
[Solid specifications](https://solid.github.io/specification/),
|
[Solid specifications](https://solidproject.org/TR/),
|
||||||
the Community Solid Server is a great companion:
|
the Community Solid Server is a great companion:
|
||||||
|
|
||||||
- 🧑🏽 **for people** who want to try out having their own Pod
|
- 🧑🏽 **for people** who want to try out having their own Pod
|
||||||
@ -107,16 +107,16 @@ These parameters give you direct access
|
|||||||
to some commonly used settings:
|
to some commonly used settings:
|
||||||
|
|
||||||
| parameter name | default value | description |
|
| parameter name | default value | description |
|
||||||
| -------------- | ------------- | ----------- |
|
|------------------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `--port, -p` | `3000` | The TCP port on which the server runs. |
|
| `--port, -p` | `3000` | The TCP port on which the server should listen. |
|
||||||
| `--baseUrl, -b` | `http://localhost:$PORT/` | The public URL of your server. |
|
| `--baseUrl, -b` | `http://localhost:$PORT/` | The base URL used internally to generate URLs. Change this if your server does not run on `http://localhost:$PORT/`. |
|
||||||
| `--loggingLevel, -l` | `info` | The detail level of logging; useful for debugging problems. |
|
| `--loggingLevel, -l` | `info` | The detail level of logging; useful for debugging problems. Use `debug` for full information. |
|
||||||
| `--config, -c` | `@css:config/default.json` | The configuration for the server. The default only stores data in memory; to persist to your filesystem, use `@css:config/file.json` |
|
| `--config, -c` | `@css:config/default.json` | The configuration for the server. The default only stores data in memory; to persist to your filesystem, use `@css:config/file.json` |
|
||||||
| `--rootFilePath, -f` | `./` | Root folder of the server, when using a file-based configuration. |
|
| `--rootFilePath, -f` | `./` | Root folder where the server stores data, when using a file-based configuration. |
|
||||||
| `--sparqlEndpoint, -s` | | URL of the SPARQL endpoint, when using a quadstore-based configuration. |
|
| `--sparqlEndpoint, -s` | | URL of the SPARQL endpoint, when using a quadstore-based configuration. |
|
||||||
| `--showStackTrace, -t` | false | Enables detailed logging on error pages. |
|
| `--showStackTrace, -t` | false | Enables detailed logging on error output. |
|
||||||
| `--podConfigJson` | `./pod-config.json` | Path to the file that keeps track of dynamic Pod configurations. |
|
| `--podConfigJson` | `./pod-config.json` | Path to the file that keeps track of dynamic Pod configurations. Only relevant when using `@css:config/dynamic.json`. |
|
||||||
| `--mainModulePath, -m` | | Path from where Components.js will start its lookup when initializing configurations.
|
| `--mainModulePath, -m` | | Path from where Components.js will start its lookup when initializing configurations. |
|
||||||
|
|
||||||
### 🧶 Custom configurations
|
### 🧶 Custom configurations
|
||||||
More substantial changes to server behavior can be achieved
|
More substantial changes to server behavior can be achieved
|
||||||
@ -139,7 +139,7 @@ the [📐 architectural diagram](https://rubenverborgh.github.io/solid-server-a
|
|||||||
can help you find your way.
|
can help you find your way.
|
||||||
|
|
||||||
If you want to help out with server development,
|
If you want to help out with server development,
|
||||||
have a look at the [📓 developer notes](https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/guides/developer-notes.md) and
|
have a look at the [📓 user documentation](https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/documentation/) and
|
||||||
[🛠️ good first issues](https://github.com/CommunitySolidServer/CommunitySolidServer/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
|
[🛠️ good first issues](https://github.com/CommunitySolidServer/CommunitySolidServer/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
|
||||||
|
|
||||||
|
|
||||||
|
41
documentation/README.md
Normal file
41
documentation/README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Documentation
|
||||||
|
|
||||||
|
Welcome to the Community Solid Server!
|
||||||
|
Here we will cover many aspects of the server,
|
||||||
|
such as how to propose changes,
|
||||||
|
what the architecture looks like,
|
||||||
|
and how to use many of the features the server provides.
|
||||||
|
|
||||||
|
The documentation here is still incomplete both in content and structure, so feel free to open
|
||||||
|
a [discussion](https://github.com/CommunitySolidServer/CommunitySolidServer/discussions) about things you want to see added.
|
||||||
|
While we try to update this documentation together with updates in the code,
|
||||||
|
it is always possible we miss something,
|
||||||
|
so please report it if you find incorrect information or links that no longer work.
|
||||||
|
|
||||||
|
An introductory tutorial that gives a quick overview of the Solid and CSS basics can be found
|
||||||
|
[here](https://github.com/KNowledgeOnWebScale/solid-linked-data-workshops-hands-on-exercises/blob/main/css-tutorial.md).
|
||||||
|
This is a good way to get started with the server and its setup.
|
||||||
|
|
||||||
|
If you want to know what is new in the latest version,
|
||||||
|
you can check out the [release notes](https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/RELEASE_NOTES.md)
|
||||||
|
for a high level overview and information on how to migrate your configuration to the next version.
|
||||||
|
A list that includes all minor changes can be found in
|
||||||
|
the [changelog](https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/CHANGELOG.md)
|
||||||
|
|
||||||
|
## Using the server
|
||||||
|
|
||||||
|
* [Basic example HTTP requests](example-requests.md)
|
||||||
|
* [How to use the Identity Provider](identity-provider.md)
|
||||||
|
|
||||||
|
## What the internals look like
|
||||||
|
|
||||||
|
* [How the server uses dependency injection](dependency-injection.md)
|
||||||
|
* [What the architecture looks like](architecture.md)
|
||||||
|
|
||||||
|
## Making changes
|
||||||
|
|
||||||
|
* [How to make changes to the repository](making-changes.md)
|
||||||
|
|
||||||
|
For core developers with push access only:
|
||||||
|
|
||||||
|
* [How to release a new version](release.md)
|
73
documentation/architecture.md
Normal file
73
documentation/architecture.md
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Architecture overview
|
||||||
|
|
||||||
|
The initial architecture document the project was started from can be found [here](https://rubenverborgh.github.io/solid-server-architecture/solid-architecture-v1-3-0.pdf).
|
||||||
|
Many things have been added since the original inception of the project,
|
||||||
|
but the core ideas within that document are still valid.
|
||||||
|
|
||||||
|
As can be seen from the architecture, an important idea is the modularity of all components.
|
||||||
|
No actual implementations are defined there, only their interfaces.
|
||||||
|
Making all the components independent of each other in such a way provides us with an enormous flexibility:
|
||||||
|
they can all be replaced by a different implementation, without impacting anything else.
|
||||||
|
This is how we can provide many different configurations for the server,
|
||||||
|
and why it is impossible to provide ready solutions for all possible combinations.
|
||||||
|
|
||||||
|
## Handlers
|
||||||
|
A very important building block that gets reused in many places is the `AsyncHandler`.
|
||||||
|
The idea is that a handler has 2 important functions.
|
||||||
|
`canHandle` determines if this class is capable of correctly handling the request,
|
||||||
|
and throws an error if it can not.
|
||||||
|
For example, a class that converts JSON-LD to turtle can handle all requests containing JSON-LD data,
|
||||||
|
but does not know what to do with a request that contains a JPEG.
|
||||||
|
The second function is `handle` where the class executes on the input data and returns the result.
|
||||||
|
If an error gets thrown here it means there is an issue with the input.
|
||||||
|
For example, if the input data claims to be JSON-LD but is actually not.
|
||||||
|
|
||||||
|
The power of using this interface really shines when using certain utility classes.
|
||||||
|
The one we use the most is the `WaterfallHandler`,
|
||||||
|
which takes as input a list of handlers of the same type.
|
||||||
|
The input and output of a `WaterfallHandler` is the same as those of its inputs,
|
||||||
|
meaning it can be used in the same places.
|
||||||
|
When doing a `canHandle` call, it will iterate over all its input handlers
|
||||||
|
to find the first one where the `canHandle` call succeeds,
|
||||||
|
and when calling `handle` it will return the result of that specific handler.
|
||||||
|
This allows us to chain together many handlers that each have their specific niche,
|
||||||
|
such as handler that each support a specific HTTP method (GET/PUT/POST/etc.),
|
||||||
|
or handlers that only take requests targeting a specific subset of URLs.
|
||||||
|
To the parent class it will look like it has a handler that supports all methods,
|
||||||
|
while in practice it will be a `WaterfallHandler` containing all these separate handlers.
|
||||||
|
|
||||||
|
Some other utility classes are the `ParallelHandler` that runs all handlers simultaneously,
|
||||||
|
and the `SequenceHandler` that runs all of them one after the other.
|
||||||
|
Since multiple handlers are executed here, these only work for handlers that have no output.
|
||||||
|
|
||||||
|
## Streams
|
||||||
|
Almost all data is handled in a streaming fashion.
|
||||||
|
This allows us to work with very large resources without having to fully load them in memory,
|
||||||
|
a client could be reading data that is being returned by the server while the server is still reading the file.
|
||||||
|
Internally this means we are mostly handling data as `Readable` objects.
|
||||||
|
We actually use `Guarded<Readable>` which is an internal format we created to help us with error handling.
|
||||||
|
Such streams can be created using utility functions such as `guardStream` and `guardedStreamFrom`.
|
||||||
|
Similarly, we have a `pipeSafely` to pipe streams in such a way that also helps with errors.
|
||||||
|
|
||||||
|
## Example request
|
||||||
|
In this section we will give a high level overview of all the components
|
||||||
|
a request passes through when it enters the server.
|
||||||
|
This is specifically an LDP request, e.g. a POST request to create a new resource.
|
||||||
|
|
||||||
|
1. The correct `HttpHandler` gets found, responsible for LDP requests.
|
||||||
|
2. The HTTP request gets parsed into a manageable format, both body and metadata such as headers.
|
||||||
|
3. The identification credentials of the request, if any, are extracted and parsed to authenticate the calling agent.
|
||||||
|
4. The request gets authorized or rejected, based on the credentials from step 3
|
||||||
|
and the authorization rules of the target resource.
|
||||||
|
5. Based on the HTTP method, the corresponding method from the `ResourceStore` gets called,
|
||||||
|
which in the case of a POST request will return the location of the newly created error.
|
||||||
|
6. The returned data and metadata get converted to an HTTP response and sent back in the `ResponseWriter`.
|
||||||
|
|
||||||
|
In case any of the steps above error, an error will be thrown.
|
||||||
|
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)
|
56
documentation/authorization.md
Normal file
56
documentation/authorization.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# Authorization
|
||||||
|
|
||||||
|
Authorization is usually handled by the `AuthorizingHttpHandler`,
|
||||||
|
and goes in the following steps:
|
||||||
|
|
||||||
|
1. Identify the credentials of the agent making the call.
|
||||||
|
2. Extract which access modes are needed for the request.
|
||||||
|
3. Reading the permissions the agent has.
|
||||||
|
4. Compare the above results to see if the request is allowed.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
There are multiple `CredentialsExtractor`s that each determine identity in a different way.
|
||||||
|
Potentially multiple extractors can apply,
|
||||||
|
making a requesting agent have multiple credentials.
|
||||||
|
The `DPoPWebIdExtractor` is most relevant for the [Solid-OIDC specification](https://solid.github.io/solid-oidc/),
|
||||||
|
as it parses the access token generated by a Solid Identity Provider.
|
||||||
|
Besides that there are always the public credentials, which everyone has.
|
||||||
|
There are also some debug extractors that can be used to simulate credentials,
|
||||||
|
which can be enabled as different options through the `config/ldp/authentication` imports.
|
||||||
|
|
||||||
|
If successful, a `CredentialsExtractor` will return a key/value map
|
||||||
|
linking the type of credentials to their specific values.
|
||||||
|
|
||||||
|
## Modes extraction
|
||||||
|
Access modes are a predefined list of `read`, `write`, `append`, `create` and `delete`.
|
||||||
|
The `ModesExtractor`s determine which modes will be necessary,
|
||||||
|
based on the request contents.
|
||||||
|
The `MethodModesExtractor` determines modes based on the HTTP method.
|
||||||
|
A GET request will always need the `read` mode for example.
|
||||||
|
Specifically for PATCH requests there are extractors for each supported PATCH type,
|
||||||
|
such as the `N3PatchModesExtractor`,
|
||||||
|
which parses the N3 Patch body to know if it will add new data or only delete data.
|
||||||
|
|
||||||
|
## Permission reading
|
||||||
|
`PermissionReaders` take the input of the above to determine which permissions are available for which credentials.
|
||||||
|
The modes from the previous step are not yet needed,
|
||||||
|
but can be used as optimization as we only need to know if we have permission on those modes.
|
||||||
|
Each reader can potentially return a potential answer if it only checks specific cases.
|
||||||
|
Those results then get combined in the `UnionPermissionReader`.
|
||||||
|
In the default configuration there are currently 4 relevant permission readers that get combined:
|
||||||
|
|
||||||
|
1. `PathBasedReader` rejects all permissions for certain paths, to prevent access to internal data.
|
||||||
|
2. `OwnerPermissionReader` grants control permissions to agents that are trying to access data in a pod that they own.
|
||||||
|
3. `AuxiliaryReader` handles all permissions for auxiliary resources by requesting those of the subject resource if necessary.
|
||||||
|
4. `WebAclReader` reads out the relevant `.acl` resource to read out the defined permissions.
|
||||||
|
|
||||||
|
All of the above is if you have WebACL enabled.
|
||||||
|
It is also possible to always grant all permissions for debugging reasons
|
||||||
|
by changing the authorization import to `config/ldp/authorization/allow-all.json`.
|
||||||
|
|
||||||
|
## Authorization
|
||||||
|
All the results of the previous steps then get combined to either allow or reject a request.
|
||||||
|
If no permissions are found for a requested mode,
|
||||||
|
or they are explicitly forbidden,
|
||||||
|
a 401/403 will be returned,
|
||||||
|
depending on if the agent was logged in or not.
|
54
documentation/dependency-injection.md
Normal file
54
documentation/dependency-injection.md
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# Dependency injection
|
||||||
|
|
||||||
|
The community server uses the _dependency injection_ framework
|
||||||
|
[Components.js](https://github.com/LinkedSoftwareDependencies/Components.js/)
|
||||||
|
to link all class instances together,
|
||||||
|
and uses [Components-Generator.js](https://github.com/LinkedSoftwareDependencies/Components-Generator.js)
|
||||||
|
to automatically generate the necessary description configurations of all classes.
|
||||||
|
This framework allows us to configure our components in a JSON file.
|
||||||
|
The advantage of this is that changing the configuration of components does not require any changes to the code,
|
||||||
|
as one can just change the default configuration file, or provide a custom configuration file.
|
||||||
|
|
||||||
|
More information can be found in the Components.js [documentation](https://componentsjs.readthedocs.io/),
|
||||||
|
but a summarized overview can be found below.
|
||||||
|
|
||||||
|
## Component files
|
||||||
|
Components.js requires a component file for every class you might want to instantiate.
|
||||||
|
Fortunately those get generated automatically by Components-Generator.js.
|
||||||
|
Calling `npm run build` will call the generator and generate those JSON-LD files in the `dist` folder.
|
||||||
|
The generator uses the `index.ts`, so new classes always have to be added there
|
||||||
|
or they will not get a component file.
|
||||||
|
|
||||||
|
## Configuration files
|
||||||
|
Configuration files are how we tell Components.js which classes to instantiate and link together.
|
||||||
|
All the community server configurations can be found in
|
||||||
|
the [`config` folder](https://github.com/CommunitySolidServer/CommunitySolidServer/tree/main/config/).
|
||||||
|
That folder also contains information about how different pre-defined configurations can be used.
|
||||||
|
|
||||||
|
A single component in such a configuration file might look as follows:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"comment": "Storage used for account management.",
|
||||||
|
"@id": "urn:solid-server:default:AccountStorage",
|
||||||
|
"@type": "JsonResourceStorage",
|
||||||
|
"source": { "@id": "urn:solid-server:default:ResourceStore" },
|
||||||
|
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
|
"container": "/.internal/accounts/"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the corresponding constructor of the `JsonResourceStorage` class:
|
||||||
|
```ts
|
||||||
|
public constructor(source: ResourceStore, baseUrl: string, container: string)
|
||||||
|
```
|
||||||
|
|
||||||
|
The important elements here are the following:
|
||||||
|
* `"comment"`: _(optional)_ A description of this component.
|
||||||
|
* `"@id"`: _(optional)_ A unique identifier of this component, which allows it to be used as parameter values in different places.
|
||||||
|
* `"@type"`: The class name of the component. This must be a TypeScript class name that is exported via `index.ts`.
|
||||||
|
|
||||||
|
As you can see from the constructor, the other fields are direct mappings from the constructor parameters.
|
||||||
|
`source` references another object, which we refer to using its identifier `urn:solid-server:default:ResourceStore`.
|
||||||
|
`baseUrl` is just a string, but here we use a variable that was set before calling Components.js
|
||||||
|
which is why it also references an `@id`.
|
||||||
|
These variables are set when starting up the server, based on the command line parameters.
|
172
documentation/identity-provider.md
Normal file
172
documentation/identity-provider.md
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
# Identity Provider
|
||||||
|
|
||||||
|
Besides implementing the [Solid protocol](https://solidproject.org/TR/protocol),
|
||||||
|
the community server can also be an Identity Provider (IDP), officially known as an OpenID Provider (OP),
|
||||||
|
following the [Solid OIDC spec](https://solid.github.io/solid-oidc/) as much as possible.
|
||||||
|
|
||||||
|
It is recommended to use the latest version
|
||||||
|
of the [Solid authentication client](https://github.com/inrupt/solid-client-authn-js)
|
||||||
|
to interact with the server.
|
||||||
|
|
||||||
|
The links here assume the server is hosted at `http://localhost:3000/`.
|
||||||
|
|
||||||
|
## Registering an account
|
||||||
|
To register an account, you can go to `http://localhost:3000/idp/register/` if this feature is enabled,
|
||||||
|
which it is on all configurations we provide.
|
||||||
|
Currently our registration page ties 3 features together on the same page:
|
||||||
|
* Creating an account on the server.
|
||||||
|
* Creating or linking a WebID to your account.
|
||||||
|
* Creating a pod on the server.
|
||||||
|
|
||||||
|
### Account
|
||||||
|
To create an account you need to provide an email address and password.
|
||||||
|
The password will be salted and hashed before being stored.
|
||||||
|
As of now, the account is only used to log in and identify yourself to the IDP
|
||||||
|
when you want to do an authenticated request,
|
||||||
|
but in future the plan is to also use this for account/pod management.
|
||||||
|
|
||||||
|
### WebID
|
||||||
|
We require each account to have a corresponding WebID.
|
||||||
|
You can either let the server create a WebID for you in a pod,
|
||||||
|
which will also need to be created then,
|
||||||
|
or you can link an already existing WebID you have on an external server.
|
||||||
|
|
||||||
|
In case you try to link your own WebID, you can choose if you want to be able
|
||||||
|
to use this server as your IDP for this WebID.
|
||||||
|
If not, you can still create a pod,
|
||||||
|
but you will not be able to direct the authentication client to this server to identify yourself.
|
||||||
|
|
||||||
|
Additionally, if you try to register with an external WebID,
|
||||||
|
the first attempt will return an error indicating you need to add an identification triple to your WebID.
|
||||||
|
After doing that you can try to register again.
|
||||||
|
This is how we verify you are the owner of that WebID.
|
||||||
|
After registration the next page will inform you
|
||||||
|
that you have to add an additional triple to your WebID if you want to use the server as your IDP.
|
||||||
|
|
||||||
|
All of the above is automated if you create the WebID on the server itself.
|
||||||
|
|
||||||
|
### Pod
|
||||||
|
To create a pod you simply have to fill in the name you want your pod to have.
|
||||||
|
This will then be used to generate the full URL of your pod.
|
||||||
|
For example, if you choose the name `test`,
|
||||||
|
your pod would be located at `http://localhost:3000/test/`
|
||||||
|
and your generated WebID would be `http://localhost:3000/test/profile/card#me`.
|
||||||
|
|
||||||
|
The generated name also depends on the configuration you chose for your server.
|
||||||
|
If you are using the subdomain feature,
|
||||||
|
such as being done in the `config/memory-subdomains.json` configuration,
|
||||||
|
the generated pod URL would be `http://test.localhost:3000/`.
|
||||||
|
|
||||||
|
## Logging in
|
||||||
|
When using an authenticating client,
|
||||||
|
you will be redirected to a login screen asking for your email and password.
|
||||||
|
After that you will be redirected to a page showing some basic information about the client.
|
||||||
|
There you need to consent that this client is allowed to identify using your WebID.
|
||||||
|
As a result the server will send a token back to the client
|
||||||
|
that contains all the information needed to use your WebID.
|
||||||
|
|
||||||
|
## Forgot password
|
||||||
|
If you forgot your password, you can recover it by going to `http://localhost:3000/idp/forgotpassword/`.
|
||||||
|
There you can enter your email address to get a recovery mail to reset your password.
|
||||||
|
This feature only works if a mail server was configured,
|
||||||
|
which by default is not the case.
|
||||||
|
|
||||||
|
## JSON API
|
||||||
|
All of the above happens through HTML pages provided by the server.
|
||||||
|
By default, the server uses the templates found in `/templates/identity/email-password/`
|
||||||
|
but different templates can be used through configuration.
|
||||||
|
|
||||||
|
These templates all make use of a JSON API exposed by the server.
|
||||||
|
For example, when doing a GET request to `http://localhost:3000/idp/register/`
|
||||||
|
with a JSON accept header, the following JSON is returned:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"required": {
|
||||||
|
"email": "string",
|
||||||
|
"password": "string",
|
||||||
|
"confirmPassword": "string",
|
||||||
|
"createWebId": "boolean",
|
||||||
|
"register": "boolean",
|
||||||
|
"createPod": "boolean",
|
||||||
|
"rootPod": "boolean"
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"webId": "string",
|
||||||
|
"podName": "string",
|
||||||
|
"template": "string"
|
||||||
|
},
|
||||||
|
"controls": {
|
||||||
|
"register": "http://localhost:3000/idp/register/",
|
||||||
|
"index": "http://localhost:3000/idp/",
|
||||||
|
"prompt": "http://localhost:3000/idp/prompt/",
|
||||||
|
"login": "http://localhost:3000/idp/login/",
|
||||||
|
"forgotPassword": "http://localhost:3000/idp/forgotpassword/"
|
||||||
|
},
|
||||||
|
"apiVersion": "0.3"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `required` and `optional` fields indicate which input fields are expected by the API.
|
||||||
|
These correspond to the fields of the HTML registration page.
|
||||||
|
To register a user, you can do a POST request with a JSON body containing the correct fields:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"email": "test@example.com",
|
||||||
|
"password": "secret",
|
||||||
|
"confirmPassword": "secret",
|
||||||
|
"createWebId": true,
|
||||||
|
"register": true,
|
||||||
|
"createPod": true,
|
||||||
|
"rootPod": false,
|
||||||
|
"podName": "test"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Two fields here that are not covered on the HTML page above are `rootPod` and `template`.
|
||||||
|
`rootPod` tells the server to put the pod in the root of the server instead of a location based on the `podName`.
|
||||||
|
By default the server will reject requests where this is `true`, except during setup.
|
||||||
|
`template` is only used by servers running the `config/dynamic.json` configuration,
|
||||||
|
which is a very custom setup where every pod can have a different Components.js configuration,
|
||||||
|
so this value can usually be ignored.
|
||||||
|
|
||||||
|
## IDP configuration
|
||||||
|
The above descriptions cover server behaviour with most default configurations,
|
||||||
|
but just like any other feature, there are several features that can be changed
|
||||||
|
through the imports in your configuration file.
|
||||||
|
|
||||||
|
All available options can be found in
|
||||||
|
the [`config/identity/` folder](https://github.com/CommunitySolidServer/CommunitySolidServer/tree/main/config/identity).
|
||||||
|
Below we go a bit deeper into the available options
|
||||||
|
|
||||||
|
### access
|
||||||
|
The `access` option allows you to set authorization restrictions on the IDP API when enabled,
|
||||||
|
similar to how authorization works on the LDP requests on the server.
|
||||||
|
For example, if the server uses WebACL as authorization scheme,
|
||||||
|
you can put a `.acl` resource in the `/idp/register/` container to restrict
|
||||||
|
who is allowed to access the registration API.
|
||||||
|
Note that for everything to work there needs to be a `.acl` resource in `/idp/` when using WebACL
|
||||||
|
so resources can be accessed as usual when the server starts up.
|
||||||
|
Make sure you change the permissions on `/idp/.acl` so not everyone can modify those.
|
||||||
|
|
||||||
|
All of the above is only relevant if you use the `restricted.json` setting for this import.
|
||||||
|
When you use `public.json` the API will simply always be accessible by everyone.
|
||||||
|
|
||||||
|
### email
|
||||||
|
In case you want users to be able to reset their password when they forget it,
|
||||||
|
you will need to tell the server which email server to use to send reset mails.
|
||||||
|
`example.json` contains an example of what this looks like,
|
||||||
|
which you will need to copy over to your base configuration and then remove the `config/identity/email` import.
|
||||||
|
|
||||||
|
### handler
|
||||||
|
There is only one option here. This import contains all the core components necessary to make the IDP work.
|
||||||
|
In case you need to make some changes to core IDP settings, this is where you would have to look.
|
||||||
|
|
||||||
|
### pod
|
||||||
|
The `pod` options determines how pods are created. `static.json` is the expected pod behaviour as described above.
|
||||||
|
`dynamic.json` is an experimental feature that allows users
|
||||||
|
to have a custom Components.js configuration for their own pod.
|
||||||
|
When using such a setup, a JSON file will be written containing all the information of the user pods
|
||||||
|
so they can be recreated when the server restarts.
|
||||||
|
|
||||||
|
### registration
|
||||||
|
This setting allows you to enable/disable registration on the server.
|
||||||
|
Disabling registration here does not disable registration during setup,
|
||||||
|
meaning you can still use this server as an IDP with the account created there.
|
0
documentation/idp.md
Normal file
0
documentation/idp.md
Normal file
33
documentation/making-changes.md
Normal file
33
documentation/making-changes.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Pull requests
|
||||||
|
The community server is fully written in [Typescript](https://www.typescriptlang.org/docs/home.html).
|
||||||
|
|
||||||
|
All changes should be done through
|
||||||
|
[pull requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork).
|
||||||
|
|
||||||
|
We recommend first discussing a possible solution in the relevant issue
|
||||||
|
to reduce the amount of changes that will be requested.
|
||||||
|
|
||||||
|
In case any of your changes are breaking, make sure you target the next major branch (`versions/x.0.0`)
|
||||||
|
instead of the main branch. Breaking changes include: changing interface/class signatures,
|
||||||
|
potentially breaking external custom configurations,
|
||||||
|
and breaking how internal data is stored.
|
||||||
|
In case of doubt you probably want to target the next major branch.
|
||||||
|
|
||||||
|
We make use of [Conventional Commits](https://www.conventionalcommits.org).
|
||||||
|
|
||||||
|
Don't forget to update the [release notes](https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/RELEASE_NOTES.md)
|
||||||
|
when adding new major features.
|
||||||
|
Also update any relevant documentation in case this is needed.
|
||||||
|
|
||||||
|
When making changes to a pull request,
|
||||||
|
we prefer to update the existing commits with a rebase instead of appending new commits,
|
||||||
|
this way the PR can be rebased directly onto the target branch
|
||||||
|
instead of needing to be squashed.
|
||||||
|
|
||||||
|
There are strict requirements from the linter and the test coverage before a PR is valid.
|
||||||
|
These are configured to run automatically when trying to commit to git.
|
||||||
|
Although there are no tests for it (yet), we strongly advice documenting with [TSdoc](https://github.com/microsoft/tsdoc).
|
||||||
|
|
||||||
|
If a list of entries is alphabetically sorted,
|
||||||
|
such as [index.ts](https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/src/index.ts),
|
||||||
|
make sure it stays that way.
|
30
documentation/release.md
Normal file
30
documentation/release.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Releasing a new version
|
||||||
|
|
||||||
|
This is only relevant if you are a developer with push access responsible for doing a new release.
|
||||||
|
|
||||||
|
Steps to follow:
|
||||||
|
* Merge `main` into `versions/x.0.0`.
|
||||||
|
* Verify if there are issues when upgrading an existing installation to the new version.
|
||||||
|
* Can the data still be accessed?
|
||||||
|
* Does authentication still work?
|
||||||
|
* Is there an issue upgrading the recipes at https://github.com/CommunitySolidServer/recipes
|
||||||
|
* None of the above has to be blocking per se, but should be noted in the release notes if relevant.
|
||||||
|
* Update all Components.js references to the new version.
|
||||||
|
* All contexts in all configs to
|
||||||
|
`https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^x.0.0/components/context.jsonld`.
|
||||||
|
* Update all `lsd` entries in `package.json` to the new version.
|
||||||
|
* Commit this with `chore: Update configs to vx.0.0`.
|
||||||
|
* `npm version major -m "Release version %s of the npm package."`
|
||||||
|
* This will update the `package.json`, generate a tag, and generate the new entries in `CHANGELOG.md`.
|
||||||
|
* Manually edit the `CHANGELOG.md`.
|
||||||
|
* First reverse the list of new entries so they go from old to new.
|
||||||
|
* Put all entries in matching categories, look at the previous release for reference.
|
||||||
|
* Most `chore` and `docs` entries can probably be removed.
|
||||||
|
* Make sure there are 2 newlines between this and the previous section.
|
||||||
|
* `git push --follow-tags`
|
||||||
|
* Merge `versions/x.0.0` into `main`.
|
||||||
|
* Do a GitHub release.
|
||||||
|
* `npm publish`
|
||||||
|
* Rename the `versions/x.0.0` branch to the next version.
|
||||||
|
* Update `.github/workflows/schedule.yml` to point at the new branch.
|
||||||
|
* Potentially upgrade the recipes at https://github.com/CommunitySolidServer/recipes
|
75
documentation/resource-store.md
Normal file
75
documentation/resource-store.md
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Resource store
|
||||||
|
Once an LDP request passes authorization, it will be passed to the `ResourceStore`.
|
||||||
|
|
||||||
|
The interface of a `ResourceStore` is mostly a 1-to-1 mapping of the HTTP methods:
|
||||||
|
|
||||||
|
* GET: `getRepresentation`
|
||||||
|
* PUT: `setRepresentation`
|
||||||
|
* POST: `addResource`
|
||||||
|
* DELETE: `deleteResource`
|
||||||
|
* PATCH: `modifyResource`
|
||||||
|
|
||||||
|
The corresponding `OperationHandler` of the relevant method
|
||||||
|
is responsible for calling the correct `ResourceStore` function.
|
||||||
|
|
||||||
|
In practice, the community server has multiple resource stores chained together,
|
||||||
|
each handling a specific part of the request and then calling the next store in the chain.
|
||||||
|
The default configurations come with the following stores:
|
||||||
|
|
||||||
|
1. `MonitoringStore`
|
||||||
|
2. `IndexRepresentationStore`
|
||||||
|
3. `LockingResourceStore`
|
||||||
|
4. `PatchingStore`
|
||||||
|
5. `RepresentationConvertingStore`
|
||||||
|
6. `DataAccessorBasedStore`
|
||||||
|
|
||||||
|
This chain can be seen in the configuration part in `config/storage/middleware/default.json`
|
||||||
|
and all the entries in `config/storage/backend`.
|
||||||
|
|
||||||
|
## MonitoringStore
|
||||||
|
This store emits the events that are necessary to emit notifications when resources change.
|
||||||
|
|
||||||
|
## IndexRepresentationStore
|
||||||
|
When doing a GET request on a container `/container/`,
|
||||||
|
this container returns the contents of `/container/index.html` instead if HTML is the preferred response type.
|
||||||
|
All these values are the defaults and can be configured for other resources and media types.
|
||||||
|
|
||||||
|
## LockingResourceStore
|
||||||
|
To prevent data corruption, the server locks resources when being targeted by a request.
|
||||||
|
Locks are only released when an operation is completely finished,
|
||||||
|
in the case of read operations this means the entire data stream is read,
|
||||||
|
and in the case of write operations this happens when all relevant data is written.
|
||||||
|
The default lock that is used is a readers-writer lock.
|
||||||
|
This allows simultaneous read requests on the same resource,
|
||||||
|
but only while no write request is in progress.
|
||||||
|
|
||||||
|
## PatchingStore
|
||||||
|
PATCH operations in Solid apply certain transformations on the target resource,
|
||||||
|
which makes them more complicated than only reading or writing data since it involves both.
|
||||||
|
The `PatchingStore` provides a generic solution for backends that do not implement the `modifyResource` function
|
||||||
|
so new backends can be added more easily.
|
||||||
|
In case the next store in the chain does not support PATCH,
|
||||||
|
the `PatchingStore` will GET the data from the next store,
|
||||||
|
apply the transformation on that data,
|
||||||
|
and then PUT it back to the store.
|
||||||
|
|
||||||
|
## RepresentationConvertingStore
|
||||||
|
This store handles everything related to content negotiation.
|
||||||
|
In case the resulting data of a GET request does not match the preferences of a request,
|
||||||
|
it will be converted here.
|
||||||
|
Similarly, if incoming data does not match the type expected by the store,
|
||||||
|
the SPARQL backend only accepts triples for example,
|
||||||
|
that is also handled here
|
||||||
|
|
||||||
|
## DataAccessorBasedStore
|
||||||
|
Large parts of the requirements of the Solid protocol specification are resolved by the `DataAccessorBasedStore`:
|
||||||
|
POST only working on containers,
|
||||||
|
DELETE not working on non-empty containers,
|
||||||
|
generating `ldp:contains` triples for containers, etc.
|
||||||
|
Most of this behaviour is independent of how the data is stored which is why it can be generalized here.
|
||||||
|
The store's name comes from the fact that it makes use of `DataAccessor`s to handle the read/write of resources.
|
||||||
|
A `DataAccessor` is a simple interface that only focuses on handling the data.
|
||||||
|
It does not concern itself with any of the necessary Solid checks as it assumes those have already been made.
|
||||||
|
This means that if a storage method needs to be supported,
|
||||||
|
only a new `DataAccessor` needs to be made,
|
||||||
|
after which it can be plugged into the rest of the server.
|
@ -1,28 +0,0 @@
|
|||||||
By default, the server will start with a set of preconfigured components.
|
|
||||||
These components are configured in [`config/default.json`](https://github.com/CommunitySolidServer/CommunitySolidServer/tree/master/config/default.json).
|
|
||||||
Learn more about the structure of this config file in the [notes for developers](https://github.com/CommunitySolidServer/CommunitySolidServer/wiki/Notes-for-developers#add-components-to-configuration).
|
|
||||||
|
|
||||||
## Local development environment
|
|
||||||
|
|
||||||
_This guide assumes the server is installed locally by cloning the git repo._
|
|
||||||
|
|
||||||
When starting the server via `bin/server.js`, you can provide another config via the `-c` flag.
|
|
||||||
For example:
|
|
||||||
```bash
|
|
||||||
$ bin/server.js -c config/default.json
|
|
||||||
```
|
|
||||||
|
|
||||||
The command above will behave in the exact same way as just running `bin/server.js`, since `config/default.json` is the default server config for when `-c` is not provided.
|
|
||||||
|
|
||||||
If you for example create a copy from `config/default.json` named `my-config.json`, and make some adjustments, you can invoke it as follows:
|
|
||||||
```bash
|
|
||||||
$ bin/server.js -c my-config.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Globally installed server
|
|
||||||
|
|
||||||
TODO: after making a first release, write a guide on how to create a custom config for it when it is globally installed.
|
|
||||||
|
|
||||||
## Including the server as dependency in another package.
|
|
||||||
|
|
||||||
TODO: after making a first release, write a guide on how to create a custom config for it when it is included as a dependency in another package.
|
|
@ -1,81 +0,0 @@
|
|||||||
The community server is fully written in [Typescript](https://www.typescriptlang.org/docs/home.html).
|
|
||||||
|
|
||||||
All changes should be done through [pull requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork). There are strict requirements from the linter and the test coverage before a PR is valid. These are configured to run automatically when trying to commit to git. Although there are no tests for it (yet), we strongly advice documenting with [TSdoc](https://github.com/microsoft/tsdoc).
|
|
||||||
|
|
||||||
The initial architecture document the project was started from can be found [here](https://rubenverborgh.github.io/solid-server-architecture/solid-architecture-v1-3-0.pdf). Even though some changes and additions have been made it is still mostly accurate.
|
|
||||||
|
|
||||||
A draft of the Solid spec can be found [here](https://github.com/solid/specification). It is still incomplete but much information can also be found in the issues. An older version can be found [here](https://github.com/solid/solid-spec/). Note that this last one is not fully accurate anymore but can still give a general overview of certain components.
|
|
||||||
|
|
||||||
Solid is inspired by LDP (Linked Data Platform) of which the spec can be found [here](https://www.w3.org/TR/ldp/). It doesn't strictly follow the spec though.
|
|
||||||
|
|
||||||
An example of how a Solid request needs to be parsed and handled can be found [here](https://github.com/solid/solid-architecture/blob/master/server/request-flow.md), including the correct status codes for specific responses.
|
|
||||||
|
|
||||||
As can be seen from the architecture, the main idea is that all components can easily be interchanged for other versions with a different implementation. This makes it imperative to reduce direct dependencies between components, which is why in general one class should never instantiate another class, it should only accept other objects through its constructors. This also makes testing much easier due to the independence of components.
|
|
||||||
|
|
||||||
Many RDF utility libraries can be found [here](https://rdf.js.org/).
|
|
||||||
|
|
||||||
## Add components to configuration
|
|
||||||
|
|
||||||
After implementing and testing your component, you have to _configure_ it so that it is enabled when starting the server.
|
|
||||||
|
|
||||||
### Dependency Injection
|
|
||||||
|
|
||||||
Due to the large number of components in this server, we make use of the _dependency injection_ framework [Components.js](https://github.com/LinkedSoftwareDependencies/Components.js).
|
|
||||||
This framework allows us to configure our components in a JSON file.
|
|
||||||
The advantage of this is that changing the configuration of components does not require any changes to the code, as one can just change the default configuration file, or provide a custom configuration file.
|
|
||||||
|
|
||||||
### Config file structure
|
|
||||||
|
|
||||||
In order to add a component to the default configuration,
|
|
||||||
you will have to update [`config/default.json`](https://github.com/CommunitySolidServer/CommunitySolidServer/tree/master/config/default.json),
|
|
||||||
or any of its _imported_ files, which exist in the [`config subfolders`](https://github.com/CommunitySolidServer/CommunitySolidServer/tree/master/config/).
|
|
||||||
|
|
||||||
A component in a configuration file has the following structure:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"@id": "urn:solid-server:my:ResourceStore",
|
|
||||||
"@type": "PatchingStore",
|
|
||||||
"PatchingStore:_source": {
|
|
||||||
"@id": "urn:solid-server:my:ResourceStore_Converting"
|
|
||||||
},
|
|
||||||
"PatchingStore:_patcher": {
|
|
||||||
"@id": "urn:solid-server:my:PatchHandler"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The important elements here are the following:
|
|
||||||
* `"@id"`: _(optional)_ A unique identifier of this component, which allows it to be used as parameter values in different places.
|
|
||||||
* `"type"`: The class name of the component. This must be a TypeScript class name that is exported via `index.ts`.
|
|
||||||
* `"PatchingStore:_source"`: _(optional)_ A constructor parameter of the `PatchingStore` class. For other classes, this will always have the structure `"[ClassName]:_[parameterName]"`.
|
|
||||||
|
|
||||||
### Tips & Tricks
|
|
||||||
|
|
||||||
As shown in the example above, the parameters `"PatchingStore:_source"` and `"PatchingStore:_patcher"` contain another `"@id"` as value. These `"@id"`'s MUST always refer to another valid component, either defined inline or elsewhere.
|
|
||||||
|
|
||||||
Defining an `"@id"` for a component is only required when your component is being used in different places. If it's just being used once as parameter value of another component, you can omit `"@id"` and define the component inline.
|
|
||||||
|
|
||||||
If you edit this config file, `npm run build` MUST have been invoked before so that the TypeScript files have been properly compiled, and the `components/` folder has been populated. The `components/` folder consists of a declarative representation of the TypeScript classes which are referred to from the config file. Since these files are auto-generated, you should NEVER change these files manually. This folder is generated using [Components-Generator.js](https://github.com/LinkedSoftwareDependencies/Components-Generator.js/).
|
|
||||||
|
|
||||||
Learn more about Components.js in its [documentation](https://componentsjs.readthedocs.io/en/latest/).
|
|
||||||
|
|
||||||
## Releasing a new version
|
|
||||||
|
|
||||||
_This is only relevant to developers with push-access._
|
|
||||||
|
|
||||||
Making a new release can be done by following these steps:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm version [major|minor|patch] -m "Release version %s of the npm package."
|
|
||||||
$ npm publish
|
|
||||||
$ git push --tags
|
|
||||||
$ git push origin master
|
|
||||||
```
|
|
||||||
|
|
||||||
(If you call this often, you can [copy this script](https://github.com/rubensworks/dotfiles/blob/master/bin/npm-release) into your dotfiles.)
|
|
||||||
|
|
||||||
When calling `npm version`, a new entry in `CHANGELOG.md` will [automatically be generated](https://github.com/rubensworks/manual-git-changelog.js) based on the git commits since last release.
|
|
||||||
The process will _halt_ until you confirm the changes in `CHANGELOG.md`.
|
|
||||||
Before confirming, it is recommended to have a look at this file, move around the commits if needed, and save the file.
|
|
||||||
|
|
||||||
**Note:** The changelog generator will make use of git tags to determine the range commit. While `npm version` will generate a git tag, you can also create one manually if you want to follow a different release process.
|
|
@ -1,11 +0,0 @@
|
|||||||
# Unable to include my component in the config file
|
|
||||||
|
|
||||||
You may be getting an error in the form of:
|
|
||||||
```
|
|
||||||
Error: Invalid components file... Could not expand the JSON-LD shortcut "MyClass". Are all the required modules available and JSON-LD contexts included?'
|
|
||||||
```
|
|
||||||
|
|
||||||
This could have several causes:
|
|
||||||
* The class is not exported from `index.ts`.
|
|
||||||
* The used component name does not correspond to the exported class name.
|
|
||||||
* The class has not been compiled using `npm run build`.
|
|
Loading…
x
Reference in New Issue
Block a user