From b592d449ebece81875e37ccc0fe8dfa4a3124a70 Mon Sep 17 00:00:00 2001
From: Joachim Van Herwegen
Date: Wed, 15 Sep 2021 16:56:18 +0200
Subject: [PATCH] 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.
---
config/app/README.md | 13 +-
config/app/init/default.json | 8 +-
.../app/init/initialize-prefilled-root.json | 17 ++
config/app/init/initialize-root.json | 17 ++
.../app/init/initializers/prefilled-root.json | 18 ++
config/app/init/initializers/root.json | 2 +-
config/app/setup/disabled.json | 13 ++
config/app/setup/handlers/redirect.json | 14 ++
config/app/setup/handlers/setup.json | 34 +++
config/app/setup/optional.json | 24 +++
config/app/setup/required.json | 31 +++
config/default.json | 3 +-
config/dynamic.json | 1 +
config/example-https-file.json | 1 +
config/file-no-setup.json | 38 ++++
config/file.json | 1 +
config/http/handler/default.json | 4 +
config/memory-subdomains.json | 3 +-
config/path-routing.json | 3 +-
config/sparql-endpoint-no-setup.json | 41 ++++
config/sparql-endpoint.json | 1 +
config/storage/key-value/memory.json | 5 +
config/storage/key-value/resource-store.json | 8 +
src/index.ts | 1 +
src/util/handlers/StaticHandler.ts | 22 ++
.../email-password/register-partial.html.ejs | 203 ++++++++++++++++++
.../register-response-partial.html.ejs | 38 ++++
.../email-password/register-response.html.ejs | 39 +---
.../identity/email-password/register.html.ejs | 179 +--------------
templates/root/{ => empty}/.acl | 7 +-
templates/root/{ => empty}/.meta | 0
templates/root/prefilled/.acl | 10 +
templates/root/prefilled/.meta | 7 +
templates/root/{ => prefilled}/index.html | 2 +-
templates/setup/index.html.ejs | 88 ++++++++
templates/setup/response.html.ejs | 24 +++
.../integration/LdpHandlerWithoutAuth.test.ts | 10 -
test/integration/Setup.test.ts | 117 ++++++++++
test/integration/config/ldp-with-auth.json | 3 +-
test/integration/config/run-with-redlock.json | 3 +-
.../config/server-dynamic-unsafe.json | 3 +-
test/integration/config/server-memory.json | 3 +-
.../config/server-subdomains-unsafe.json | 3 +-
.../config/server-without-auth.json | 3 +-
test/integration/config/setup-memory.json | 45 ++++
test/unit/util/handlers/StaticHandler.test.ts | 18 ++
test/util/Util.ts | 1 +
47 files changed, 883 insertions(+), 246 deletions(-)
create mode 100644 config/app/init/initialize-prefilled-root.json
create mode 100644 config/app/init/initialize-root.json
create mode 100644 config/app/init/initializers/prefilled-root.json
create mode 100644 config/app/setup/disabled.json
create mode 100644 config/app/setup/handlers/redirect.json
create mode 100644 config/app/setup/handlers/setup.json
create mode 100644 config/app/setup/optional.json
create mode 100644 config/app/setup/required.json
create mode 100644 config/file-no-setup.json
create mode 100644 config/sparql-endpoint-no-setup.json
create mode 100644 src/util/handlers/StaticHandler.ts
create mode 100644 templates/identity/email-password/register-partial.html.ejs
create mode 100644 templates/identity/email-password/register-response-partial.html.ejs
rename templates/root/{ => empty}/.acl (59%)
rename templates/root/{ => empty}/.meta (100%)
create mode 100644 templates/root/prefilled/.acl
create mode 100644 templates/root/prefilled/.meta
rename templates/root/{ => prefilled}/index.html (97%)
create mode 100644 templates/setup/index.html.ejs
create mode 100644 templates/setup/response.html.ejs
create mode 100644 test/integration/Setup.test.ts
create mode 100644 test/integration/config/setup-memory.json
create mode 100644 test/unit/util/handlers/StaticHandler.test.ts
diff --git a/config/app/README.md b/config/app/README.md
index 29bc738f7..1e7b2965a 100644
--- a/config/app/README.md
+++ b/config/app/README.md
@@ -8,4 +8,15 @@ This is the entry point to the main server setup.
## Init
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.
diff --git a/config/app/init/default.json b/config/app/init/default.json
index 2eecaf4c5..6a41eecf4 100644
--- a/config/app/init/default.json
+++ b/config/app/init/default.json
@@ -1,8 +1,7 @@
{
"@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"
+ "files-scs:config/app/init/base/init.json"
],
"@graph": [
{
@@ -10,7 +9,10 @@
"@id": "urn:solid-server:default:ParallelInitializer",
"@type": "ParallelHandler",
"handlers": [
- { "@id": "urn:solid-server:default:RootInitializer" }
+ {
+ "comment": "This handler is here because having this array empty gives Components.js errors.",
+ "@type": "StaticHandler"
+ }
]
}
]
diff --git a/config/app/init/initialize-prefilled-root.json b/config/app/init/initialize-prefilled-root.json
new file mode 100644
index 000000000..a9ef56542
--- /dev/null
+++ b/config/app/init/initialize-prefilled-root.json
@@ -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" }
+ ]
+ }
+ ]
+}
diff --git a/config/app/init/initialize-root.json b/config/app/init/initialize-root.json
new file mode 100644
index 000000000..2eecaf4c5
--- /dev/null
+++ b/config/app/init/initialize-root.json
@@ -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" }
+ ]
+ }
+ ]
+}
diff --git a/config/app/init/initializers/prefilled-root.json b/config/app/init/initializers/prefilled-root.json
new file mode 100644
index 000000000..ab25afa90
--- /dev/null
+++ b/config/app/init/initializers/prefilled-root.json
@@ -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" }
+ }
+ }
+ ]
+}
diff --git a/config/app/init/initializers/root.json b/config/app/init/initializers/root.json
index ef92f7275..852c44771 100644
--- a/config/app/init/initializers/root.json
+++ b/config/app/init/initializers/root.json
@@ -9,7 +9,7 @@
"store": { "@id": "urn:solid-server:default:ResourceStore" },
"generator": {
"@type": "TemplatedResourcesGenerator",
- "templateFolder": "@css:templates/root",
+ "templateFolder": "@css:templates/root/empty",
"factory": { "@type": "ExtensionBasedMapperFactory" },
"templateEngine": { "@type": "HandlebarsTemplateEngine" }
}
diff --git a/config/app/setup/disabled.json b/config/app/setup/disabled.json
new file mode 100644
index 000000000..93e8e08d4
--- /dev/null
+++ b/config/app/setup/disabled.json
@@ -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"
+ }
+ ]
+}
diff --git a/config/app/setup/handlers/redirect.json b/config/app/setup/handlers/redirect.json
new file mode 100644
index 000000000..35d391b0a
--- /dev/null
+++ b/config/app/setup/handlers/redirect.json
@@ -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" }
+ },
+ ]
+}
diff --git a/config/app/setup/handlers/setup.json b/config/app/setup/handlers/setup.json
new file mode 100644
index 000000000..a1c82a25e
--- /dev/null
+++ b/config/app/setup/handlers/setup.json
@@ -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" }
+ }
+ ]
+}
diff --git a/config/app/setup/optional.json b/config/app/setup/optional.json
new file mode 100644
index 000000000..a52a08a76
--- /dev/null
+++ b/config/app/setup/optional.json
@@ -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" }
+ }
+ }
+ ]
+}
diff --git a/config/app/setup/required.json b/config/app/setup/required.json
new file mode 100644
index 000000000..33e4c5c9d
--- /dev/null
+++ b/config/app/setup/required.json
@@ -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" }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/config/default.json b/config/default.json
index 71f0a800f..1e519ead6 100644
--- a/config/default.json
+++ b/config/default.json
@@ -2,7 +2,8 @@
"@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/init/initialize-prefilled-root.json",
+ "files-scs:config/app/setup/optional.json",
"files-scs:config/http/handler/default.json",
"files-scs:config/http/middleware/websockets.json",
"files-scs:config/http/server-factory/websockets.json",
diff --git a/config/dynamic.json b/config/dynamic.json
index 05248946f..3dc1fc05b 100644
--- a/config/dynamic.json
+++ b/config/dynamic.json
@@ -3,6 +3,7 @@
"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",
diff --git a/config/example-https-file.json b/config/example-https-file.json
index 04c1fe27b..ea2d1ce56 100644
--- a/config/example-https-file.json
+++ b/config/example-https-file.json
@@ -3,6 +3,7 @@
"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",
diff --git a/config/file-no-setup.json b/config/file-no-setup.json
new file mode 100644
index 000000000..b2cc81153
--- /dev/null
+++ b/config/file-no-setup.json
@@ -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."
+ }
+ ]
+}
diff --git a/config/file.json b/config/file.json
index 03bf127a9..b8190db4a 100644
--- a/config/file.json
+++ b/config/file.json
@@ -3,6 +3,7 @@
"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",
diff --git a/config/http/handler/default.json b/config/http/handler/default.json
index 14001848d..0de9adf89 100644
--- a/config/http/handler/default.json
+++ b/config/http/handler/default.json
@@ -1,5 +1,8 @@
{
"@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": "These are all the handlers a request will go through until it is handled.",
@@ -11,6 +14,7 @@
"@type": "WaterfallHandler",
"handlers": [
{ "@id": "urn:solid-server:default:StaticAssetHandler" },
+ { "@id": "urn:solid-server:default:SetupHandler" },
{ "@id": "urn:solid-server:default:IdentityProviderHandler" },
{ "@id": "urn:solid-server:default:LdpHandler" }
]
diff --git a/config/memory-subdomains.json b/config/memory-subdomains.json
index 51fbe6611..a60168ccd 100644
--- a/config/memory-subdomains.json
+++ b/config/memory-subdomains.json
@@ -2,7 +2,8 @@
"@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/init/initialize-root.json",
+ "files-scs:config/app/setup/optional.json",
"files-scs:config/http/handler/default.json",
"files-scs:config/http/middleware/websockets.json",
"files-scs:config/http/server-factory/websockets.json",
diff --git a/config/path-routing.json b/config/path-routing.json
index 8714594eb..8cca10147 100644
--- a/config/path-routing.json
+++ b/config/path-routing.json
@@ -2,7 +2,8 @@
"@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/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",
diff --git a/config/sparql-endpoint-no-setup.json b/config/sparql-endpoint-no-setup.json
new file mode 100644
index 000000000..15ce12c11
--- /dev/null
+++ b/config/sparql-endpoint-no-setup.json
@@ -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."
+ ]
+ }
+ ]
+}
diff --git a/config/sparql-endpoint.json b/config/sparql-endpoint.json
index e27fc343a..5d82ac86b 100644
--- a/config/sparql-endpoint.json
+++ b/config/sparql-endpoint.json
@@ -3,6 +3,7 @@
"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",
diff --git a/config/storage/key-value/memory.json b/config/storage/key-value/memory.json
index 5777bb5f1..783f86b79 100644
--- a/config/storage/key-value/memory.json
+++ b/config/storage/key-value/memory.json
@@ -28,6 +28,11 @@
"comment": "Storage used for account management.",
"@id": "urn:solid-server:default:AccountStorage",
"@type": "MemoryMapStorage"
+ },
+ {
+ "comment": "Storage used by setup components.",
+ "@id": "urn:solid-server:default:SetupStorage",
+ "@type": "MemoryMapStorage"
}
]
}
diff --git a/config/storage/key-value/resource-store.json b/config/storage/key-value/resource-store.json
index 38efa90a3..be4a89174 100644
--- a/config/storage/key-value/resource-store.json
+++ b/config/storage/key-value/resource-store.json
@@ -47,6 +47,14 @@
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
"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.",
"@id": "urn:solid-server:default:PathBasedAuthorizer",
diff --git a/src/index.ts b/src/index.ts
index 82e90e6a6..703558162 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -317,6 +317,7 @@ export * from './util/handlers/BooleanHandler';
export * from './util/handlers/ConditionalHandler';
export * from './util/handlers/ParallelHandler';
export * from './util/handlers/SequenceHandler';
+export * from './util/handlers/StaticHandler';
export * from './util/handlers/UnsupportedAsyncHandler';
export * from './util/handlers/WaterfallHandler';
diff --git a/src/util/handlers/StaticHandler.ts b/src/util/handlers/StaticHandler.ts
new file mode 100644
index 000000000..38f47a610
--- /dev/null
+++ b/src/util/handlers/StaticHandler.ts
@@ -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 extends AsyncHandler {
+ private readonly value?: T;
+
+ public constructor(value?: T) {
+ super();
+ this.value = value;
+ }
+
+ public async handle(): Promise {
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
+ return this.value!;
+ }
+}
diff --git a/templates/identity/email-password/register-partial.html.ejs b/templates/identity/email-password/register-partial.html.ejs
new file mode 100644
index 000000000..638f3a5b4
--- /dev/null
+++ b/templates/identity/email-password/register-partial.html.ejs
@@ -0,0 +1,203 @@
+<% const isBlankForm = !('prefilled' in locals); %>
+<% prefilled = locals.prefilled || {}; %>
+
+
+
+
+
+
+
+
diff --git a/templates/identity/email-password/register-response-partial.html.ejs b/templates/identity/email-password/register-response-partial.html.ejs
new file mode 100644
index 000000000..0c141edc9
--- /dev/null
+++ b/templates/identity/email-password/register-response-partial.html.ejs
@@ -0,0 +1,38 @@
+<% if (createPod) { %>
+
Your new Pod
+
+ Your new Pod is located at <%= podBaseUrl %>.
+
+ You can store your documents and data there.
+
+<% } %>
+
+<% if (createWebId) { %>
+
Your new WebID
+
+ Your new WebID is <%= webId %>.
+
+ You can use this identifier to interact with Solid pods and apps.
+
+<% } %>
+
+<% if (register) { %>
+
Your new account
+
+ Via your email address <%= email %>,
+ <% if (authenticating) { %>
+ you can now log in
+ <% } else { %>
+ this server lets you log in to Solid apps
+ <% } %>
+ with your WebID <%= webId %>
+
+ <% if (!createWebId) { %>
+
+ You will need to add the triple
+ <%= `<${webId}> <${oidcIssuer}>.`%>
+ to your existing WebID document <%= webId %>
+ to indicate that you trust this server as a login provider.
+
+ <% } %>
+<% } %>
diff --git a/templates/identity/email-password/register-response.html.ejs b/templates/identity/email-password/register-response.html.ejs
index b6f667dd5..bb0689c8d 100644
--- a/templates/identity/email-password/register-response.html.ejs
+++ b/templates/identity/email-password/register-response.html.ejs
@@ -4,41 +4,4 @@
We wish you an exciting experience!
-<% if (createPod) { %>
-
Your new Pod
-
- Your new Pod is located at <%= podBaseUrl %>.
-
- You can store your documents and data there.
-
-<% } %>
-
-<% if (createWebId) { %>
-
Your new WebID
-
- Your new WebID is <%= webId %>.
-
- You can use this identifier to interact with Solid pods and apps.
-
-<% } %>
-
-<% if (register) { %>
-
Your new account
-
- Via your email address <%= email %>,
- <% if (authenticating) { %>
- you can now log in
- <% } else { %>
- this server lets you log in to Solid apps
- <% } %>
- with your WebID <%= webId %>
-
- <% if (!createWebId) { %>
-
- You will need to add the triple
- <%= `<${webId}> <${oidcIssuer}>.`%>
- to your existing WebID document <%= webId %>
- to indicate that you trust this server as a login provider.
-
-
-
diff --git a/templates/root/.acl b/templates/root/empty/.acl
similarity index 59%
rename from templates/root/.acl
rename to templates/root/empty/.acl
index 107adcc82..65b4fa2b8 100644
--- a/templates/root/.acl
+++ b/templates/root/empty/.acl
@@ -1,13 +1,10 @@
+# Root ACL resource generated by the Community Server to allow public access
@prefix acl: .
@prefix foaf: .
<#authorization>
a acl:Authorization;
acl:agentClass foaf:Agent;
- acl:mode acl:Read;
- acl:mode acl:Write;
- acl:mode acl:Append;
- acl:mode acl:Delete;
- acl:mode acl:Control;
+ acl:mode acl:Read, acl:Write, acl:Append, acl:Control;
acl:accessTo <./>;
acl:default <./>.
diff --git a/templates/root/.meta b/templates/root/empty/.meta
similarity index 100%
rename from templates/root/.meta
rename to templates/root/empty/.meta
diff --git a/templates/root/prefilled/.acl b/templates/root/prefilled/.acl
new file mode 100644
index 000000000..65b4fa2b8
--- /dev/null
+++ b/templates/root/prefilled/.acl
@@ -0,0 +1,10 @@
+# Root ACL resource generated by the Community Server to allow public access
+@prefix acl: .
+@prefix foaf: .
+
+<#authorization>
+ a acl:Authorization;
+ acl:agentClass foaf:Agent;
+ acl:mode acl:Read, acl:Write, acl:Append, acl:Control;
+ acl:accessTo <./>;
+ acl:default <./>.
diff --git a/templates/root/prefilled/.meta b/templates/root/prefilled/.meta
new file mode 100644
index 000000000..8d5a9bc50
--- /dev/null
+++ b/templates/root/prefilled/.meta
@@ -0,0 +1,7 @@
+@prefix pim: .
+
+# 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.
diff --git a/templates/root/index.html b/templates/root/prefilled/index.html
similarity index 97%
rename from templates/root/index.html
rename to templates/root/prefilled/index.html
index 91bb1b163..905b39078 100644
--- a/templates/root/index.html
+++ b/templates/root/prefilled/index.html
@@ -59,7 +59,7 @@
Prevent public write and control access to the root Pod
- by modifying .acl.
+ by modifying .acl.
Disable Pod registration
diff --git a/templates/setup/index.html.ejs b/templates/setup/index.html.ejs
new file mode 100644
index 000000000..78632009f
--- /dev/null
+++ b/templates/setup/index.html.ejs
@@ -0,0 +1,88 @@
+
Welcome to Solid
+
+ This server implements
+ the Solid protocol
+ so you can create your own Solid Pod
+ and identity.
+
+
+
Making this server public
+
+ Before making this server public,
+ you might want to disable Pod registration
+ by changing
+ the configuration.
+
+
+
Setting up the server
+
+ The default 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,
+ read the guidelines below.
+
+
+ When using the file-based version of the server,
+ you can easily choose any folder on your disk to use as root.
+
+ Use the --help switch to learn more.
+
+
+ To make sure the server is set up exactly as you want it,
+ please fill in the form below.
+
+
+ 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 config/app/setup/ and possibly config/app/init/.
+