diff --git a/.dev/config.json b/.dev/config.json index 05af6b01..640d4ba7 100644 --- a/.dev/config.json +++ b/.dev/config.json @@ -8,7 +8,13 @@ }, "infrastructure": { "httpServer": { - "apiKey": "This_is_a_test_APIKEY_with_30_chars+" + "authentication": { + "apiKey": { + "keys": { + "default": { "key": "This_is_a_test_APIKEY_with_30_chars+" } + } + } + } } }, "modules": { diff --git a/.dev/scripts/establishRelationshipAndSpamMessages.ts b/.dev/scripts/establishRelationshipAndSpamMessages.ts index 7b8c434d..ac279784 100644 --- a/.dev/scripts/establishRelationshipAndSpamMessages.ts +++ b/.dev/scripts/establishRelationshipAndSpamMessages.ts @@ -1,15 +1,15 @@ import { sleep } from "@js-soft/ts-utils"; -import { ConnectorClient, RelationshipStatus } from "@nmshd/connector-sdk"; +import { ApiKeyAuthenticator, ConnectorClient, RelationshipStatus } from "@nmshd/connector-sdk"; async function run() { const connector1 = ConnectorClient.create({ baseUrl: "http://localhost:3000", - apiKey: "This_is_a_test_APIKEY_with_30_chars+" + authenticator: new ApiKeyAuthenticator("This_is_a_test_APIKEY_with_30_chars+") }); const connector2 = ConnectorClient.create({ baseUrl: "http://localhost:3001", - apiKey: "This_is_a_test_APIKEY_with_30_chars+" + authenticator: new ApiKeyAuthenticator("This_is_a_test_APIKEY_with_30_chars+") }); const { connector1Address, connector2Address } = await establishOrReturnRelationship(connector1, connector2); diff --git a/.dev/scripts/syncConnector1.sh b/.dev/scripts/syncConnector1.sh index 10144154..8ea0fe9e 100755 --- a/.dev/scripts/syncConnector1.sh +++ b/.dev/scripts/syncConnector1.sh @@ -2,4 +2,4 @@ set -e -curl -H "X-API-KEY: This_is_a_test_APIKEY_with_30_chars+" -X POST http://localhost:3000/api/v2/Account/Sync +curl -H "X-API-KEY: This_is_a_test_APIKEY_with_30_chars+" -X POST http://localhost:3000/api/core/v1/Account/Sync diff --git a/.dev/scripts/syncConnector2.sh b/.dev/scripts/syncConnector2.sh index 9900a61a..59c78b34 100755 --- a/.dev/scripts/syncConnector2.sh +++ b/.dev/scripts/syncConnector2.sh @@ -2,4 +2,4 @@ set -e -curl -H "X-API-KEY: This_is_a_test_APIKEY_with_30_chars+" -X POST http://localhost:3001/api/v2/Account/Sync +curl -H "X-API-KEY: This_is_a_test_APIKEY_with_30_chars+" -X POST http://localhost:3001/api/core/v1/Account/Sync diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 7b6c1a02..a8b7a93b 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -6,12 +6,6 @@ schedule: ["after 10pm every weekday", "before 5am every weekday", "every weekend"], reviewers: ["jkoenig134", "Milena-Czierlinski"], packageRules: [ - { - // we don't want to update typescript-rest currently, because the connector v6 is incompatible with the latest version - matchDatasources: ["npm"], - matchPackageNames: ["@nmshd/typescript-rest"], - enabled: false - }, { // all patch versions of all packages should be part of a single group groupName: "patch-all", diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 70b6a69b..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,635 +0,0 @@ -# Changelog - -## Discontinued - -This changelog is discontinued in favor of the [GitHub Releases](https://github.com/nmshd/connector/releases) - -## 3.11.4 - -- health checks now use `https_proxy` if set - -## 3.11.3 - -- upgrade the runtime version to 4.10.6 - -## 3.11.2 - -- upgrade nodejs to 22.2.0 - -## 3.11.1 - -- upgrade nodejs to 20.13.1 - -## 3.11.0 - --> SDK 4.3.0 - -- add query parameter to `GET /api/v2/Attributes/Own/Repository` -- upgrade the runtime version to 4.7.1 - -## 3.10.1 - -- the prefix `acc-` that is appended to the configured dbName in the config is now configurable via the key `database:dbNamePrefix` - -## 3.10.0 - --> SDK 4.2.0 - -- add routes for deleting attributes - - `DELETE /api/v2/Attributes/Own/Shared/{id}` Delete a own shared attribute and notify Peer - - `DELETE /api/v2/Attributes/Peer/Shared/{id}` Delete a peer shared attribute and notify Owner - - `DELETE /api/v2/Attributes/{id}` Delete a repository attribute - - `DELETE /api/v2/Attributes/Third/Party/{id}` Delete a Third Party attribute and notify Peer -- upgrade the runtime version to 4.6.0 - -## 3.9.4 - -- the `https_proxy` environment variable is now respected by the connector - -## 3.9.3 - -- errors resulting from the backbone will now be correctly return a `500` http status code - -## 3.9.2 - -- align the url configuration of the `messageBrokerPublisher`s mqtt implementation - -## 3.9.1 - -- upgrade the runtime version to 4.3.7 - -## 3.9.0 - -- add new module `messageBrokerPublisher` (see https://enmeshed.eu/operate/configuration#messagebrokerpublisher for more details on how to configure it) - - the `amqpPublisher` module is now deprecated - - the `pubSubPublisher` module is now deprecated - -## 3.8.1 - -- upgrade the runtime version to 4.3.6 - When querying attributes by tag, single tags will now work properly - -## 3.8.0 - --> SDK 4.1.0 - -- add routes for querying versions of attributes - - `GET /api/v2/Attributes/Own/Repository` Get all the repository attributes - - `GET /api/v2/Attributes/Own/Shared/Identity` Get all own shared identity attributes - - `GET /api/v2/Attributes/Peer/Shared/Identity` Get all peer shared identity attributes - - `GET /api/v2/Attributes/{id}/Versions` Get all versions of one repository attribute - - `GET /api/v2/Attributes/{id}/Versions/Shared` Get all shared versions of one repository attribute - -## 3.7.3 - -- the webhooksV2 module is now named webhooks - - => configuring webhooksV2 is deprecated and will be removed in a future version - -## 3.7.2 - --> SDK 4.0.0 - -- upgrade the runtime version to 4.0.0 - -## 3.7.1 - -- upgrade the runtime version to 3.7.0 -- upgrade assorted dependencies - -## 3.7.0 - --> SDK 3.0.0 - -- upgrade the runtime version to 3.5.3 - - this will improve the performance of internal queries on FerretDB (e.g. while sending messages) -- upgrade nodejs to 20.11.0 -- fix: `POST /api/v2/Attributes` will no longer accept RelationshipAttributes, as this was unintentional and led to wrong behavior -- add routes for attribute succession: - - `POST /api/v2/Attributes/{predecessorId}/Succeed`: Succeeds Repository Attributes and Relationship Attributes. - - `POST /api/v2/Attributes/{attributeId}/NotifyPeer`: Notifies a peer about a succession of a previously shared Identity Attribute. -- Enable the notification module by default - -## 3.6.3 - --> SDK 2.2.6 - -- update the connector repository url - -## 3.6.2 - --> SDK 2.2.5 - -- provenance sbom for the Docker Images - -## 3.6.1 - -- provenance attestations on the Docker Images - -## 3.6.0 - -- new module: 'PubSubPublisher' (see https://enmeshed.eu/operate/configuration#pubsubpublisher for more details on how to configure it) -- upgrade the runtime version to 2.10.0 - -## 3.5.6 - --> SDK 2.2.4 - -- upgrade the runtime version to 2.9.1 -- upgrade nodejs to 20.9.0 - -## 3.5.5 - --> SDK 2.2.3 - -- security audit -- helm chart - - now available on artifacthub - - more metadata -- upgrade the runtime version to 2.8.1 -- upgrade nodejs to 18.18.2 - -## 3.5.4 - -- the connector logs json when running in kubernetes -- update the links to the documentation - -## 3.5.3 - -- helm chart: re-deploy the connector when the configmap changes - -## 3.5.2 - -- fix problem with non-latin characters in filenames that caused a download of the file to return a 500 -- upgrade the runtime version to 2.7.2 -- upgrade nodejs to 18.18.0 - -## 3.5.1 - -- minor Bugfix for the WebhooksV2 module - -## 3.5.0 - --> SDK 2.2.2 - -- upgrade the runtime version to 2.6.1 - - support for the new [FreeTextRequestItem](https://enmeshed.eu/integrate/requests-and-requestitems#freetextrequestitem) - - support for the AttributeValue [Statement](https://enmeshed.eu/integrate/attribute-values#statement) - -## 3.4.0 - --> SDK 2.2.0 - -- expose new IQL query type via the Connector API - - `POST /api/v2/Attributes/ValidateIQLQuery` to validate an IQL query - - `POST /api/v2/Attributes/ExecuteIQLQuery` to execute an IQL query -- upgrade the runtime version to 2.5.2 - -## 3.3.10 - -- (helm chart) set defaults for the liveness and readiness probes -- make health check more robust and performant - -## 3.3.9 - -- Docker images are now provided for the following architectures: - - `linux/amd64` - - `linux/arm64` - - `linux/arm64/v8` - - `linux/arm/v7` - -## 3.3.8 - --> SDK 2.1.8 - -- upgrade libraries -- upgrade the runtime to version 2.4.7 - -## 3.3.7 - -- use fully qualified app name in the helm chart - -## 3.3.6 - -- bump npm packages - -## 3.3.5 - -- upgrade nodejs to 18.16.0 - -## 3.3.4 - -- the helm chart now allows to configure the image of the `ferretdb` sidecar (use `ferretdb.image` in the config file) - -## 3.3.3 - -- set the `CAP_NET_BIND_SERVICE` capability for the node executable in the docker image (required for the Connector to bind to ports < 1024 when running as non-root) - -## 3.3.2 - -- the helm chart now deploys a Deployment instead of a Pod (some configuration options have changed significantly) - -## 3.3.1 - --> SDK 2.1.7 - -- upgrade the runtime to version 2.4.4 -- upgrade nodejs to 18.15.0 - -## 3.3.0 - -- do not send stack traces over http by default -- add a debug mode for the connector (use `{ "debug": true }` in the config file) where stack traces are sent over http -- `coreHttpApi` docs arent allowed to enable in the production mode -- the `httpServer` infrastructure now allows to configure helmet fine grained over the `helmetOptions` option - -## 3.2.8 - -- better error handling in the `amqpPublisher` module - -## 3.2.7 - --> SDK 2.1.6 - -- upgrade nodejs to 18.14.2 -- upgrade the runtime to version 2.4.4 - -## 3.2.6 - --> SDK 2.1.5 - -- upgrade the runtime to version 2.3.6 (fixes a bug that forbids querying for Requests by their Request item's `@type`) - -## 3.2.5 - --> SDK 2.1.4 - -- upgrade the runtime to version 2.3.4 - -## 3.2.4 - --> SDK 2.1.3 - -- \[helm-chart\] add a `ferretdb` sidecar container to the helm chart to connect to PostgreSQL databases -- upgrade the runtime to version 2.3.3 -- upgrade nodejs to 18.13.0 - -## 3.2.3 - -- update the favicon used in the openapi docs - -## 3.2.2 - --> SDK 2.1.2 - -- upgrade the runtime to version 2.3.1 - -## 3.2.1 - -- add a helm chart for the connector - -## 3.2.0 - -- upgrade the runtime to version 2.3.0 (RequestModule full onExistingRelationship support) - -## 3.1.2 - -- upgrade the runtime to version 2.2.1 - -## 3.1.1 - --> SDK 2.1.1 - -- upgrade the runtime to version 2.1.1 (additional validations for Request Items) - -## 3.1.0 - --> SDK 2.1.0 - -- upgrade the runtime to version 2.1.0 (possibility to send `ThirdPartyRelationshipAttributeQuery`s with more than one `thirdParty` by passing an array of strings instead of a single string) - -## 3.0.4 - -- upgrade the runtime to version 2.0.1 ([`ProprietaryJSON`](https://enmeshed.eu/integrate/attribute-values#proprietaryjson) AttributeValueType) - -## 3.0.3 - --> SDK 2.0.3 - -- remove `@context` and `@version` from documentations - -## 3.0.2 - --> SDK 2.0.2 - -- remove RelationshipStatus `Revoked` - -## 3.0.1 - --> SDK 2.0.1 - -- add RelationshipStatus `Revoked` - -## 3.0.0 - --> SDK 2.0.0 - -- upgrade the runtime to version 2.0.0 -- switch from `root` user to the `node` user in the Docker image -- upgrade nodejs to 18.11.0 -- the deprecated webhooks module has been removed -- change API version to v2 (-> route prefix changes from /api/v1 to /api/v2) -- remove support for revoke of Relationship Changes -- enable the new Runtime-builtin Module AttributeListenerModule -- new `POST /api/v1/Attributes/ExecuteThirdPartyRelationshipAttributeQuery` route for executing ThirdPartyRelationshipAttribute queries -- bugfix(webhooksV2): events are now correctly triggered for triggers with wildcards -- update AttributeQuery requests (`POST /api/v2/Attributes/ExecuteIdentityAttributeQuery` & `POST /api/v2/Attributes/ExecuteRelationshipAttributeQuery`) to match the Runtime API -- `peer` is now optional for validating outgoing requests using the `/api/v2/Requests/Outgoing/Validate` route -- enable GET of Files via truncated reference -- remove unused properties from the DTOs -- remove Message.relationshipIds -- add Message.recipients.relationshipId -- the Connector now validates the Accept header correctly on every route -- routes for generating QrCodes for Files and RelationshipTemplates without Tokens -- bugfix: update misspelled Health in openapidoc to ConnectorHealth -- add documentation and update SDK for `maxNumberOfAllocations` -- add routes for executing `IdentityAttributeQuery` and `RelationshipAttributeQuery` -- add attribute routes -- two mandatory new modules: `RequestModule` and `DeciderModule` -- amqpPublisher module -- add `/api/v2/Requests/Incoming(/...)` and `/api/v2/Requests/Outgoing(/...)` routes. - -## 2.3.5 - -- upgrade nodejs to 16.16.0 - -## 2.3.4 - -- bugfix: add missing axios dependency - -## 2.3.3 - -- upgrade the runtime to version 1.4.2 - -## 2.3.2 - -- upgrade the runtime to version 1.4.1 - -## 2.3.1 - --> SDK 1.2.2 - -- upgrade the runtime to version 1.4.0 - -## 2.3.0 - -- new module: 'webhooksV2' (see https://enmeshed.eu/operate/configuration#webhooksV2 for more details on how to configure it) -- the 'webhooks' module is now deprecated - -## 2.2.1 - -- format number strings (e.g. "1.9" and "1") to their number representations in the environment variable parsing - -## 2.2.0 - --> SDK 1.2.0 - -- upgrade the runtime to version 1.3.4 -- add routes to create and validate challenges -- upgrade NodeJS to version 16.14.0 (LTS) -- add a possibility to configure the Connector using environment variables - - nested fields can now be separated by a colon (`:`) or a double underscore (`__`), casing in the property names will not be changed (no more conversion to UPPER_CASE neccessary) - - e.g. `INFRASTRUCTURE__HTTP_SERVER__API_KEY` (the old representation of `{ "infrastructure": { "httpServer": { "apiKey": "y" } } }`) will now be configured as `infrastructure:httpServer:apiKey` - -## 2.1.10 - -- upgrade the runtime to version 1.2.20 - > this fixes the validation of `expiresAt` fields - -## 2.1.9 - -- upgrade the runtime to version 1.2.19 - -## 2.1.8 - -- upgrade the runtime to version 1.2.18 - -## 2.1.7 - -- upgrade the runtime to version 1.2.17 -- add configuration option for the coreHttpApi to persist the authentication in rapidoc using the browsers `localStorage` - > **Note**: this feature is disabled by default and not recommended for production use. - -## 2.1.6 - -- upgrade the runtime to version 1.2.16 -- rendered QR-Codes now include the prefix `nmshd://qr#` that opens the Enmeshed App when the Code is scanned using a QR-Code Reader - -## 2.1.5 - -- remove `upgrade-insecure-requests` from the CSP to allow accessing the swagger and rapidoc UIs using http - -## 2.1.4 - --> SDK 1.1.7 - -- run `tini` together with the Connector to ensure kernel events will be propagated to the Connector - -## 2.1.3 - --> SDK 1.1.6 - -- upgrade the runtime to version 1.2.11 -- check for creation change status in the AutoAcceptRelationshipCreationChanges module to avoid and error that results in accepting an already accepted change - -## 2.1.2 - -- upgrade the runtime to version 1.2.4 - -## 2.1.1 - -- upgrade the runtime to version 1.0.8 - -## 2.1.0 - -- the `httpServer` configuration moved from `modules` to `infrastructure` -- the `apiKey` in the `httpServer` infrastructure is now mandatory - -## 2.0.8 - --> SDK 1.1.5 - -- open source release - -## 2.0.7 - --> SDK 1.1.4 - -- preparations for open source release - -## 2.0.6 - -- update OpenAPI docs - -## 2.0.5 - -- use DATABASE\_\_DB_NAME (aliased to DATABASE_NAME) instead of ACCOUNT for configuring the MongoDB database - > for backwards compatibilitiy you can still use ACCOUNT -- the `httpEndpointEventPublisher` module was renamed to `webhooks` - -## 2.0.4 - -- upgrade NodeJS to version 16.13.0 (LTS) -- send CORS header for invalidJsonInPayload error - -## 2.0.3 - -- simplify CORS policy and disable it by default (allow everthing by setting env var `MODULES__HTTP_SERVER__CORS__ORIGIN` to `true`) -- upgrade the runtime to version 1.0.4 - -## 2.0.2 - --> SDK 1.1.3 - -- upgrade the runtime to version 1.0.2 - -## 2.0.1 - --> SDK 1.1.2 - -- the `Monitoring/Support` endpoint now additionally returns the runtime version as part of its `version` property -- the `Monitoring/Version` endpoint now additionally returns the runtime version - -## 2.0.0 - -- upgrade the runtime to open source version 1.0.1 -- upgrade Node.js to 16.10.0 - -**breaking changes** - -- the structure of some data has changed significantly => the connector has to be deleted and recreated from scratch -- renamed coreSync module to sync -- the coreLibrary part of the configuration was renamed to transportLibrary (only affected when using a custom config file) - -## 1.3.2 - -- upgrade the runtime version to 2.0.6 - -## 1.3.1 - --> SDK 1.1.1 - -- upgrade the runtime version to 2.0.5 - -## 1.3.0 - --> SDK 1.1.0 - -- upgrade the runtime version to 2.0.1 -- tokens can now be ephemeral (not saved in DB) - -## 1.2.12 - -- upgrade the runtime version to 1.8.4 -- exceptions in modules will not crash the connector anymore - -## 1.2.11 - -- upgrade the runtime version to 1.7.13 -- errors in the CoreSync module will not crash the connector anymore - -## 1.2.10 - -- upgrade the runtime version to 1.7.11 - -## 1.2.9 - -- upgrade the runtime version to 1.7.10 -- upgrade the mongodb library to 1.0.4. Authentication without username an password fails if you pass an `authSource` in the database connection string - -## 1.2.8 - --> SDK 1.0.5 - -- return status-code 201 for the routes `/api/v1/RelationshipTemplates/:id/Token` and `/api/v1/Files/:id/Token` with accept set to `image/png` and `application/json` - -## 1.2.7 - -- upgrade the runtime version to 1.7.1 - -## 1.2.6 - -- added the possibility to provide a custom config file - - mount the file inside the container and specify the file location in the `CUSTOM_CONFIG_LOCATION` environment variable - -## 1.2.5 - --> SDK 1.0.4 - -- upgrade runtime version to 1.7.0 -- `/api/v1/Files/:id/Token` supports an expiresAt query parameter to override the default behaviour -- `/api/v1/RelationshipTemplates/:id/Token` supports an expiresAt query parameter to override the default behaviour - -## 1.2.4 - --> SDK 1.0.3 - -- `/Monitoring/Support` is now showing the identityInfo of the connector - -## 1.2.3 - -- `/Monitoring/Support` is not showing the platformClientSecret anymore - -## 1.2.2 - -- `/health` checks if the Connector is authorized on the Enmeshed backend - -## 1.2.1 - --> SDK 1.0.2 - -- upgrade the runtime to version 1.6.4 -- clientId and clientId are checked on connector startup -- `/api/v1/Account/LastCompletedSyncRun` renamed to `/api/v1/Account/SyncInfo` - -## 1.2.0 - -- provided `Auto Accept Relationship Creation Changes` module. - - enable by setting `MODULES__AUTO_ACCEPT_RELATIONSHIP_CREATION_CHANGES__ENABLED` to "true" - -## 1.1.0 - -- upgrade the runtime to version 1.5.6 -- required setting the PLATFORM_CLIENT_ID and PLATFORM_CLIENT_SECRET - -## 1.0.7 - -- upgrade the runtime to version 1.5.5 - -## 1.0.6 - -- upgrade the runtime to version 1.5.4 - -## 1.0.5 - -- provided openapi docs for the `/api/v1/Account/LastCompletedSyncRun` Route - -## 1.0.4 - -- upgrade the runtime to version 1.2.0 - -## 1.0.3 - --> SDK 1.0.1 - -- Added /api/v1/Account/LastCompletedSyncRun Route -- upgrade nodejs to 16.5.0 - -## 1.0.2 - -- tested on the new backend - -## 1.0.1 - -- fix concurrent requests on the `/api/v1/Account/Sync` route diff --git a/README_dev.md b/README_dev.md index 28e1436b..184c5a13 100644 --- a/README_dev.md +++ b/README_dev.md @@ -139,18 +139,28 @@ npm run test:local -- testSuiteName 4. build the Connector `npm run build` 5. create a config file (for example `local.config.json`) - ``` + ```json { - "debug": true, - "transportLibrary": { - "baseUrl": "", - "platformClientId": "", - "platformClientSecret": "" - }, - "database": { "driver": "lokijs", "folder": "./" }, - "logging": { "categories": { "default": { "appenders": ["console"] } } }, - "infrastructure": { "httpServer": { "apiKey": "", "port": 8080 } }, - "modules": { "coreHttpApi": { "docs": { "enabled": true } } } + "debug": true, + "transportLibrary": { + "baseUrl": "", + "platformClientId": "", + "platformClientSecret": "" + }, + "database": { "driver": "lokijs", "folder": "./" }, + "logging": { "categories": { "default": { "appenders": ["console"] } } }, + "infrastructure": { + "httpServer": { + "authentication": { + "apiKey": { + "enabled": true, + "keys": { "": { "key": "" } } + } + }, + "port": 8080 + } + }, + "modules": { "coreHttpApi": { "docs": { "enabled": true } } } } ``` diff --git a/config.schema.json b/config.schema.json index bea7d30b..c3043937 100644 --- a/config.schema.json +++ b/config.schema.json @@ -32,10 +32,6 @@ "type": "string", "default": "default", "minLength": 1 - }, - "dbNamePrefix": { - "type": "string", - "default": "acc-" } }, "required": ["connectionString"], @@ -51,17 +47,77 @@ "type": "boolean", "default": true }, + "authentication": { + "additionalProperties": false, + "properties": { + "apiKey": { + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "headerName": { + "type": "string" + }, + "keys": { + "additionalProperties": { + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "expiresAt": { + "pattern": "^([+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24:?00)([.,]\\d+(?!:))?)?(\\17[0-5]\\d([.,]\\d+)?)?([zZ]|([+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$", + "type": "string" + }, + "key": { + "type": "string" + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["key"], + "type": "object" + }, + "type": "object" + } + }, + "required": ["keys"], + "type": "object" + }, + "jwtBearer": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "oidc": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, "cors": { "$ref": "#/definitions/CorsOptions", "default": { "origin": false } - }, - "apiKey": { - "type": "string" } }, - "required": ["apiKey"], "type": "object" } }, diff --git a/helmChart/README.md b/helmChart/README.md index 5c0c4460..65505f8f 100644 --- a/helmChart/README.md +++ b/helmChart/README.md @@ -20,7 +20,11 @@ You can find a more detailed documentation [in the enmeshed docs](https://enmesh platformClientSecret: "" infrastructure: httpServer: - apiKey: "" + authentication: + apiKey: + keys: + : + key: "" ``` ### Install the chart @@ -44,7 +48,11 @@ config: platformClientSecret: "" infrastructure: httpServer: - apiKey: "" + authentication: + apiKey: + keys: + : + key: "" pod: ferretdb: diff --git a/package-lock.json b/package-lock.json index dedd05db..d1c0f7f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,9 +18,9 @@ "@js-soft/node-logger": "1.2.1", "@js-soft/ts-utils": "^2.3.5", "@nmshd/connector-types": "*", - "@nmshd/runtime": "6.63.7", + "@nmshd/runtime": "7.0.0-alpha.70", "@nmshd/typescript-ioc": "^3.2.5", - "@nmshd/typescript-rest": "3.1.6", + "@nmshd/typescript-rest": "^3.2.1", "agentkeepalive": "4.6.0", "amqplib": "^0.10.9", "axios": "^1.12.2", @@ -34,6 +34,7 @@ "helmet": "8.1.0", "json-stringify-safe": "5.0.1", "jsonschema": "1.5.0", + "jwt-decode": "^4.0.0", "mqtt": "^5.14.1", "nconf": "0.13.0", "on-headers": "1.1.0", @@ -50,8 +51,8 @@ "@js-soft/eslint-config-ts": "2.0.4", "@js-soft/license-check": "1.0.10", "@nmshd/connector-sdk": "*", - "@nmshd/content": "6.63.7", - "@nmshd/core-types": "6.63.7", + "@nmshd/content": "7.0.0-alpha.70", + "@nmshd/core-types": "7.0.0-alpha.70", "@nmshd/typescript-rest-swagger": "^1.4.3", "@types/amqplib": "^0.10.7", "@types/compression": "^1.8.1", @@ -2026,39 +2027,39 @@ "link": true }, "node_modules/@nmshd/consumption": { - "version": "6.63.7", - "resolved": "https://registry.npmjs.org/@nmshd/consumption/-/consumption-6.63.7.tgz", - "integrity": "sha512-Q+7/k1nu+6CkE7BeswGtxs69Tsz4Qhv/Q884n8xWhvapn5nvrJM+Z1+thgoDLjyjQ192bsG0Yp5z9rce+G1Xbg==", + "version": "7.0.0-alpha.70", + "resolved": "https://registry.npmjs.org/@nmshd/consumption/-/consumption-7.0.0-alpha.70.tgz", + "integrity": "sha512-tAhbp2IqP9Mzq8xkSw/30fnzs5cKLWBStSABppNeWkoAjvi3xcGU8nVRoTSXIFDcf+1lgF6UCSMIJwqXhgKXUw==", "license": "MIT", "dependencies": { "@js-soft/docdb-querytranslator": "^1.1.6", "@js-soft/ts-serval": "2.0.14", "@js-soft/ts-utils": "2.3.5", - "@nmshd/content": "6.63.7", - "@nmshd/core-types": "6.63.7", + "@nmshd/content": "7.0.0-alpha.70", + "@nmshd/core-types": "7.0.0-alpha.70", "@nmshd/iql": "^1.0.4", - "@nmshd/transport": "6.63.7", + "@nmshd/transport": "7.0.0-alpha.70", "lodash": "^4.17.21", "ts-simple-nameof": "^1.3.3" } }, "node_modules/@nmshd/content": { - "version": "6.63.7", - "resolved": "https://registry.npmjs.org/@nmshd/content/-/content-6.63.7.tgz", - "integrity": "sha512-tG6hJ3rSV4QGY+ZY1eZuwzLFFZDEqwdolJzi7z6FJPcCGV3lxJANdfFQMmawF61ap7r25PfbRPcw8xOFgD/nGQ==", + "version": "7.0.0-alpha.70", + "resolved": "https://registry.npmjs.org/@nmshd/content/-/content-7.0.0-alpha.70.tgz", + "integrity": "sha512-47O3KMKJsQO+vgfGdRCUNcqn6SAqtyBN6z2fwsyNX17FNzEh8/cS4znH0KwPbkiyuRihO8uyxfYfC7mucRorbQ==", "license": "MIT", "dependencies": { "@js-soft/ts-serval": "2.0.14", - "@nmshd/core-types": "6.63.7", + "@nmshd/core-types": "7.0.0-alpha.70", "@nmshd/iql": "^1.0.4", "luxon": "^3.7.2", "ts-simple-nameof": "^1.3.3" } }, "node_modules/@nmshd/core-types": { - "version": "6.63.7", - "resolved": "https://registry.npmjs.org/@nmshd/core-types/-/core-types-6.63.7.tgz", - "integrity": "sha512-/7jJY/A33cvVATZoSOPG+zgluDyw9uVayrOTPImvYbh54V5iqiiSIAsVvMFOPWgGBFeXi9gd4ORSei6bsehSVA==", + "version": "7.0.0-alpha.70", + "resolved": "https://registry.npmjs.org/@nmshd/core-types/-/core-types-7.0.0-alpha.70.tgz", + "integrity": "sha512-iCzQZrvCpn/euag6CgP2f6aiaapKy9W/Js3+e2vzLKMAoffvGhrAVy3xp6DOtIMpOK3wDnRaYj+kQ2eH/wPNAg==", "license": "MIT", "dependencies": { "@js-soft/logging-abstractions": "^1.0.2", @@ -2086,9 +2087,9 @@ "license": "MIT" }, "node_modules/@nmshd/runtime": { - "version": "6.63.7", - "resolved": "https://registry.npmjs.org/@nmshd/runtime/-/runtime-6.63.7.tgz", - "integrity": "sha512-nem8bNh1WtZAdp3aa0y0MU+j6Ts+PCsrhPC6SBDBkX3tLUgr6v16niQd5nAKDS9yEF2c2VIKAa2wPYZy3WdS+g==", + "version": "7.0.0-alpha.70", + "resolved": "https://registry.npmjs.org/@nmshd/runtime/-/runtime-7.0.0-alpha.70.tgz", + "integrity": "sha512-m4FTUIKkmDMPnynttbdWBflnawxHyRPejVecWTdr+WUxPXEtPZQzWAFWkf+0z5Zty2EqwAbkeq1rTaBPL8wtPA==", "license": "MIT", "peer": true, "dependencies": { @@ -2096,13 +2097,13 @@ "@js-soft/logging-abstractions": "^1.0.2", "@js-soft/ts-serval": "2.0.14", "@js-soft/ts-utils": "^2.3.5", - "@nmshd/consumption": "6.63.7", - "@nmshd/content": "6.63.7", - "@nmshd/core-types": "6.63.7", + "@nmshd/consumption": "7.0.0-alpha.70", + "@nmshd/content": "7.0.0-alpha.70", + "@nmshd/core-types": "7.0.0-alpha.70", "@nmshd/crypto": "2.1.3", "@nmshd/iql": "^1.0.4", - "@nmshd/runtime-types": "6.63.7", - "@nmshd/transport": "6.63.7", + "@nmshd/runtime-types": "7.0.0-alpha.70", + "@nmshd/transport": "7.0.0-alpha.70", "@nmshd/typescript-ioc": "3.2.5", "ajv": "^8.17.1", "ajv-errors": "^3.0.0", @@ -2115,27 +2116,26 @@ } }, "node_modules/@nmshd/runtime-types": { - "version": "6.63.7", - "resolved": "https://registry.npmjs.org/@nmshd/runtime-types/-/runtime-types-6.63.7.tgz", - "integrity": "sha512-TsTGHY9u7JEVmcwMQaLEltkOPZ0inFC086WJHt+rYrVyMrt5KUUGGACLI3I0TS+CPazC2zW997CSdO8tL3bAjQ==", + "version": "7.0.0-alpha.70", + "resolved": "https://registry.npmjs.org/@nmshd/runtime-types/-/runtime-types-7.0.0-alpha.70.tgz", + "integrity": "sha512-PAT7dnxXMbmI9a5s4Fss7+b/Z69rpQzCXPLBmXvIFF0hF5p9Y1TjjjW45H5d37xBpsC33UzYVTLvTQe6M/YJGg==", "license": "MIT" }, "node_modules/@nmshd/transport": { - "version": "6.63.7", - "resolved": "https://registry.npmjs.org/@nmshd/transport/-/transport-6.63.7.tgz", - "integrity": "sha512-N+rdzBBxxxY5Q40N5hbYmCD7ifhw1r6aRaMjq9ifNj2hBSGiH8mF/dfmC3WXM6pNyBjLQm04VcXD2IeWc7KcqQ==", + "version": "7.0.0-alpha.70", + "resolved": "https://registry.npmjs.org/@nmshd/transport/-/transport-7.0.0-alpha.70.tgz", + "integrity": "sha512-qjNahdaBGPQvLKRlUYD7MTgo4LaRKY8kp4yBbC1HFkWQI/d3KXmU/7YANfupn3xfQaYcfesww1QlTLrRYB0UXQ==", "license": "MIT", "dependencies": { "@js-soft/docdb-access-abstractions": "1.2.1", "@js-soft/logging-abstractions": "^1.0.2", "@js-soft/simple-logger": "1.0.6", "@js-soft/ts-utils": "^2.3.5", - "@nmshd/core-types": "6.63.7", + "@nmshd/core-types": "7.0.0-alpha.70", "@nmshd/crypto": "2.1.3", "axios": "^1.12.2", "fast-json-patch": "^3.1.1", "form-data": "^4.0.4", - "https-proxy-agent": "^7.0.6", "json-stringify-safe": "^5.0.1", "lodash": "^4.17.21", "luxon": "^3.7.2", @@ -2155,22 +2155,22 @@ } }, "node_modules/@nmshd/typescript-rest": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@nmshd/typescript-rest/-/typescript-rest-3.1.6.tgz", - "integrity": "sha512-UM8VQGytoqU3zPNpruA0svYMrIxE9GD+U8G6Q4coH0uKoqPEpRcqUbtF4wn4bnHLEsUFkMmVw6Z47lPExmUyPQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@nmshd/typescript-rest/-/typescript-rest-3.2.1.tgz", + "integrity": "sha512-PZzr90cooBrK7Ydt7KOFteP7MHc9H+Qe771bql0HAIoLow1jixcu6RXmpBPG6JJA4Ip0Xxtth5SDSlB9csbh6g==", "license": "MIT", "peer": true, "dependencies": { - "@types/body-parser": "1.19.5", - "@types/cookie-parser": "^1.4.8", - "@types/express": "^5.0.2", - "@types/multer": "^1.4.13", + "@types/body-parser": "1.19.6", + "@types/cookie-parser": "^1.4.9", + "@types/express": "^5.0.3", + "@types/multer": "^2.0.0", "body-parser": "^2.2.0", "cookie-parser": "^1.4.7", "express": "^5.1.0", - "fs-extra": "^11.3.0", + "fs-extra": "^11.3.2", "lodash": "^4.17.21", - "multer": "^2.0.1", + "multer": "^2.0.2", "reflect-metadata": "^0.2.2", "require-glob": "^4.1.0", "swagger-ui-express": "^5.0.1", @@ -2208,53 +2208,6 @@ "node": ">=6.0.0" } }, - "node_modules/@nmshd/typescript-rest-swagger/node_modules/@nmshd/typescript-rest": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@nmshd/typescript-rest/-/typescript-rest-3.2.1.tgz", - "integrity": "sha512-PZzr90cooBrK7Ydt7KOFteP7MHc9H+Qe771bql0HAIoLow1jixcu6RXmpBPG6JJA4Ip0Xxtth5SDSlB9csbh6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "1.19.6", - "@types/cookie-parser": "^1.4.9", - "@types/express": "^5.0.3", - "@types/multer": "^2.0.0", - "body-parser": "^2.2.0", - "cookie-parser": "^1.4.7", - "express": "^5.1.0", - "fs-extra": "^11.3.2", - "lodash": "^4.17.21", - "multer": "^2.0.2", - "reflect-metadata": "^0.2.2", - "require-glob": "^4.1.0", - "swagger-ui-express": "^5.0.1", - "yamljs": "^0.3.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@nmshd/typescript-rest-swagger/node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@nmshd/typescript-rest-swagger/node_modules/@types/multer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", - "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3254,9 +3207,9 @@ } }, "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "license": "MIT", "dependencies": { "@types/connect": "*", @@ -3480,9 +3433,9 @@ "license": "MIT" }, "node_modules/@types/multer": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.13.tgz", - "integrity": "sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", "license": "MIT", "dependencies": { "@types/express": "*" @@ -9185,6 +9138,15 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -13885,8 +13847,8 @@ "name": "@nmshd/connector-sdk", "license": "MIT", "dependencies": { - "@nmshd/content": "6.63.7", - "@nmshd/runtime-types": "6.63.7", + "@nmshd/content": "7.0.0-alpha.70", + "@nmshd/runtime-types": "7.0.0-alpha.70", "axios": "^1.12.2", "form-data": "^4.0.4", "qs": "^6.14.0" @@ -13913,8 +13875,8 @@ "peerDependencies": { "@js-soft/docdb-access-abstractions": "^1.2.1", "@js-soft/ts-utils": "^2.3.5", - "@nmshd/runtime": "^6.63.7", - "@nmshd/typescript-rest": "3.1.6", + "@nmshd/runtime": "7.0.0-alpha.70", + "@nmshd/typescript-rest": "^3.2.1", "express": "^5.1.0" } } diff --git a/package.json b/package.json index 92ddbb7d..67a9e324 100644 --- a/package.json +++ b/package.json @@ -84,9 +84,9 @@ "@js-soft/node-logger": "1.2.1", "@js-soft/ts-utils": "^2.3.5", "@nmshd/connector-types": "*", - "@nmshd/runtime": "6.63.7", + "@nmshd/runtime": "7.0.0-alpha.70", "@nmshd/typescript-ioc": "^3.2.5", - "@nmshd/typescript-rest": "3.1.6", + "@nmshd/typescript-rest": "^3.2.1", "agentkeepalive": "4.6.0", "amqplib": "^0.10.9", "axios": "^1.12.2", @@ -100,6 +100,7 @@ "helmet": "8.1.0", "json-stringify-safe": "5.0.1", "jsonschema": "1.5.0", + "jwt-decode": "^4.0.0", "mqtt": "^5.14.1", "nconf": "0.13.0", "on-headers": "1.1.0", @@ -116,8 +117,8 @@ "@js-soft/eslint-config-ts": "2.0.4", "@js-soft/license-check": "1.0.10", "@nmshd/connector-sdk": "*", - "@nmshd/content": "6.63.7", - "@nmshd/core-types": "6.63.7", + "@nmshd/content": "7.0.0-alpha.70", + "@nmshd/core-types": "7.0.0-alpha.70", "@nmshd/typescript-rest-swagger": "^1.4.3", "@types/amqplib": "^0.10.7", "@types/compression": "^1.8.1", diff --git a/packages/sdk/README.md b/packages/sdk/README.md index 8a060c29..3b13ccde 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -37,7 +37,10 @@ npm i @nmshd/connector-sdk 1. Initialize the `ConnectorClient` ```typescript - const connectorClient = ConnectorClient.create({ baseUrl: "https://", apiKey: "" }); + const connectorClient = ConnectorClient.create({ + baseUrl: "https://", + authenticator: new ApiKeyAuthenticator("") + }); ``` 2. Start using the client diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 21a92e81..45d42bb2 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -29,8 +29,8 @@ "build:schemas:watch": "npx nodemon -e ts -w 'src/types' --exec 'npm run build:schemas'" }, "dependencies": { - "@nmshd/content": "6.63.7", - "@nmshd/runtime-types": "6.63.7", + "@nmshd/content": "7.0.0-alpha.70", + "@nmshd/runtime-types": "7.0.0-alpha.70", "axios": "^1.12.2", "form-data": "^4.0.4", "qs": "^6.14.0" diff --git a/packages/sdk/src/ConnectorClient.ts b/packages/sdk/src/ConnectorClient.ts index da8a28c5..51e5f6a5 100644 --- a/packages/sdk/src/ConnectorClient.ts +++ b/packages/sdk/src/ConnectorClient.ts @@ -1,5 +1,4 @@ import axios, { AxiosInstance } from "axios"; -import { ApiKeyAuthenticator } from "./authentication"; import { ConnectorClientConfig } from "./ConnectorClientConfig"; import { AccountEndpoint, @@ -56,10 +55,7 @@ export class ConnectorClient { paramsSerializer: { dots: true, indexes: null } }); - const authenticator = "authenticator" in config ? config.authenticator : "apiKey" in config ? new ApiKeyAuthenticator(config.apiKey) : null; - - if (!authenticator) throw new Error("No authenticator provided. Please provide an authenticator or an API key."); - this.axiosInstance.interceptors.request.use(async (requestConfig) => await authenticator.authenticate(requestConfig)); + this.axiosInstance.interceptors.request.use(async (requestConfig) => await config.authenticator.authenticate(requestConfig)); this.axiosInstance.interceptors.request.use((config) => { const correlationId = this.#correlationId; diff --git a/packages/sdk/src/ConnectorClientConfig.ts b/packages/sdk/src/ConnectorClientConfig.ts index a6022b30..00d2f5c1 100644 --- a/packages/sdk/src/ConnectorClientConfig.ts +++ b/packages/sdk/src/ConnectorClientConfig.ts @@ -2,16 +2,9 @@ import http from "http"; import https from "https"; import { IConnectorClientAuthenticator } from "./authentication/IConnectorClientAuthenticator"; -export type ConnectorClientConfig = { +export interface ConnectorClientConfig { baseUrl: string; httpAgent?: http.Agent; httpsAgent?: https.Agent; -} & ( - | { authenticator: IConnectorClientAuthenticator } - | { - /** - * @deprecated Instead, set the `authenticator` property to `new ApiKeyAuthenticator()` - */ - apiKey: string; - } -); + authenticator: IConnectorClientAuthenticator; +} diff --git a/packages/sdk/src/endpoints/AccountEndpoint.ts b/packages/sdk/src/endpoints/AccountEndpoint.ts index 2aad152e..877f35b9 100644 --- a/packages/sdk/src/endpoints/AccountEndpoint.ts +++ b/packages/sdk/src/endpoints/AccountEndpoint.ts @@ -3,14 +3,14 @@ import { Endpoint } from "./Endpoint"; export class AccountEndpoint extends Endpoint { public async getIdentityInfo(): Promise> { - return await this.get("/api/v2/Account/IdentityInfo"); + return await this.get("/api/core/v1/Account/IdentityInfo"); } public async sync(): Promise> { - return await this.post("/api/v2/Account/Sync", undefined, 204); + return await this.post("/api/core/v1/Account/Sync", undefined, 204); } public async getSyncInfo(): Promise> { - return await this.get("/api/v2/Account/SyncInfo"); + return await this.get("/api/core/v1/Account/SyncInfo"); } } diff --git a/packages/sdk/src/endpoints/AnnouncementsEndpoint.ts b/packages/sdk/src/endpoints/AnnouncementsEndpoint.ts index bb393fad..f1ef7ba9 100644 --- a/packages/sdk/src/endpoints/AnnouncementsEndpoint.ts +++ b/packages/sdk/src/endpoints/AnnouncementsEndpoint.ts @@ -5,6 +5,6 @@ import { Endpoint } from "./Endpoint"; export class AnnouncementsEndpoint extends Endpoint { public async getAnnouncements(request: GetAnnouncementsRequest): Promise> { - return await this.get("/api/v2/Announcements", request); + return await this.get("/api/core/v1/Announcements", request); } } diff --git a/packages/sdk/src/endpoints/AttributesEndpoint.ts b/packages/sdk/src/endpoints/AttributesEndpoint.ts index 73a96dec..19acc823 100644 --- a/packages/sdk/src/endpoints/AttributesEndpoint.ts +++ b/packages/sdk/src/endpoints/AttributesEndpoint.ts @@ -16,7 +16,6 @@ import { GetOwnSharedIdentityAttributesRequest, GetPeerSharedIdentityAttributesRequest, GetSharedVersionsOfAttributeRequest, - GetValidAttributesRequest, NotifyPeerAboutRepositoryAttributeSuccessionRequest, NotifyPeerAboutRepositoryAttributeSuccessionResponse, SucceedAttributeRequest, @@ -26,91 +25,87 @@ import { Endpoint } from "./Endpoint"; export class AttributesEndpoint extends Endpoint { public async canCreateRepositoryAttribute(request: CanCreateRepositoryAttributeRequest): Promise> { - return await this.put("/api/v2/Attributes/CanCreate", request); + return await this.put("/api/core/v1/Attributes/CanCreate", request); } public async createRepositoryAttribute(request: CreateRepositoryAttributeRequest): Promise> { - return await this.post("/api/v2/Attributes", request); + return await this.post("/api/core/v1/Attributes", request); } public async succeedAttribute(predecessorId: string, request: SucceedAttributeRequest): Promise> { - return await this.post(`/api/v2/Attributes/${predecessorId}/Succeed`, request); + return await this.post(`/api/core/v1/Attributes/${predecessorId}/Succeed`, request); } public async notifyPeerAboutRepositoryAttributeSuccession( attributeId: string, request: NotifyPeerAboutRepositoryAttributeSuccessionRequest ): Promise> { - return await this.post(`/api/v2/Attributes/${attributeId}/NotifyPeer`, request); + return await this.post(`/api/core/v1/Attributes/${attributeId}/NotifyPeer`, request); } public async getAttributes(request: GetAttributesRequest): Promise> { - return await this.get("/api/v2/Attributes", request); + return await this.get("/api/core/v1/Attributes", request); } public async getAttribute(attributeId: string): Promise> { - return await this.get(`/api/v2/Attributes/${attributeId}`); - } - - public async getValidAttributes(request: GetValidAttributesRequest): Promise> { - return await this.get("/api/v2/Attributes/Valid", request); + return await this.get(`/api/core/v1/Attributes/${attributeId}`); } public async getAttributeTagCollection(): Promise> { - return await this.get("/api/v2/Attributes/TagCollection"); + return await this.get("/api/core/v1/Attributes/TagCollection"); } public async getOwnRepositoryAttributes(request?: GetOwnRepositoryAttributesRequest): Promise> { - return await this.get("/api/v2/Attributes/Own/Repository", request); + return await this.get("/api/core/v1/Attributes/Own/Repository", request); } public async getOwnSharedIdentityAttributes(request: GetOwnSharedIdentityAttributesRequest): Promise> { - return await this.get("/api/v2/Attributes/Own/Shared/Identity", request); + return await this.get("/api/core/v1/Attributes/Own/Shared/Identity", request); } public async getPeerSharedIdentityAttributes(request: GetPeerSharedIdentityAttributesRequest): Promise> { - return await this.get("/api/v2/Attributes/Peer/Shared/Identity", request); + return await this.get("/api/core/v1/Attributes/Peer/Shared/Identity", request); } public async getVersionsOfAttribute(attributeId: string): Promise> { - return await this.get(`/api/v2/Attributes/${attributeId}/Versions`); + return await this.get(`/api/core/v1/Attributes/${attributeId}/Versions`); } public async getSharedVersionsOfAttribute(attributeId: string, request: GetSharedVersionsOfAttributeRequest): Promise> { - return await this.get(`/api/v2/Attributes/${attributeId}/Versions/Shared`, request); + return await this.get(`/api/core/v1/Attributes/${attributeId}/Versions/Shared`, request); } public async deleteOwnSharedAttributeAndNotifyPeer(attributeId: string): Promise> { - return await this.delete(`/api/v2/Attributes/Own/Shared/${attributeId}`); + return await this.delete(`/api/core/v1/Attributes/Own/Shared/${attributeId}`); } public async deletePeerSharedAttributeAndNotifyOwner(attributeId: string): Promise> { - return await this.delete(`/api/v2/Attributes/Peer/Shared/${attributeId}`); + return await this.delete(`/api/core/v1/Attributes/Peer/Shared/${attributeId}`); } public async deleteRepositoryAttribute(attributeId: string): Promise> { - return await this.delete(`/api/v2/Attributes/${attributeId}`, undefined, 204); + return await this.delete(`/api/core/v1/Attributes/${attributeId}`, undefined, 204); } public async deleteThirdPartyRelationshipAttributeAndNotifyPeer( attributeId: string ): Promise> { - return await this.delete(`/api/v2/Attributes/ThirdParty/${attributeId}`); + return await this.delete(`/api/core/v1/Attributes/ThirdParty/${attributeId}`); } public async executeIdentityAttributeQuery(request: ExecuteIdentityAttributeQueryRequest): Promise> { - return await this.post("/api/v2/Attributes/ExecuteIdentityAttributeQuery", request, 200); + return await this.post("/api/core/v1/Attributes/ExecuteIdentityAttributeQuery", request, 200); } public async executeRelationshipAttributeQuery(request: ExecuteRelationshipAttributeQueryRequest): Promise> { - return await this.post("/api/v2/Attributes/ExecuteRelationshipAttributeQuery", request, 200); + return await this.post("/api/core/v1/Attributes/ExecuteRelationshipAttributeQuery", request, 200); } public async executeThirdPartyRelationshipAttributeQuery(request: ExecuteThirdPartyRelationshipAttributeQueryRequest): Promise> { - return await this.post("/api/v2/Attributes/ExecuteThirdPartyRelationshipAttributeQuery", request, 200); + return await this.post("/api/core/v1/Attributes/ExecuteThirdPartyRelationshipAttributeQuery", request, 200); } public async executeIQLQuery(request: ExecuteIQLQueryRequest): Promise> { - return await this.post("/api/v2/Attributes/ExecuteIQLQuery", request, 200); + return await this.post("/api/core/v1/Attributes/ExecuteIQLQuery", request, 200); } } diff --git a/packages/sdk/src/endpoints/BackboneNotificationsEndpoint.ts b/packages/sdk/src/endpoints/BackboneNotificationsEndpoint.ts index 54f44b0b..7af2311d 100644 --- a/packages/sdk/src/endpoints/BackboneNotificationsEndpoint.ts +++ b/packages/sdk/src/endpoints/BackboneNotificationsEndpoint.ts @@ -3,6 +3,6 @@ import { Endpoint } from "./Endpoint"; export class BackboneNotificationsEndpoint extends Endpoint { public async sendBackboneNotification(request: { recipients: string[]; code: string }): Promise> { - return await this.post("/api/v2/BackboneNotifications", request, 204); + return await this.post("/api/core/v1/BackboneNotifications", request, 204); } } diff --git a/packages/sdk/src/endpoints/ChallengesEndpoint.ts b/packages/sdk/src/endpoints/ChallengesEndpoint.ts index 201f3c9d..ec5ff868 100644 --- a/packages/sdk/src/endpoints/ChallengesEndpoint.ts +++ b/packages/sdk/src/endpoints/ChallengesEndpoint.ts @@ -4,10 +4,10 @@ import { Endpoint } from "./Endpoint"; export class ChallengesEndpoint extends Endpoint { public async createChallenge(request: CreateChallengeRequest): Promise> { - return await this.post("/api/v2/Challenges", request); + return await this.post("/api/core/v1/Challenges", request); } public async validateChallenge(request: ValidateChallengeRequest): Promise> { - return await this.post("/api/v2/Challenges/Validate", request, 200); + return await this.post("/api/core/v1/Challenges/Validate", request, 200); } } diff --git a/packages/sdk/src/endpoints/FilesEndpoint.ts b/packages/sdk/src/endpoints/FilesEndpoint.ts index f2a36bd4..1537b91d 100644 --- a/packages/sdk/src/endpoints/FilesEndpoint.ts +++ b/packages/sdk/src/endpoints/FilesEndpoint.ts @@ -13,12 +13,12 @@ import { Endpoint } from "./Endpoint"; export class FilesEndpoint extends Endpoint { public async getFiles(request?: GetAllFilesRequest): Promise> { - return await this.get("/api/v2/Files", request); + return await this.get("/api/core/v1/Files", request); } public async uploadOwnFile(request: UploadOwnFileRequest): Promise> { const response = await this.postMultipart( - "/api/v2/Files/Own", + "/api/core/v1/Files/Own", { title: request.title, description: request.description, expiresAt: request.expiresAt, file: request.file, tags: request.tags }, request.filename ); @@ -26,42 +26,42 @@ export class FilesEndpoint extends Endpoint { } public async getOwnFiles(request?: GetOwnFilesRequest): Promise> { - return await this.get("/api/v2/Files/Own", request); + return await this.get("/api/core/v1/Files/Own", request); } public async loadPeerFile(request: LoadPeerFileRequest): Promise> { - return await this.post("/api/v2/Files/Peer", request); + return await this.post("/api/core/v1/Files/Peer", request); } public async getPeerFiles(request?: GetPeerFilesRequest): Promise> { - return await this.get("/api/v2/Files/Peer", request); + return await this.get("/api/core/v1/Files/Peer", request); } public async getFile(fileIdOrReference: string): Promise> { - return await this.get(`/api/v2/Files/${fileIdOrReference}`); + return await this.get(`/api/core/v1/Files/${fileIdOrReference}`); } public async downloadFile(fileId: string): Promise> { - return await this.download(`/api/v2/Files/${fileId}/Download`); + return await this.download(`/api/core/v1/Files/${fileId}/Download`); } - public async getQrCodeForFile(fileId: string, newQRCodeFormat?: boolean): Promise> { - return await this.downloadQrCode("GET", `/api/v2/Files/${fileId}`, { newQRCodeFormat: newQRCodeFormat ? "true" : undefined }); + public async getQrCodeForFile(fileId: string): Promise> { + return await this.downloadQrCode("GET", `/api/core/v1/Files/${fileId}`); } public async createTokenForFile(fileId: string, request?: CreateTokenForFileRequest): Promise> { - return await this.post(`/api/v2/Files/${fileId}/Token`, request, undefined); + return await this.post(`/api/core/v1/Files/${fileId}/Token`, request, undefined); } public async createTokenQrCodeForFile(fileId: string, request?: CreateTokenQrCodeForFileRequest): Promise> { - return await this.downloadQrCode("POST", `/api/v2/Files/${fileId}/Token`, request); + return await this.downloadQrCode("POST", `/api/core/v1/Files/${fileId}/Token`, request); } public async deleteFile(fileId: string): Promise> { - return await this.delete(`/api/v2/Files/${fileId}`, undefined, 204); + return await this.delete(`/api/core/v1/Files/${fileId}`, undefined, 204); } public async regenerateFileOwnershipToken(fileId: string): Promise> { - return await this.patch(`/api/v2/Files/${fileId}/RegenerateOwnershipToken`, undefined); + return await this.patch(`/api/core/v1/Files/${fileId}/RegenerateOwnershipToken`, undefined); } } diff --git a/packages/sdk/src/endpoints/IdentityMetadataEndpoint.ts b/packages/sdk/src/endpoints/IdentityMetadataEndpoint.ts index ec413be6..df690a83 100644 --- a/packages/sdk/src/endpoints/IdentityMetadataEndpoint.ts +++ b/packages/sdk/src/endpoints/IdentityMetadataEndpoint.ts @@ -4,14 +4,14 @@ import { Endpoint } from "./Endpoint"; export class IdentityMetadataEndpoint extends Endpoint { public async upsertIdentityMetadata(request: UpsertIdentityMetadataRequest): Promise> { - return await this.put("/api/v2/IdentityMetadata", request); + return await this.put("/api/core/v1/IdentityMetadata", request); } public async getIdentityMetadata(reference: string, key?: string): Promise> { - return await this.get("/api/v2/IdentityMetadata", { reference: reference, key: key }); + return await this.get("/api/core/v1/IdentityMetadata", { reference: reference, key: key }); } public async deleteIdentityMetadata(reference: string, key?: string): Promise> { - return await this.delete("/api/v2/IdentityMetadata", { reference: reference, key: key }, 204); + return await this.delete("/api/core/v1/IdentityMetadata", { reference: reference, key: key }, 204); } } diff --git a/packages/sdk/src/endpoints/IncomingRequestsEndpoint.ts b/packages/sdk/src/endpoints/IncomingRequestsEndpoint.ts index 6014a4c8..3f5e435b 100644 --- a/packages/sdk/src/endpoints/IncomingRequestsEndpoint.ts +++ b/packages/sdk/src/endpoints/IncomingRequestsEndpoint.ts @@ -12,26 +12,26 @@ import { Endpoint } from "./Endpoint"; export class IncomingRequestsEndpoint extends Endpoint { public async canAccept(requestId: string, request: CanAcceptIncomingRequestRequest): Promise> { - return await this.put(`/api/v2/Requests/Incoming/${requestId}/CanAccept`, request); + return await this.put(`/api/core/v1/Requests/Incoming/${requestId}/CanAccept`, request); } public async accept(requestId: string, request: AcceptIncomingRequestRequest): Promise> { - return await this.put(`/api/v2/Requests/Incoming/${requestId}/Accept`, request); + return await this.put(`/api/core/v1/Requests/Incoming/${requestId}/Accept`, request); } public async canReject(requestId: string, request: CanRejectIncomingRequestRequest): Promise> { - return await this.put(`/api/v2/Requests/Incoming/${requestId}/CanReject`, request); + return await this.put(`/api/core/v1/Requests/Incoming/${requestId}/CanReject`, request); } public async reject(requestId: string, request: RejectIncomingRequestRequest): Promise> { - return await this.put(`/api/v2/Requests/Incoming/${requestId}/Reject`, request); + return await this.put(`/api/core/v1/Requests/Incoming/${requestId}/Reject`, request); } public async getRequest(requestId: string): Promise> { - return await this.get(`/api/v2/Requests/Incoming/${requestId}`); + return await this.get(`/api/core/v1/Requests/Incoming/${requestId}`); } public async getRequests(request: GetIncomingRequestsRequest): Promise> { - return await this.get("/api/v2/Requests/Incoming", request); + return await this.get("/api/core/v1/Requests/Incoming", request); } } diff --git a/packages/sdk/src/endpoints/MessagesEndpoint.ts b/packages/sdk/src/endpoints/MessagesEndpoint.ts index 4e4d8721..4728a651 100644 --- a/packages/sdk/src/endpoints/MessagesEndpoint.ts +++ b/packages/sdk/src/endpoints/MessagesEndpoint.ts @@ -9,22 +9,22 @@ export class MessagesEndpoint extends Endpoint { } public async getMessages(request?: GetMessagesRequest): Promise> { - return await this.get("/api/v2/Messages", request); + return await this.get("/api/core/v1/Messages", request); } public async sendMessage(request: SendMessageRequest): Promise> { - return await this.post("/api/v2/Messages", request); + return await this.post("/api/core/v1/Messages", request); } public async getMessage(messageId: string): Promise> { - return await this.get(`/api/v2/Messages/${messageId}`); + return await this.get(`/api/core/v1/Messages/${messageId}`); } public async getAttachment(messageId: string, attachmentId: string): Promise> { - return await this.get(`/api/v2/Messages/${messageId}/Attachments/${attachmentId}`); + return await this.get(`/api/core/v1/Messages/${messageId}/Attachments/${attachmentId}`); } public async downloadAttachment(messageId: string, attachmentId: string): Promise> { - return await this.download(`/api/v2/Messages/${messageId}/Attachments/${attachmentId}/Download`); + return await this.download(`/api/core/v1/Messages/${messageId}/Attachments/${attachmentId}/Download`); } } diff --git a/packages/sdk/src/endpoints/OutgoingRequestsEndpoint.ts b/packages/sdk/src/endpoints/OutgoingRequestsEndpoint.ts index 368d6ad8..1cc8b9a6 100644 --- a/packages/sdk/src/endpoints/OutgoingRequestsEndpoint.ts +++ b/packages/sdk/src/endpoints/OutgoingRequestsEndpoint.ts @@ -4,18 +4,18 @@ import { Endpoint } from "./Endpoint"; export class OutgoingRequestsEndpoint extends Endpoint { public async canCreateRequest(request: CanCreateOutgoingRequestRequest): Promise> { - return await this.post("/api/v2/Requests/Outgoing/Validate", request); + return await this.post("/api/core/v1/Requests/Outgoing/Validate", request); } public async createRequest(request: CreateOutgoingRequestRequest): Promise> { - return await this.post("/api/v2/Requests/Outgoing", request); + return await this.post("/api/core/v1/Requests/Outgoing", request); } public async getRequest(requestId: string): Promise> { - return await this.get(`/api/v2/Requests/Outgoing/${requestId}`); + return await this.get(`/api/core/v1/Requests/Outgoing/${requestId}`); } public async getRequests(request: GetOutgoingRequestsRequest): Promise> { - return await this.get("/api/v2/Requests/Outgoing", request); + return await this.get("/api/core/v1/Requests/Outgoing", request); } } diff --git a/packages/sdk/src/endpoints/RelationshipTemplatesEndpoint.ts b/packages/sdk/src/endpoints/RelationshipTemplatesEndpoint.ts index 4fbbc88e..0d38e726 100644 --- a/packages/sdk/src/endpoints/RelationshipTemplatesEndpoint.ts +++ b/packages/sdk/src/endpoints/RelationshipTemplatesEndpoint.ts @@ -18,41 +18,41 @@ export class RelationshipTemplatesEndpoint extends Endpoint { } public async getRelationshipTemplates(request?: GetRelationshipTemplatesRequest): Promise> { - return await this.get("/api/v2/RelationshipTemplates", request); + return await this.get("/api/core/v1/RelationshipTemplates", request); } public async getRelationshipTemplate(id: string): Promise> { - return await this.get(`/api/v2/RelationshipTemplates/${id}`); + return await this.get(`/api/core/v1/RelationshipTemplates/${id}`); } public async getOwnRelationshipTemplates(request?: GetOwnRelationshipTemplatesRequest): Promise> { - return await this.get("/api/v2/RelationshipTemplates/Own", request); + return await this.get("/api/core/v1/RelationshipTemplates/Own", request); } public async createOwnRelationshipTemplate(request: CreateOwnRelationshipTemplateRequest): Promise> { - return await this.post("/api/v2/RelationshipTemplates/Own", request); + return await this.post("/api/core/v1/RelationshipTemplates/Own", request); } - public async getQrCodeForOwnRelationshipTemplate(id: string, newQRCodeFormat?: boolean): Promise> { - return await this.downloadQrCode("GET", `/api/v2/RelationshipTemplates/${id}`, { newQRCodeFormat: newQRCodeFormat ? "true" : undefined }); + public async getQrCodeForOwnRelationshipTemplate(id: string): Promise> { + return await this.downloadQrCode("GET", `/api/core/v1/RelationshipTemplates/${id}`); } public async createTokenForOwnRelationshipTemplate(id: string, request?: CreateTokenForOwnRelationshipTemplateRequest): Promise> { - return await this.post(`/api/v2/RelationshipTemplates/Own/${id}/Token`, request, undefined); + return await this.post(`/api/core/v1/RelationshipTemplates/Own/${id}/Token`, request, undefined); } public async createTokenQrCodeForOwnRelationshipTemplate( id: string, request?: CreateTokenQrCodeForOwnRelationshipTemplateRequest ): Promise> { - return await this.downloadQrCode("POST", `/api/v2/RelationshipTemplates/Own/${id}/Token`, request); + return await this.downloadQrCode("POST", `/api/core/v1/RelationshipTemplates/Own/${id}/Token`, request); } public async getPeerRelationshipTemplates(request?: GetPeerRelationshipTemplatesRequest): Promise> { - return await this.get("/api/v2/RelationshipTemplates/Peer", request); + return await this.get("/api/core/v1/RelationshipTemplates/Peer", request); } public async loadPeerRelationshipTemplate(request: LoadPeerRelationshipTemplateRequest): Promise> { - return await this.post("/api/v2/RelationshipTemplates/Peer", request); + return await this.post("/api/core/v1/RelationshipTemplates/Peer", request); } } diff --git a/packages/sdk/src/endpoints/RelationshipsEndpoint.ts b/packages/sdk/src/endpoints/RelationshipsEndpoint.ts index 31886902..db84f9d1 100644 --- a/packages/sdk/src/endpoints/RelationshipsEndpoint.ts +++ b/packages/sdk/src/endpoints/RelationshipsEndpoint.ts @@ -4,58 +4,58 @@ import { Endpoint } from "./Endpoint"; export class RelationshipsEndpoint extends Endpoint { public async canCreateRelationship(request: CanCreateRelationshipRequest): Promise> { - return await this.put("/api/v2/Relationships/CanCreate", request); + return await this.put("/api/core/v1/Relationships/CanCreate", request); } public async createRelationship(request: CreateRelationshipRequest): Promise> { - return await this.post("/api/v2/Relationships", request); + return await this.post("/api/core/v1/Relationships", request); } public async getRelationships(request?: GetRelationshipsRequest): Promise> { - return await this.get("/api/v2/Relationships", request); + return await this.get("/api/core/v1/Relationships", request); } public async getRelationship(relationshipId: string): Promise> { - return await this.get(`/api/v2/Relationships/${relationshipId}`); + return await this.get(`/api/core/v1/Relationships/${relationshipId}`); } public async acceptRelationship(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Accept`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Accept`); } public async rejectRelationship(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Reject`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Reject`); } public async revokeRelationship(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Revoke`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Revoke`); } public async getAttributesForRelationship(relationshipId: string): Promise> { - return await this.get(`/api/v2/Relationships/${relationshipId}/Attributes`); + return await this.get(`/api/core/v1/Relationships/${relationshipId}/Attributes`); } public async terminateRelationship(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Terminate`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Terminate`); } public async decomposeRelationship(relationshipId: string): Promise> { - return await this.delete(`/api/v2/Relationships/${relationshipId}`, undefined, 204); + return await this.delete(`/api/core/v1/Relationships/${relationshipId}`, undefined, 204); } public async requestRelationshipReactivation(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Reactivate`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Reactivate`); } public async acceptRelationshipReactivation(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Reactivate/Accept`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Reactivate/Accept`); } public async rejectRelationshipReactivation(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Reactivate/Reject`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Reactivate/Reject`); } public async revokeRelationshipReactivation(relationshipId: string): Promise> { - return await this.put(`/api/v2/Relationships/${relationshipId}/Reactivate/Revoke`); + return await this.put(`/api/core/v1/Relationships/${relationshipId}/Reactivate/Revoke`); } } diff --git a/packages/sdk/src/endpoints/TokensEndpoint.ts b/packages/sdk/src/endpoints/TokensEndpoint.ts index 45c638ff..1f3d91eb 100644 --- a/packages/sdk/src/endpoints/TokensEndpoint.ts +++ b/packages/sdk/src/endpoints/TokensEndpoint.ts @@ -9,26 +9,26 @@ export class TokensEndpoint extends Endpoint { } public async getToken(tokenId: string): Promise> { - return await this.get(`/api/v2/Tokens/${tokenId}`); + return await this.get(`/api/core/v1/Tokens/${tokenId}`); } - public async getQrCodeForToken(tokenId: string, newQRCodeFormat?: boolean): Promise> { - return await this.downloadQrCode("GET", `/api/v2/Tokens/${tokenId}`, { newQRCodeFormat: newQRCodeFormat ? "true" : undefined }); + public async getQrCodeForToken(tokenId: string): Promise> { + return await this.downloadQrCode("GET", `/api/core/v1/Tokens/${tokenId}`); } public async getOwnTokens(request?: GetOwnTokensRequest): Promise> { - return await this.get("/api/v2/Tokens/Own", request); + return await this.get("/api/core/v1/Tokens/Own", request); } public async createOwnToken(request: CreateOwnTokenRequest): Promise> { - return await this.post("/api/v2/Tokens/Own", request); + return await this.post("/api/core/v1/Tokens/Own", request); } public async getPeerTokens(request?: GetPeerTokensRequest): Promise> { - return await this.get("/api/v2/Tokens/Peer", request); + return await this.get("/api/core/v1/Tokens/Peer", request); } public async loadPeerToken(request: LoadPeerTokenRequest): Promise> { - return await this.post("/api/v2/Tokens/Peer", request); + return await this.post("/api/core/v1/Tokens/Peer", request); } } diff --git a/packages/sdk/src/types/attributes/index.ts b/packages/sdk/src/types/attributes/index.ts index 6d3035e6..89e89010 100644 --- a/packages/sdk/src/types/attributes/index.ts +++ b/packages/sdk/src/types/attributes/index.ts @@ -13,7 +13,6 @@ export * from "./requests/GetOwnRepositoryAttributesRequest"; export * from "./requests/GetOwnSharedIdentityAttributesRequest"; export * from "./requests/GetPeerSharedIdentityAttributesRequest"; export * from "./requests/GetSharedVersionsOfAttributeRequest"; -export * from "./requests/GetValidAttributesRequest"; export * from "./requests/NotifyPeerAboutRepositoryAttributeSuccessionRequest"; export * from "./requests/NotifyPeerAboutRepositoryAttributeSuccessionResponse"; export * from "./requests/SucceedAttributeRequest"; diff --git a/packages/sdk/src/types/attributes/requests/CanCreateRepositoryAttributeRequest.ts b/packages/sdk/src/types/attributes/requests/CanCreateRepositoryAttributeRequest.ts index af4eb496..5bd5486a 100644 --- a/packages/sdk/src/types/attributes/requests/CanCreateRepositoryAttributeRequest.ts +++ b/packages/sdk/src/types/attributes/requests/CanCreateRepositoryAttributeRequest.ts @@ -4,7 +4,5 @@ export interface CanCreateRepositoryAttributeRequest { content: { value: AttributeValues.Identity.Json; tags?: string[]; - validFrom?: string; - validTo?: string; }; } diff --git a/packages/sdk/src/types/attributes/requests/CreateRepositoryAttributeRequest.ts b/packages/sdk/src/types/attributes/requests/CreateRepositoryAttributeRequest.ts index e910a214..d3e1638d 100644 --- a/packages/sdk/src/types/attributes/requests/CreateRepositoryAttributeRequest.ts +++ b/packages/sdk/src/types/attributes/requests/CreateRepositoryAttributeRequest.ts @@ -4,7 +4,5 @@ export interface CreateRepositoryAttributeRequest { content: { value: AttributeValues.Identity.Json; tags?: string[]; - validFrom?: string; - validTo?: string; }; } diff --git a/packages/sdk/src/types/attributes/requests/GetAttributesRequest.ts b/packages/sdk/src/types/attributes/requests/GetAttributesRequest.ts index a5a1a7d8..4b609fe9 100644 --- a/packages/sdk/src/types/attributes/requests/GetAttributesRequest.ts +++ b/packages/sdk/src/types/attributes/requests/GetAttributesRequest.ts @@ -4,8 +4,6 @@ export interface GetAttributesRequest { "@type"?: string; tags?: string[]; owner?: string; - validFrom?: string; - validTo?: string; key?: string; isTechnical?: string; confidentiality?: "public" | "private" | "protected"; diff --git a/packages/sdk/src/types/attributes/requests/GetOwnRepositoryAttributesRequest.ts b/packages/sdk/src/types/attributes/requests/GetOwnRepositoryAttributesRequest.ts index 73d7ea06..66070b8c 100644 --- a/packages/sdk/src/types/attributes/requests/GetOwnRepositoryAttributesRequest.ts +++ b/packages/sdk/src/types/attributes/requests/GetOwnRepositoryAttributesRequest.ts @@ -2,7 +2,5 @@ export interface GetOwnRepositoryAttributesRequest { onlyLatestVersions?: boolean; createdAt?: string; "content.tags"?: string | string[]; - "content.validFrom"?: string | string[]; - "content.validTo"?: string | string[]; "content.value.@type"?: string | string[]; } diff --git a/packages/sdk/src/types/attributes/requests/GetOwnSharedIdentityAttributesRequest.ts b/packages/sdk/src/types/attributes/requests/GetOwnSharedIdentityAttributesRequest.ts index 69cc500c..4bfb3276 100644 --- a/packages/sdk/src/types/attributes/requests/GetOwnSharedIdentityAttributesRequest.ts +++ b/packages/sdk/src/types/attributes/requests/GetOwnSharedIdentityAttributesRequest.ts @@ -1,11 +1,8 @@ export interface GetOwnSharedIdentityAttributesRequest { peer: string; - onlyValid?: boolean; createdAt?: string; "content.@type"?: string | string[]; "content.tags"?: string | string[]; - "content.validFrom"?: string | string[]; - "content.validTo"?: string | string[]; "content.key"?: string | string[]; "content.isTechnical"?: string | string[]; "content.confidentiality"?: string | string[]; diff --git a/packages/sdk/src/types/attributes/requests/GetPeerSharedIdentityAttributesRequest.ts b/packages/sdk/src/types/attributes/requests/GetPeerSharedIdentityAttributesRequest.ts index bcc2cb50..3941695f 100644 --- a/packages/sdk/src/types/attributes/requests/GetPeerSharedIdentityAttributesRequest.ts +++ b/packages/sdk/src/types/attributes/requests/GetPeerSharedIdentityAttributesRequest.ts @@ -1,11 +1,8 @@ export interface GetPeerSharedIdentityAttributesRequest { peer: string; - onlyValid?: boolean; createdAt?: string; "content.@type"?: string | string[]; "content.tags"?: string | string[]; - "content.validFrom"?: string | string[]; - "content.validTo"?: string | string[]; "content.key"?: string | string[]; "content.isTechnical"?: string | string[]; "content.confidentiality"?: string | string[]; diff --git a/packages/sdk/src/types/attributes/requests/GetValidAttributesRequest.ts b/packages/sdk/src/types/attributes/requests/GetValidAttributesRequest.ts deleted file mode 100644 index a7c2261c..00000000 --- a/packages/sdk/src/types/attributes/requests/GetValidAttributesRequest.ts +++ /dev/null @@ -1,20 +0,0 @@ -export interface GetValidAttributesRequest { - content?: { - "@type"?: string; - tags?: string[]; - owner?: string; - key?: string; - isTechnical?: string; - confidentiality?: "public" | "private" | "protected"; - value?: { - "@type"?: string; - }; - }; - succeeds?: string; - succeededBy?: string; - shareInfo?: { - requestReference?: string; - peer?: string; - sourceAttribute?: string; - }; -} diff --git a/packages/sdk/src/types/attributes/requests/SucceedAttributeRequest.ts b/packages/sdk/src/types/attributes/requests/SucceedAttributeRequest.ts index 6c0f8cff..f9a0b55c 100644 --- a/packages/sdk/src/types/attributes/requests/SucceedAttributeRequest.ts +++ b/packages/sdk/src/types/attributes/requests/SucceedAttributeRequest.ts @@ -4,7 +4,5 @@ export interface SucceedAttributeRequest { successorContent: { value: AttributeValues.Identity.Json | AttributeValues.Relationship.Json; tags?: string[]; - validFrom?: string; - validTo?: string; }; } diff --git a/packages/sdk/src/types/files/requests/CreateTokenQrCodeForFileRequest.ts b/packages/sdk/src/types/files/requests/CreateTokenQrCodeForFileRequest.ts index 7003ea7e..dcaf7bf8 100644 --- a/packages/sdk/src/types/files/requests/CreateTokenQrCodeForFileRequest.ts +++ b/packages/sdk/src/types/files/requests/CreateTokenQrCodeForFileRequest.ts @@ -6,5 +6,4 @@ export interface CreateTokenQrCodeForFileRequest { passwordIsPin?: true; passwordLocationIndicator?: string | number; }; - newQRCodeFormat?: boolean; } diff --git a/packages/sdk/src/types/files/requests/UploadOwnFileRequest.ts b/packages/sdk/src/types/files/requests/UploadOwnFileRequest.ts index baa342ff..494bb8ac 100644 --- a/packages/sdk/src/types/files/requests/UploadOwnFileRequest.ts +++ b/packages/sdk/src/types/files/requests/UploadOwnFileRequest.ts @@ -1,5 +1,5 @@ export interface UploadOwnFileRequest { - title: string; + title?: string; description?: string; expiresAt: string; file: Uint8Array; diff --git a/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts b/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts index 0be08691..493a9d08 100644 --- a/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts +++ b/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts @@ -6,5 +6,4 @@ export interface CreateTokenQrCodeForOwnRelationshipTemplateRequest { passwordIsPin?: true; passwordLocationIndicator?: string | number; }; - newQRCodeFormat?: boolean; } diff --git a/packages/types/package.json b/packages/types/package.json index 5ebe9675..ab6cad83 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -22,27 +22,7 @@ "scripts": { "build": "tsc", "build:ci": "tsc", - "build:watch": "tsc --watch", - "test": "jest -i", - "test:ci": "npm run test", - "test:local": "npm run test" - }, - "jest": { - "maxWorkers": 2, - "preset": "ts-jest", - "testEnvironment": "node", - "testPathIgnorePatterns": [ - "/node_modules/" - ], - "testTimeout": 60000, - "transform": { - "^.+\\.ts$": [ - "ts-jest", - { - "tsconfig": "test/tsconfig.json" - } - ] - } + "build:watch": "tsc --watch" }, "dependencies": { "qrcode": "^1.5.4" @@ -58,8 +38,8 @@ "peerDependencies": { "@js-soft/docdb-access-abstractions": "^1.2.1", "@js-soft/ts-utils": "^2.3.5", - "@nmshd/runtime": "^6.63.7", - "@nmshd/typescript-rest": "3.1.6", + "@nmshd/runtime": "7.0.0-alpha.70", + "@nmshd/typescript-rest": "^3.2.1", "express": "^5.1.0" }, "publishConfig": { diff --git a/packages/types/src/AbstractConnectorRuntime.ts b/packages/types/src/AbstractConnectorRuntime.ts index 5009514e..5cf76e8b 100644 --- a/packages/types/src/AbstractConnectorRuntime.ts +++ b/packages/types/src/AbstractConnectorRuntime.ts @@ -4,7 +4,7 @@ import { ConnectorRuntimeBuildInformation } from "./ConnectorRuntimeBuildInforma import { IConnectorInfrastructureRegistry } from "./infrastructure"; export interface ConnectorRuntimeConfig extends RuntimeConfig { - database: { dbName: string; dbNamePrefix: string }; + database: { dbName: string }; } export abstract class AbstractConnectorRuntime extends Runtime { diff --git a/packages/types/src/QRCode.ts b/packages/types/src/QRCode.ts deleted file mode 100644 index 3f2b82ac..00000000 --- a/packages/types/src/QRCode.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as qrcodeLibrary from "qrcode"; - -export class QRCode { - private constructor(private readonly base64: string) {} - - public asBase64(): string { - return this.base64; - } - - public static async for(reference: string): Promise { - const dataUrl = await qrcodeLibrary.toDataURL(reference.startsWith("http") ? reference : `nmshd://tr#${reference}`); - const base64 = dataUrl.split(",")[1]; - - return new QRCode(base64); - } -} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index c4bacacc..df9baadb 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -4,4 +4,3 @@ export * from "./ConnectorRuntimeBuildInformation"; export * from "./ConnectorRuntimeModule"; export * from "./DocumentationLink"; export * from "./infrastructure"; -export * from "./QRCode"; diff --git a/packages/types/src/infrastructure/httpServer/BaseController.ts b/packages/types/src/infrastructure/httpServer/BaseController.ts index fba808ea..7d3a2d22 100644 --- a/packages/types/src/infrastructure/httpServer/BaseController.ts +++ b/packages/types/src/infrastructure/httpServer/BaseController.ts @@ -1,7 +1,7 @@ import { Result } from "@js-soft/ts-utils"; import { Return } from "@nmshd/typescript-rest"; import express from "express"; -import { QRCode } from "../../QRCode"; +import * as qrcodeLibrary from "qrcode"; import { Envelope } from "./common/Envelope"; import { Mimetype } from "./common/Mimetype"; @@ -62,19 +62,15 @@ export abstract class BaseController { .send(buffer); } - protected async qrCode>( - result: T, - qrPredicate: (result: T) => Promise, - filename: string, - response: express.Response, - status: number - ): Promise { + protected async qrCode>(result: T, filename: string, response: express.Response, status: number): Promise { this.guard(result); const mimetype = Mimetype.png(); - const qrCode = await qrPredicate(result); - const buffer = Buffer.from(qrCode.asBase64(), "base64"); + const reference = result.value.reference.url; + const dataUrl = await qrcodeLibrary.toDataURL(reference); + const base64 = dataUrl.split(",")[1]; + const buffer = Buffer.from(base64, "base64"); response .status(status) diff --git a/packages/types/src/infrastructure/httpServer/HttpServerRole.ts b/packages/types/src/infrastructure/httpServer/HttpServerRole.ts deleted file mode 100644 index 5491d788..00000000 --- a/packages/types/src/infrastructure/httpServer/HttpServerRole.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum HttpServerRole { - ADMIN = "admin", - DEVELOPER = "developer", - MONITORING = "monitoring" -} diff --git a/packages/types/src/infrastructure/httpServer/index.ts b/packages/types/src/infrastructure/httpServer/index.ts index be018de1..de0629f4 100644 --- a/packages/types/src/infrastructure/httpServer/index.ts +++ b/packages/types/src/infrastructure/httpServer/index.ts @@ -2,6 +2,4 @@ export * from "./BaseController"; export * from "./common"; export * from "./globals"; export * from "./HttpMethod"; -export * from "./HttpServerRole"; export * from "./IHttpServer"; -export * from "./middlewares"; diff --git a/packages/types/src/infrastructure/httpServer/middlewares/index.ts b/packages/types/src/infrastructure/httpServer/middlewares/index.ts deleted file mode 100644 index 863fd5d9..00000000 --- a/packages/types/src/infrastructure/httpServer/middlewares/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./routeRequiresRoles"; diff --git a/packages/types/src/infrastructure/httpServer/middlewares/routeRequiresRoles.ts b/packages/types/src/infrastructure/httpServer/middlewares/routeRequiresRoles.ts deleted file mode 100644 index ebe94050..00000000 --- a/packages/types/src/infrastructure/httpServer/middlewares/routeRequiresRoles.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Errors } from "@nmshd/typescript-rest"; -import express from "express"; - -export function routeRequiresRoles(...requiredRoles: [string, ...string[]]) { - if (requiredRoles.length === 0) throw new Error("At least one role must be specified."); - - return (req: express.Request, _: express.Response, next: express.NextFunction): void => { - const userRoles = req.userRoles; - const hasRole = userRoles && Array.isArray(userRoles) && requiredRoles.some((role) => userRoles.includes(role)); - if (!hasRole) { - next(new Errors.ForbiddenError("You are not allowed to access this endpoint.")); - return; - } - - next(); - }; -} diff --git a/packages/types/test/infrastructure/httpServer/middlewares/routeRequiresRoles.test.ts b/packages/types/test/infrastructure/httpServer/middlewares/routeRequiresRoles.test.ts deleted file mode 100644 index e1af3bb8..00000000 --- a/packages/types/test/infrastructure/httpServer/middlewares/routeRequiresRoles.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable jest/no-conditional-expect, jest/no-conditional-in-test */ -import { Errors } from "@nmshd/typescript-rest"; -import express from "express"; -import { routeRequiresRoles } from "../../../../src"; - -describe("routeRequiresRoles middleware", () => { - const res = {} as any as express.Response; - - test.each([ - [["admin"], ["admin"], true], - [["admin"], [], false], - [["admin"], ["aRandomRole"], false], - [["admin", "core:messages"], ["core:messages"], true], - [["admin"], undefined, false] - ])("should properly handle the required and given roles", (requiredRoles: string[], userRoles: string[] | undefined, shouldBeAuthorized: boolean) => { - const next = jest.fn(); - - const fn = routeRequiresRoles(requiredRoles.at(0)!, ...requiredRoles.slice(1)); - fn({ userRoles } as any as express.Request, res, next); - - expect(next).toHaveBeenCalledTimes(1); - - if (shouldBeAuthorized) { - expect(next).toHaveBeenCalledWith(); - } else { - expect(next).toHaveBeenCalledWith(new Errors.ForbiddenError("You are not allowed to access this endpoint.")); - } - }); - - test("should throw an error if no roles are specified", () => { - expect(() => { - // @ts-expect-error - routeRequiresRoles(); - }).toThrow("At least one role must be specified."); - }); -}); diff --git a/packages/types/test/tsconfig.json b/packages/types/test/tsconfig.json deleted file mode 100644 index 334c34f9..00000000 --- a/packages/types/test/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "module": "commonjs", - "sourceMap": true, - "declaration": true, - "outDir": "../dist-test", - "strict": true, - "useUnknownInCatchVariables": false, - "allowSyntheticDefaultImports": true, - "emitDecoratorMetadata": true, - "esModuleInterop": true, - "experimentalDecorators": true, - "resolveJsonModule": true, - "moduleResolution": "node", - "forceConsistentCasingInFileNames": true, - "noImplicitReturns": true, - "strictNullChecks": true, - "strictPropertyInitialization": false, - "downlevelIteration": true, - "lib": ["es2022", "dom"], - "baseUrl": "../" - }, - "include": ["**/*.ts"], - "exclude": [] -} diff --git a/src/ConnectorRuntime.ts b/src/ConnectorRuntime.ts index 1cdba4a6..b1c1f550 100644 --- a/src/ConnectorRuntime.ts +++ b/src/ConnectorRuntime.ts @@ -17,7 +17,8 @@ import { ConsumptionServices, DataViewExpander, GetIdentityInfoResponse, ModuleC import { AccountController, TransportCoreErrors } from "@nmshd/transport"; import axios from "axios"; import correlator from "correlation-id"; -import { HttpsProxyAgent } from "https-proxy-agent"; +import { Agent as HTTPAgent, AgentOptions as HTTPAgentOptions } from "http"; +import { Agent as HTTPSAgent, AgentOptions as HTTPSAgentOptions } from "https"; import { checkServerIdentity, PeerCertificate } from "tls"; import { ConnectorRuntimeConfig } from "./ConnectorRuntimeConfig"; import { HealthChecker } from "./HealthChecker"; @@ -121,7 +122,6 @@ export class ConnectorRuntime extends AbstractConnectorRuntime { - const db = await this.databaseConnection.getDatabase(`${this.runtimeConfig.database.dbNamePrefix}${this.runtimeConfig.database.dbName}`); + const db = await this.databaseConnection.getDatabase(this.runtimeConfig.database.dbName); this.accountController = await new AccountController(this.transport, db, this.transport.config).init().catch((e) => { if (e instanceof ApplicationError && e.code === "error.transport.general.platformClientInvalid") { @@ -187,7 +187,9 @@ export class ConnectorRuntime extends AbstractConnectorRuntime = { DATABASE_NAME: "database:dbName", // eslint-disable-line @typescript-eslint/naming-convention - API_KEY: "infrastructure:httpServer:apiKey", // eslint-disable-line @typescript-eslint/naming-convention DATABASE_CONNECTION_STRING: "database:connectionString", // eslint-disable-line @typescript-eslint/naming-convention SYNC_ENABLED: "modules:sync:enabled", // eslint-disable-line @typescript-eslint/naming-convention PLATFORM_CLIENT_ID: "transportLibrary:platformClientId", // eslint-disable-line @typescript-eslint/naming-convention diff --git a/src/infrastructure/httpServer/HttpServer.ts b/src/infrastructure/httpServer/HttpServer.ts index ee0b59dc..644bbd94 100644 --- a/src/infrastructure/httpServer/HttpServer.ts +++ b/src/infrastructure/httpServer/HttpServer.ts @@ -1,21 +1,27 @@ -import { sleep } from "@js-soft/ts-utils"; -import { ConnectorInfrastructure, Envelope, HttpErrors, HttpMethod, HttpServerRole, IHttpServer, InfrastructureConfiguration, routeRequiresRoles } from "@nmshd/connector-types"; +import { ConnectorInfrastructure, HttpMethod, IHttpServer, InfrastructureConfiguration } from "@nmshd/connector-types"; import { Container } from "@nmshd/typescript-ioc"; -import { Server } from "@nmshd/typescript-rest"; +import { Server, ServiceAuthenticator, routeRequiresAuthorization } from "@nmshd/typescript-rest"; import compression from "compression"; import correlator from "correlation-id"; import cors, { CorsOptions } from "cors"; -import express, { Application, RequestHandler, Router } from "express"; +import express, { Application, RequestHandler } from "express"; import { AuthOptions as BearerAuthOptions, auth as bearerAuth } from "express-oauth2-jwt-bearer"; import { ConfigParams as OauthParams, auth as openidAuth } from "express-openid-connect"; import helmet, { HelmetOptions } from "helmet"; import http from "http"; import { RequestTracker } from "./RequestTracker"; -import { csrfErrorHandler } from "./middlewares/csrfErrorHandler"; -import { RouteNotFoundError, genericErrorHandler } from "./middlewares/genericErrorHandler"; -import { requestLogger } from "./middlewares/requestLogger"; -import { setDurationHeader } from "./middlewares/setResponseDurationHeader"; -import { setResponseTimeHeader } from "./middlewares/setResponseTimeHeader"; +import { + ApiKeyAuthenticationConfig, + RouteNotFoundError, + apiKeyAuth, + csrfErrorHandler, + enforceAuthentication, + genericErrorHandler, + isApiKeyAuthenticationEnabled, + requestLogger, + setDurationHeader, + setResponseTimeHeader +} from "./middlewares"; export interface CustomEndpoint { httpMethod: HttpMethod; @@ -36,12 +42,14 @@ export interface ControllerConfig { } export interface HttpServerConfiguration extends InfrastructureConfiguration { - oidc?: OauthParams; - jwtBearer?: BearerAuthOptions; port?: number; - apiKey: string; cors?: CorsOptions; helmetOptions?: HelmetOptions; + authentication: { + apiKey: ApiKeyAuthenticationConfig; + oidc: { enabled?: boolean; rolesPath?: string } & OauthParams; + jwtBearer: { enabled?: boolean } & BearerAuthOptions; + }; } export class HttpServer extends ConnectorInfrastructure implements IHttpServer { @@ -92,11 +100,10 @@ export class HttpServer extends ConnectorInfrastructure this.useUnsecuredCustomEndpoints(); this.useHealthEndpoint(); - this.initAuthentication(); this.useAuthentication(); this.useVersionEndpoint(); - this.useResponsesEndpoint(); + this.useRequestsEndpoint(); this.useSupportEndpoint(); this.useCustomControllers(); @@ -137,6 +144,10 @@ export class HttpServer extends ConnectorInfrastructure } } + get #authenticator(): ServiceAuthenticator { + return { getRoles: (req) => req.userRoles ?? [] }; + } + private useUnsecuredCustomEndpoints() { const securedCustomEndpoints = this.customEndpoints.filter((e) => !e.authenticationRequired); for (const endpoint of securedCustomEndpoints) { @@ -190,99 +201,59 @@ export class HttpServer extends ConnectorInfrastructure this.app.use(genericErrorHandler(this.connectorMode, this.logger)); } - private initAuthentication() { - if (!this.configuration.apiKey && !this.configuration.oidc && !this.configuration.jwtBearer) { + private useAuthentication() { + const apiKeyAuthenticationEnabled = isApiKeyAuthenticationEnabled(this.configuration.authentication.apiKey); + const oidcAuthenticationEnabled = this.configuration.authentication.oidc.enabled ?? Object.keys(this.configuration.authentication.oidc).length !== 0; + const jwtBearerAuthenticationEnabled = this.configuration.authentication.jwtBearer.enabled ?? Object.keys(this.configuration.authentication.jwtBearer).length !== 0; + if (!apiKeyAuthenticationEnabled && !oidcAuthenticationEnabled && !jwtBearerAuthenticationEnabled) { switch (this.connectorMode) { case "debug": + this.app.use((req: express.Request, _: express.Response, next: express.NextFunction) => { + req.userRoles = ["**"]; + + next(); + }); return; case "production": throw new Error(`No API key and OAuth config set in configuration. At least one is required in production mode.`); } } - this.initApiKey(); - this.initOIDC(); - this.initJWTBearer(); - } - - private initOIDC() { - if (!this.configuration.oidc) return; - - this.app.use(openidAuth({ ...this.configuration.oidc, authRequired: false })); - } - - private initJWTBearer() { - if (!this.configuration.jwtBearer) return; - - this.app.use( - bearerAuth({ - ...this.configuration.jwtBearer, - authRequired: false - }) - ); - } - - private initApiKey() { - if (!this.configuration.apiKey) return; - - const apiKeyPolicy = /^(?=.*[A-Z].*[A-Z])(?=.*[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~])(?=.*[0-9].*[0-9])(?=.*[a-z].*[a-z]).{30,}$/; - if (!this.configuration.apiKey.match(apiKeyPolicy)) { - this.logger.warn( - "The configured API key does not meet the requirements. It must be at least 30 characters long and contain at least 2 digits, 2 uppercase letters, 2 lowercase letters and 1 special character (!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~])." - ); - this.logger.warn("The API key will be used as is, but it is recommended to change it as it will not be supported in future versions."); + if (apiKeyAuthenticationEnabled) { + this.app.use(apiKeyAuth(this.configuration.authentication.apiKey)); } - } - - private useAuthentication() { - if (!this.configuration.apiKey && !this.configuration.oidc && !this.configuration.jwtBearer) return; - - const unauthorized = async (_: express.Request, res: express.Response) => { - await sleep(1000 * (Math.floor(Math.random() * 4) + 1)); - res.status(401).send(Envelope.error(HttpErrors.unauthorized(), this.connectorMode)); - }; - this.app.use(async (req, res, next) => { - const apiKeyFromHeader = req.headers["x-api-key"]; - if (this.configuration.apiKey && apiKeyFromHeader) { - if (apiKeyFromHeader !== this.configuration.apiKey) return await unauthorized(req, res); + if (oidcAuthenticationEnabled) { + const config = { ...this.configuration.authentication.oidc, authRequired: false }; + // remove the enabled and rolesPath properties as they are not supported by the express-openid-connect library + delete config.enabled; + delete config.rolesPath; - const apiKeyRoles = this.connectorMode === "debug" ? [HttpServerRole.ADMIN, HttpServerRole.DEVELOPER] : [HttpServerRole.ADMIN]; - req.userRoles = apiKeyRoles; - - next(); - return; - } - - if (this.configuration.jwtBearer && req.headers["authorization"]) { - if (!req.auth) return await unauthorized(req, res); - - const scope = req.auth.payload.scope; - - if (typeof scope === "string") { - req.userRoles = scope.split(" "); - } else { - this.logger.warn("JWT Bearer token does not contain a scope, using empty array as default."); - req.userRoles = []; - } - - next(); - return; - } - - if (this.configuration.oidc) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- we need to check if req.oidc is defined as there could be cases where the auth middleware is not applied - if (!req.oidc) return next(new Error("req.oidc is not found, did you include the auth middleware?")); - if (!req.oidc.isAuthenticated()) return await res.oidc.login(); + this.app.use(openidAuth(config)); + } - req.userRoles = []; + if (jwtBearerAuthenticationEnabled) { + const config = { ...this.configuration.authentication.jwtBearer, authRequired: false }; + // remove the enabled property as it is not supported by the express-oauth2-jwt-bearer library + delete config.enabled; - next(); - return; - } + this.app.use(bearerAuth(config)); + } - await unauthorized(req, res); - }); + this.app.use( + enforceAuthentication( + { + apiKey: { + enabled: apiKeyAuthenticationEnabled, + headerName: this.configuration.authentication.apiKey.headerName.toLocaleLowerCase() + }, + jwtBearer: { enabled: jwtBearerAuthenticationEnabled }, + oidc: { enabled: oidcAuthenticationEnabled, rolesPath: this.configuration.authentication.oidc.rolesPath }, + connectorMode: this.connectorMode + }, + this.logger + ) + ); } private useHealthEndpoint() { @@ -294,20 +265,20 @@ export class HttpServer extends ConnectorInfrastructure } private useVersionEndpoint() { - this.app.get("/Monitoring/Version", routeRequiresRoles(HttpServerRole.ADMIN, HttpServerRole.MONITORING), (_: express.Request, res: express.Response) => { + this.app.get("/Monitoring/Version", routeRequiresAuthorization(this.#authenticator, "monitoring:version"), (_: express.Request, res: express.Response) => { const buildInformation = this.runtime.getBuildInformation(); res.status(200).json(buildInformation); }); } - private useResponsesEndpoint() { - this.app.get("/Monitoring/Requests", routeRequiresRoles(HttpServerRole.ADMIN, HttpServerRole.MONITORING), (_: express.Request, res: express.Response) => { + private useRequestsEndpoint() { + this.app.get("/Monitoring/Requests", routeRequiresAuthorization(this.#authenticator, "monitoring:requests"), (_: express.Request, res: express.Response) => { res.status(200).json(this.requestTracker.getCount()); }); } private useSupportEndpoint() { - this.app.get("/Monitoring/Support", routeRequiresRoles(HttpServerRole.ADMIN, HttpServerRole.MONITORING), async (_: express.Request, res: express.Response) => { + this.app.get("/Monitoring/Support", routeRequiresAuthorization(this.#authenticator, "monitoring:support"), async (_: express.Request, res: express.Response) => { const supportInformation = await this.runtime.getSupportInformation(); res.status(200).json(supportInformation); }); @@ -336,15 +307,7 @@ export class HttpServer extends ConnectorInfrastructure } }); - Server.registerAuthenticator({ - getMiddleware: () => (_req, _res, next) => next(), - - initialize: (_app: Router) => { - // no initialization needed - }, - - getRoles: (req) => req.userRoles ?? [] - }); + Server.registerAuthenticator(this.#authenticator); for (const controller of this.controllers) { Server.loadControllers(this.app, controller.globs, controller.baseDirectory); diff --git a/src/infrastructure/httpServer/middlewares/authentication/apiKeyAuth.ts b/src/infrastructure/httpServer/middlewares/authentication/apiKeyAuth.ts new file mode 100644 index 00000000..862e83e2 --- /dev/null +++ b/src/infrastructure/httpServer/middlewares/authentication/apiKeyAuth.ts @@ -0,0 +1,76 @@ +import { CoreDate } from "@nmshd/core-types"; +import express from "express"; + +declare global { + namespace Express { + interface Request { + apiKey?: { + validateApiKey(apiKey: string): { isValid: boolean; scopes?: string[] }; + }; + } + } +} + +export interface ApiKeyAuthenticationConfig { + enabled?: boolean; + headerName: string; + keys: Record< + string, + { + enabled?: boolean; + key: string; + description?: string; + expiresAt?: string; + scopes?: string[]; + } + >; +} + +export function apiKeyAuth(config: ApiKeyAuthenticationConfig): express.RequestHandler { + if (!isApiKeyAuthenticationEnabled(config)) throw new Error("API key authentication is not enabled in configuration. At least one API key is required."); + + const apiKeys = getValidApiKeys(config); + return (req: express.Request, _res: express.Response, next: express.NextFunction) => { + const validateApiKey = (apiKey: string): { isValid: boolean; scopes?: string[] } => { + const matchingApiKey = apiKeys.find((keyDefinition) => keyDefinition.apiKey === apiKey); + + // even if the API key is found, we need to check if it is still valid because it might have been expired between server start and request + if (!matchingApiKey || matchingApiKey.expiresAt?.isExpired()) return { isValid: false }; + + return { isValid: true, scopes: matchingApiKey.scopes }; + }; + + req.apiKey = { validateApiKey }; + + next(); + }; +} + +export function isApiKeyAuthenticationEnabled(config: ApiKeyAuthenticationConfig): boolean { + return config.enabled ?? Object.keys(config.keys).length !== 0; +} + +function getValidApiKeys(config: ApiKeyAuthenticationConfig): { apiKey: string; expiresAt?: CoreDate; scopes?: string[] }[] { + const configuredApiKeys = config.keys; + + const allApiKeys = Object.values(configuredApiKeys).map((def) => def.key); + if (allApiKeys.length !== new Set(allApiKeys).size) { + throw new Error("Duplicate API keys found in configuration. Each API key must be unique."); + } + + const validApiKeys = Object.entries(configuredApiKeys) + .filter((apiKey) => apiKey[1].enabled !== false) + .filter((apiKey) => apiKey[1].expiresAt === undefined || !CoreDate.from(apiKey[1].expiresAt).isExpired()); + + if (validApiKeys.length === 0) throw new Error("No valid API keys found in configuration. At least one is required."); + + const apiKeyPolicy = /^(?=.*[A-Z].*[A-Z])(?=.*[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~])(?=.*[0-9].*[0-9])(?=.*[a-z].*[a-z]).{30,}$/; + const apiKeysViolatingThePolicy = validApiKeys.filter((apiKey) => !apiKey[1].key.match(apiKeyPolicy)); + if (apiKeysViolatingThePolicy.length !== 0) { + throw new Error( + `The API keys with the following key(s) does not meet the requirements: ${apiKeysViolatingThePolicy.map((k) => k[0]).join(", ")}. They must be at least 30 characters long and contain at least 2 digits, 2 uppercase letters, 2 lowercase letters and 1 special character (!"#$%&'()*+,-./:;<=>?@[\\]^_\`{|}~).` + ); + } + + return validApiKeys.map((apiKey) => ({ apiKey: apiKey[1].key, expiresAt: apiKey[1].expiresAt ? CoreDate.from(apiKey[1].expiresAt) : undefined, scopes: apiKey[1].scopes })); +} diff --git a/src/infrastructure/httpServer/middlewares/authentication/enforceAuthentication.ts b/src/infrastructure/httpServer/middlewares/authentication/enforceAuthentication.ts new file mode 100644 index 00000000..44824407 --- /dev/null +++ b/src/infrastructure/httpServer/middlewares/authentication/enforceAuthentication.ts @@ -0,0 +1,120 @@ +import { ILogger } from "@js-soft/logging-abstractions"; +import { sleep } from "@js-soft/ts-utils"; +import { Envelope, HttpErrors } from "@nmshd/connector-types"; +import { CoreDate } from "@nmshd/core-types"; +import express from "express"; +import { RequestContext as OIDCRequestContext } from "express-openid-connect"; +import { jwtDecode } from "jwt-decode"; + +export function enforceAuthentication( + config: { + apiKey: { enabled: boolean; headerName: string }; + jwtBearer: { enabled: boolean }; + oidc: { enabled: boolean; rolesPath?: string }; + connectorMode: "debug" | "production"; + }, + logger: ILogger +): express.RequestHandler { + const unauthorized = async (res: express.Response) => { + await sleep(1000 * (Math.floor(Math.random() * 4) + 1)); + res.status(401).send(Envelope.error(HttpErrors.unauthorized(), config.connectorMode)); + }; + + return async (req: express.Request, res: express.Response, next: express.NextFunction) => { + const xApiKeyHeaderValue = req.headers[config.apiKey.headerName]; + const apiKeyFromHeader = Array.isArray(xApiKeyHeaderValue) ? xApiKeyHeaderValue[0] : xApiKeyHeaderValue; + if (config.apiKey.enabled && apiKeyFromHeader) { + const validationResult = req.apiKey!.validateApiKey(apiKeyFromHeader); + if (!validationResult.isValid) return await unauthorized(res); + + const defaultApiKeyRoles = ["**"]; + req.userRoles = validationResult.scopes ?? defaultApiKeyRoles; + + next(); + return; + } + + if (config.jwtBearer.enabled && req.headers["authorization"]) { + // req.auth is set by the jwt-bearer middleware if the bearer token in the Authorization header is valid + if (!req.auth) return await unauthorized(res); + + const scope = req.auth.payload.scope; + + if (typeof scope === "string") { + req.userRoles = scope.split(" "); + } else { + logger.warn("JWT Bearer token does not contain a scope, using empty array as default."); + req.userRoles = []; + } + + next(); + return; + } + + if (config.oidc.enabled) { + const oidcContext = req.oidc; + + const rejectRequest = async (req: express.Request, res: express.Response) => { + if (req.xhr || (!req.accepts("html") && req.accepts("json"))) return await unauthorized(res); + + return await res.oidc.login(); + }; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- we need to check if req.oidc is defined as there could be cases where the auth middleware is not applied + if (!oidcContext) return next(new Error("req.oidc is not found, did you include the auth middleware?")); + + if (!oidcContext.isAuthenticated()) return await rejectRequest(req, res); + + if (oidcContext.accessToken?.isExpired()) { + const refreshToken = oidcContext.refreshToken; + if (!refreshToken) return await rejectRequest(req, res); + + const decodedRefreshToken = jwtDecode(refreshToken); + + if (CoreDate.from((decodedRefreshToken.exp ?? 0) * 1000).isExpired()) { + return await rejectRequest(req, res); + } + + try { + await req.oidc.accessToken?.refresh(); + } catch { + return await rejectRequest(req, res); + } + } + + req.userRoles = extractRolesFromOIDC(logger, oidcContext, config.oidc.rolesPath); + + next(); + return; + } + + await unauthorized(res); + }; +} + +function extractRolesFromOIDC(logger: ILogger, context: OIDCRequestContext, rolesPath?: string): string[] { + if (!context.user || !rolesPath) return []; + + const segments = rolesPath.split("."); + if (segments.length === 0) return []; + + let current: any = context.user; + const processedSegments = []; + + for (const segment of segments) { + processedSegments.push(segment); + if (!current[segment]) { + logger.warn(`Roles path '${processedSegments.join(".")}' not found in OIDC user info, using empty array as default.`); + return []; + } + + current = current[segment]; + } + + if (!Array.isArray(current)) { + logger.warn(`Roles path '${rolesPath}' does not point to an array in OIDC user info, using empty array as default.`); + return []; + } + + return current; +} diff --git a/src/infrastructure/httpServer/middlewares/authentication/index.ts b/src/infrastructure/httpServer/middlewares/authentication/index.ts new file mode 100644 index 00000000..e4678829 --- /dev/null +++ b/src/infrastructure/httpServer/middlewares/authentication/index.ts @@ -0,0 +1,2 @@ +export * from "./apiKeyAuth"; +export * from "./enforceAuthentication"; diff --git a/src/infrastructure/httpServer/middlewares/index.ts b/src/infrastructure/httpServer/middlewares/index.ts new file mode 100644 index 00000000..5aa0f78a --- /dev/null +++ b/src/infrastructure/httpServer/middlewares/index.ts @@ -0,0 +1,6 @@ +export * from "./authentication"; +export * from "./csrfErrorHandler"; +export * from "./genericErrorHandler"; +export * from "./requestLogger"; +export * from "./setResponseDurationHeader"; +export * from "./setResponseTimeHeader"; diff --git a/src/jsonSchemas/connectorConfig.json b/src/jsonSchemas/connectorConfig.json index c123a559..10822498 100644 --- a/src/jsonSchemas/connectorConfig.json +++ b/src/jsonSchemas/connectorConfig.json @@ -13,15 +13,12 @@ "dbName": { "type": "string" }, - "dbNamePrefix": { - "type": "string" - }, "driver": { "const": "mongodb", "type": "string" } }, - "required": ["connectionString", "dbName", "dbNamePrefix", "driver"], + "required": ["connectionString", "dbName", "driver"], "type": "object" }, { @@ -30,9 +27,6 @@ "dbName": { "type": "string" }, - "dbNamePrefix": { - "type": "string" - }, "driver": { "const": "lokijs", "type": "string" @@ -41,7 +35,7 @@ "type": "string" } }, - "required": ["dbName", "dbNamePrefix", "driver", "folder"], + "required": ["dbName", "driver", "folder"], "type": "object" } ] @@ -58,21 +52,80 @@ "httpServer": { "additionalProperties": false, "properties": { - "apiKey": { - "type": "string" + "authentication": { + "additionalProperties": false, + "properties": { + "apiKey": { + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "headerName": { + "type": "string" + }, + "keys": { + "additionalProperties": { + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "expiresAt": { + "pattern": "^([+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24:?00)([.,]\\d+(?!:))?)?(\\17[0-5]\\d([.,]\\d+)?)?([zZ]|([+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$", + "type": "string" + }, + "key": { + "type": "string" + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["key"], + "type": "object" + }, + "type": "object" + } + }, + "required": ["headerName", "keys"], + "type": "object" + }, + "jwtBearer": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "oidc": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" }, "cors": {}, "enabled": { "type": "boolean" }, "helmetOptions": {}, - "oidc": {}, - "jwtBearer": {}, "port": { "type": ["string", "number"] } }, - "required": ["enabled", "apiKey"], + "required": ["enabled", "authentication"], "type": "object" } }, diff --git a/src/jsonSchemas/connectorConfig.ts b/src/jsonSchemas/connectorConfig.ts index a3d52ecb..3c372868 100644 --- a/src/jsonSchemas/connectorConfig.ts +++ b/src/jsonSchemas/connectorConfig.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ // To regenerate the json schema, execute the following command: -// npx ts-json-schema-generator -p ./src/jsonSchemas/connectorConfig.ts -o ./src/jsonSchemas/connectorConfig.json -t "ConnectorConfig" --no-top-ref +// npx ts-json-schema-generator -p ./src/jsonSchemas/connectorConfig.ts -o ./src/jsonSchemas/connectorConfig.json -t "ConnectorConfig" --no-top-ref && npx prettier --write src/jsonSchemas/connectorConfig.json export interface MongoDBSettings { driver: "mongodb"; @@ -15,7 +15,7 @@ export interface LokiJSSettings { export interface ConnectorConfig { debug: boolean; - database: (MongoDBSettings | LokiJSSettings) & { dbName: string; dbNamePrefix: string }; + database: (MongoDBSettings | LokiJSSettings) & { dbName: string }; transportLibrary: IConfigOverwrite; @@ -40,13 +40,32 @@ interface ModuleConfiguration { interface InfrastructureConfiguration { httpServer: { - oidc?: any; - jwtBearer?: any; enabled: boolean; port?: string | number; - apiKey: string; cors?: any; helmetOptions?: any; + authentication: { + apiKey?: { + enabled?: boolean; + headerName: string; + keys: Record< + string, + { + enabled?: boolean; + key: string; + description?: string; + /** + * @errorMessage must match ISO8601 datetime format + * @pattern ^([+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([.,]\d+(?!:))?)?(\17[0-5]\d([.,]\d+)?)?([zZ]|([+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$ + */ + expiresAt?: string; + scopes?: string[]; + } + >; + }; + oidc?: any & { enabled?: boolean }; + jwtBearer?: any & { enabled?: boolean }; + }; }; } diff --git a/src/modules/coreHttpApi/controllers/AccountController.ts b/src/modules/coreHttpApi/controllers/AccountController.ts index 6ec8cffe..a774f5fb 100644 --- a/src/modules/coreHttpApi/controllers/AccountController.ts +++ b/src/modules/coreHttpApi/controllers/AccountController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, GET, Path, POST, Security } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:account"]) -@Path("/api/v2/Account") +@Security("core:account") +@Path("/api/core/v1/Account") export class AccountController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/AnnouncementsController.ts b/src/modules/coreHttpApi/controllers/AnnouncementsController.ts index e65d1ef0..2db0e6bc 100644 --- a/src/modules/coreHttpApi/controllers/AnnouncementsController.ts +++ b/src/modules/coreHttpApi/controllers/AnnouncementsController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, GET, Path, QueryParam, Security } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:announcements"]) -@Path("/api/v2/Announcements") +@Security("core:announcements") +@Path("/api/core/v1/Announcements") export class AnnouncementsController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/AttributesController.ts b/src/modules/coreHttpApi/controllers/AttributesController.ts index 1dfc2b28..9276214f 100644 --- a/src/modules/coreHttpApi/controllers/AttributesController.ts +++ b/src/modules/coreHttpApi/controllers/AttributesController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { ConsumptionServices, RuntimeErrors } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, Context, DELETE, GET, POST, PUT, Path, PathParam, QueryParam, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:attributes"]) -@Path("/api/v2/Attributes") +@Security("core:attributes") +@Path("/api/core/v1/Attributes") export class AttributesController extends BaseController { public constructor(@Inject private readonly consumptionServices: ConsumptionServices) { super(); @@ -82,11 +82,10 @@ export class AttributesController extends BaseController { @Context context: ServiceContext, @QueryParam("peer") peer: string, @QueryParam("hideTechnical") hideTechnical?: boolean, - @QueryParam("onlyLatestVersions") onlyLatestVersions?: boolean, - @QueryParam("onlyValid") onlyValid?: boolean + @QueryParam("onlyLatestVersions") onlyLatestVersions?: boolean ): Promise { - const query: Record = this.extractQuery(context.request.query, ["peer", "hideTechnical", "onlyLatestVersions", "onlyValid"]); - const result = await this.consumptionServices.attributes.getOwnSharedAttributes({ peer, hideTechnical, query, onlyLatestVersions, onlyValid }); + const query: Record = this.extractQuery(context.request.query, ["peer", "hideTechnical", "onlyLatestVersions"]); + const result = await this.consumptionServices.attributes.getOwnSharedAttributes({ peer, hideTechnical, query, onlyLatestVersions }); return this.ok(result); } @@ -97,12 +96,11 @@ export class AttributesController extends BaseController { @Context context: ServiceContext, @QueryParam("peer") peer: string, @QueryParam("hideTechnical") hideTechnical?: boolean, - @QueryParam("onlyLatestVersions") onlyLatestVersions?: boolean, - @QueryParam("onlyValid") onlyValid?: boolean + @QueryParam("onlyLatestVersions") onlyLatestVersions?: boolean ): Promise { - const query: Record = this.extractQuery(context.request.query, ["peer", "hideTechnical", "onlyLatestVersions", "onlyValid"]); + const query: Record = this.extractQuery(context.request.query, ["peer", "hideTechnical", "onlyLatestVersions"]); - const result = await this.consumptionServices.attributes.getPeerSharedAttributes({ peer, hideTechnical, query, onlyLatestVersions, onlyValid }); + const result = await this.consumptionServices.attributes.getPeerSharedAttributes({ peer, hideTechnical, query, onlyLatestVersions }); return this.ok(result); } @@ -132,14 +130,6 @@ export class AttributesController extends BaseController { return this.ok(result); } - @GET - @Path("/Valid") - @Accept("application/json") - public async getValidAttributes(@Context context: ServiceContext): Promise { - const result = await this.consumptionServices.attributes.getAttributes({ query: context.request.query, onlyValid: true }); - return this.ok(result); - } - @GET @Path("/TagCollection") @Accept("application/json") diff --git a/src/modules/coreHttpApi/controllers/BackboneNotificationsController.ts b/src/modules/coreHttpApi/controllers/BackboneNotificationsController.ts index ca82dfc1..3a63bbbb 100644 --- a/src/modules/coreHttpApi/controllers/BackboneNotificationsController.ts +++ b/src/modules/coreHttpApi/controllers/BackboneNotificationsController.ts @@ -1,10 +1,10 @@ -import { BaseController, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController } from "@nmshd/connector-types"; import { TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, Path, POST, Security } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:backboneNotifications"]) -@Path("/api/v2/BackboneNotifications") +@Security("core:backboneNotifications") +@Path("/api/core/v1/BackboneNotifications") export class BackboneNotificationsController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/ChallengesController.ts b/src/modules/coreHttpApi/controllers/ChallengesController.ts index 73122642..2cef0c92 100644 --- a/src/modules/coreHttpApi/controllers/ChallengesController.ts +++ b/src/modules/coreHttpApi/controllers/ChallengesController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, Path, POST, Return, Security } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:challenges"]) -@Path("/api/v2/Challenges") +@Security("core:challenges") +@Path("/api/core/v1/Challenges") export class ChallengesController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/FilesController.ts b/src/modules/coreHttpApi/controllers/FilesController.ts index 57912583..2e41497e 100644 --- a/src/modules/coreHttpApi/controllers/FilesController.ts +++ b/src/modules/coreHttpApi/controllers/FilesController.ts @@ -1,4 +1,4 @@ -import { BaseController, Envelope, HttpServerRole, Mimetype, QRCode } from "@nmshd/connector-types"; +import { BaseController, Envelope, Mimetype } from "@nmshd/connector-types"; import { Reference } from "@nmshd/core-types"; import { OwnerRestriction, TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; @@ -15,15 +15,14 @@ import { Path, PathParam, POST, - QueryParam, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; import express from "express"; -@Security([HttpServerRole.ADMIN, "core:*", "core:files"]) -@Path("/api/v2/Files") +@Security("core:files") +@Path("/api/core/v1/Files") export class FilesController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); @@ -34,7 +33,7 @@ export class FilesController extends BaseController { @Accept("application/json") public async uploadOwnFile( @FormParam("expiresAt") expiresAt: string, - @FormParam("title") title: string, + @FormParam("title") title?: string, @FileParam("file") file?: Express.Multer.File, @FormParam("description") description?: string, @FormParam("tags") tags?: string[] @@ -100,19 +99,14 @@ export class FilesController extends BaseController { @GET @Path("/:idOrReference") @Accept("application/json", "image/png") - public async getFile( - @PathParam("idOrReference") idOrReference: string, - @ContextAccept accept: string, - @ContextResponse response: express.Response, - @QueryParam("newQRCodeFormat") newQRCodeFormat?: boolean - ): Promise { + public async getFile(@PathParam("idOrReference") idOrReference: string, @ContextAccept accept: string, @ContextResponse response: express.Response): Promise { const fileId = idOrReference.startsWith("FIL") ? idOrReference : Reference.from(idOrReference).id.toString(); const result = await this.transportServices.files.getFile({ id: fileId }); switch (accept) { case "image/png": - return await this.qrCode(result, (r) => QRCode.for(newQRCodeFormat ? r.value.reference.url : r.value.reference.truncated), `${fileId}.png`, response, 200); + return await this.qrCode(result, `${fileId}.png`, response, 200); default: return this.ok(result); } @@ -127,9 +121,6 @@ export class FilesController extends BaseController { @ContextResponse response: express.Response, request: any ): Promise | void> { - const newQRCodeFormat = request["newQRCodeFormat"] === true; - delete request["newQRCodeFormat"]; - const result = await this.transportServices.files.createTokenForFile({ fileId: id, expiresAt: request.expiresAt, @@ -140,7 +131,7 @@ export class FilesController extends BaseController { switch (accept) { case "image/png": - return await this.qrCode(result, (r) => QRCode.for(newQRCodeFormat ? r.value.reference.url : r.value.reference.truncated), `${id}.png`, response, 201); + return await this.qrCode(result, `${id}.png`, response, 201); default: return this.created(result); } diff --git a/src/modules/coreHttpApi/controllers/IdentityMetadataController.ts b/src/modules/coreHttpApi/controllers/IdentityMetadataController.ts index fbc56103..13bc553c 100644 --- a/src/modules/coreHttpApi/controllers/IdentityMetadataController.ts +++ b/src/modules/coreHttpApi/controllers/IdentityMetadataController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { ConsumptionServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, DELETE, GET, PUT, Path, QueryParam, Security } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:identityMetadata"]) -@Path("/api/v2/IdentityMetadata") +@Security("core:identityMetadata") +@Path("/api/core/v1/IdentityMetadata") export class IdentityMetadataController extends BaseController { public constructor(@Inject private readonly consumptionServices: ConsumptionServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/IncomingRequestsController.ts b/src/modules/coreHttpApi/controllers/IncomingRequestsController.ts index 6f040cbc..88d4fb9b 100644 --- a/src/modules/coreHttpApi/controllers/IncomingRequestsController.ts +++ b/src/modules/coreHttpApi/controllers/IncomingRequestsController.ts @@ -1,11 +1,11 @@ import { ApplicationError } from "@js-soft/ts-utils"; -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { ConsumptionServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, Context, GET, Path, PathParam, PUT, Security, ServiceContext } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:requests:*", "core:requests:incoming"]) -@Path("/api/v2/Requests/Incoming") +@Security(["core:requests", "core:requests:incoming"]) +@Path("/api/core/v1/Requests/Incoming") export class IncomingRequestsController extends BaseController { public constructor(@Inject private readonly consumptionServices: ConsumptionServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/MessagesController.ts b/src/modules/coreHttpApi/controllers/MessagesController.ts index 70c24a4a..0cf726d7 100644 --- a/src/modules/coreHttpApi/controllers/MessagesController.ts +++ b/src/modules/coreHttpApi/controllers/MessagesController.ts @@ -1,11 +1,11 @@ -import { BaseController, Envelope, HttpServerRole, Mimetype } from "@nmshd/connector-types"; +import { BaseController, Envelope, Mimetype } from "@nmshd/connector-types"; import { TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, Context, ContextResponse, GET, Path, PathParam, POST, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; import express from "express"; -@Security([HttpServerRole.ADMIN, "core:*", "core:messages"]) -@Path("/api/v2/Messages") +@Security("core:messages") +@Path("/api/core/v1/Messages") export class MessagesController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/OutgoingRequestsController.ts b/src/modules/coreHttpApi/controllers/OutgoingRequestsController.ts index 423ae8a8..011a5d0d 100644 --- a/src/modules/coreHttpApi/controllers/OutgoingRequestsController.ts +++ b/src/modules/coreHttpApi/controllers/OutgoingRequestsController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { ConsumptionServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, Context, GET, Path, PathParam, POST, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:requests:*", "core:requests:outgoing"]) -@Path("/api/v2/Requests/Outgoing") +@Security(["core:requests", "core:requests:outgoing"]) +@Path("/api/core/v1/Requests/Outgoing") export class OutgoingRequestsController extends BaseController { public constructor(@Inject private readonly consumptionServices: ConsumptionServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts b/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts index 76413a03..3f9de71d 100644 --- a/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts +++ b/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts @@ -1,11 +1,11 @@ -import { BaseController, Envelope, HttpServerRole, QRCode } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { OwnerRestriction, TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; -import { Accept, Context, ContextAccept, ContextResponse, GET, POST, Path, PathParam, QueryParam, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; +import { Accept, Context, ContextAccept, ContextResponse, GET, POST, Path, PathParam, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; import express from "express"; -@Security([HttpServerRole.ADMIN, "core:*", "core:relationshipTemplates"]) -@Path("/api/v2/RelationshipTemplates") +@Security("core:relationshipTemplates") +@Path("/api/core/v1/RelationshipTemplates") export class RelationshipTemplatesController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); @@ -44,17 +44,12 @@ export class RelationshipTemplatesController extends BaseController { @GET @Path("/:id") @Accept("application/json", "image/png") - public async getRelationshipTemplate( - @PathParam("id") id: string, - @ContextAccept accept: string, - @ContextResponse response: express.Response, - @QueryParam("newQRCodeFormat") newQRCodeFormat?: boolean - ): Promise { + public async getRelationshipTemplate(@PathParam("id") id: string, @ContextAccept accept: string, @ContextResponse response: express.Response): Promise { const result = await this.transportServices.relationshipTemplates.getRelationshipTemplate({ id }); switch (accept) { case "image/png": - return await this.qrCode(result, (r) => QRCode.for(newQRCodeFormat ? r.value.reference.url : r.value.reference.truncated), `${id}.png`, response, 200); + return await this.qrCode(result, `${id}.png`, response, 200); default: return this.ok(result); } @@ -85,9 +80,6 @@ export class RelationshipTemplatesController extends BaseController { @ContextResponse response: express.Response, request: any ): Promise | void> { - const newQRCodeFormat = request["newQRCodeFormat"] === true; - delete request["newQRCodeFormat"]; - const result = await this.transportServices.relationshipTemplates.createTokenForOwnRelationshipTemplate({ templateId: id, expiresAt: request.expiresAt, @@ -98,7 +90,7 @@ export class RelationshipTemplatesController extends BaseController { switch (accept) { case "image/png": - return await this.qrCode(result, (r) => QRCode.for(newQRCodeFormat ? r.value.reference.url : r.value.reference.truncated), `${id}.png`, response, 201); + return await this.qrCode(result, `${id}.png`, response, 201); default: return this.created(result); } diff --git a/src/modules/coreHttpApi/controllers/RelationshipsController.ts b/src/modules/coreHttpApi/controllers/RelationshipsController.ts index 9b8bc670..0ce0a06a 100644 --- a/src/modules/coreHttpApi/controllers/RelationshipsController.ts +++ b/src/modules/coreHttpApi/controllers/RelationshipsController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, Context, DELETE, GET, Path, PathParam, POST, PUT, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.ADMIN, "core:*", "core:relationships"]) -@Path("/api/v2/Relationships") +@Security("core:relationships") +@Path("/api/core/v1/Relationships") export class RelationshipsController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); diff --git a/src/modules/coreHttpApi/controllers/TokensController.ts b/src/modules/coreHttpApi/controllers/TokensController.ts index ab36c78a..fd47b505 100644 --- a/src/modules/coreHttpApi/controllers/TokensController.ts +++ b/src/modules/coreHttpApi/controllers/TokensController.ts @@ -1,11 +1,11 @@ -import { BaseController, Envelope, HttpServerRole, QRCode } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { OwnerRestriction, TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; -import { Accept, Context, ContextAccept, ContextResponse, GET, Path, PathParam, POST, QueryParam, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; +import { Accept, Context, ContextAccept, ContextResponse, GET, Path, PathParam, POST, Return, Security, ServiceContext } from "@nmshd/typescript-rest"; import express from "express"; -@Security([HttpServerRole.ADMIN, "core:*", "core:tokens"]) -@Path("/api/v2/Tokens") +@Security("core:tokens") +@Path("/api/core/v1/Tokens") export class TokensController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); @@ -54,17 +54,12 @@ export class TokensController extends BaseController { @GET @Path("/:id") @Accept("application/json", "image/png") - public async getToken( - @PathParam("id") id: string, - @ContextAccept accept: string, - @ContextResponse response: express.Response, - @QueryParam("newQRCodeFormat") newQRCodeFormat?: boolean - ): Promise { + public async getToken(@PathParam("id") id: string, @ContextAccept accept: string, @ContextResponse response: express.Response): Promise { const result = await this.transportServices.tokens.getToken({ id }); switch (accept) { case "image/png": - return await this.qrCode(result, (r) => QRCode.for(newQRCodeFormat ? r.value.reference.url : r.value.reference.truncated), `${id}.png`, response, 200); + return await this.qrCode(result, `${id}.png`, response, 200); default: return this.ok(result); } diff --git a/src/modules/coreHttpApi/debug-controllers/IdentityDeletionProcessController.ts b/src/modules/coreHttpApi/debug-controllers/IdentityDeletionProcessController.ts index 0e77d17e..4a09446f 100644 --- a/src/modules/coreHttpApi/debug-controllers/IdentityDeletionProcessController.ts +++ b/src/modules/coreHttpApi/debug-controllers/IdentityDeletionProcessController.ts @@ -1,10 +1,10 @@ -import { BaseController, Envelope, HttpServerRole } from "@nmshd/connector-types"; +import { BaseController, Envelope } from "@nmshd/connector-types"; import { TransportServices } from "@nmshd/runtime"; import { Inject } from "@nmshd/typescript-ioc"; import { Accept, DELETE, GET, Path, POST, QueryParam, Security } from "@nmshd/typescript-rest"; -@Security([HttpServerRole.DEVELOPER]) -@Path("/api/v2/IdentityDeletionProcess") +@Security("debug:identityDeletionProcess") +@Path("/api/core/v1/IdentityDeletionProcess") export class IdentityDeletionProcessController extends BaseController { public constructor(@Inject private readonly transportServices: TransportServices) { super(); diff --git a/src/modules/coreHttpApi/openapi.yml b/src/modules/coreHttpApi/openapi.yml index 0d10cb6d..34ee3694 100644 --- a/src/modules/coreHttpApi/openapi.yml +++ b/src/modules/coreHttpApi/openapi.yml @@ -160,7 +160,7 @@ paths: # ------------------- Account ------------------- - /api/v2/Account/IdentityInfo: + /api/core/v1/Account/IdentityInfo: get: operationId: getIdentityInfo description: Shows the Account Information. @@ -192,7 +192,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Account/SyncInfo: + /api/core/v1/Account/SyncInfo: get: operationId: getSyncInfo description: show information about the last completed sync run @@ -231,7 +231,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Account/Sync: + /api/core/v1/Account/Sync: post: operationId: sync description: > @@ -257,7 +257,7 @@ paths: # ------------------- Announcements ------------------- - /api/v2/Announcements: + /api/core/v1/Announcements: get: operationId: getAnnouncements description: Query Announcements @@ -298,7 +298,7 @@ paths: # ------------------- Attributes ------------------- - /api/v2/Attributes/CanCreate: + /api/core/v1/Attributes/CanCreate: put: operationId: canCreateRepositoryAttribute description: "Checks if a Repository Attribute can be created with the given parameters." @@ -320,10 +320,6 @@ paths: $ref: "#/components/schemas/AttributeValue" tags: $ref: "#/components/schemas/IdentityAttributeContent_tags" - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" responses: 200: description: Success @@ -349,7 +345,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes: + /api/core/v1/Attributes: post: operationId: createRepositoryAttribute description: "Creates a Repository Attribute." @@ -371,10 +367,6 @@ paths: $ref: "#/components/schemas/AttributeValue" tags: $ref: "#/components/schemas/IdentityAttributeContent_tags" - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" responses: 201: description: Success @@ -426,16 +418,6 @@ paths: required: false schema: $ref: "#/components/schemas/TextFilter" - - name: content.validFrom - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - - name: content.validTo - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - name: content.key in: query required: false @@ -507,7 +489,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/Own/Repository: + /api/core/v1/Attributes/Own/Repository: get: operationId: getOwnRepositoryAttributes tags: @@ -523,16 +505,6 @@ paths: required: false schema: $ref: "#/components/schemas/TextFilter" - - name: content.validFrom - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - - name: content.validTo - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - name: content.value.@type in: query required: false @@ -585,7 +557,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/Own/Shared/Identity: + /api/core/v1/Attributes/Own/Shared/Identity: get: operationId: getOwnSharedIdentityAttributes tags: @@ -606,16 +578,6 @@ paths: required: false schema: $ref: "#/components/schemas/TextFilter" - - name: content.validFrom - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - - name: content.validTo - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - name: content.key in: query required: false @@ -661,11 +623,6 @@ paths: required: true schema: $ref: "#/components/schemas/Address" - - name: onlyValid - in: query - required: false - schema: - type: boolean - name: hideTechnical in: query required: false @@ -705,7 +662,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/Peer/Shared/Identity: + /api/core/v1/Attributes/Peer/Shared/Identity: get: operationId: getPeerSharedIdentityAttributes tags: @@ -727,16 +684,6 @@ paths: required: false schema: $ref: "#/components/schemas/TextFilter" - - name: content.validFrom - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - - name: content.validTo - in: query - required: false - schema: - $ref: "#/components/schemas/DateFilter" - name: content.key in: query required: false @@ -777,11 +724,6 @@ paths: required: true schema: $ref: "#/components/schemas/Address" - - name: onlyValid - in: query - required: false - schema: - type: boolean - name: hideTechnical in: query required: false @@ -821,7 +763,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/{id}/Versions: + /api/core/v1/Attributes/{id}/Versions: get: operationId: getVersionsOfAttribute tags: @@ -859,7 +801,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/{id}/Versions/Shared: + /api/core/v1/Attributes/{id}/Versions/Shared: get: operationId: getSharedVersionsOfAttribute tags: @@ -912,7 +854,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/{predecessorId}/Succeed: + /api/core/v1/Attributes/{predecessorId}/Succeed: post: operationId: succeedAttribute description: Succeeds either a relationship attribute or a repository attribute. @@ -941,10 +883,6 @@ paths: $ref: "#/components/schemas/AttributeValue" tags: $ref: "#/components/schemas/IdentityAttributeContent_tags" - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" responses: 201: @@ -987,7 +925,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Attributes/{attributeId}/NotifyPeer: + /api/core/v1/Attributes/{attributeId}/NotifyPeer: post: operationId: notifyPeerAboutRepositoryAttributeSuccession description: | @@ -1052,7 +990,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Attributes/{id}: + /api/core/v1/Attributes/{id}: get: operationId: getAttribute description: Fetches the attribute with the given `id`. @@ -1120,7 +1058,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Attributes/Own/Shared/{id}: + /api/core/v1/Attributes/Own/Shared/{id}: delete: operationId: deleteOwnSharedAttributeAndNotifyPeer description: Delete an own shared attribute and notify the peer. @@ -1169,7 +1107,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Attributes/Peer/Shared/{id}: + /api/core/v1/Attributes/Peer/Shared/{id}: delete: operationId: deletePeerSharedAttributeAndNotifyOwner description: Delete an peer shared attribute and notify the owner. @@ -1218,7 +1156,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Attributes/ThirdParty/{id}: + /api/core/v1/Attributes/ThirdParty/{id}: delete: operationId: deleteThirdPartyRelationshipAttributeAndNotifyPeer description: Delete a ThirdPartyRelationshipAttribute and notify the peer. @@ -1267,100 +1205,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Attributes/Valid: - get: - operationId: getValidAttributes - description: List valid Attributes - tags: - - Attributes - parameters: - - name: content.@type - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: content.tags - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: content.owner - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: content.key - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: content.isTechnical - in: query - required: false - schema: - $ref: "#/components/schemas/BooleanFilter" - - name: content.confidentiality - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: content.value.@type - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: succeeds - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: succeededBy - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: shareInfo.requestReference - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: shareInfo.peer - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - - name: shareInfo.sourceAttribute - in: query - required: false - schema: - $ref: "#/components/schemas/TextFilter" - responses: - 200: - description: Success - content: - application/json: - schema: - type: object - properties: - result: - type: array - items: - $ref: "#/components/schemas/Attribute" - required: - - result - headers: - X-Response-Duration-ms: - schema: - $ref: "#/components/schemas/HeaderContent_X-Response-Duration-ms" - X-Response-Time: - schema: - $ref: "#/components/schemas/HeaderContent_X-Response-Time" - 401: - $ref: "#/components/responses/Unauthorized" - 403: - $ref: "#/components/responses/Forbidden" - - /api/v2/Attributes/TagCollection: + /api/core/v1/Attributes/TagCollection: get: operationId: getAttributeTagCollection description: List valid Tags for Attributes @@ -1392,7 +1237,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/ExecuteIdentityAttributeQuery: + /api/core/v1/Attributes/ExecuteIdentityAttributeQuery: post: operationId: executeIdentityQuery description: Execute an IdentityAttributeQuery @@ -1412,10 +1257,6 @@ paths: items: type: string type: array - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" valueType: description: The valueType of the attribute. type: string @@ -1449,7 +1290,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/ExecuteRelationshipAttributeQuery: + /api/core/v1/Attributes/ExecuteRelationshipAttributeQuery: post: operationId: executeRelationshipQuery description: Execute a RelationshipAttributeQuery @@ -1470,10 +1311,6 @@ paths: owner: description: The owner of the relationship attribute. type: string - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" attributeCreationHints: description: This describes how to create an attribute if it does not exist. type: object @@ -1559,7 +1396,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/ExecuteThirdPartyRelationshipAttributeQuery: + /api/core/v1/Attributes/ExecuteThirdPartyRelationshipAttributeQuery: post: operationId: executeThirdPartyRelationshipQuery description: Execute a ThirdPartyAttributeQuery @@ -1585,10 +1422,6 @@ paths: type: array items: $ref: "#/components/schemas/Address" - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" required: - key - owner @@ -1621,7 +1454,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/ExecuteIQLQuery: + /api/core/v1/Attributes/ExecuteIQLQuery: post: operationId: executeIQLQuery description: Execute IQL Query @@ -1660,7 +1493,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Attributes/ValidateIQLQuery: + /api/core/v1/Attributes/ValidateIQLQuery: post: operationId: validateIQLQuery description: Validate IQL Query @@ -1723,7 +1556,7 @@ paths: # ------------------- BackboneNotifications ------------------- - /api/v2/BackboneNotifications: + /api/core/v1/BackboneNotifications: post: operationId: sendBackboneNotification description: Send a BackboneNotification. @@ -1765,7 +1598,7 @@ paths: # ------------------- Challenges ------------------- - /api/v2/Challenges: + /api/core/v1/Challenges: post: operationId: createChallenge description: Create a signed challenge. @@ -1805,7 +1638,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Challenges/Validate: + /api/core/v1/Challenges/Validate: post: operationId: validateChallenge description: Validate a challenge. @@ -1863,7 +1696,7 @@ paths: # ------------------- Files ------------------- - /api/v2/Files: + /api/core/v1/Files: get: operationId: getAllFileMetadata description: Queries metadata of all files. @@ -1949,7 +1782,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Files/Own: + /api/core/v1/Files/Own: post: operationId: uploadNewOwnFile description: Uploads a new own file with metadata. @@ -1985,8 +1818,8 @@ paths: type: array items: type: string - description: Tags for the file. - example: ["tag1", "tag2"] + description: The tags of the File. A tag is valid if it is contained in the AttributeTagCollection for the IdentityAttribute value type IdentityFileReference and starts with the prefix `bkb:` or if it starts with the custom tag prefix `x:` or `X:`, the prefix `urn:`, the prefix `language:` followed by a valid ISO 639 language code or the prefix `mimetype:` followed by a valid MIME type. + example: ["x:tag1", "x:tag2"] nullable: false required: - file @@ -2093,7 +1926,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Files/Peer: + /api/core/v1/Files/Peer: post: operationId: loadPeerFile description: Loads a file of another identity. After it is loaded once, you can retrieve it without the need for the reference by calling one of the GET-routes. @@ -2211,7 +2044,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Files/{idOrReference}: + /api/core/v1/Files/{idOrReference}: get: operationId: getFileMetadata description: | @@ -2229,13 +2062,6 @@ paths: - $ref: "#/components/schemas/FileID" - $ref: "#/components/schemas/FileReferenceTruncated" - $ref: "#/components/schemas/FileReferenceUrl" - - in: query - name: newQRCodeFormat - description: If set to true, the QRCode will contain the new url format. This is only relevant if the accept header is set to `image/png`. - required: false - schema: - type: boolean - default: false responses: 200: @@ -2269,7 +2095,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Files/{id}/Download: + /api/core/v1/Files/{id}/Download: get: operationId: downloadFile description: Downloads the file with the given `id`. @@ -2306,7 +2132,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Files/{id}/Token: + /api/core/v1/Files/{id}/Token: post: operationId: createTokenForFile description: Creates a `Token` for the `File` with the given `id`. If the accept header is set to `image/png` instead of `application/json`, a QR Code containing the reference to the token is shown. @@ -2330,7 +2156,7 @@ paths: type: string format: date-time ephemeral: - description: If set to true the token will not be cached in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to true. Will be ignored if the accept header is set to `image/png`. + description: If set to true the token will not be stored in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to true. Will be ignored if the accept header is set to `image/png`. type: boolean forIdentity: $ref: "#/components/schemas/Address" @@ -2340,10 +2166,6 @@ paths: $ref: "#/components/schemas/PasswordProtection" nullable: true description: The password that will be required to load this Token and information about the password. - newQRCodeFormat: - type: boolean - description: If set to true, the QRCode will contain the new url format. This is only relevant if the accept header is set to `image/png`. - nullable: true responses: 201: description: Success @@ -2376,7 +2198,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Files/{id}/RegenerateOwnershipToken: + /api/core/v1/Files/{id}/RegenerateOwnershipToken: patch: operationId: regenerateOwnershipToken description: Regenerates the ownership token for the file with the given `id`. This will invalidate the previous ownership token. @@ -2416,7 +2238,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Files/{id}: + /api/core/v1/Files/{id}: delete: operationId: deleteFile description: Delete a File. @@ -2448,7 +2270,7 @@ paths: # ------------------- IdentityMetadata ------------------- - /api/v2/IdentityMetadata: + /api/core/v1/IdentityMetadata: put: operationId: upsertIdentityMetadata description: Creates or updates an IdentityMetadata object for the specified `reference` and `key` combination. @@ -2573,7 +2395,7 @@ paths: # ------------------- Messages ------------------- - /api/v2/Messages: + /api/core/v1/Messages: post: operationId: sendMessage description: > @@ -2724,7 +2546,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Messages/{id}: + /api/core/v1/Messages/{id}: get: operationId: getMessage description: Fetches the message with the given `id`. @@ -2764,7 +2586,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Messages/{messageId}/Attachments/{attachmentId}: + /api/core/v1/Messages/{messageId}/Attachments/{attachmentId}: get: operationId: getMetadataOfMessageAttachment description: Returns the attachment's metadata of the given `attachmentId` of message with `messageId`. @@ -2809,7 +2631,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Messages/{messageId}/Attachments/{attachmentId}/Download: + /api/core/v1/Messages/{messageId}/Attachments/{attachmentId}/Download: get: operationId: downloadAttachmentOfMessage description: Downloads the file of the given `attachmentId` of message with `messageId`. @@ -2852,7 +2674,7 @@ paths: # ------------------- Relationships ------------------- - /api/v2/Relationships/CanCreate: + /api/core/v1/Relationships/CanCreate: put: operationId: canCreateRelationship description: Checks if a Relationship can be created with a given RelationshipTemplate to its creator. Optionally, the potential `creationContent` of the Relationship can also be validated. @@ -2910,7 +2732,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships: + /api/core/v1/Relationships: post: operationId: createRelationship description: Creates a `Relationship` to the creator of a given relationshipTemplateId. The `RelationshipTemplate` of the given `relationshipTemplateId` must come from another identity and must be loaded by `POST /RelationshipTemplates/Peer` first. @@ -2972,7 +2794,7 @@ paths: - Relationships parameters: - in: query - name: template.id + name: templateId schema: $ref: "#/components/schemas/IdFilter" - in: query @@ -3010,7 +2832,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Relationships/{id}: + /api/core/v1/Relationships/{id}: get: operationId: getRelationshipById description: Fetches the `Relationship` with the given `id`. @@ -3080,7 +2902,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Attributes: + /api/core/v1/Relationships/{id}/Attributes: get: operationId: getAttributesForRelationship description: Queries attributes that are related to the given relationship. @@ -3120,7 +2942,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Relationships/{id}/Accept: + /api/core/v1/Relationships/{id}/Accept: put: operationId: acceptRelationship description: Accepts the pending Relationship. @@ -3161,7 +2983,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Reject: + /api/core/v1/Relationships/{id}/Reject: put: operationId: rejectRelationship description: Rejects the pending Relationship. @@ -3203,7 +3025,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Revoke: + /api/core/v1/Relationships/{id}/Revoke: put: operationId: revokeRelationship description: Revoke the pending relationship. If the relationship was created by another identity the request will return with the error code 500. @@ -3245,7 +3067,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Terminate: + /api/core/v1/Relationships/{id}/Terminate: put: operationId: terminateRelationship description: Terminate the relationship. @@ -3287,7 +3109,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Reactivate: + /api/core/v1/Relationships/{id}/Reactivate: put: operationId: requestRelationshipReactivation description: Request the relationship reactivation. @@ -3329,7 +3151,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Reactivate/Accept: + /api/core/v1/Relationships/{id}/Reactivate/Accept: put: operationId: acceptRelationshipReactivation description: Accept a relationship reactivation. @@ -3371,7 +3193,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Reactivate/Reject: + /api/core/v1/Relationships/{id}/Reactivate/Reject: put: operationId: rejectRelationshipReactivation description: Reject a relationship reactivation. @@ -3413,7 +3235,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Relationships/{id}/Reactivate/Revoke: + /api/core/v1/Relationships/{id}/Reactivate/Revoke: put: operationId: revokeRelationshipReactivation description: Revoke a relationship reactivation. @@ -3457,7 +3279,7 @@ paths: # ------------------- RelationshipTemplates ------------------- - /api/v2/RelationshipTemplates: + /api/core/v1/RelationshipTemplates: get: operationId: getRelationshipTemplates description: Queries `RelationshipTemplates`. @@ -3535,7 +3357,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/RelationshipTemplates/Own: + /api/core/v1/RelationshipTemplates/Own: post: operationId: createOwnRelationshipTemplate description: Creates a new `RelationshipTemplate`. @@ -3676,7 +3498,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/RelationshipTemplates/Peer: + /api/core/v1/RelationshipTemplates/Peer: post: operationId: loadPeerRelationshipTemplate description: Loads a `RelationshipTemplate` created by others. This is a prerequisite for using the template while creating a new `Relationship`. @@ -3795,7 +3617,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/RelationshipTemplates/{id}: + /api/core/v1/RelationshipTemplates/{id}: get: operationId: getRelationshipTemplate description: Fetches the `RelationshipTemplate` with the given `id` when the accept header is set to `application/json` or a QR Code containing the reference to the RelationshipTemplate if the accept header it set to `image/png`. @@ -3808,13 +3630,6 @@ paths: required: true schema: $ref: "#/components/schemas/RelationshipTemplateID" - - in: query - name: newQRCodeFormat - description: If set to true, the QRCode will contain the new url format. This is only relevant if the accept header is set to `image/png`. - required: false - schema: - type: boolean - default: false responses: 200: description: Success @@ -3847,7 +3662,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/RelationshipTemplates/Own/{id}/Token: + /api/core/v1/RelationshipTemplates/Own/{id}/Token: post: operationId: createTokenForOwnRelationshipTemplate description: Creates a `Token` for the own `RelationshipTemplate` with the given `id`. If the accept header is set to `image/png` instead of `application/json`, a QR Code containing the reference to the token is shown. @@ -3871,7 +3686,7 @@ paths: type: string format: date-time ephemeral: - description: If set to true the token will not be cached in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to true. Will be ignored if the accept header is set to `image/png`. + description: If set to true the token will not be stored in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to true. Will be ignored if the accept header is set to `image/png`. type: boolean forIdentity: $ref: "#/components/schemas/Address" @@ -3881,10 +3696,6 @@ paths: $ref: "#/components/schemas/PasswordProtection" nullable: true description: The password that will be required to load this Token and information about the password. If passwordProtection is set for the RelationshipTemplate, the same passwordProtection must also be given here. - newQRCodeFormat: - type: boolean - description: If set to true, the QRCode will contain the new url format. This is only relevant if the accept header is set to `image/png`. - nullable: true responses: 201: description: Success @@ -3919,7 +3730,7 @@ paths: # ------------------- Requests ------------------- - /api/v2/Requests/Incoming: + /api/core/v1/Requests/Incoming: get: operationId: getIncomingRequests description: Queries incoming `Requests`. @@ -4017,7 +3828,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Requests/Incoming/{id}: + /api/core/v1/Requests/Incoming/{id}: get: operationId: getIncomingRequest description: Fetches the incoming `Request` with the given `id`. @@ -4057,7 +3868,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Requests/Incoming/{id}/CanAccept: + /api/core/v1/Requests/Incoming/{id}/CanAccept: put: operationId: canAcceptIncomingRequest description: Checks if the `Request` with the given `id` can be accepted. @@ -4103,7 +3914,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Requests/Incoming/{id}/Accept: + /api/core/v1/Requests/Incoming/{id}/Accept: put: operationId: acceptIncomingRequest description: Accepts the incoming `Request` with the given `id`. @@ -4149,7 +3960,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Requests/Incoming/{id}/CanReject: + /api/core/v1/Requests/Incoming/{id}/CanReject: put: operationId: canRejectIncomingRequest description: Checks if the `Request` with the given `id` can be rejected. @@ -4195,7 +4006,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Requests/Incoming/{id}/Reject: + /api/core/v1/Requests/Incoming/{id}/Reject: put: operationId: rejectIncomingRequest description: Rejects the incoming `Request` with the given `id`. @@ -4241,7 +4052,7 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Requests/Outgoing: + /api/core/v1/Requests/Outgoing: get: operationId: getOutgoingRequests description: Queries outgoing `Requests`. @@ -4371,7 +4182,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Requests/Outgoing/{id}: + /api/core/v1/Requests/Outgoing/{id}: get: operationId: getOutgoingRequest description: Fetches the `Request` with the given `id`. @@ -4411,10 +4222,10 @@ paths: 404: $ref: "#/components/responses/NotFound" - /api/v2/Requests/Outgoing/Validate: + /api/core/v1/Requests/Outgoing/Validate: post: operationId: validateOutgoingRequest - description: Validates the given `OutgoingRequest` before creating it via POST `/api/v2/Requests/Outgoing`. + description: Validates the given `OutgoingRequest` before creating it via POST `/api/core/v1/Requests/Outgoing`. tags: - Requests requestBody: @@ -4452,7 +4263,7 @@ paths: # ------------------- Tokens ------------------- - /api/v2/Tokens/Own: + /api/core/v1/Tokens/Own: post: operationId: createOwnToken description: Creates a new `Token` with the given content. @@ -4478,7 +4289,7 @@ paths: nullable: false description: A timestamp that describes when this token expires. An expired token cannot be fetched from the platform anymore. However it will still be available for auditing purposes. ephemeral: - description: If set to true the token will not be cached in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to false. + description: If set to true the token will not be stored in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to false. type: boolean example: false forIdentity: @@ -4584,7 +4395,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Tokens/Peer: + /api/core/v1/Tokens/Peer: post: operationId: loadPeerToken description: Load a `Token` created by others. @@ -4601,7 +4412,7 @@ paths: nullable: false description: The base64 encoded truncated reference or url reference of the Token, which actually consists of all information to get and decrypt it. ephemeral: - description: If set to true the token will not be cached in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to false. + description: If set to true the token will not be stored in the database of the Connector. Note that you will not be able to fetch this token unless you remember the reference of the token. Defaults to false. type: boolean password: type: string @@ -4701,7 +4512,7 @@ paths: 403: $ref: "#/components/responses/Forbidden" - /api/v2/Tokens/{id}: + /api/core/v1/Tokens/{id}: get: operationId: getToken description: Fetches the `Token` with the given `id`. @@ -4714,13 +4525,6 @@ paths: required: true schema: $ref: "#/components/schemas/TokenID" - - in: query - name: newQRCodeFormat - description: If set to true, the QRCode will contain the new url format. This is only relevant if the accept header is set to `image/png`. - required: false - schema: - type: boolean - default: false responses: 200: description: Success @@ -5163,10 +4967,6 @@ components: description: The address of the identity that owns the attribute. tags: $ref: "#/components/schemas/IdentityAttributeContent_tags" - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" value: "$ref": "#/components/schemas/AttributeValue" @@ -5191,10 +4991,6 @@ components: allOf: - $ref: "#/components/schemas/Address" description: The address of the identity that owns the attribute. - validFrom: - $ref: "#/components/schemas/AttributeContent_validFrom" - validTo: - $ref: "#/components/schemas/AttributeContent_validTo" value: "$ref": "#/components/schemas/AttributeValue" required: @@ -5204,22 +5000,12 @@ components: - owner - value - AttributeContent_validFrom: - type: string - format: date-time - description: The date and time when the attribute becomes valid. - - AttributeContent_validTo: - type: string - format: date-time - description: The date and time when the attribute expires. - IdentityAttributeContent_tags: type: array items: type: string - description: The tags of the attribute. - example: ["tag_1", "tag_2"] + description: The tags of the IdentityAttribute. A tag is valid if it is contained in the AttributeTagCollection and starts with the prefix `bkb:` or if it starts with the custom tag prefix `x:` or `X:`, the prefix `urn:`, the prefix `language:` followed by a valid ISO 639 language code or the prefix `mimetype:` followed by a valid MIME type. + example: ["x:tag1", "x:tag2"] Confidentiality: enum: @@ -5518,8 +5304,8 @@ components: type: array items: type: string - description: Tags for the file. - example: [tag1, tag2] + description: The tags of the File. A tag is valid if it is contained in the AttributeTagCollection for the IdentityAttribute value type IdentityFileReference and starts with the prefix `bkb:` or if it starts with the custom tag prefix `x:` or `X:`, the prefix `urn:`, the prefix `language:` followed by a valid ISO 639 language code or the prefix `mimetype:` followed by a valid MIME type. + example: [x:tag1, x:tag2] nullable: true filesize: type: integer @@ -5553,11 +5339,6 @@ components: isOwn: type: boolean nullable: false - truncatedReference: - type: string - format: byte - nullable: false - description: The base64 encoded truncated reference of the File, which actually consists of all information to get and decrypt it. reference: type: object allOf: @@ -5576,7 +5357,6 @@ components: - $ref: "#/components/schemas/Address" required: - id - - title - filename - filesize - createdAt @@ -5585,7 +5365,7 @@ components: - expiresAt - mimetype - isOwn - - truncatedReference + - reference - owner FileReferenceTruncated: @@ -5663,9 +5443,6 @@ components: properties: "@type": type: string - title: - type: string - description: Will be rendered as title of the request. description: type: string description: Will be rendered as description of the request. @@ -6255,9 +6032,9 @@ components: - $ref: "#/components/schemas/RelationshipID" nullable: false description: The ID of the relationship. - template: + templateId: allOf: - - $ref: "#/components/schemas/RelationshipTemplate" + - $ref: "#/components/schemas/RelationshipTemplateID" nullable: false status: $ref: "#/components/schemas/RelationshipStatus" @@ -6308,7 +6085,7 @@ components: description: The audit log of the relationship. required: - id - - template + - templateId - status - peer - peerIdentity @@ -6422,11 +6199,6 @@ components: - $ref: "#/components/schemas/RelationshipTemplateContent" - $ref: "#/components/schemas/ArbitraryRelationshipTemplateContent" nullable: false - truncatedReference: - type: string - format: byte - nullable: false - description: The base64 encoded truncated reference of the RelationshipTemplate, which actually consists of all information to get and decrypt it. reference: type: object allOf: @@ -6439,7 +6211,7 @@ components: - createdAt - expiresAt - content - - truncatedReference + - reference RelationshipAuditLogEntry: type: object @@ -6573,11 +6345,6 @@ components: $ref: "#/components/schemas/PasswordProtection" nullable: true description: The password that is required to load this Token and information about the password. - truncatedReference: - type: string - format: byte - nullable: false - description: The base64 encoded truncated reference of the Token, which actually consists of all information to get and decrypt it. reference: type: object allOf: @@ -6589,7 +6356,7 @@ components: - content - createdAt - expiresAt - - truncatedReference + - reference TokenContent: type: object diff --git a/test/attributes.test.ts b/test/attributes.test.ts index ec0465da..6ac1bf5b 100644 --- a/test/attributes.test.ts +++ b/test/attributes.test.ts @@ -47,7 +47,7 @@ describe("Attributes", () => { "@type": "GivenName", value: "AGivenName" }, - tags: ["content:edu.de"] + tags: ["x:content.edu.de"] } }); @@ -61,7 +61,7 @@ describe("Attributes", () => { "@type": "GivenName", value: "AGivenName" }, - tags: ["content:edu.de"] + tags: ["x:content.edu.de"] } }); @@ -91,7 +91,7 @@ describe("Attributes", () => { "@type": "GivenName", value: "AGivenName" }, - tags: ["content:edu.de"] + tags: ["x:content.edu.de"] } }) ).result.id; @@ -104,11 +104,6 @@ describe("Attributes", () => { expect(getAttributesResponse).toBeSuccessful(); }); - test("should get the created attribute in the list of valid attributes", async () => { - const getAttributesResponse = await client1.attributes.getValidAttributes({}); - expect(getAttributesResponse).toBeSuccessful(); - }); - test("should succeed a Repository Attribute", async () => { const newRepositoryAttribute: CreateRepositoryAttributeRequest = { content: { @@ -116,7 +111,7 @@ describe("Attributes", () => { "@type": "GivenName", value: "AGivenName" }, - tags: ["content:edu.de"] + tags: ["x:content.edu.de"] } }; const createAttributeResponse = await client1.attributes.createRepositoryAttribute(newRepositoryAttribute); @@ -129,7 +124,7 @@ describe("Attributes", () => { "@type": "GivenName", value: "ANewGivenName" }, - tags: ["content:edu.de"] + tags: ["x:content.edu.de"] } }); @@ -219,7 +214,7 @@ describe("Attributes Query", () => { "@type": "GivenName", value: "AGivenName" }, - tags: ["content:edu.de"] + tags: ["x:content.edu.de"] } }) ).result; @@ -229,8 +224,6 @@ describe("Attributes Query", () => { .addStringSet("content.@type") .addStringArraySet("content.tags") .addStringSet("content.owner") - .addDateSet("content.validFrom") - .addDateSet("content.validTo") .addStringSet("content.key") .addBooleanSet("content.isTechnical") .addStringSet("content.confidentiality") @@ -244,35 +237,6 @@ describe("Attributes Query", () => { await conditions.executeTests((c, q) => c.attributes.getAttributes(q)); }); - test("should query valid attributes", async () => { - const attribute = ( - await client1.attributes.createRepositoryAttribute({ - content: { - value: { - "@type": "GivenName", - value: "AGivenName" - } - } - }) - ).result; - - const conditions = new QueryParamConditions(attribute, client1) - .addStringSet("content.@type") - .addStringArraySet("content.tags") - .addStringSet("content.owner") - .addStringSet("content.key") - .addBooleanSet("content.isTechnical") - .addStringSet("content.confidentiality") - .addStringSet("content.value.@type") - .addStringSet("succeeds") - .addStringSet("succeededBy") - .addStringSet("shareInfo.requestReference") - .addStringSet("shareInfo.peer") - .addStringSet("shareInfo.sourceAttribute"); - - await conditions.executeTests((c, q) => c.attributes.getValidAttributes(q)); - }); - test("should query own shared identity attributes", async () => { const attribute = await executeFullCreateAndShareRepositoryAttributeFlow(client1, client2, { "@type": "GivenName", diff --git a/test/debug/identityDeletionProcess.test.ts b/test/debug/identityDeletionProcess.test.ts index 7b56dccb..89143482 100644 --- a/test/debug/identityDeletionProcess.test.ts +++ b/test/debug/identityDeletionProcess.test.ts @@ -16,50 +16,50 @@ beforeAll(async () => { afterAll(() => launcher.stop()); describe("Identity Deletion Process", () => { - afterEach(async () => await axiosInstance.delete("/api/v2/IdentityDeletionProcess")); + afterEach(async () => await axiosInstance.delete("/api/core/v1/IdentityDeletionProcess")); test("should return 400 when no identity deletion process is active", async () => { - const getResult = await axiosInstance.get("/api/v2/IdentityDeletionProcess"); + const getResult = await axiosInstance.get("/api/core/v1/IdentityDeletionProcess"); expect(getResult.status).toBe(400); }); test("should start an identity deletion and get its status", async () => { - const response = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/v2/IdentityDeletionProcess"); + const response = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/core/v1/IdentityDeletionProcess"); expect(response.status).toBe(200); const identityDeletionProcess = response.data.result; - expect(identityDeletionProcess.status).toBe("Approved"); + expect(identityDeletionProcess.status).toBe("Active"); expect(DateTime.fromISO(identityDeletionProcess.gracePeriodEndsAt!).toMillis()).toBeGreaterThan(DateTime.now().toMillis()); }); test("should get the active identity deletion process", async () => { - const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/v2/IdentityDeletionProcess"); + const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/core/v1/IdentityDeletionProcess"); expect(initiateResult.status).toBe(200); const identityDeletionProcess = initiateResult.data.result; - const getResult = await axiosInstance.get<{ result: IdentityDeletionProcessDTO }>("/api/v2/IdentityDeletionProcess"); + const getResult = await axiosInstance.get<{ result: IdentityDeletionProcessDTO }>("/api/core/v1/IdentityDeletionProcess"); expect(getResult.status).toBe(200); expect(getResult.data.result.status).toBe(identityDeletionProcess.status); expect(getResult.data.result.gracePeriodEndsAt).toBe(identityDeletionProcess.gracePeriodEndsAt); }); test("should return 400 when trying to start a new identity deletion process", async () => { - const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/v2/IdentityDeletionProcess"); + const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/core/v1/IdentityDeletionProcess"); expect(initiateResult.status).toBe(200); - const initiateResult2 = await axiosInstance.post("/api/v2/IdentityDeletionProcess"); + const initiateResult2 = await axiosInstance.post("/api/core/v1/IdentityDeletionProcess"); expect(initiateResult2.status).toBe(400); }); test("should cancel an identity deletion", async () => { - const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/v2/IdentityDeletionProcess"); + const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcessDTO }>("/api/core/v1/IdentityDeletionProcess"); expect(initiateResult.status).toBe(200); - const cancelResult = await axiosInstance.delete("/api/v2/IdentityDeletionProcess"); + const cancelResult = await axiosInstance.delete("/api/core/v1/IdentityDeletionProcess"); expect(cancelResult.status).toBe(200); expect(cancelResult.data.result.status).toBe("Cancelled"); - const getResult = await axiosInstance.get("/api/v2/IdentityDeletionProcess"); + const getResult = await axiosInstance.get("/api/core/v1/IdentityDeletionProcess"); expect(getResult.status).toBe(400); }); }); diff --git a/test/errors.test.ts b/test/errors.test.ts index 73532e97..f2236c1e 100644 --- a/test/errors.test.ts +++ b/test/errors.test.ts @@ -5,9 +5,17 @@ import { validateSchema, ValidationSchema } from "./lib/validation"; const launcher = new Launcher(); let axiosClient: AxiosInstance; +const onlyRelationshipsApiKey = `${launcher.apiKey}onlyRelationships`; +const scopelessApiKey = `${launcher.apiKey}scopeless`; beforeAll(async () => { - const baseUrl = await launcher.launchSimple(); + const apiKeys = { + allPermissions: { key: launcher.apiKey }, + onlyRelationships: { key: onlyRelationshipsApiKey, scopes: ["core:relationships"] }, + scopeLess: { key: scopelessApiKey, scopes: [] } + }; + + const baseUrl = await launcher.launchSimple(apiKeys); axiosClient = axios.create({ baseURL: baseUrl, validateStatus: (_) => true, @@ -19,25 +27,43 @@ afterAll(() => launcher.stop()); describe("Errors", () => { test("http error 401", async () => { - const response = await axiosClient.get("/api/v2/Files", { headers: { "X-API-KEY": "invalid" } }); + const response = await axiosClient.get("/api/core/v1/Files", { headers: { "X-API-KEY": "invalid" } }); expect(response.status).toBe(401); validateSchema(ValidationSchema.Error, response.data.error); }); + test.each(["/Monitoring/Version", "/Monitoring/Requests", "/Monitoring/Support", "/api/core/v1/Files"])( + "http error 403 on route '%s' with apiKey that can only access /api/core/v1/Relationships", + async (route: string) => { + const response = await axiosClient.get(route, { headers: { "X-API-KEY": onlyRelationshipsApiKey } }); + expect(response.status).toBe(403); + validateSchema(ValidationSchema.Error, response.data.error); + } + ); + + test.each(["/Monitoring/Version", "/Monitoring/Requests", "/Monitoring/Support", "/api/core/v1/Files"])( + "http error 403 on route '%s' with apiKey that can not access authorized routes", + async (route: string) => { + const response = await axiosClient.get(route, { headers: { "X-API-KEY": scopelessApiKey } }); + expect(response.status).toBe(403); + validateSchema(ValidationSchema.Error, response.data.error); + } + ); + test("http error 404", async () => { - const response = await axiosClient.get("/apii/v2/Files"); + const response = await axiosClient.get("/apii/core/v1/Files"); expect(response.status).toBe(404); validateSchema(ValidationSchema.Error, response.data.error); }); test("http error 405", async () => { - const response = await axiosClient.patch("/api/v2/Files", undefined); + const response = await axiosClient.patch("/api/core/v1/Files", undefined); expect(response.status).toBe(405); validateSchema(ValidationSchema.Error, response.data.error); }); test("http error 400", async () => { - const response = await axiosClient.post("/api/v2/Files/Own", undefined); + const response = await axiosClient.post("/api/core/v1/Files/Own", undefined); expect(response.status).toBe(400); expect(response.data.error.docs).toBe("https://enmeshed.eu/integrate/error-codes#error.runtime.validation.invalidPropertyValue"); validateSchema(ValidationSchema.Error, response.data.error); diff --git a/test/files.test.ts b/test/files.test.ts index 064338f4..5d3ca4fa 100644 --- a/test/files.test.ts +++ b/test/files.test.ts @@ -97,7 +97,7 @@ describe("File Upload", () => { test("cannot upload a file that is null", async () => { // Cannot use client1.files.uploadOwn because it cannot deal with null values - const _response = await (client1.files as any).httpClient.post("/api/v2/Files/Own", makeUploadRequest({ file: null as any })); + const _response = await (client1.files as any).httpClient.post("/api/core/v1/Files/Own", makeUploadRequest({ file: null as any })); const response = (client1.files as any).makeResult(_response); expect(response).toBeAnError("must have required property 'content'", "error.runtime.validation.invalidPropertyValue"); @@ -118,9 +118,9 @@ describe("File Upload", () => { }); test("can upload file with tags", async () => { - const response = await client1.files.uploadOwnFile(await makeUploadRequest({ tags: ["tag1", "tag2"] })); + const response = await client1.files.uploadOwnFile(await makeUploadRequest({ tags: ["x:tag1", "x:tag2"] })); expect(response).toBeSuccessful(); - expect(response.result.tags).toStrictEqual(["tag1", "tag2"]); + expect(response.result.tags).toStrictEqual(["x:tag1", "x:tag2"]); }); test("cannot upload a file with expiry date in the past", async () => { diff --git a/test/iqlquery.test.ts b/test/iqlquery.test.ts index 94922ab6..95ed3288 100644 --- a/test/iqlquery.test.ts +++ b/test/iqlquery.test.ts @@ -39,7 +39,7 @@ beforeAll(async () => { "@type": "GivenName", value: "ASecondGivenName" }, - tags: ["language:de", "content:edu.de.higher"] + tags: ["language:de", "x:content.edu.de.higher"] } ]; attributeIds = []; @@ -69,9 +69,9 @@ afterAll(() => launcher.stop()); test("Local IQL Query", async () => { const table = [ - { iqlQuery: "#content:edu.de.higher", matches: [1] }, - { iqlQuery: "#content:edu.de.higher || #language:en", matches: [0, 1] }, - { iqlQuery: "#content:edu.de.higher && ( #language:de || #language:en )", matches: [1] } + { iqlQuery: "#x:content.edu.de.higher", matches: [1] }, + { iqlQuery: "#x:content.edu.de.higher || #language:en", matches: [0, 1] }, + { iqlQuery: "#x:content.edu.de.higher && ( #language:de || #language:en )", matches: [1] } ]; for (const e of table) { @@ -86,8 +86,8 @@ test("Local IQL Query", async () => { test("Remote ReadAttributeRequest containing IQL Query", async () => { const table = [ - { iqlQuery: "#content:edu.de.higher", matches: 1 }, - { iqlQuery: "#content:edu.de.higher && ( #language:de || #language:en )", matches: 1 } + { iqlQuery: "#x:content.edu.de.higher", matches: 1 }, + { iqlQuery: "#x:content.edu.de.higher && ( #language:de || #language:en )", matches: 1 } ]; /* Create request on C2. */ @@ -136,8 +136,8 @@ test("Remote ReadAttributeRequest containing IQL Query", async () => { test("Remote ProposeAttributeRequest containing IQL Query with existing attribute response", async () => { const table = [ - { iqlQuery: "#content:edu.de.higher", matches: 1 }, - { iqlQuery: "#content:edu.de.higher && ( #language:de || #language:en )", matches: 1 } + { iqlQuery: "#x:content.edu.de.higher", matches: 1 }, + { iqlQuery: "#x:content.edu.de.higher && ( #language:de || #language:en )", matches: 1 } ]; /* Create request on C2. */ diff --git a/test/lib/Launcher.ts b/test/lib/Launcher.ts index 53df7add..1eedcb17 100644 --- a/test/lib/Launcher.ts +++ b/test/lib/Launcher.ts @@ -18,14 +18,16 @@ export type ConnectorClientWithMetadata = ConnectorClient & { /* eslint-enable @typescript-eslint/naming-convention */ }; +export type LauncherApiKeyDefinition = Record; + export class Launcher { private readonly _processes: { connector: ChildProcess; webhookServer: Server | undefined }[] = []; public readonly apiKey = "This_is_a_test_APIKEY_with_30_chars+"; - public async launchSimple(): Promise { + public async launchSimple(apiKeys?: LauncherApiKeyDefinition): Promise { const port = await getPort(); const accountName = await this.randomString(); - const { connector, webhookServer } = await this.spawnConnector(port, accountName); + const { connector, webhookServer } = await this.spawnConnector(port, accountName, undefined, apiKeys); this._processes.push({ connector, webhookServer @@ -56,7 +58,7 @@ export class Launcher { httpsAgent: debugging ? new https.Agent({ keepAlive: false }) : undefined, authenticator: new ApiKeyAuthenticator(this.apiKey) }) as ConnectorClientWithMetadata; - connectorClient["_metadata"] = { accountName: `acc-${accountName}` }; + connectorClient["_metadata"] = { accountName }; connectorClient._eventBus = new MockEventBus(); @@ -88,10 +90,11 @@ export class Launcher { return await Random.string(7, RandomCharacterRange.Alphabet); } - private async spawnConnector(port: number, accountName: string, eventBus?: MockEventBus) { + private async spawnConnector(port: number, accountName: string, eventBus?: MockEventBus, apiKeys: LauncherApiKeyDefinition = { test: { key: this.apiKey } }) { const env = process.env; env["infrastructure:httpServer:port"] = port.toString(); - env["infrastructure:httpServer:apiKey"] = this.apiKey; + + for (const [key, value] of Object.entries(apiKeys)) env[`infrastructure:httpServer:authentication:apiKey:keys:${key}`] = JSON.stringify(value); const notDefinedEnvironmentVariables = ["NMSHD_TEST_BASEURL", "NMSHD_TEST_CLIENTID", "NMSHD_TEST_CLIENTSECRET"].filter((env) => !process.env[env]); if (notDefinedEnvironmentVariables.length > 0) { diff --git a/test/modules/cli/identity/identityStatus.test.ts b/test/modules/cli/identity/identityStatus.test.ts index 56a06f48..4e81dbe1 100644 --- a/test/modules/cli/identity/identityStatus.test.ts +++ b/test/modules/cli/identity/identityStatus.test.ts @@ -3,14 +3,15 @@ import { identityDeletionInitHandler, identityStatusHandler } from "../../../../ import { resetDB, setupEnvironment } from "../setup"; describe("Identity status", () => { + const randomAccountName = Math.random().toString(36).substring(2, 15); const identityStatusPattern = /Identity Address: did:e:((([A-Za-z0-9]+(-[A-Za-z0-9]+)*)\.)+[a-z]{2,}|localhost):dids:[0-9a-f]{22}/; beforeAll(() => { - setupEnvironment(); + setupEnvironment(randomAccountName); }); afterAll(async () => { - await resetDB(); + await resetDB(randomAccountName); }); afterEach(() => { @@ -31,7 +32,7 @@ describe("Identity status", () => { await identityStatusHandler({}); expect(consoleSpy).toHaveBeenCalledTimes(3); expect(consoleSpy.mock.lastCall![0]).toMatch(identityStatusPattern); - expect(consoleSpy.mock.lastCall![0]).toContain("Identity deletion status: Approved"); + expect(consoleSpy.mock.lastCall![0]).toContain("Identity deletion status: Active"); expect(consoleSpy.mock.lastCall![0]).toMatch(/End of grace period:/); }); }); diff --git a/test/modules/cli/identityDeletion/identityDeletion.test.ts b/test/modules/cli/identityDeletion/identityDeletion.test.ts index 5cc2fc99..a0b1c236 100644 --- a/test/modules/cli/identityDeletion/identityDeletion.test.ts +++ b/test/modules/cli/identityDeletion/identityDeletion.test.ts @@ -2,12 +2,14 @@ import { identityDeletionCancelHandler, identityDeletionInitHandler } from "../. import { resetDB, setupEnvironment } from "../setup"; describe("Identity deletion", () => { + const randomAccountName = Math.random().toString(36).substring(2, 15); + beforeAll(() => { - setupEnvironment(); + setupEnvironment(randomAccountName); }); afterAll(async () => { - await resetDB(); + await resetDB(randomAccountName); }); beforeEach(() => { diff --git a/test/modules/cli/setup.ts b/test/modules/cli/setup.ts index 39a2c5d2..2c361bd4 100644 --- a/test/modules/cli/setup.ts +++ b/test/modules/cli/setup.ts @@ -2,15 +2,14 @@ import { rm } from "fs/promises"; import { join } from "path"; import getPort from "../../lib/getPort"; -export function setupEnvironment(): void { +export function setupEnvironment(randomAccountName: string): void { process.env.database = JSON.stringify({ driver: "lokijs", folder: "./", - dbName: `default${process.pid}`, - dbNamePrefix: "test-" + dbName: `default${randomAccountName}` }); process.env.CUSTOM_CONFIG_LOCATION = ".dev/test.json"; - process.env.API_KEY = "test"; + process.env["infrastructure:httpServer:authentication:apiKey:keys:test:key"] = "test"; process.env["infrastructure:httpServer:port"] = getPort().toString(); process.env["transportLibrary:baseUrl"] = process.env["NMSHD_TEST_BASEURL"]; @@ -18,9 +17,9 @@ export function setupEnvironment(): void { process.env["transportLibrary:platformClientSecret"] = process.env["NMSHD_TEST_CLIENTSECRET"]; } -export async function resetDB(): Promise { +export async function resetDB(randomAccountName: string): Promise { try { - await rm(join(__dirname, `../../../test-default${process.pid}.db`)); + await rm(join(__dirname, `../../../default${randomAccountName}.db`)); } catch (_e) { // ignore } diff --git a/test/relationships.test.ts b/test/relationships.test.ts index c81489f7..24dd9d1d 100644 --- a/test/relationships.test.ts +++ b/test/relationships.test.ts @@ -69,7 +69,7 @@ describe("Relationships", () => { test("query relationships", async () => { await establishRelationship(client1, client2); const relationship = await getRelationship(client1); - const conditions = new QueryParamConditions(relationship, client1).addStringSet("peer").addStringSet("status").addStringSet("template.id"); + const conditions = new QueryParamConditions(relationship, client1).addStringSet("peer").addStringSet("status").addStringSet("templateId"); await conditions.executeTests((c, q) => c.relationships.getRelationships(q)); }); diff --git a/test/spec.test.ts b/test/spec.test.ts index 44323ebc..897e875e 100644 --- a/test/spec.test.ts +++ b/test/spec.test.ts @@ -56,15 +56,15 @@ describe.skip("test openapi spec against routes", () => { // Paths to ignore in regard to return code consistency (Post requests that return 200 due to no creation, deletes that return 204) /* eslint-disable @typescript-eslint/naming-convention */ const returnCodeOverwrite: Record | undefined> = { - "/api/v2/Account/Sync": { post: "204" }, - "/api/v2/Attributes/ExecuteIQLQuery": { post: "200" }, - "/api/v2/Attributes/ValidateIQLQuery": { post: "200" }, - "/api/v2/BackboneNotifications": { post: "204" }, - "/api/v2/Challenges/Validate": { post: "200" }, - "/api/v2/Relationships/{param}": { delete: "204" }, - "/api/v2/Attributes/{param}": { delete: "204" }, - "/api/v2/Files/{param}": { delete: "204" }, - "/api/v2/IdentityMetadata": { delete: "204" } + "/api/core/v1/Account/Sync": { post: "204" }, + "/api/core/v1/Attributes/ExecuteIQLQuery": { post: "200" }, + "/api/core/v1/Attributes/ValidateIQLQuery": { post: "200" }, + "/api/core/v1/BackboneNotifications": { post: "204" }, + "/api/core/v1/Challenges/Validate": { post: "200" }, + "/api/core/v1/Relationships/{param}": { delete: "204" }, + "/api/core/v1/Attributes/{param}": { delete: "204" }, + "/api/core/v1/Files/{param}": { delete: "204" }, + "/api/core/v1/IdentityMetadata": { delete: "204" } }; /* eslint-enable @typescript-eslint/naming-convention */ @@ -99,10 +99,10 @@ describe.skip("test openapi spec against routes", () => { test("all generated params should be in the manual spec", () => { const pathsWithDBQueries = [ - { path: "/api/v2/Attributes/Own/Shared/Identity", method: "get" }, - { path: "/api/v2/Attributes/Peer/Shared/Identity", method: "get" }, - { path: "/api/v2/Attributes/Own/Shared/Identity", method: "get" }, - { path: "/api/v2/Attributes/Own/Repository", method: "get" } + { path: "/api/core/v1/Attributes/Own/Shared/Identity", method: "get" }, + { path: "/api/core/v1/Attributes/Peer/Shared/Identity", method: "get" }, + { path: "/api/core/v1/Attributes/Own/Shared/Identity", method: "get" }, + { path: "/api/core/v1/Attributes/Own/Repository", method: "get" } ]; const generatedPaths = getPaths(generatedOpenApiSpec);