diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index cfdde6f1a..0c1bf6453 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,6 +5,9 @@ - The server can be started with a new parameter to automatically generate accounts and pods, for more info see [here](guides/seeding-pods.md). - A new `RedirectingHttpHandler` class has been added which can be used to redirect certain URLs. +- A new default configuration `config/https-file-cli.json` + that can set the HTTPS parameters through the CLI has been added. + This is also an example of how to add CLI parameters through a custom configuration. ### Configuration changes You might need to make changes to your v3 configuration if you use a custom config. @@ -18,6 +21,8 @@ The following changes pertain to the imports in the default configs: The following changes are relevant for v3 custom configs that replaced certain features. - The key/value storage configs in `config/storage/key-value/*` have been changed to reduce config duplication. All storages there that were only relevant for 1 class have been moved to the config of that class. +- Due to a parameter rename in `CombinedSettingsResolver`, + `config/app/variables/resolver/resolver.json` has been updated. ### Interface changes These changes are relevant if you wrote custom modules for the server that depend on existing interfaces. @@ -27,6 +32,7 @@ These changes are relevant if you wrote custom modules for the server that depen and has been moved to a separate `ResourceSet` interface. - Several `ModesExtractor`s `PermissionBasedAuthorizer` now take a `ResourceSet` as constructor parameter. - `RepresentationMetadata` no longer accepts strings for predicates in any of its functions. +- `CombinedSettingsResolver` parameter `computers` has been renamed to `resolvers`. ## v3.0.0 ### New features diff --git a/config/app/variables/resolver/resolver.json b/config/app/variables/resolver/resolver.json index 46dcf812f..2f73e0880 100644 --- a/config/app/variables/resolver/resolver.json +++ b/config/app/variables/resolver/resolver.json @@ -5,63 +5,63 @@ "comment": "Converts an input key/value object into an object mapping values to Components.js variables", "@id": "urn:solid-server-app-setup:default:SettingsResolver", "@type": "CombinedSettingsResolver", - "computers": [ + "resolvers": [ { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:baseUrl", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:baseUrl", + "CombinedSettingsResolver:_resolvers_value": { "@type": "BaseUrlExtractor" } }, { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:loggingLevel", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:loggingLevel", + "CombinedSettingsResolver:_resolvers_value": { "@type": "KeyExtractor", "key": "loggingLevel", "defaultValue": "info" } }, { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:port", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:port", + "CombinedSettingsResolver:_resolvers_value": { "@type": "KeyExtractor", "key": "port", "defaultValue": 3000 } }, { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:rootFilePath", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:rootFilePath", + "CombinedSettingsResolver:_resolvers_value": { "@type": "AssetPathExtractor", "key": "rootFilePath", "defaultPath": "./" } }, { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:sparqlEndpoint", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:sparqlEndpoint", + "CombinedSettingsResolver:_resolvers_value": { "@type": "KeyExtractor", "key": "sparqlEndpoint" } }, { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:showStackTrace", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:showStackTrace", + "CombinedSettingsResolver:_resolvers_value": { "@type": "KeyExtractor", "key": "showStackTrace", "defaultValue": false } }, { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:podConfigJson", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:podConfigJson", + "CombinedSettingsResolver:_resolvers_value": { "@type": "AssetPathExtractor", "key": "podConfigJson", "defaultPath": "./pod-config.json" } }, { - "CombinedSettingsResolver:_computers_key": "urn:solid-server:default:variable:seededPodConfigJson", - "CombinedSettingsResolver:_computers_value": { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:default:variable:seededPodConfigJson", + "CombinedSettingsResolver:_resolvers_value": { "@type": "AssetPathExtractor", "key": "seededPodConfigJson" } diff --git a/config/https-file-cli.json b/config/https-file-cli.json new file mode 100644 index 000000000..31e8ceba3 --- /dev/null +++ b/config/https-file-cli.json @@ -0,0 +1,109 @@ +{ + "@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^3.0.0/components/context.jsonld", + "import": [ + "files-scs:config/app/main/default.json", + "files-scs:config/app/init/default.json", + "files-scs:config/app/setup/required.json", + "files-scs:config/app/variables/default.json", + "files-scs:config/http/handler/default.json", + "files-scs:config/http/middleware/websockets.json", + + "files-scs:config/http/static/default.json", + "files-scs:config/identity/access/public.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/modes/default.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": [ + "Adds CLI options --httpsKey and --httpsCert and uses those to start an HTTPS server.", + "The http/server-factory import above has been omitted since that feature is set below." + ] + }, + { + "@id": "urn:solid-server-app-setup:default:CliExtractor", + "@type": "YargsCliExtractor", + "extendedParameters": { + "httpsKey": { + "demandOption": true, + "requiresArg": true, + "type": "string", + "describe": "File path to the HTTPS key." + }, + "httpsCert": { + "demandOption": true, + "requiresArg": true, + "type": "string", + "describe": "File path to the HTTPS certificate." + } + } + }, + { + "comment": "Adds resolvers to assign the CLI values to the Components.js variables.", + "@id": "urn:solid-server-app-setup:default:SettingsResolver", + "@type": "CombinedSettingsResolver", + "resolvers": [ + { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:custom:variable:httpsKey", + "CombinedSettingsResolver:_resolvers_value": { + "@type": "KeyExtractor", + "key": "httpsKey" + } + }, + { + "CombinedSettingsResolver:_resolvers_key": "urn:solid-server:custom:variable:httpsCert", + "CombinedSettingsResolver:_resolvers_value": { + "@type": "KeyExtractor", + "key": "httpsCert" + } + } + ] + }, + { + "comment": [ + "Creates an HTTPS server with the settings provided via the command line.", + "Replaces the example import from config/http/server-factory.https-example.json." + ], + "@id": "urn:solid-server:default:ServerFactory", + "@type": "WebSocketServerFactory", + "baseServerFactory": { + "@id": "urn:solid-server:default:HttpServerFactory", + "@type": "BaseHttpServerFactory", + "handler": { "@id": "urn:solid-server:default:HttpHandler" }, + "options_showStackTrace": { "@id": "urn:solid-server:default:variable:showStackTrace" }, + "options_https": true, + "options_key": { + "@id": "urn:solid-server:custom:variable:httpsKey", + "@type": "Variable" + }, + "options_cert": { + "@id": "urn:solid-server:custom:variable:httpsCert", + "@type": "Variable" + } + }, + "webSocketHandler": { + "@type": "UnsecureWebSocketsProtocol", + "source": { "@id": "urn:solid-server:default:ResourceStore" } + } + } + ] +} diff --git a/src/init/cli/YargsCliExtractor.ts b/src/init/cli/YargsCliExtractor.ts index 2330174e2..9d41750c9 100644 --- a/src/init/cli/YargsCliExtractor.ts +++ b/src/init/cli/YargsCliExtractor.ts @@ -31,10 +31,13 @@ export class YargsCliExtractor extends CliExtractor { * @param parameters - Parameters that should be parsed from the CLI. @range {json} * Format details can be found at https://yargs.js.org/docs/#api-reference-optionskey-opt * @param options - Additional options to configure yargs. @range {json} + * @param extendedParameters - The same as @parameters. Separate variable so in Components.js + * we can have both a default set and a user-added version. @range {json} */ - public constructor(parameters: YargsArgOptions = {}, options: CliOptions = {}) { + public constructor(parameters: YargsArgOptions = {}, options: CliOptions = {}, + extendedParameters: YargsArgOptions = {}) { super(); - this.yargsArgOptions = parameters; + this.yargsArgOptions = { ...parameters, ...extendedParameters }; this.yargvOptions = options; } diff --git a/src/init/variables/CombinedSettingsResolver.ts b/src/init/variables/CombinedSettingsResolver.ts index 9fe2a9df7..b8000d6e8 100644 --- a/src/init/variables/CombinedSettingsResolver.ts +++ b/src/init/variables/CombinedSettingsResolver.ts @@ -6,16 +6,16 @@ import { SettingsResolver } from './SettingsResolver'; * Generates variable values by running a set of {@link SettingsExtractor}s on the input. */ export class CombinedSettingsResolver extends SettingsResolver { - public readonly computers: Record; + public readonly resolvers: Record; - public constructor(computers: Record) { + public constructor(resolvers: Record) { super(); - this.computers = computers; + this.resolvers = resolvers; } public async handle(input: Record): Promise> { const vars: Record = {}; - for (const [ name, computer ] of Object.entries(this.computers)) { + for (const [ name, computer ] of Object.entries(this.resolvers)) { try { vars[name] = await computer.handleSafe(input); } catch (err: unknown) { diff --git a/test/unit/init/cli/YargsCliExtractor.test.ts b/test/unit/init/cli/YargsCliExtractor.test.ts index 312aa0c82..e23b77487 100644 --- a/test/unit/init/cli/YargsCliExtractor.test.ts +++ b/test/unit/init/cli/YargsCliExtractor.test.ts @@ -4,6 +4,7 @@ import { YargsCliExtractor } from '../../../../src/init/cli/YargsCliExtractor'; const error = jest.spyOn(console, 'error').mockImplementation(jest.fn()); const log = jest.spyOn(console, 'log').mockImplementation(jest.fn()); const exit = jest.spyOn(process, 'exit').mockImplementation(jest.fn() as any); + describe('A YargsCliExtractor', (): void => { const parameters: YargsArgOptions = { baseUrl: { alias: 'b', requiresArg: true, type: 'string' }, @@ -41,6 +42,16 @@ describe('A YargsCliExtractor', (): void => { await expect(extractor.handle(argv)).resolves.toEqual(expect.objectContaining({})); }); + it('combines parameters and extra parameters.', async(): Promise => { + extractor = new YargsCliExtractor(parameters, {}, { test: { alias: 't', requiresArg: true, type: 'string' }}); + const argv = [ 'node', 'script', '-b', 'http://localhost:3000/', '-p', '3000', '-t', 'test' ]; + await expect(extractor.handle(argv)).resolves.toEqual(expect.objectContaining({ + baseUrl: 'http://localhost:3000/', + port: 3000, + test: 'test', + })); + }); + it('prints usage if defined.', async(): Promise => { extractor = new YargsCliExtractor(parameters, { usage: 'node ./bin/server.js [args]' }); const argv = [ 'node', 'script', '--help' ]; diff --git a/test/unit/init/variables/CombinedSettingsResolver.test.ts b/test/unit/init/variables/CombinedSettingsResolver.test.ts index 8f262e14a..9e803272e 100644 --- a/test/unit/init/variables/CombinedSettingsResolver.test.ts +++ b/test/unit/init/variables/CombinedSettingsResolver.test.ts @@ -5,22 +5,22 @@ describe('A CombinedSettingsResolver', (): void => { const values = { test: 'data' }; const varPort = 'urn:solid-server:default:variable:port'; const varLog = 'urn:solid-server:default:variable:loggingLevel'; - let computerPort: jest.Mocked; - let computerLog: jest.Mocked; + let resolverPort: jest.Mocked; + let resolverLog: jest.Mocked; let resolver: CombinedSettingsResolver; beforeEach(async(): Promise => { - computerPort = { + resolverPort = { handleSafe: jest.fn().mockResolvedValue(3000), } as any; - computerLog = { + resolverLog = { handleSafe: jest.fn().mockResolvedValue('info'), } as any; resolver = new CombinedSettingsResolver({ - [varPort]: computerPort, - [varLog]: computerLog, + [varPort]: resolverPort, + [varLog]: resolverLog, }); }); @@ -32,7 +32,7 @@ describe('A CombinedSettingsResolver', (): void => { }); it('rethrows the error if something goes wrong.', async(): Promise => { - computerPort.handleSafe.mockRejectedValueOnce(new Error('bad data')); + resolverPort.handleSafe.mockRejectedValueOnce(new Error('bad data')); await expect(resolver.handle(values)).rejects.toThrow(`Error in computing value for variable ${varPort}: bad data`); }); });