mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Integrate setup behaviour
This adds options for enabling setup to the config folder. All default configs with permanent storage (file/sparql) are configured to require setup at server start. Memory-based configs merely have it as an option.
This commit is contained in:
parent
4e1a2f5981
commit
b592d449eb
@ -8,4 +8,15 @@ This is the entry point to the main server setup.
|
|||||||
|
|
||||||
## Init
|
## Init
|
||||||
Contains a list of initializer that need to be run when starting the server.
|
Contains a list of initializer that need to be run when starting the server.
|
||||||
* *default*: The default setup that makes sure the root container has the necessary resources.
|
* *default*: The default setup. The ParallelHandler can be used to add custom Initializers.
|
||||||
|
* *initialize-root*: Makes sure the root container has the necessary resources to function properly.
|
||||||
|
This is only relevant if setup is disabled but root container access is still required.
|
||||||
|
* *initialize-prefilled-root*: Similar to `initialize-root` but adds some introductory resources to the root container.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
Handles the setup page the first time the server is started.
|
||||||
|
* *disabled*: Disables the setup page. Root container access will be impossible unless handled by the Init config above.
|
||||||
|
Registration and pod creation is still possible if that feature is enabled.
|
||||||
|
* *optional*: Setup is available at `/setup` but the server can already be used.
|
||||||
|
Everyone can access the setup page so make sure to complete that as soon as possible.
|
||||||
|
* *required*: All requests will be redirected to the setup page until setup is completed.
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/init/base/init.json",
|
"files-scs:config/app/init/base/init.json"
|
||||||
"files-scs:config/app/init/initializers/root.json"
|
|
||||||
],
|
],
|
||||||
"@graph": [
|
"@graph": [
|
||||||
{
|
{
|
||||||
@ -10,7 +9,10 @@
|
|||||||
"@id": "urn:solid-server:default:ParallelInitializer",
|
"@id": "urn:solid-server:default:ParallelInitializer",
|
||||||
"@type": "ParallelHandler",
|
"@type": "ParallelHandler",
|
||||||
"handlers": [
|
"handlers": [
|
||||||
{ "@id": "urn:solid-server:default:RootInitializer" }
|
{
|
||||||
|
"comment": "This handler is here because having this array empty gives Components.js errors.",
|
||||||
|
"@type": "StaticHandler"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
17
config/app/init/initialize-prefilled-root.json
Normal file
17
config/app/init/initialize-prefilled-root.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/init/base/init.json",
|
||||||
|
"files-scs:config/app/init/initializers/prefilled-root.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "These handlers are called whenever the server is started, and can be used to ensure that all necessary resources for booting are available.",
|
||||||
|
"@id": "urn:solid-server:default:ParallelInitializer",
|
||||||
|
"@type": "ParallelHandler",
|
||||||
|
"handlers": [
|
||||||
|
{ "@id": "urn:solid-server:default:RootInitializer" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
17
config/app/init/initialize-root.json
Normal file
17
config/app/init/initialize-root.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/init/base/init.json",
|
||||||
|
"files-scs:config/app/init/initializers/root.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "These handlers are called whenever the server is started, and can be used to ensure that all necessary resources for booting are available.",
|
||||||
|
"@id": "urn:solid-server:default:ParallelInitializer",
|
||||||
|
"@type": "ParallelHandler",
|
||||||
|
"handlers": [
|
||||||
|
{ "@id": "urn:solid-server:default:RootInitializer" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
18
config/app/init/initializers/prefilled-root.json
Normal file
18
config/app/init/initializers/prefilled-root.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "Makes sure the root container exists and contains the necessary resources.",
|
||||||
|
"@id": "urn:solid-server:default:RootInitializer",
|
||||||
|
"@type": "RootInitializer",
|
||||||
|
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
|
"store": { "@id": "urn:solid-server:default:ResourceStore" },
|
||||||
|
"generator": {
|
||||||
|
"@type": "TemplatedResourcesGenerator",
|
||||||
|
"templateFolder": "@css:templates/root/prefilled",
|
||||||
|
"factory": { "@type": "ExtensionBasedMapperFactory" },
|
||||||
|
"templateEngine": { "@type": "HandlebarsTemplateEngine" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -9,7 +9,7 @@
|
|||||||
"store": { "@id": "urn:solid-server:default:ResourceStore" },
|
"store": { "@id": "urn:solid-server:default:ResourceStore" },
|
||||||
"generator": {
|
"generator": {
|
||||||
"@type": "TemplatedResourcesGenerator",
|
"@type": "TemplatedResourcesGenerator",
|
||||||
"templateFolder": "@css:templates/root",
|
"templateFolder": "@css:templates/root/empty",
|
||||||
"factory": { "@type": "ExtensionBasedMapperFactory" },
|
"factory": { "@type": "ExtensionBasedMapperFactory" },
|
||||||
"templateEngine": { "@type": "HandlebarsTemplateEngine" }
|
"templateEngine": { "@type": "HandlebarsTemplateEngine" }
|
||||||
}
|
}
|
||||||
|
13
config/app/setup/disabled.json
Normal file
13
config/app/setup/disabled.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/init/initializers/root.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "Completely disables the setup page.",
|
||||||
|
"@id": "urn:solid-server:default:SetupHandler",
|
||||||
|
"@type": "UnsupportedAsyncHandler"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
14
config/app/setup/handlers/redirect.json
Normal file
14
config/app/setup/handlers/redirect.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "Redirects all request to the setup.",
|
||||||
|
"@id": "urn:solid-server:default:SetupRedirectHandler",
|
||||||
|
"@type": "RedirectAllHttpHandler",
|
||||||
|
"args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
|
"args_target": "/setup",
|
||||||
|
"args_targetExtractor": { "@id": "urn:solid-server:default:TargetExtractor" },
|
||||||
|
"args_responseWriter": { "@id": "urn:solid-server:default:ResponseWriter" }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
34
config/app/setup/handlers/setup.json
Normal file
34
config/app/setup/handlers/setup.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/init/initializers/root.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "Handles everything related to the first-time server setup.",
|
||||||
|
"@id": "urn:solid-server:default:SetupHttpHandler",
|
||||||
|
"@type": "SetupHttpHandler",
|
||||||
|
"args_requestParser": { "@id": "urn:solid-server:default:RequestParser" },
|
||||||
|
"args_errorHandler": { "@id": "urn:solid-server:default:ErrorHandler" },
|
||||||
|
"args_responseWriter": { "@id": "urn:solid-server:default:ResponseWriter" },
|
||||||
|
"args_initializer": { "@id": "urn:solid-server:default:RootInitializer" },
|
||||||
|
"args_registrationManager": { "@id": "urn:solid-server:default:SetupRegistrationManager" },
|
||||||
|
"args_converter": { "@id": "urn:solid-server:default:RepresentationConverter" },
|
||||||
|
"args_storageKey": "setupCompleted-1.0",
|
||||||
|
"args_storage": { "@id": "urn:solid-server:default:SetupStorage" },
|
||||||
|
"args_viewTemplate": "@css:templates/setup/index.html.ejs",
|
||||||
|
"args_responseTemplate": "@css:templates/setup/response.html.ejs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Separate manager from the RegistrationHandler in case registration is disabled.",
|
||||||
|
"@id": "urn:solid-server:default:SetupRegistrationManager",
|
||||||
|
"@type": "RegistrationManager",
|
||||||
|
"args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
|
"args_webIdSuffix": "/profile/card#me",
|
||||||
|
"args_identifierGenerator": { "@id": "urn:solid-server:default:IdentifierGenerator" },
|
||||||
|
"args_ownershipValidator": { "@id": "urn:solid-server:auth:password:OwnershipValidator" },
|
||||||
|
"args_accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" },
|
||||||
|
"args_podManager": { "@id": "urn:solid-server:default:PodManager" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
24
config/app/setup/optional.json
Normal file
24
config/app/setup/optional.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/setup/handlers/setup.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "Combines both the redirect and the setup.",
|
||||||
|
"@id": "urn:solid-server:default:SetupHandler",
|
||||||
|
"@type": "ConditionalHandler",
|
||||||
|
"storageKey": "setupCompleted-1.0",
|
||||||
|
"storageValue": true,
|
||||||
|
"storage": { "@id": "urn:solid-server:default:SetupStorage" },
|
||||||
|
"source": {
|
||||||
|
"@type": "RouterHandler",
|
||||||
|
"args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
|
"args_targetExtractor": { "@id": "urn:solid-server:default:TargetExtractor" },
|
||||||
|
"args_allowedMethods": [ "*" ],
|
||||||
|
"args_allowedPathNames": [ "/setup" ],
|
||||||
|
"args_handler": { "@id": "urn:solid-server:default:SetupHttpHandler" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
31
config/app/setup/required.json
Normal file
31
config/app/setup/required.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/setup/handlers/redirect.json",
|
||||||
|
"files-scs:config/app/setup/handlers/setup.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "Combines both the redirect and the setup.",
|
||||||
|
"@id": "urn:solid-server:default:SetupHandler",
|
||||||
|
"@type": "ConditionalHandler",
|
||||||
|
"storageKey": "setupCompleted-1.0",
|
||||||
|
"storageValue": true,
|
||||||
|
"storage": { "@id": "urn:solid-server:default:SetupStorage" },
|
||||||
|
"source": {
|
||||||
|
"@type": "WaterfallHandler",
|
||||||
|
"handlers": [
|
||||||
|
{ "@id": "urn:solid-server:default:SetupRedirectHandler" },
|
||||||
|
{
|
||||||
|
"@type": "RouterHandler",
|
||||||
|
"args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
|
"args_targetExtractor": { "@id": "urn:solid-server:default:TargetExtractor" },
|
||||||
|
"args_allowedMethods": [ "*" ],
|
||||||
|
"args_allowedPathNames": [ "/setup" ],
|
||||||
|
"args_handler": { "@id": "urn:solid-server:default:SetupHttpHandler" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-prefilled-root.json",
|
||||||
|
"files-scs:config/app/setup/optional.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/default.json",
|
||||||
|
"files-scs:config/app/setup/required.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/default.json",
|
||||||
|
"files-scs:config/app/setup/required.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
|
|
||||||
|
38
config/file-no-setup.json
Normal file
38
config/file-no-setup.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/main/default.json",
|
||||||
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
|
"files-scs:config/http/handler/default.json",
|
||||||
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
"files-scs:config/http/static/default.json",
|
||||||
|
"files-scs:config/identity/email/default.json",
|
||||||
|
"files-scs:config/identity/handler/default.json",
|
||||||
|
"files-scs:config/identity/ownership/token.json",
|
||||||
|
"files-scs:config/identity/pod/static.json",
|
||||||
|
"files-scs:config/identity/registration/enabled.json",
|
||||||
|
"files-scs:config/ldp/authentication/dpop-bearer.json",
|
||||||
|
"files-scs:config/ldp/authorization/webacl.json",
|
||||||
|
"files-scs:config/ldp/handler/default.json",
|
||||||
|
"files-scs:config/ldp/metadata-parser/default.json",
|
||||||
|
"files-scs:config/ldp/metadata-writer/default.json",
|
||||||
|
"files-scs:config/ldp/permissions/acl.json",
|
||||||
|
"files-scs:config/storage/backend/file.json",
|
||||||
|
"files-scs:config/storage/key-value/resource-store.json",
|
||||||
|
"files-scs:config/storage/middleware/default.json",
|
||||||
|
"files-scs:config/util/auxiliary/acl.json",
|
||||||
|
"files-scs:config/util/identifiers/suffix.json",
|
||||||
|
"files-scs:config/util/index/default.json",
|
||||||
|
"files-scs:config/util/logging/winston.json",
|
||||||
|
"files-scs:config/util/representation-conversion/default.json",
|
||||||
|
"files-scs:config/util/resource-locker/memory.json",
|
||||||
|
"files-scs:config/util/variables/default.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": "A single-pod server that stores its resources on disk."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/default.json",
|
||||||
|
"files-scs:config/app/setup/required.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/init/initializers/root.json"
|
||||||
|
],
|
||||||
"@graph": [
|
"@graph": [
|
||||||
{
|
{
|
||||||
"comment": "These are all the handlers a request will go through until it is handled.",
|
"comment": "These are all the handlers a request will go through until it is handled.",
|
||||||
@ -11,6 +14,7 @@
|
|||||||
"@type": "WaterfallHandler",
|
"@type": "WaterfallHandler",
|
||||||
"handlers": [
|
"handlers": [
|
||||||
{ "@id": "urn:solid-server:default:StaticAssetHandler" },
|
{ "@id": "urn:solid-server:default:StaticAssetHandler" },
|
||||||
|
{ "@id": "urn:solid-server:default:SetupHandler" },
|
||||||
{ "@id": "urn:solid-server:default:IdentityProviderHandler" },
|
{ "@id": "urn:solid-server:default:IdentityProviderHandler" },
|
||||||
{ "@id": "urn:solid-server:default:LdpHandler" }
|
{ "@id": "urn:solid-server:default:LdpHandler" }
|
||||||
]
|
]
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/optional.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
41
config/sparql-endpoint-no-setup.json
Normal file
41
config/sparql-endpoint-no-setup.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/main/default.json",
|
||||||
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
|
"files-scs:config/http/handler/default.json",
|
||||||
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
"files-scs:config/http/static/default.json",
|
||||||
|
"files-scs:config/identity/email/default.json",
|
||||||
|
"files-scs:config/identity/handler/default.json",
|
||||||
|
"files-scs:config/identity/ownership/token.json",
|
||||||
|
"files-scs:config/identity/pod/static.json",
|
||||||
|
"files-scs:config/identity/registration/enabled.json",
|
||||||
|
"files-scs:config/ldp/authentication/dpop-bearer.json",
|
||||||
|
"files-scs:config/ldp/authorization/webacl.json",
|
||||||
|
"files-scs:config/ldp/handler/default.json",
|
||||||
|
"files-scs:config/ldp/metadata-parser/default.json",
|
||||||
|
"files-scs:config/ldp/metadata-writer/default.json",
|
||||||
|
"files-scs:config/ldp/permissions/acl.json",
|
||||||
|
"files-scs:config/storage/backend/sparql.json",
|
||||||
|
"files-scs:config/storage/key-value/memory.json",
|
||||||
|
"files-scs:config/storage/middleware/default.json",
|
||||||
|
"files-scs:config/util/auxiliary/acl.json",
|
||||||
|
"files-scs:config/util/identifiers/suffix.json",
|
||||||
|
"files-scs:config/util/index/default.json",
|
||||||
|
"files-scs:config/util/logging/winston.json",
|
||||||
|
"files-scs:config/util/representation-conversion/default.json",
|
||||||
|
"files-scs:config/util/resource-locker/memory.json",
|
||||||
|
"files-scs:config/util/variables/default.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"comment": [
|
||||||
|
"A single-pod server that stores its resources in a SPARQL endpoint.",
|
||||||
|
"This server only supports RDF data. For this reason it can not use its resource store for internal key/value storage."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/default.json",
|
||||||
|
"files-scs:config/app/setup/required.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
@ -28,6 +28,11 @@
|
|||||||
"comment": "Storage used for account management.",
|
"comment": "Storage used for account management.",
|
||||||
"@id": "urn:solid-server:default:AccountStorage",
|
"@id": "urn:solid-server:default:AccountStorage",
|
||||||
"@type": "MemoryMapStorage"
|
"@type": "MemoryMapStorage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Storage used by setup components.",
|
||||||
|
"@id": "urn:solid-server:default:SetupStorage",
|
||||||
|
"@type": "MemoryMapStorage"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,14 @@
|
|||||||
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
"container": "/.internal/accounts/"
|
"container": "/.internal/accounts/"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"comment": "Storage used by setup components.",
|
||||||
|
"@id": "urn:solid-server:default:SetupStorage",
|
||||||
|
"@type": "JsonResourceStorage",
|
||||||
|
"source": { "@id": "urn:solid-server:default:ResourceStore" },
|
||||||
|
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
||||||
|
"container": "/.internal/setup/"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"comment": "Block external access to the storage containers to avoid exposing internal data.",
|
"comment": "Block external access to the storage containers to avoid exposing internal data.",
|
||||||
"@id": "urn:solid-server:default:PathBasedAuthorizer",
|
"@id": "urn:solid-server:default:PathBasedAuthorizer",
|
||||||
|
@ -317,6 +317,7 @@ export * from './util/handlers/BooleanHandler';
|
|||||||
export * from './util/handlers/ConditionalHandler';
|
export * from './util/handlers/ConditionalHandler';
|
||||||
export * from './util/handlers/ParallelHandler';
|
export * from './util/handlers/ParallelHandler';
|
||||||
export * from './util/handlers/SequenceHandler';
|
export * from './util/handlers/SequenceHandler';
|
||||||
|
export * from './util/handlers/StaticHandler';
|
||||||
export * from './util/handlers/UnsupportedAsyncHandler';
|
export * from './util/handlers/UnsupportedAsyncHandler';
|
||||||
export * from './util/handlers/WaterfallHandler';
|
export * from './util/handlers/WaterfallHandler';
|
||||||
|
|
||||||
|
22
src/util/handlers/StaticHandler.ts
Normal file
22
src/util/handlers/StaticHandler.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { AsyncHandler } from './AsyncHandler';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler that always resolves and always returns the stored value.
|
||||||
|
* Will return undefined if no value is stored.
|
||||||
|
*
|
||||||
|
* The generic type extends `any` due to Components.js requirements.
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
|
||||||
|
export class StaticHandler<T extends any = void> extends AsyncHandler<any, T> {
|
||||||
|
private readonly value?: T;
|
||||||
|
|
||||||
|
public constructor(value?: T) {
|
||||||
|
super();
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handle(): Promise<T> {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||||
|
return this.value!;
|
||||||
|
}
|
||||||
|
}
|
203
templates/identity/email-password/register-partial.html.ejs
Normal file
203
templates/identity/email-password/register-partial.html.ejs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<% const isBlankForm = !('prefilled' in locals); %>
|
||||||
|
<% prefilled = locals.prefilled || {}; %>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Your WebID</legend>
|
||||||
|
<p>
|
||||||
|
A <em>WebID</em> is a unique identifier for you
|
||||||
|
in the form of a URL.
|
||||||
|
<br>
|
||||||
|
You WebID lets you log in to Solid apps
|
||||||
|
and access non-public data in Pods.
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" id="createWebIdOn" name="createWebId" value="on"<%
|
||||||
|
if (isBlankForm || prefilled.createWebId) { %> checked<% } %>>
|
||||||
|
Create a new WebID for my Pod.
|
||||||
|
</label>
|
||||||
|
<p id="createWebIdForm">
|
||||||
|
Please also create a Pod below, since your WebID will be stored there.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" id="createWebIdOff" name="createWebId" value=""<%
|
||||||
|
if (!isBlankForm && !prefilled.createWebId) { %> checked<% } %>>
|
||||||
|
Use my existing WebID to access my Pod.
|
||||||
|
</label>
|
||||||
|
<ol id="existingWebIdForm">
|
||||||
|
<li>
|
||||||
|
<label for="webId">Existing WebID:</label>
|
||||||
|
<input id="webId" type="text" name="webId" value="<%= prefilled.webId || '' %>">
|
||||||
|
</li>
|
||||||
|
<li class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="register" name="register"<%
|
||||||
|
if (isBlankForm || prefilled.register) { %> checked<% } %>>
|
||||||
|
Use my new account to log in with this WebID.
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Your Pod</legend>
|
||||||
|
<p>
|
||||||
|
A Pod is a place to store your data.
|
||||||
|
<br>
|
||||||
|
If you create a new WebID, you must also create a Pod to store that WebID.
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="createPod" name="createPod"<%
|
||||||
|
if (isBlankForm || prefilled.createPod) { %> checked<% } %>>
|
||||||
|
Create a new Pod with my WebID as owner
|
||||||
|
</label>
|
||||||
|
<ol id="createPodForm">
|
||||||
|
<li class="radio" id="rootPodOnForm">
|
||||||
|
<label>
|
||||||
|
<input type="radio" id="rootPodOn" name="rootPod" value="on"<%
|
||||||
|
if (locals.allowRoot && (isBlankForm || prefilled.rootPod)) { %> checked<% } %>>
|
||||||
|
... in the root.
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<li class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" id="rootPodOff" name="rootPod" value=""<%
|
||||||
|
if (!locals.allowRoot || (!isBlankForm && !prefilled.rootPod)) { %> checked<% } %>>
|
||||||
|
... in its own namespace.
|
||||||
|
</label>
|
||||||
|
<ol id="podNameForm">
|
||||||
|
<li>
|
||||||
|
<label for="podName">Pod name:</label>
|
||||||
|
<input id="podName" type="text" name="podName" value="<%= prefilled.podName || '' %>">
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Your account</legend>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Choose the credentials you want to use to log in to this server in the future.
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<label for="email">Email:</label>
|
||||||
|
<input id="email" type="text" name="email" value="<%= prefilled.email || '' %>" >
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<ol id="passwordForm">
|
||||||
|
<li>
|
||||||
|
<label for="password">Password:</label>
|
||||||
|
<input id="password" type="password" name="password">
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label for="confirmPassword">Confirm password:</label>
|
||||||
|
<input id="confirmPassword" type="password" name="confirmPassword">
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div id="noPasswordForm" class="hidden">
|
||||||
|
<p>
|
||||||
|
Since you will be using your existing WebID setup to access your pod,
|
||||||
|
<br>
|
||||||
|
you do <em>not</em> need to set a password.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Assist the user with filling out the form by hiding irrelevant fields
|
||||||
|
(() => {
|
||||||
|
// Wire up the UI elements
|
||||||
|
const elements = {};
|
||||||
|
[
|
||||||
|
'createWebIdOn', 'createWebIdOff', 'createWebIdForm', 'existingWebIdForm', 'webId',
|
||||||
|
'createPod', 'createPodForm', 'rootPodOnForm', 'rootPodOn', 'rootPodOff', 'podNameForm', 'podName',
|
||||||
|
'register', 'passwordForm', 'noPasswordForm',
|
||||||
|
].forEach(id => {
|
||||||
|
elements[id] = document.getElementById(id);
|
||||||
|
elements[id].addEventListener('change', updateUI);
|
||||||
|
});
|
||||||
|
elements.mainForm = document.getElementById('<%= formId %>');
|
||||||
|
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
// Updates the UI when something has changed
|
||||||
|
function updateUI({ srcElement } = {}) {
|
||||||
|
// When Pod creation is required, automatically tick the corresponding checkbox
|
||||||
|
if (elements.createWebIdOn.checked)
|
||||||
|
elements.createPod.checked = true;
|
||||||
|
elements.createPod.disabled = elements.createWebIdOn.checked;
|
||||||
|
|
||||||
|
// Hide irrelevant fields
|
||||||
|
setVisibility('createWebIdForm', elements.createWebIdOn.checked);
|
||||||
|
setVisibility('existingWebIdForm', elements.createWebIdOff.checked);
|
||||||
|
setVisibility('createPodForm', elements.createPod.checked);
|
||||||
|
setVisibility('rootPodOnForm', <%= locals.allowRoot %>);
|
||||||
|
setVisibility('podNameForm', elements.rootPodOff.checked);
|
||||||
|
setVisibility('passwordForm', elements.createWebIdOn.checked || elements.register.checked);
|
||||||
|
setVisibility('noPasswordForm', !isVisible('passwordForm'));
|
||||||
|
|
||||||
|
// If child elements have just been activated, focus on them
|
||||||
|
if (srcElement?.checked) {
|
||||||
|
switch(document.activeElement) {
|
||||||
|
case elements.createWebIdOff:
|
||||||
|
const { webId } = elements;
|
||||||
|
webId.value = webId.value.startsWith('http') ? webId.value : 'https://';
|
||||||
|
webId.focus();
|
||||||
|
break;
|
||||||
|
case elements.createPod:
|
||||||
|
if (elements.rootPodOn.checked) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case elements.rootPodOff:
|
||||||
|
elements.podName.focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether the given element is visible
|
||||||
|
function isVisible(element) {
|
||||||
|
return !(elements[element] ?? element).classList.contains('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the visibility of the given element
|
||||||
|
function setVisibility(element, visible) {
|
||||||
|
// Show or hide the element
|
||||||
|
element = elements[element] ?? element;
|
||||||
|
element.classList[visible ? 'remove' : 'add']('hidden');
|
||||||
|
|
||||||
|
// Disable children of hidden elements,
|
||||||
|
// such that the browser does not expect input for them
|
||||||
|
for (const child of getDescendants(element)) {
|
||||||
|
if ('disabled' in child)
|
||||||
|
child.disabled = !visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtains all children, grandchildren, etc. of the given element
|
||||||
|
function getDescendants(element) {
|
||||||
|
return [...element.querySelectorAll("*")];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: take form id as input?
|
||||||
|
// Enable all elements on form submission (otherwise their value is not submitted)
|
||||||
|
elements.mainForm.addEventListener('submit', () => {
|
||||||
|
for (const child of getDescendants(elements.mainForm))
|
||||||
|
child.disabled = false;
|
||||||
|
});
|
||||||
|
elements.mainForm.addEventListener('formdata', updateUI);
|
||||||
|
})();
|
||||||
|
</script>
|
@ -0,0 +1,38 @@
|
|||||||
|
<% if (createPod) { %>
|
||||||
|
<h2>Your new Pod</h2>
|
||||||
|
<p>
|
||||||
|
Your new Pod is located at <a href="<%= podBaseUrl %>" class="link"><%= podBaseUrl %></a>.
|
||||||
|
<br>
|
||||||
|
You can store your documents and data there.
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (createWebId) { %>
|
||||||
|
<h2>Your new WebID</h2>
|
||||||
|
<p>
|
||||||
|
Your new WebID is <a href="<%= webId %>" class="link"><%= webId %></a>.
|
||||||
|
<br>
|
||||||
|
You can use this identifier to interact with Solid pods and apps.
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (register) { %>
|
||||||
|
<h2>Your new account</h2>
|
||||||
|
<p>
|
||||||
|
Via your email address <em><%= email %></em>,
|
||||||
|
<% if (authenticating) { %>
|
||||||
|
you can now <a href="<%= controls.login %>">log in</a>
|
||||||
|
<% } else { %>
|
||||||
|
this server lets you log in to Solid apps
|
||||||
|
<% } %>
|
||||||
|
with your WebID <a href="<%= webId %>" class="link"><%= webId %></a>
|
||||||
|
</p>
|
||||||
|
<% if (!createWebId) { %>
|
||||||
|
<p>
|
||||||
|
You will need to add the triple
|
||||||
|
<code><%= `<${webId}> <http://www.w3.org/ns/solid/terms#oidcIssuer> <${oidcIssuer}>.`%></code>
|
||||||
|
to your existing WebID document <em><%= webId %></em>
|
||||||
|
to indicate that you trust this server as a login provider.
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
@ -4,41 +4,4 @@
|
|||||||
We wish you an exciting experience!
|
We wish you an exciting experience!
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<% if (createPod) { %>
|
<%- include('./register-response-partial.html.ejs') %>
|
||||||
<h2>Your new Pod</h2>
|
|
||||||
<p>
|
|
||||||
Your new Pod is located at <a href="<%= podBaseUrl %>" class="link"><%= podBaseUrl %></a>.
|
|
||||||
<br>
|
|
||||||
You can store your documents and data there.
|
|
||||||
</p>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% if (createWebId) { %>
|
|
||||||
<h2>Your new WebID</h2>
|
|
||||||
<p>
|
|
||||||
Your new WebID is <a href="<%= webId %>" class="link"><%= webId %></a>.
|
|
||||||
<br>
|
|
||||||
You can use this identifier to interact with Solid pods and apps.
|
|
||||||
</p>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% if (register) { %>
|
|
||||||
<h2>Your new account</h2>
|
|
||||||
<p>
|
|
||||||
Via your email address <em><%= email %></em>,
|
|
||||||
<% if (authenticating) { %>
|
|
||||||
you can now <a href="<%= controls.login %>">log in</a>
|
|
||||||
<% } else { %>
|
|
||||||
this server lets you log in to Solid apps
|
|
||||||
<% } %>
|
|
||||||
with your WebID <a href="<%= webId %>" class="link"><%= webId %></a>
|
|
||||||
</p>
|
|
||||||
<% if (!createWebId) { %>
|
|
||||||
<p>
|
|
||||||
You will need to add the triple
|
|
||||||
<code><%= `<${webId}> <http://www.w3.org/ns/solid/terms#oidcIssuer> <${oidcIssuer}>.`%></code>
|
|
||||||
to your existing WebID document <em><%= webId %></em>
|
|
||||||
to indicate that you trust this server as a login provider.
|
|
||||||
</p>
|
|
||||||
<% } %>
|
|
||||||
<% } %>
|
|
||||||
|
@ -1,188 +1,11 @@
|
|||||||
<h1>Sign up</h1>
|
<h1>Sign up</h1>
|
||||||
<form method="post" id="mainForm">
|
<form method="post" id="mainForm">
|
||||||
<% const isBlankForm = !('prefilled' in locals); %>
|
|
||||||
<% prefilled = locals.prefilled || {}; %>
|
|
||||||
|
|
||||||
<% if (locals.message) { %>
|
<% if (locals.message) { %>
|
||||||
<p class="error">Error: <%= message %></p>
|
<p class="error">Error: <%= message %></p>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<fieldset>
|
<%- include('./register-partial.html.ejs', { allowRoot: false, formId: 'mainForm' }) %>
|
||||||
<legend>Your WebID</legend>
|
|
||||||
<p>
|
|
||||||
A <em>WebID</em> is a unique identifier for you
|
|
||||||
in the form of a URL.
|
|
||||||
<br>
|
|
||||||
You WebID lets you log in to Solid apps
|
|
||||||
and access non-public data in Pods.
|
|
||||||
</p>
|
|
||||||
<ol>
|
|
||||||
<li class="radio">
|
|
||||||
<label>
|
|
||||||
<input type="radio" id="createWebIdOn" name="createWebId" value="on"<%
|
|
||||||
if (isBlankForm || prefilled.createWebId) { %> checked<% } %>>
|
|
||||||
Create a new WebID for my Pod.
|
|
||||||
</label>
|
|
||||||
<p id="createWebIdForm">
|
|
||||||
Please also create a Pod below, since your WebID will be stored there.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li class="radio">
|
|
||||||
<label>
|
|
||||||
<input type="radio" id="createWebIdOff" name="createWebId" value=""<%
|
|
||||||
if (!isBlankForm && !prefilled.createWebId) { %> checked<% } %>>
|
|
||||||
Use my existing WebID to access my Pod.
|
|
||||||
</label>
|
|
||||||
<ol id="existingWebIdForm">
|
|
||||||
<li>
|
|
||||||
<label for="webId">Existing WebID:</label>
|
|
||||||
<input id="webId" type="text" name="webId" value="<%= prefilled.webId || '' %>">
|
|
||||||
</li>
|
|
||||||
<li class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="register" name="register"<%
|
|
||||||
if (isBlankForm || prefilled.register) { %> checked<% } %>>
|
|
||||||
Use my new account to log in with this WebID.
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Your Pod</legend>
|
|
||||||
<p>
|
|
||||||
A Pod is a place to store your data.
|
|
||||||
<br>
|
|
||||||
If you create a new WebID, you must also create a Pod to store that WebID.
|
|
||||||
</p>
|
|
||||||
<ol>
|
|
||||||
<li class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="createPod" name="createPod"<%
|
|
||||||
if (isBlankForm || prefilled.createPod) { %> checked<% } %>>
|
|
||||||
Create a new Pod with my WebID as owner.
|
|
||||||
</label>
|
|
||||||
<ol id="createPodForm">
|
|
||||||
<li>
|
|
||||||
<label for="podName">Pod name:</label>
|
|
||||||
<input id="podName" type="text" name="podName" value="<%= prefilled.podName || '' %>">
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Your account</legend>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
Choose the credentials you want to use to log in to this server in the future.
|
|
||||||
</p>
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
<label for="email">Email:</label>
|
|
||||||
<input id="email" type="text" name="email" value="<%= prefilled.email || '' %>" >
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
<ol id="passwordForm">
|
|
||||||
<li>
|
|
||||||
<label for="password">Password:</label>
|
|
||||||
<input id="password" type="password" name="password">
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="confirmPassword">Confirm password:</label>
|
|
||||||
<input id="confirmPassword" type="password" name="confirmPassword">
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
<div id="noPasswordForm" class="hidden">
|
|
||||||
<p>
|
|
||||||
Since you will be using your existing WebID setup to access your pod,
|
|
||||||
<br>
|
|
||||||
you do <em>not</em> need to set a password.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<p class="actions"><button type="submit" name="submit">Sign up</button></p>
|
<p class="actions"><button type="submit" name="submit">Sign up</button></p>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<script>
|
|
||||||
// Assist the user with filling out the form by hiding irrelevant fields
|
|
||||||
(() => {
|
|
||||||
// Wire up the UI elements
|
|
||||||
const elements = {};
|
|
||||||
[
|
|
||||||
'createWebIdOn', 'createWebIdOff', 'createWebIdForm', 'existingWebIdForm', 'webId',
|
|
||||||
'createPod', 'createPodForm', 'podName',
|
|
||||||
'register', 'passwordForm', 'noPasswordForm', 'mainForm',
|
|
||||||
].forEach(id => {
|
|
||||||
elements[id] = document.getElementById(id);
|
|
||||||
elements[id].addEventListener('change', updateUI);
|
|
||||||
});
|
|
||||||
updateUI();
|
|
||||||
mainForm.classList.add('loaded');
|
|
||||||
|
|
||||||
// Updates the UI when something has changed
|
|
||||||
function updateUI({ srcElement } = {}) {
|
|
||||||
// When Pod creation is required, automatically tick the corresponding checkbox
|
|
||||||
if (elements.createWebIdOn.checked)
|
|
||||||
elements.createPod.checked = true;
|
|
||||||
elements.createPod.disabled = elements.createWebIdOn.checked;
|
|
||||||
|
|
||||||
// Hide irrelevant fields
|
|
||||||
setVisibility('createWebIdForm', elements.createWebIdOn.checked);
|
|
||||||
setVisibility('existingWebIdForm', elements.createWebIdOff.checked);
|
|
||||||
setVisibility('createPodForm', elements.createPod.checked);
|
|
||||||
setVisibility('passwordForm', elements.createWebIdOn.checked || elements.register.checked);
|
|
||||||
setVisibility('noPasswordForm', !isVisible('passwordForm'));
|
|
||||||
|
|
||||||
// If child elements have just been activated, focus on them
|
|
||||||
if (srcElement?.checked) {
|
|
||||||
switch(document.activeElement) {
|
|
||||||
case elements.createWebIdOff:
|
|
||||||
const { webId } = elements;
|
|
||||||
webId.value = webId.value.startsWith('http') ? webId.value : 'https://';
|
|
||||||
webId.focus();
|
|
||||||
break;
|
|
||||||
case elements.createPod:
|
|
||||||
elements.podName.focus();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks whether the given element is visible
|
|
||||||
function isVisible(element) {
|
|
||||||
return !(elements[element] ?? element).classList.contains('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the visibility of the given element
|
|
||||||
function setVisibility(element, visible) {
|
|
||||||
// Show or hide the element
|
|
||||||
element = elements[element] ?? element;
|
|
||||||
element.classList[visible ? 'remove' : 'add']('hidden');
|
|
||||||
|
|
||||||
// Disable children of hidden elements,
|
|
||||||
// such that the browser does not expect input for them
|
|
||||||
for (const child of getDescendants(element)) {
|
|
||||||
if ('disabled' in child)
|
|
||||||
child.disabled = !visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtains all children, grandchildren, etc. of the given element
|
|
||||||
function getDescendants(element) {
|
|
||||||
return [...element.querySelectorAll("*")];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable all elements on form submission (otherwise their value is not submitted)
|
|
||||||
elements.mainForm.addEventListener('submit', () => {
|
|
||||||
for (const child of getDescendants(elements.mainForm))
|
|
||||||
child.disabled = false;
|
|
||||||
});
|
|
||||||
elements.mainForm.addEventListener('formdata', updateUI);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
|
# Root ACL resource generated by the Community Server to allow public access
|
||||||
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
||||||
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
|
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
|
||||||
|
|
||||||
<#authorization>
|
<#authorization>
|
||||||
a acl:Authorization;
|
a acl:Authorization;
|
||||||
acl:agentClass foaf:Agent;
|
acl:agentClass foaf:Agent;
|
||||||
acl:mode acl:Read;
|
acl:mode acl:Read, acl:Write, acl:Append, acl:Control;
|
||||||
acl:mode acl:Write;
|
|
||||||
acl:mode acl:Append;
|
|
||||||
acl:mode acl:Delete;
|
|
||||||
acl:mode acl:Control;
|
|
||||||
acl:accessTo <./>;
|
acl:accessTo <./>;
|
||||||
acl:default <./>.
|
acl:default <./>.
|
10
templates/root/prefilled/.acl
Normal file
10
templates/root/prefilled/.acl
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Root ACL resource generated by the Community Server to allow public access
|
||||||
|
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
|
||||||
|
|
||||||
|
<#authorization>
|
||||||
|
a acl:Authorization;
|
||||||
|
acl:agentClass foaf:Agent;
|
||||||
|
acl:mode acl:Read, acl:Write, acl:Append, acl:Control;
|
||||||
|
acl:accessTo <./>;
|
||||||
|
acl:default <./>.
|
7
templates/root/prefilled/.meta
Normal file
7
templates/root/prefilled/.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@prefix pim: <http://www.w3.org/ns/pim/space#>.
|
||||||
|
|
||||||
|
# It is imperative the root container is marked as a pim:Storage :
|
||||||
|
# Solid, §4.1: "Servers exposing the storage resource MUST advertise by including the HTTP Link header
|
||||||
|
# with rel="type" targeting http://www.w3.org/ns/pim/space#Storage when responding to storage’s request URI."
|
||||||
|
# https://solid.github.io/specification/protocol#storage
|
||||||
|
<> a pim:Storage.
|
@ -59,7 +59,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Prevent public write and control access to the root Pod
|
Prevent public write and control access to the root Pod
|
||||||
by modifying <a href=".acl"><code>.acl</code></a>.
|
by modifying <a href="../../../.acl"><code>.acl</code></a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Disable Pod registration
|
Disable Pod registration
|
88
templates/setup/index.html.ejs
Normal file
88
templates/setup/index.html.ejs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<h1>Welcome to Solid</h1>
|
||||||
|
<p>
|
||||||
|
This server implements
|
||||||
|
the <a href="https://solid.github.io/specification/protocol">Solid protocol</a>
|
||||||
|
so you can create your own <a href="https://solidproject.org/about">Solid Pod</a>
|
||||||
|
and identity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="public">Making this server public</h2>
|
||||||
|
<p>
|
||||||
|
Before making this server public,
|
||||||
|
you might want to <strong>disable Pod registration</strong>
|
||||||
|
by <a href="https://github.com/solid/community-server/blob/main/config/identity/README.md">changing
|
||||||
|
the configuration</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="setup">Setting up the server</h2>
|
||||||
|
<p>
|
||||||
|
The <em>default</em> configuration stores data only in memory,
|
||||||
|
so be sure to choose a configuration that saves data to disk.
|
||||||
|
If you are exposing this server publicly,
|
||||||
|
<a href="#public">read the guidelines below</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When using the file-based version of the server,
|
||||||
|
you can easily choose any folder on your disk to use as root.
|
||||||
|
<br>
|
||||||
|
Use the <code>--help</code> switch to learn more.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To make sure the server is set up exactly as you want it,
|
||||||
|
please fill in the form below.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In case you want to automate the server initialization and want to get rid of this setup screen,
|
||||||
|
update your config with new imports from <code>config/app/setup/</code> and possibly <code>config/app/init/</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form method="post" id="mainForm">
|
||||||
|
<% const safePrefilled = locals.prefilled || {}; %>
|
||||||
|
|
||||||
|
<% if (locals.message) { %>
|
||||||
|
<p class="error"><%= message %></p>
|
||||||
|
<% } %>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Choose options</legend>
|
||||||
|
<ol>
|
||||||
|
<li class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="initialize" name="initialize" checked>
|
||||||
|
Allow access to the root container.
|
||||||
|
</label>
|
||||||
|
<p>
|
||||||
|
This defaults to public access for everyone.
|
||||||
|
Disabling this makes it impossible to access the root container and add resources,
|
||||||
|
but new pods can still be created through registration,
|
||||||
|
which is ideal if you only want data to be edited in the pods.
|
||||||
|
This option is irrelevant when creating a root pod with the option below.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="registration" name="registration" checked>
|
||||||
|
Provision a pod, create a WebID, and/or register an identity.
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="registrationForm">
|
||||||
|
<%- include('../identity/email-password/register-partial.html.ejs', { allowRoot: true, formId: 'mainForm' }) %>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<p class="actions"><button type="submit" name="submit">Submit</button></p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const registrationCheckbox = document.getElementById('registration');
|
||||||
|
registrationCheckbox.addEventListener('change', updateUI);
|
||||||
|
const registrationForm = document.getElementById('registrationForm');
|
||||||
|
|
||||||
|
function updateUI() {
|
||||||
|
const visible = registrationCheckbox.checked;
|
||||||
|
registrationForm.classList[visible ? 'remove' : 'add']('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUI();
|
||||||
|
</script>
|
24
templates/setup/response.html.ejs
Normal file
24
templates/setup/response.html.ejs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<h1 id="public">Server successfully set up</h1>
|
||||||
|
|
||||||
|
<% if (initialize && !registration) { %>
|
||||||
|
<p>
|
||||||
|
You have chosen to allow the root container to be accessible.
|
||||||
|
Prevent public write and control access to the root
|
||||||
|
by modifying <a href=".acl"><code>.acl</code></a>.
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (registration) { %>
|
||||||
|
<%- include('../identity/email-password/register-response-partial.html.ejs', { authenticating: false }) %>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<h2>Have a wonderful Solid experience</h2>
|
||||||
|
<p>
|
||||||
|
<strong>Learn more about Solid
|
||||||
|
at <a href="https://solidproject.org/">solidproject.org</a>.</strong>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
You are warmly invited
|
||||||
|
to <a href="https://github.com/solid/community-server/discussions">share your experiences</a>
|
||||||
|
and to <a href="https://github.com/solid/community-server/issues">report any bugs</a> you encounter.
|
||||||
|
</p>
|
@ -72,13 +72,6 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
|
|||||||
expect(response.headers.get('link')).toContain(`<${PIM.Storage}>; rel="type"`);
|
expect(response.headers.get('link')).toContain(`<${PIM.Storage}>; rel="type"`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can read the root container index page when asking for HTML.', async(): Promise<void> => {
|
|
||||||
const response = await getResource(baseUrl, { accept: 'text/html' }, { contentType: 'text/html' });
|
|
||||||
|
|
||||||
await expect(response.text()).resolves.toContain('Welcome to Solid');
|
|
||||||
expect(response.headers.get('link')).toContain(`<${PIM.Storage}>; rel="type"`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can read a container listing with a query string.', async(): Promise<void> => {
|
it('can read a container listing with a query string.', async(): Promise<void> => {
|
||||||
// Helper functions would fail due to query params
|
// Helper functions would fail due to query params
|
||||||
const response = await fetch(`${baseUrl}?abc=def&xyz`, { headers: { accept: 'text/turtle' }});
|
const response = await fetch(`${baseUrl}?abc=def&xyz`, { headers: { accept: 'text/turtle' }});
|
||||||
@ -92,9 +85,6 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
|
|||||||
const quads = parser.parse(await response.text());
|
const quads = parser.parse(await response.text());
|
||||||
const store = new Store(quads);
|
const store = new Store(quads);
|
||||||
expect(store.countQuads(namedNode(baseUrl), RDF.terms.type, LDP.terms.Container, null)).toBe(1);
|
expect(store.countQuads(namedNode(baseUrl), RDF.terms.type, LDP.terms.Container, null)).toBe(1);
|
||||||
const contains = store.getObjects(namedNode(baseUrl), LDP.terms.contains, null);
|
|
||||||
expect(contains).toHaveLength(1);
|
|
||||||
expect(contains[0].value).toBe(`${baseUrl}index.html`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can add a document to the store, read it and delete it.', async(): Promise<void> => {
|
it('can add a document to the store, read it and delete it.', async(): Promise<void> => {
|
||||||
|
117
test/integration/Setup.test.ts
Normal file
117
test/integration/Setup.test.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import fetch from 'cross-fetch';
|
||||||
|
import type { App } from '../../src/init/App';
|
||||||
|
import { joinUrl } from '../../src/util/PathUtil';
|
||||||
|
import { getPort } from '../util/Util';
|
||||||
|
import { getDefaultVariables, getTestConfigPath, instantiateFromConfig } from './Config';
|
||||||
|
|
||||||
|
const port = getPort('SetupMemory');
|
||||||
|
const baseUrl = `http://localhost:${port}/`;
|
||||||
|
|
||||||
|
// Some tests with real Requests/Responses until the mocking library has been removed from the tests
|
||||||
|
describe('A Solid server with setup', (): void => {
|
||||||
|
const email = 'test@test.email';
|
||||||
|
const password = 'password!';
|
||||||
|
const podName = 'test';
|
||||||
|
const setupUrl = joinUrl(baseUrl, '/setup');
|
||||||
|
let app: App;
|
||||||
|
|
||||||
|
// `beforeEach` since the server needs to restart to reset setup
|
||||||
|
beforeEach(async(): Promise<void> => {
|
||||||
|
const instances = await instantiateFromConfig(
|
||||||
|
'urn:solid-server:test:Instances',
|
||||||
|
getTestConfigPath('setup-memory.json'),
|
||||||
|
getDefaultVariables(port, baseUrl),
|
||||||
|
) as Record<string, any>;
|
||||||
|
({ app } = instances);
|
||||||
|
await app.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async(): Promise<void> => {
|
||||||
|
await app.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('catches all requests.', async(): Promise<void> => {
|
||||||
|
let res = await fetch(baseUrl, { method: 'GET', headers: { accept: 'text/html' }});
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('Welcome to Solid');
|
||||||
|
|
||||||
|
res = await fetch(joinUrl(baseUrl, '/random/path/'), { method: 'GET', headers: { accept: 'text/html' }});
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('Welcome to Solid');
|
||||||
|
|
||||||
|
res = await fetch(joinUrl(baseUrl, '/random/path/'), { method: 'PUT', headers: { accept: 'text/html' }});
|
||||||
|
expect(res.status).toBe(405);
|
||||||
|
await expect(res.text()).resolves.toContain('Welcome to Solid');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create a server that disables root but allows registration.', async(): Promise<void> => {
|
||||||
|
let res = await fetch(setupUrl, { method: 'POST', headers: { accept: 'text/html' }});
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('Server successfully set up');
|
||||||
|
|
||||||
|
// Root access disabled
|
||||||
|
res = await fetch(baseUrl);
|
||||||
|
expect(res.status).toBe(403);
|
||||||
|
|
||||||
|
// Registration still possible
|
||||||
|
const registerParams = { email, podName, password, confirmPassword: password, createWebId: true };
|
||||||
|
res = await fetch(joinUrl(baseUrl, 'idp/register'), {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { accept: 'text/html', 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify(registerParams),
|
||||||
|
});
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
|
||||||
|
res = await fetch(joinUrl(baseUrl, podName, '/profile/card'));
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('foaf:PersonalProfileDocument');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create a server with a public root.', async(): Promise<void> => {
|
||||||
|
let res = await fetch(setupUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { accept: 'text/html', 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({ initialize: true }),
|
||||||
|
});
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('Server successfully set up');
|
||||||
|
|
||||||
|
// Root access enabled
|
||||||
|
res = await fetch(baseUrl);
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('<> a <http://www.w3.org/ns/pim/space#Storage>');
|
||||||
|
|
||||||
|
// Root pod registration is never allowed
|
||||||
|
const registerParams = { email, podName, password, confirmPassword: password, createWebId: true, rootPod: true };
|
||||||
|
res = await fetch(joinUrl(baseUrl, 'idp/register'), {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { accept: 'text/html', 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify(registerParams),
|
||||||
|
});
|
||||||
|
expect(res.status).toBe(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create a server with a root pod.', async(): Promise<void> => {
|
||||||
|
const registerParams = { email, podName, password, confirmPassword: password, createWebId: true, rootPod: true };
|
||||||
|
let res = await fetch(setupUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { accept: 'text/html', 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({ registration: true, initialize: true, ...registerParams }),
|
||||||
|
});
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('Server successfully set up');
|
||||||
|
|
||||||
|
// Root profile created
|
||||||
|
res = await fetch(joinUrl(baseUrl, '/profile/card'));
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
await expect(res.text()).resolves.toContain('foaf:PersonalProfileDocument');
|
||||||
|
|
||||||
|
// Pod root is not accessible even though initialize was set to true
|
||||||
|
res = await fetch(joinUrl(baseUrl, 'resource'), {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { accept: 'text/html', 'content-type': 'text/plain' },
|
||||||
|
body: 'random data',
|
||||||
|
});
|
||||||
|
expect(res.status).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
"files-scs:config/http/handler/simple.json",
|
"files-scs:config/http/handler/simple.json",
|
||||||
"files-scs:config/http/middleware/no-websockets.json",
|
"files-scs:config/http/middleware/no-websockets.json",
|
||||||
"files-scs:config/http/server-factory/no-websockets.json",
|
"files-scs:config/http/server-factory/no-websockets.json",
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
"files-scs:config/http/handler/simple.json",
|
"files-scs:config/http/handler/simple.json",
|
||||||
"files-scs:config/http/middleware/no-websockets.json",
|
"files-scs:config/http/middleware/no-websockets.json",
|
||||||
"files-scs:config/http/server-factory/no-websockets.json",
|
"files-scs:config/http/server-factory/no-websockets.json",
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/no-websockets.json",
|
"files-scs:config/http/middleware/no-websockets.json",
|
||||||
"files-scs:config/http/server-factory/no-websockets.json",
|
"files-scs:config/http/server-factory/no-websockets.json",
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/no-websockets.json",
|
"files-scs:config/http/middleware/no-websockets.json",
|
||||||
"files-scs:config/http/server-factory/no-websockets.json",
|
"files-scs:config/http/server-factory/no-websockets.json",
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
"import": [
|
"import": [
|
||||||
"files-scs:config/app/main/default.json",
|
"files-scs:config/app/main/default.json",
|
||||||
"files-scs:config/app/init/default.json",
|
"files-scs:config/app/init/initialize-root.json",
|
||||||
|
"files-scs:config/app/setup/disabled.json",
|
||||||
"files-scs:config/http/handler/default.json",
|
"files-scs:config/http/handler/default.json",
|
||||||
"files-scs:config/http/middleware/websockets.json",
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
"files-scs:config/http/server-factory/websockets.json",
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
45
test/integration/config/setup-memory.json
Normal file
45
test/integration/config/setup-memory.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/app/main/default.json",
|
||||||
|
"files-scs:config/app/init/default.json",
|
||||||
|
"files-scs:config/app/setup/required.json",
|
||||||
|
"files-scs:config/http/handler/default.json",
|
||||||
|
"files-scs:config/http/middleware/websockets.json",
|
||||||
|
"files-scs:config/http/server-factory/websockets.json",
|
||||||
|
"files-scs:config/http/static/default.json",
|
||||||
|
"files-scs:config/identity/email/default.json",
|
||||||
|
"files-scs:config/identity/handler/default.json",
|
||||||
|
"files-scs:config/identity/ownership/token.json",
|
||||||
|
"files-scs:config/identity/pod/static.json",
|
||||||
|
"files-scs:config/identity/registration/enabled.json",
|
||||||
|
"files-scs:config/ldp/authentication/dpop-bearer.json",
|
||||||
|
"files-scs:config/ldp/authorization/webacl.json",
|
||||||
|
"files-scs:config/ldp/handler/default.json",
|
||||||
|
"files-scs:config/ldp/metadata-parser/default.json",
|
||||||
|
"files-scs:config/ldp/metadata-writer/default.json",
|
||||||
|
"files-scs:config/ldp/permissions/acl.json",
|
||||||
|
"files-scs:config/storage/backend/memory.json",
|
||||||
|
"files-scs:config/storage/key-value/resource-store.json",
|
||||||
|
"files-scs:config/storage/middleware/default.json",
|
||||||
|
"files-scs:config/util/auxiliary/acl.json",
|
||||||
|
"files-scs:config/util/identifiers/suffix.json",
|
||||||
|
"files-scs:config/util/index/default.json",
|
||||||
|
"files-scs:config/util/logging/winston.json",
|
||||||
|
"files-scs:config/util/representation-conversion/default.json",
|
||||||
|
"files-scs:config/util/resource-locker/memory.json",
|
||||||
|
"files-scs:config/util/variables/default.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"@id": "urn:solid-server:test:Instances",
|
||||||
|
"@type": "RecordObject",
|
||||||
|
"RecordObject:_record": [
|
||||||
|
{
|
||||||
|
"RecordObject:_record_key": "app",
|
||||||
|
"RecordObject:_record_value": { "@id": "urn:solid-server:default:App" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
18
test/unit/util/handlers/StaticHandler.test.ts
Normal file
18
test/unit/util/handlers/StaticHandler.test.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { StaticHandler } from '../../../../src/util/handlers/StaticHandler';
|
||||||
|
|
||||||
|
describe('A StaticHandler', (): void => {
|
||||||
|
it('can handle everything.', async(): Promise<void> => {
|
||||||
|
const handler = new StaticHandler();
|
||||||
|
await expect(handler.canHandle(null)).resolves.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the stored value.', async(): Promise<void> => {
|
||||||
|
const handler = new StaticHandler('apple');
|
||||||
|
await expect(handler.handle()).resolves.toEqual('apple');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns undefined if there is no stored value.', async(): Promise<void> => {
|
||||||
|
const handler = new StaticHandler();
|
||||||
|
await expect(handler.handle()).resolves.toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
@ -13,6 +13,7 @@ const portNames = [
|
|||||||
'PodCreation',
|
'PodCreation',
|
||||||
'RedisResourceLocker',
|
'RedisResourceLocker',
|
||||||
'ServerFetch',
|
'ServerFetch',
|
||||||
|
'SetupMemory',
|
||||||
'SparqlStorage',
|
'SparqlStorage',
|
||||||
'Subdomains',
|
'Subdomains',
|
||||||
'WebSocketsProtocol',
|
'WebSocketsProtocol',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user