mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Remove setup
This commit is contained in:
parent
ea83ea59a1
commit
5eff035cb3
@ -19,16 +19,6 @@ This is the entry point to the main server setup.
|
|||||||
* *default*: The main application. This should only be changed/replaced
|
* *default*: The main application. This should only be changed/replaced
|
||||||
if you want to start from a different kind of class.
|
if you want to start from a different kind of class.
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
## Variables
|
## Variables
|
||||||
|
|
||||||
Handles parsing CLI parameters and assigning values to Components.js variables.
|
Handles parsing CLI parameters and assigning values to Components.js variables.
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld",
|
|
||||||
"@graph": [
|
|
||||||
{
|
|
||||||
"comment": "Completely disables the setup page.",
|
|
||||||
"@id": "urn:solid-server:default:SetupHandler",
|
|
||||||
"@type": "UnsupportedAsyncHandler"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld",
|
|
||||||
"@graph": [
|
|
||||||
{
|
|
||||||
"comment": "Redirects all request to the setup.",
|
|
||||||
"@id": "urn:solid-server:default:SetupRedirectHandler",
|
|
||||||
"@type": "RedirectingHttpHandler",
|
|
||||||
"redirects": [
|
|
||||||
{
|
|
||||||
"RedirectingHttpHandler:_redirects_key": ".*",
|
|
||||||
"RedirectingHttpHandler:_redirects_value": "/setup"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
|
||||||
"targetExtractor": { "@id": "urn:solid-server:default:TargetExtractor" },
|
|
||||||
"responseWriter": { "@id": "urn:solid-server:default:ResponseWriter" },
|
|
||||||
"statusCode": 302
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
{
|
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld",
|
|
||||||
"@graph": [
|
|
||||||
{
|
|
||||||
"comment": "Handles everything related to the first-time server setup.",
|
|
||||||
"@id": "urn:solid-server:default:SetupParsingHandler",
|
|
||||||
"@type": "ParsingHttpHandler",
|
|
||||||
"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_operationHandler": {
|
|
||||||
"@id": "urn:solid-server:default:SetupHttpHandler",
|
|
||||||
"@type": "SetupHttpHandler",
|
|
||||||
"args_handler": {
|
|
||||||
"@type": "SetupHandler",
|
|
||||||
"args_initializer": { "@id": "urn:solid-server:default:SetupInitializer" },
|
|
||||||
"args_registrationManager": { "@id": "urn:solid-server:default:SetupRegistrationManager" }
|
|
||||||
},
|
|
||||||
"args_converter": { "@id": "urn:solid-server:default:RepresentationConverter" },
|
|
||||||
"args_storageKey": "setupCompleted-2.0",
|
|
||||||
"args_storage": { "@id": "urn:solid-server:default:SetupStorage" },
|
|
||||||
"args_templateEngine": {
|
|
||||||
"comment": "Renders the specific page and embeds it into the main HTML body.",
|
|
||||||
"@type": "ChainedTemplateEngine",
|
|
||||||
"renderedName": "htmlBody",
|
|
||||||
"engines": [
|
|
||||||
{
|
|
||||||
"comment": "Renders the main setup template.",
|
|
||||||
"@type": "StaticTemplateEngine",
|
|
||||||
"templateEngine": { "@id": "urn:solid-server:default:TemplateEngine" },
|
|
||||||
"template": "@css:templates/setup/index.html.ejs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"comment": "Will embed the result of the first engine into the main HTML template.",
|
|
||||||
"@type": "StaticTemplateEngine",
|
|
||||||
"templateEngine": { "@id": "urn:solid-server:default:TemplateEngine" },
|
|
||||||
"template": "@css:templates/main.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" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"comment": "Separate initializer as we only want a simple one that sets the root .acl.",
|
|
||||||
"@id": "urn:solid-server:default:SetupInitializer",
|
|
||||||
"@type": "ContainerInitializer",
|
|
||||||
"args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
|
|
||||||
"args_path": "/",
|
|
||||||
"args_store": { "@id": "urn:solid-server:default:ResourceStore" },
|
|
||||||
"args_generator": {
|
|
||||||
"@type": "StaticFolderGenerator",
|
|
||||||
"templateFolder": "@css:templates/root/empty",
|
|
||||||
"resourcesGenerator": { "@id": "urn:solid-server:default:TemplatedResourcesGenerator" }
|
|
||||||
},
|
|
||||||
"args_storageKey": "rootInitialized",
|
|
||||||
"args_storage": { "@id": "urn:solid-server:default:SetupStorage" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld",
|
|
||||||
"import": [
|
|
||||||
"css: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-2.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_allowedPathNames": [ "/setup" ],
|
|
||||||
"args_handler": { "@id": "urn:solid-server:default:SetupParsingHandler" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld",
|
|
||||||
"import": [
|
|
||||||
"css:config/app/setup/handlers/redirect.json",
|
|
||||||
"css: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-2.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_allowedPathNames": [ "/setup" ],
|
|
||||||
"args_handler": { "@id": "urn:solid-server:default:SetupParsingHandler" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-prefilled-root.json",
|
"css:config/app/init/initialize-prefilled-root.json",
|
||||||
"css:config/app/setup/optional.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
@ -37,7 +36,7 @@
|
|||||||
{
|
{
|
||||||
"comment": [
|
"comment": [
|
||||||
"A Solid server that stores its resources on disk and uses WAC for authorization.",
|
"A Solid server that stores its resources on disk and uses WAC for authorization.",
|
||||||
"No setup is required and the root container is initialized to allow full access for everyone so make sure to change this."
|
"No registration and the root container is initialized to allow full access for everyone so make sure to change this."
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"@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:OidcHandler" },
|
{ "@id": "urn:solid-server:default:OidcHandler" },
|
||||||
{ "@id": "urn:solid-server:default:NotificationHttpHandler" },
|
{ "@id": "urn:solid-server:default:NotificationHttpHandler" },
|
||||||
{ "@id": "urn:solid-server:default:StorageDescriptionHandler" },
|
{ "@id": "urn:solid-server:default:StorageDescriptionHandler" },
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
"@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:StorageDescriptionHandler" },
|
{ "@id": "urn:solid-server:default:StorageDescriptionHandler" },
|
||||||
{ "@id": "urn:solid-server:default:LdpHandler" }
|
{ "@id": "urn:solid-server:default:LdpHandler" }
|
||||||
]
|
]
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -36,12 +36,6 @@
|
|||||||
"HtmlViewHandler:_templates_value": { "@id": "urn:solid-server:auth:password:RegistrationRoute" }
|
"HtmlViewHandler:_templates_value": { "@id": "urn:solid-server:auth:password:RegistrationRoute" }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"comment": "Root access is disabled when registration is enabled to prevent nested storage containers.",
|
|
||||||
"@id": "urn:solid-server:default:SetupHttpHandler",
|
|
||||||
"@type": "SetupHttpHandler",
|
|
||||||
"allowRootPod": false
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/optional.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
@ -38,7 +37,7 @@
|
|||||||
"comment": [
|
"comment": [
|
||||||
"A single-pod server that stores its resources in a SPARQL endpoint and uses WAC for authorization.",
|
"A single-pod server that stores its resources in a SPARQL endpoint and uses WAC for authorization.",
|
||||||
"This server only supports RDF data. For this reason it can not use its resource store for internal key/value storage.",
|
"This server only supports RDF data. For this reason it can not use its resource store for internal key/value storage.",
|
||||||
"No setup is required and the root container is initialized to allow full access for everyone so make sure to change this."
|
"No registration and the root container is initialized to allow full access for everyone so make sure to change this."
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/static-root.json",
|
"css:config/app/init/static-root.json",
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/app/variables/default.json",
|
"css:config/app/variables/default.json",
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -19,7 +19,6 @@ flowchart LR
|
|||||||
subgraph WaterfallHandlerArgs[" "]
|
subgraph WaterfallHandlerArgs[" "]
|
||||||
direction TB
|
direction TB
|
||||||
StaticAssetHandler("<strong>StaticAssetHandler</strong><br>StaticAssetHandler")
|
StaticAssetHandler("<strong>StaticAssetHandler</strong><br>StaticAssetHandler")
|
||||||
SetupHandler("<strong>SetupHandler</strong><br><i>HttpHandler</i>")
|
|
||||||
OidcHandler("<strong>OidcHandler</strong><br><i>HttpHandler</i>")
|
OidcHandler("<strong>OidcHandler</strong><br><i>HttpHandler</i>")
|
||||||
NotificationHttpHandler("<strong>NotificationHttpHandler</strong><br><i>HttpHandler</i>")
|
NotificationHttpHandler("<strong>NotificationHttpHandler</strong><br><i>HttpHandler</i>")
|
||||||
StorageDescriptionHandler("<strong>StorageDescriptionHandler</strong><br><i>HttpHandler</i>")
|
StorageDescriptionHandler("<strong>StorageDescriptionHandler</strong><br><i>HttpHandler</i>")
|
||||||
@ -28,8 +27,7 @@ flowchart LR
|
|||||||
LdpHandler("<strong>LdpHandler</strong><br><i>HttpHandler</i>")
|
LdpHandler("<strong>LdpHandler</strong><br><i>HttpHandler</i>")
|
||||||
end
|
end
|
||||||
|
|
||||||
StaticAssetHandler --> SetupHandler
|
StaticAssetHandler --> OidcHandler
|
||||||
SetupHandler --> OidcHandler
|
|
||||||
OidcHandler --> NotificationHttpHandler
|
OidcHandler --> NotificationHttpHandler
|
||||||
NotificationHttpHandler --> StorageDescriptionHandler
|
NotificationHttpHandler --> StorageDescriptionHandler
|
||||||
StorageDescriptionHandler --> AuthResourceHttpHandler
|
StorageDescriptionHandler --> AuthResourceHttpHandler
|
||||||
@ -52,17 +50,6 @@ An example of this is the favicon, where the `/favicon.ico` URL
|
|||||||
is directed to the favicon file at `/templates/images/favicon.ico`.
|
is directed to the favicon file at `/templates/images/favicon.ico`.
|
||||||
It can also map entire folders to a specific path, such as `/.well-known/css/styles/` which contains all stylesheets.
|
It can also map entire folders to a specific path, such as `/.well-known/css/styles/` which contains all stylesheets.
|
||||||
|
|
||||||
## SetupHandler
|
|
||||||
|
|
||||||
The `urn:solid-server:default:SetupHandler` is responsible
|
|
||||||
for redirecting all requests to `/setup` until setup is finished,
|
|
||||||
thereby ensuring that setup needs to be finished before anything else can be done on the server,
|
|
||||||
and handling the actual setup request that is sent to `/setup`.
|
|
||||||
Once setup is finished, this handler will reject all requests and thus no longer be relevant.
|
|
||||||
|
|
||||||
If the server is configured to not have setup enabled,
|
|
||||||
the corresponding identifier will point to a handler that always rejects all requests.
|
|
||||||
|
|
||||||
## OidcHandler
|
## OidcHandler
|
||||||
|
|
||||||
The `urn:solid-server:default:OidcHandler` handles all requests related
|
The `urn:solid-server:default:OidcHandler` handles all requests related
|
||||||
|
@ -134,7 +134,7 @@ To register a user, you can do a POST request with a JSON body containing the co
|
|||||||
|
|
||||||
Two fields here that are not covered on the HTML page above are `rootPod` and `template`.
|
Two fields here that are not covered on the HTML page above are `rootPod` and `template`.
|
||||||
`rootPod` tells the server to put the pod in the root of the server instead of a location based on the `podName`.
|
`rootPod` tells the server to put the pod in the root of the server instead of a location based on the `podName`.
|
||||||
By default the server will reject requests where this is `true`, except during setup.
|
By default the server will reject requests where this is `true`.
|
||||||
`template` is only used by servers running the `config/dynamic.json` configuration,
|
`template` is only used by servers running the `config/dynamic.json` configuration,
|
||||||
which is a very custom setup where every pod can have a different Components.js configuration,
|
which is a very custom setup where every pod can have a different Components.js configuration,
|
||||||
so this value can usually be ignored.
|
so this value can usually be ignored.
|
||||||
@ -186,5 +186,3 @@ so they can be recreated when the server restarts.
|
|||||||
### registration
|
### registration
|
||||||
|
|
||||||
This setting allows you to enable/disable registration on the server.
|
This setting allows you to enable/disable registration on the server.
|
||||||
Disabling registration here does not disable registration during setup,
|
|
||||||
meaning you can still use this server as an IDP with the account created there.
|
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
"postrelease": "ts-node ./scripts/finalizeRelease.ts",
|
"postrelease": "ts-node ./scripts/finalizeRelease.ts",
|
||||||
"start": "node ./bin/server.js",
|
"start": "node ./bin/server.js",
|
||||||
"start:file": "node ./bin/server.js -c config/file.json -f ./data",
|
"start:file": "node ./bin/server.js -c config/file.json -f ./data",
|
||||||
"start:file-no-setup": "node ./bin/server.js -c config/file-no-setup.json -f ./data",
|
"start:file-root": "node ./bin/server.js -c config/file-root.json -f ./data",
|
||||||
"test": "npm run test:ts && npm run jest",
|
"test": "npm run test:ts && npm run jest",
|
||||||
"test:deploy": "test/deploy/validate-configs.sh",
|
"test:deploy": "test/deploy/validate-configs.sh",
|
||||||
"test:ts": "tsc -p test --noEmit",
|
"test:ts": "tsc -p test --noEmit",
|
||||||
|
@ -209,10 +209,6 @@ export * from './init/final/Finalizable';
|
|||||||
export * from './init/final/FinalizableHandler';
|
export * from './init/final/FinalizableHandler';
|
||||||
export * from './init/final/Finalizer';
|
export * from './init/final/Finalizer';
|
||||||
|
|
||||||
// Init/Setup
|
|
||||||
export * from './init/setup/SetupHandler';
|
|
||||||
export * from './init/setup/SetupHttpHandler';
|
|
||||||
|
|
||||||
// Init/Cli
|
// Init/Cli
|
||||||
export * from './init/cli/CliExtractor';
|
export * from './init/cli/CliExtractor';
|
||||||
export * from './init/cli/YargsCliExtractor';
|
export * from './init/cli/YargsCliExtractor';
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
import { BasicRepresentation } from '../../http/representation/BasicRepresentation';
|
|
||||||
import type { Representation } from '../../http/representation/Representation';
|
|
||||||
import { BaseInteractionHandler } from '../../identity/interaction/BaseInteractionHandler';
|
|
||||||
import type { RegistrationManager } from '../../identity/interaction/email-password/util/RegistrationManager';
|
|
||||||
import type { InteractionHandlerInput } from '../../identity/interaction/InteractionHandler';
|
|
||||||
import { getLoggerFor } from '../../logging/LogUtil';
|
|
||||||
import { APPLICATION_JSON } from '../../util/ContentTypes';
|
|
||||||
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
|
||||||
import { readJsonStream } from '../../util/StreamUtil';
|
|
||||||
import type { Initializer } from '../Initializer';
|
|
||||||
|
|
||||||
export interface SetupHandlerArgs {
|
|
||||||
/**
|
|
||||||
* Used for registering a pod during setup.
|
|
||||||
*/
|
|
||||||
registrationManager?: RegistrationManager;
|
|
||||||
/**
|
|
||||||
* Initializer to call in case no registration procedure needs to happen.
|
|
||||||
* This Initializer should make sure the necessary resources are there so the server can work correctly.
|
|
||||||
*/
|
|
||||||
initializer?: Initializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On POST requests, runs an initializer and/or performs a registration step, both optional.
|
|
||||||
*/
|
|
||||||
export class SetupHandler extends BaseInteractionHandler {
|
|
||||||
protected readonly logger = getLoggerFor(this);
|
|
||||||
|
|
||||||
private readonly registrationManager?: RegistrationManager;
|
|
||||||
private readonly initializer?: Initializer;
|
|
||||||
|
|
||||||
public constructor(args: SetupHandlerArgs) {
|
|
||||||
super({});
|
|
||||||
this.registrationManager = args.registrationManager;
|
|
||||||
this.initializer = args.initializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async handlePost({ operation }: InteractionHandlerInput): Promise<Representation> {
|
|
||||||
const json = operation.body.isEmpty ? {} : await readJsonStream(operation.body.data);
|
|
||||||
|
|
||||||
const output: Record<string, any> = { initialize: false, registration: false };
|
|
||||||
if (json.registration) {
|
|
||||||
Object.assign(output, await this.register(json));
|
|
||||||
output.registration = true;
|
|
||||||
} else if (json.initialize) {
|
|
||||||
// We only want to initialize if no registration happened
|
|
||||||
await this.initialize();
|
|
||||||
output.initialize = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.debug(`Output: ${JSON.stringify(output)}`);
|
|
||||||
|
|
||||||
return new BasicRepresentation(JSON.stringify(output), APPLICATION_JSON);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call the initializer.
|
|
||||||
* Errors if no initializer was defined.
|
|
||||||
*/
|
|
||||||
private async initialize(): Promise<void> {
|
|
||||||
if (!this.initializer) {
|
|
||||||
throw new NotImplementedHttpError('This server is not configured with a setup initializer.');
|
|
||||||
}
|
|
||||||
await this.initializer.handleSafe();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a user based on the given input.
|
|
||||||
* Errors if no registration manager is defined.
|
|
||||||
*/
|
|
||||||
private async register(json: NodeJS.Dict<any>): Promise<Record<string, any>> {
|
|
||||||
if (!this.registrationManager) {
|
|
||||||
throw new NotImplementedHttpError('This server is not configured to support registration during setup.');
|
|
||||||
}
|
|
||||||
// Validate the input JSON
|
|
||||||
const validated = this.registrationManager.validateInput(json, true);
|
|
||||||
this.logger.debug(`Validated input: ${JSON.stringify(validated)}`);
|
|
||||||
|
|
||||||
// Register and/or create a pod as requested. Potentially does nothing if all booleans are false.
|
|
||||||
return this.registrationManager.register(validated, true);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
import type { Operation } from '../../http/Operation';
|
|
||||||
import { OkResponseDescription } from '../../http/output/response/OkResponseDescription';
|
|
||||||
import type { ResponseDescription } from '../../http/output/response/ResponseDescription';
|
|
||||||
import { BasicRepresentation } from '../../http/representation/BasicRepresentation';
|
|
||||||
import type { InteractionHandler } from '../../identity/interaction/InteractionHandler';
|
|
||||||
import { getLoggerFor } from '../../logging/LogUtil';
|
|
||||||
import type { OperationHttpHandlerInput } from '../../server/OperationHttpHandler';
|
|
||||||
import { OperationHttpHandler } from '../../server/OperationHttpHandler';
|
|
||||||
import type { RepresentationConverter } from '../../storage/conversion/RepresentationConverter';
|
|
||||||
import type { KeyValueStorage } from '../../storage/keyvalue/KeyValueStorage';
|
|
||||||
import { APPLICATION_JSON, TEXT_HTML } from '../../util/ContentTypes';
|
|
||||||
import { MethodNotAllowedHttpError } from '../../util/errors/MethodNotAllowedHttpError';
|
|
||||||
import type { TemplateEngine } from '../../util/templates/TemplateEngine';
|
|
||||||
|
|
||||||
export interface SetupHttpHandlerArgs {
|
|
||||||
/**
|
|
||||||
* Used for converting the input data.
|
|
||||||
*/
|
|
||||||
converter: RepresentationConverter;
|
|
||||||
/**
|
|
||||||
* Handles the requests.
|
|
||||||
*/
|
|
||||||
handler: InteractionHandler;
|
|
||||||
/**
|
|
||||||
* Key that is used to store the boolean in the storage indicating setup is finished.
|
|
||||||
*/
|
|
||||||
storageKey: string;
|
|
||||||
/**
|
|
||||||
* Used to store setup status.
|
|
||||||
*/
|
|
||||||
storage: KeyValueStorage<string, boolean>;
|
|
||||||
/**
|
|
||||||
* Renders the main view.
|
|
||||||
*/
|
|
||||||
templateEngine: TemplateEngine;
|
|
||||||
/**
|
|
||||||
* Determines if pods can be created in the root of the server.
|
|
||||||
* Relevant to make sure there are no nested storages if registration is enabled for example.
|
|
||||||
* Defaults to `true`.
|
|
||||||
*/
|
|
||||||
allowRootPod?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the initial setup of a server.
|
|
||||||
* Will capture all requests until setup is finished,
|
|
||||||
* this to prevent accidentally running unsafe servers.
|
|
||||||
*
|
|
||||||
* GET requests will return the view template which should contain the setup information for the user.
|
|
||||||
* POST requests will be sent to the InteractionHandler.
|
|
||||||
* After successfully completing a POST request this handler will disable itself and become unreachable.
|
|
||||||
* All other methods will be rejected.
|
|
||||||
*/
|
|
||||||
export class SetupHttpHandler extends OperationHttpHandler {
|
|
||||||
protected readonly logger = getLoggerFor(this);
|
|
||||||
|
|
||||||
private readonly handler: InteractionHandler;
|
|
||||||
private readonly converter: RepresentationConverter;
|
|
||||||
private readonly storageKey: string;
|
|
||||||
private readonly storage: KeyValueStorage<string, boolean>;
|
|
||||||
private readonly templateEngine: TemplateEngine;
|
|
||||||
private readonly allowRootPod: boolean;
|
|
||||||
|
|
||||||
public constructor(args: SetupHttpHandlerArgs) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.handler = args.handler;
|
|
||||||
this.converter = args.converter;
|
|
||||||
this.storageKey = args.storageKey;
|
|
||||||
this.storage = args.storage;
|
|
||||||
this.templateEngine = args.templateEngine;
|
|
||||||
this.allowRootPod = args.allowRootPod ?? true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async handle({ operation }: OperationHttpHandlerInput): Promise<ResponseDescription> {
|
|
||||||
switch (operation.method) {
|
|
||||||
case 'GET': return this.handleGet(operation);
|
|
||||||
case 'POST': return this.handlePost(operation);
|
|
||||||
default: throw new MethodNotAllowedHttpError([ operation.method ]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the HTML representation of the setup page.
|
|
||||||
*/
|
|
||||||
private async handleGet(operation: Operation): Promise<ResponseDescription> {
|
|
||||||
const result = await this.templateEngine.handleSafe({ contents: { allowRootPod: this.allowRootPod }});
|
|
||||||
const representation = new BasicRepresentation(result, operation.target, TEXT_HTML);
|
|
||||||
return new OkResponseDescription(representation.metadata, representation.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the input data to JSON and calls the setup handler.
|
|
||||||
* On success `true` will be written to the storage key.
|
|
||||||
*/
|
|
||||||
private async handlePost(operation: Operation): Promise<ResponseDescription> {
|
|
||||||
// Convert input data to JSON
|
|
||||||
// Allows us to still support form data
|
|
||||||
if (operation.body.metadata.contentType) {
|
|
||||||
const args = {
|
|
||||||
representation: operation.body,
|
|
||||||
preferences: { type: { [APPLICATION_JSON]: 1 }},
|
|
||||||
identifier: operation.target,
|
|
||||||
};
|
|
||||||
operation = {
|
|
||||||
...operation,
|
|
||||||
body: await this.converter.handleSafe(args),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const representation = await this.handler.handleSafe({ operation });
|
|
||||||
await this.storage.set(this.storageKey, true);
|
|
||||||
|
|
||||||
return new OkResponseDescription(representation.metadata, representation.data);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
<div id="input-partial">
|
|
||||||
<%- include('./input-partial.html.ejs') %>
|
|
||||||
</div>
|
|
||||||
<div id="response-partial">
|
|
||||||
<h1 id="public">Server setup complete</h1>
|
|
||||||
<p>
|
|
||||||
Congratulations!
|
|
||||||
Your Solid server is now ready to use.
|
|
||||||
<br>
|
|
||||||
You can now visit its <a href="./">homepage</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div id="response-initialize">
|
|
||||||
<h2>Root Pod</h2>
|
|
||||||
<p>
|
|
||||||
<strong>Warning: the root Pod is publicly accessible.</strong>
|
|
||||||
<br>
|
|
||||||
Prevent public write and control access to the root
|
|
||||||
by modifying its <a href=".acl">ACL document</a>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="response-registration">
|
|
||||||
<%- include('../identity/email-password/register-response-partial.html.ejs', { idpIndex: '' }) %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function updateResponse(json) {
|
|
||||||
// Swap visibility
|
|
||||||
setVisibility('input-partial', false);
|
|
||||||
setVisibility('response-partial', true);
|
|
||||||
|
|
||||||
setVisibility('response-initialize', json.initialize);
|
|
||||||
|
|
||||||
setVisibility('response-registration', json.registration);
|
|
||||||
if (json.registration) {
|
|
||||||
updateResponseFields(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setVisibility('response-partial', false);
|
|
||||||
|
|
||||||
addPostListener('mainForm', 'error', '', updateResponse);
|
|
||||||
</script>
|
|
@ -1,79 +0,0 @@
|
|||||||
<h1>Set up your Solid server</h1>
|
|
||||||
<p>
|
|
||||||
Your Solid server needs a <strong>one-time setup</strong>
|
|
||||||
so it acts exactly the way you want.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<form method="post" id="mainForm">
|
|
||||||
<p class="error" id="error"></p>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Accounts on this server</legend>
|
|
||||||
<ol>
|
|
||||||
<li class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" <% if (!allowRootPod) { %> checked <% } %> disabled>
|
|
||||||
Enable account registration.
|
|
||||||
</label>
|
|
||||||
<p>
|
|
||||||
This can only be changed in the configuration.
|
|
||||||
See the <a href="https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/config/README.md">general configuration documentation</a>
|
|
||||||
and the <a href="https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/config/identity/README.md">identity specific options</a> to find out how.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="registration" name="registration">
|
|
||||||
Sign me up for an account.
|
|
||||||
</label>
|
|
||||||
<p>
|
|
||||||
Any existing root Pod will be disabled.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li class="checkbox" id="initializeForm">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="initialize" name="initialize" <% if (!allowRootPod) { %> disabled <% } %>>
|
|
||||||
Expose a public root Pod.
|
|
||||||
</label>
|
|
||||||
<p>
|
|
||||||
By default, the public has read and write access to the root Pod.
|
|
||||||
<br>
|
|
||||||
You typically only want to choose this
|
|
||||||
for rapid testing and development.
|
|
||||||
<br>
|
|
||||||
This requires registration to be disabled.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset id="registrationForm">
|
|
||||||
<legend>Sign up</legend>
|
|
||||||
<%-
|
|
||||||
include('../identity/email-password/register-partial.html.ejs', {
|
|
||||||
allowRootPod: allowRootPod,
|
|
||||||
})
|
|
||||||
%>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<p class="actions"><button type="submit">Complete setup</button></p>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Show or hide the account creation form when needed -->
|
|
||||||
<script>
|
|
||||||
[
|
|
||||||
'registration', 'registrationForm', 'initializeForm',
|
|
||||||
].forEach(registerElement);
|
|
||||||
|
|
||||||
Object.assign(visibilityConditions, {
|
|
||||||
registrationForm: () => elements.registration.checked,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assigning elements to `visibilityConditions` causes the `disabled` to be removed.
|
|
||||||
// We don't want this for the initialize form.
|
|
||||||
const registration = document.getElementById('registration');
|
|
||||||
registration.addEventListener('change', () => {
|
|
||||||
const initializeForm = document.getElementById('initializeForm');
|
|
||||||
initializeForm.classList[elements.registration.checked ? 'add' : 'remove']('hidden');
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,128 +0,0 @@
|
|||||||
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);
|
|
||||||
expect(res.url).toBe(setupUrl);
|
|
||||||
await expect(res.text()).resolves.toContain('Set up your Solid server');
|
|
||||||
|
|
||||||
res = await fetch(joinUrl(baseUrl, '/random/path/'), { method: 'GET', headers: { accept: 'text/html' }});
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
expect(res.url).toBe(setupUrl);
|
|
||||||
await expect(res.text()).resolves.toContain('Set up your Solid server');
|
|
||||||
|
|
||||||
res = await fetch(joinUrl(baseUrl, '/random/path/'), { method: 'PUT' });
|
|
||||||
expect(res.status).toBe(405);
|
|
||||||
expect(res.url).toBe(setupUrl);
|
|
||||||
await expect(res.json()).resolves.toEqual(expect.objectContaining({ name: 'MethodNotAllowedHttpError' }));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can create a server that disables root but allows registration.', async(): Promise<void> => {
|
|
||||||
let res = await fetch(setupUrl, { method: 'POST' });
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
await expect(res.json()).resolves.toEqual({ initialize: false, registration: false });
|
|
||||||
|
|
||||||
// Root access disabled
|
|
||||||
res = await fetch(baseUrl);
|
|
||||||
expect(res.status).toBe(401);
|
|
||||||
|
|
||||||
// Registration still possible
|
|
||||||
const registerParams = { email, podName, password, confirmPassword: password, createWebId: true };
|
|
||||||
res = await fetch(joinUrl(baseUrl, 'idp/register/'), {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { '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: { 'content-type': 'application/json' },
|
|
||||||
body: JSON.stringify({ initialize: true }),
|
|
||||||
});
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
await expect(res.json()).resolves.toEqual({ initialize: true, registration: false });
|
|
||||||
|
|
||||||
// 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: { '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: { 'content-type': 'application/json' },
|
|
||||||
body: JSON.stringify({ registration: true, initialize: true, ...registerParams }),
|
|
||||||
});
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
const json = await res.json();
|
|
||||||
expect(json).toEqual(expect.objectContaining({
|
|
||||||
registration: true,
|
|
||||||
initialize: false,
|
|
||||||
oidcIssuer: baseUrl,
|
|
||||||
webId: `${baseUrl}profile/card#me`,
|
|
||||||
email,
|
|
||||||
podBaseUrl: baseUrl,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 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: { 'content-type': 'text/plain' },
|
|
||||||
body: 'random data',
|
|
||||||
});
|
|
||||||
expect(res.status).toBe(401);
|
|
||||||
});
|
|
||||||
});
|
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/default.json",
|
"css:config/app/init/default.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/simple.json",
|
"css:config/http/handler/simple.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/disabled.json",
|
"css:config/http/notifications/disabled.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/simple.json",
|
"css:config/http/handler/simple.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/disabled.json",
|
"css:config/http/notifications/disabled.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/legacy-websockets.json",
|
"css:config/http/notifications/legacy-websockets.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/default.json",
|
"css:config/app/init/default.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
|
|
||||||
"css:config/http/handler/simple.json",
|
"css:config/http/handler/simple.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/websockets.json",
|
"css:config/http/notifications/websockets.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/websockets.json",
|
"css:config/http/notifications/websockets.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/default.json",
|
"css:config/app/init/default.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/websockets.json",
|
"css:config/http/notifications/websockets.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/disabled.json",
|
"css:config/http/notifications/disabled.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/disabled.json",
|
"css:config/http/notifications/disabled.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/websockets.json",
|
"css:config/http/notifications/websockets.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/simple.json",
|
"css:config/http/handler/simple.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/websockets.json",
|
"css:config/http/notifications/websockets.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/simple.json",
|
"css:config/http/handler/simple.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/disabled.json",
|
"css:config/http/notifications/disabled.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/disabled.json",
|
"css:config/http/notifications/disabled.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/simple.json",
|
"css:config/http/handler/simple.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/websockets.json",
|
"css:config/http/notifications/websockets.json",
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld",
|
|
||||||
"import": [
|
|
||||||
"css:config/app/main/default.json",
|
|
||||||
"css:config/app/init/default.json",
|
|
||||||
"css:config/app/setup/required.json",
|
|
||||||
"css:config/http/handler/default.json",
|
|
||||||
"css:config/http/middleware/default.json",
|
|
||||||
"css:config/http/notifications/websockets.json",
|
|
||||||
"css:config/http/server-factory/http.json",
|
|
||||||
"css:config/http/static/default.json",
|
|
||||||
"css:config/identity/access/public.json",
|
|
||||||
"css:config/identity/email/default.json",
|
|
||||||
"css:config/identity/handler/default.json",
|
|
||||||
"css:config/identity/ownership/token.json",
|
|
||||||
"css:config/identity/pod/static.json",
|
|
||||||
"css:config/identity/registration/enabled.json",
|
|
||||||
"css:config/ldp/authentication/dpop-bearer.json",
|
|
||||||
"css:config/ldp/authorization/webacl.json",
|
|
||||||
"css:config/ldp/handler/default.json",
|
|
||||||
"css:config/ldp/metadata-parser/default.json",
|
|
||||||
"css:config/ldp/metadata-writer/default.json",
|
|
||||||
"css:config/ldp/modes/default.json",
|
|
||||||
"css:config/storage/backend/memory.json",
|
|
||||||
"css:config/storage/key-value/resource-store.json",
|
|
||||||
"css:config/storage/middleware/default.json",
|
|
||||||
"css:config/util/auxiliary/acl.json",
|
|
||||||
"css:config/util/identifiers/suffix.json",
|
|
||||||
"css:config/util/index/default.json",
|
|
||||||
"css:config/util/logging/winston.json",
|
|
||||||
"css:config/util/representation-conversion/default.json",
|
|
||||||
"css:config/util/resource-locker/memory.json",
|
|
||||||
"css:config/util/variables/default.json"
|
|
||||||
],
|
|
||||||
"@graph": [
|
|
||||||
{
|
|
||||||
"@id": "urn:solid-server:test:Instances",
|
|
||||||
"@type": "RecordObject",
|
|
||||||
"record": [
|
|
||||||
{
|
|
||||||
"RecordObject:_record_key": "app",
|
|
||||||
"RecordObject:_record_value": { "@id": "urn:solid-server:default:App" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/webhooks.json",
|
"css:config/http/notifications/webhooks.json",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"import": [
|
"import": [
|
||||||
"css:config/app/main/default.json",
|
"css:config/app/main/default.json",
|
||||||
"css:config/app/init/initialize-root.json",
|
"css:config/app/init/initialize-root.json",
|
||||||
"css:config/app/setup/disabled.json",
|
|
||||||
"css:config/http/handler/default.json",
|
"css:config/http/handler/default.json",
|
||||||
"css:config/http/middleware/default.json",
|
"css:config/http/middleware/default.json",
|
||||||
"css:config/http/notifications/websockets.json",
|
"css:config/http/notifications/websockets.json",
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
import type { Operation } from '../../../../src/http/Operation';
|
|
||||||
import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
|
|
||||||
import type { RegistrationResponse,
|
|
||||||
RegistrationManager } from '../../../../src/identity/interaction/email-password/util/RegistrationManager';
|
|
||||||
import type { Initializer } from '../../../../src/init/Initializer';
|
|
||||||
import { SetupHandler } from '../../../../src/init/setup/SetupHandler';
|
|
||||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
|
||||||
import { readJsonStream } from '../../../../src/util/StreamUtil';
|
|
||||||
|
|
||||||
describe('A SetupHandler', (): void => {
|
|
||||||
let operation: Operation;
|
|
||||||
let details: RegistrationResponse;
|
|
||||||
let registrationManager: jest.Mocked<RegistrationManager>;
|
|
||||||
let initializer: jest.Mocked<Initializer>;
|
|
||||||
let handler: SetupHandler;
|
|
||||||
|
|
||||||
beforeEach(async(): Promise<void> => {
|
|
||||||
operation = {
|
|
||||||
method: 'POST',
|
|
||||||
target: { path: 'http://example.com/setup' },
|
|
||||||
preferences: {},
|
|
||||||
body: new BasicRepresentation(),
|
|
||||||
};
|
|
||||||
|
|
||||||
initializer = {
|
|
||||||
handleSafe: jest.fn(),
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
details = {
|
|
||||||
email: 'alice@test.email',
|
|
||||||
createWebId: true,
|
|
||||||
register: true,
|
|
||||||
createPod: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
registrationManager = {
|
|
||||||
validateInput: jest.fn((input): any => input),
|
|
||||||
register: jest.fn().mockResolvedValue(details),
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
handler = new SetupHandler({ registrationManager, initializer });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('error if no Initializer is defined and initialization is requested.', async(): Promise<void> => {
|
|
||||||
handler = new SetupHandler({});
|
|
||||||
operation.body = new BasicRepresentation(JSON.stringify({ initialize: true }), 'application/json');
|
|
||||||
await expect(handler.handle({ operation })).rejects.toThrow(NotImplementedHttpError);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('error if no RegistrationManager is defined and registration is requested.', async(): Promise<void> => {
|
|
||||||
handler = new SetupHandler({});
|
|
||||||
operation.body = new BasicRepresentation(JSON.stringify({ registration: true }), 'application/json');
|
|
||||||
await expect(handler.handle({ operation })).rejects.toThrow(NotImplementedHttpError);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls the Initializer when requested.', async(): Promise<void> => {
|
|
||||||
operation.body = new BasicRepresentation(JSON.stringify({ initialize: true }), 'application/json');
|
|
||||||
const result = await handler.handle({ operation });
|
|
||||||
await expect(readJsonStream(result.data)).resolves.toEqual({ initialize: true, registration: false });
|
|
||||||
expect(result.metadata.contentType).toBe('application/json');
|
|
||||||
expect(initializer.handleSafe).toHaveBeenCalledTimes(1);
|
|
||||||
expect(registrationManager.validateInput).toHaveBeenCalledTimes(0);
|
|
||||||
expect(registrationManager.register).toHaveBeenCalledTimes(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls the RegistrationManager when requested.', async(): Promise<void> => {
|
|
||||||
const body = { registration: true, email: 'test@example.com' };
|
|
||||||
operation.body = new BasicRepresentation(JSON.stringify(body), 'application/json');
|
|
||||||
const result = await handler.handle({ operation });
|
|
||||||
await expect(readJsonStream(result.data)).resolves.toEqual({ initialize: false, registration: true, ...details });
|
|
||||||
expect(result.metadata.contentType).toBe('application/json');
|
|
||||||
expect(initializer.handleSafe).toHaveBeenCalledTimes(0);
|
|
||||||
expect(registrationManager.validateInput).toHaveBeenCalledTimes(1);
|
|
||||||
expect(registrationManager.register).toHaveBeenCalledTimes(1);
|
|
||||||
expect(registrationManager.validateInput).toHaveBeenLastCalledWith(body, true);
|
|
||||||
expect(registrationManager.register).toHaveBeenLastCalledWith(body, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('defaults to an empty JSON body if no data is provided.', async(): Promise<void> => {
|
|
||||||
operation.body = new BasicRepresentation();
|
|
||||||
const result = await handler.handle({ operation });
|
|
||||||
await expect(readJsonStream(result.data)).resolves.toEqual({ initialize: false, registration: false });
|
|
||||||
expect(result.metadata.contentType).toBe('application/json');
|
|
||||||
expect(initializer.handleSafe).toHaveBeenCalledTimes(0);
|
|
||||||
expect(registrationManager.validateInput).toHaveBeenCalledTimes(0);
|
|
||||||
expect(registrationManager.register).toHaveBeenCalledTimes(0);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,119 +0,0 @@
|
|||||||
import type { Operation } from '../../../../src/http/Operation';
|
|
||||||
import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
|
|
||||||
import type { Representation } from '../../../../src/http/representation/Representation';
|
|
||||||
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
|
|
||||||
import type { InteractionHandler } from '../../../../src/identity/interaction/InteractionHandler';
|
|
||||||
import { SetupHttpHandler } from '../../../../src/init/setup/SetupHttpHandler';
|
|
||||||
import type { HttpRequest } from '../../../../src/server/HttpRequest';
|
|
||||||
import type { HttpResponse } from '../../../../src/server/HttpResponse';
|
|
||||||
import { getBestPreference } from '../../../../src/storage/conversion/ConversionUtil';
|
|
||||||
import type { RepresentationConverterArgs,
|
|
||||||
RepresentationConverter } from '../../../../src/storage/conversion/RepresentationConverter';
|
|
||||||
import type { KeyValueStorage } from '../../../../src/storage/keyvalue/KeyValueStorage';
|
|
||||||
import { APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED } from '../../../../src/util/ContentTypes';
|
|
||||||
import { MethodNotAllowedHttpError } from '../../../../src/util/errors/MethodNotAllowedHttpError';
|
|
||||||
import { readableToString } from '../../../../src/util/StreamUtil';
|
|
||||||
import type { TemplateEngine } from '../../../../src/util/templates/TemplateEngine';
|
|
||||||
import { CONTENT_TYPE } from '../../../../src/util/Vocabularies';
|
|
||||||
|
|
||||||
describe('A SetupHttpHandler', (): void => {
|
|
||||||
const request: HttpRequest = {} as any;
|
|
||||||
const response: HttpResponse = {} as any;
|
|
||||||
let operation: Operation;
|
|
||||||
const storageKey = 'completed';
|
|
||||||
let representation: Representation;
|
|
||||||
let interactionHandler: jest.Mocked<InteractionHandler>;
|
|
||||||
let templateEngine: jest.Mocked<TemplateEngine>;
|
|
||||||
let converter: jest.Mocked<RepresentationConverter>;
|
|
||||||
let storage: jest.Mocked<KeyValueStorage<string, any>>;
|
|
||||||
let handler: SetupHttpHandler;
|
|
||||||
|
|
||||||
beforeEach(async(): Promise<void> => {
|
|
||||||
operation = {
|
|
||||||
method: 'GET',
|
|
||||||
target: { path: 'http://example.com/setup' },
|
|
||||||
preferences: {},
|
|
||||||
body: new BasicRepresentation(),
|
|
||||||
};
|
|
||||||
|
|
||||||
templateEngine = {
|
|
||||||
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
converter = {
|
|
||||||
handleSafe: jest.fn((input: RepresentationConverterArgs): Representation => {
|
|
||||||
// Just find the best match;
|
|
||||||
const type = getBestPreference(input.preferences.type!, { '*/*': 1 })!;
|
|
||||||
const metadata = new RepresentationMetadata(input.representation.metadata, { [CONTENT_TYPE]: type.value });
|
|
||||||
return new BasicRepresentation(input.representation.data, metadata);
|
|
||||||
}),
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
representation = new BasicRepresentation();
|
|
||||||
interactionHandler = {
|
|
||||||
handleSafe: jest.fn().mockResolvedValue(representation),
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
storage = new Map<string, any>() as any;
|
|
||||||
|
|
||||||
handler = new SetupHttpHandler({
|
|
||||||
converter,
|
|
||||||
storageKey,
|
|
||||||
storage,
|
|
||||||
handler: interactionHandler,
|
|
||||||
templateEngine,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('only accepts GET and POST operations.', async(): Promise<void> => {
|
|
||||||
operation = {
|
|
||||||
method: 'DELETE',
|
|
||||||
target: { path: 'http://example.com/setup' },
|
|
||||||
preferences: {},
|
|
||||||
body: new BasicRepresentation(),
|
|
||||||
};
|
|
||||||
await expect(handler.handle({ operation, request, response })).rejects.toThrow(MethodNotAllowedHttpError);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls the template engine for GET requests.', async(): Promise<void> => {
|
|
||||||
const result = await handler.handle({ operation, request, response });
|
|
||||||
expect(result.data).toBeDefined();
|
|
||||||
await expect(readableToString(result.data!)).resolves.toBe('<html>');
|
|
||||||
expect(result.metadata?.contentType).toBe('text/html');
|
|
||||||
|
|
||||||
// Setup is still enabled since this was a GET request
|
|
||||||
expect(storage.get(storageKey)).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the handler result as 200 response.', async(): Promise<void> => {
|
|
||||||
operation.method = 'POST';
|
|
||||||
const result = await handler.handle({ operation, request, response });
|
|
||||||
expect(result.statusCode).toBe(200);
|
|
||||||
expect(result.data).toBe(representation.data);
|
|
||||||
expect(result.metadata).toBe(representation.metadata);
|
|
||||||
expect(interactionHandler.handleSafe).toHaveBeenCalledTimes(1);
|
|
||||||
expect(interactionHandler.handleSafe).toHaveBeenLastCalledWith({ operation });
|
|
||||||
|
|
||||||
// Handler is now disabled due to successful POST
|
|
||||||
expect(storage.get(storageKey)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts input bodies to JSON.', async(): Promise<void> => {
|
|
||||||
operation.method = 'POST';
|
|
||||||
operation.body.metadata.contentType = APPLICATION_X_WWW_FORM_URLENCODED;
|
|
||||||
const result = await handler.handle({ operation, request, response });
|
|
||||||
expect(result.statusCode).toBe(200);
|
|
||||||
expect(result.data).toBe(representation.data);
|
|
||||||
expect(result.metadata).toBe(representation.metadata);
|
|
||||||
expect(interactionHandler.handleSafe).toHaveBeenCalledTimes(1);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const { body, ...partialOperation } = operation;
|
|
||||||
expect(interactionHandler.handleSafe).toHaveBeenLastCalledWith(
|
|
||||||
{ operation: expect.objectContaining(partialOperation) },
|
|
||||||
);
|
|
||||||
expect(interactionHandler.handleSafe.mock.calls[0][0].operation.body.metadata.contentType).toBe(APPLICATION_JSON);
|
|
||||||
|
|
||||||
// Handler is now disabled due to successful POST
|
|
||||||
expect(storage.get(storageKey)).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
x
Reference in New Issue
Block a user