From 15dda2cc8f0c656f98591fbc7b58fb6e1eebedd5 Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Thu, 2 Jan 2025 13:38:58 +0100 Subject: [PATCH 1/9] BC-8621 call sync legacy indexes via rest --- .../schulcloud-server-init/tasks/main.yml | 21 +++++++++ .../templates/management-configmap.yml.j2 | 11 +++++ .../templates/management-deployment.yml.j2 | 2 + apps/server/src/apps/management.app.ts | 21 ++++++--- .../feathers/feathers-service.provider.ts | 4 +- .../database-management.controller.ts | 10 ++++- .../modules/management/management.module.ts | 2 + config/default.schema.json | 5 +++ src/services/index.js | 2 + src/services/sync-legacy-indexes/index.js | 43 +++++++++++++++++++ 10 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 ansible/roles/schulcloud-server-init/templates/management-configmap.yml.j2 create mode 100644 src/services/sync-legacy-indexes/index.js diff --git a/ansible/roles/schulcloud-server-init/tasks/main.yml b/ansible/roles/schulcloud-server-init/tasks/main.yml index 9051679e0c..c2dd43ad61 100644 --- a/ansible/roles/schulcloud-server-init/tasks/main.yml +++ b/ansible/roles/schulcloud-server-init/tasks/main.yml @@ -20,6 +20,27 @@ tags: - configmap + - name: Management Api Configmap File + kubernetes.core.k8s: + kubeconfig: ~/.kube/config + namespace: "{{ NAMESPACE }}" + template: management-configmap.yml.j2 + when: WITH_SCHULCLOUD_INIT + tags: + - configmap + + - name: Remove Management Api Configmap File + kubernetes.core.k8s: + kubeconfig: ~/.kube/config + namespace: "{{ NAMESPACE }}" + state: absent + api_version: v1 + kind: ConfigMap + name: api-management-configmap + when: not WITH_SCHULCLOUD_INIT + tags: + - configmap + - name: Management Deployment kubernetes.core.k8s: kubeconfig: ~/.kube/config diff --git a/ansible/roles/schulcloud-server-init/templates/management-configmap.yml.j2 b/ansible/roles/schulcloud-server-init/templates/management-configmap.yml.j2 new file mode 100644 index 0000000000..a044293953 --- /dev/null +++ b/ansible/roles/schulcloud-server-init/templates/management-configmap.yml.j2 @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: api-management-configmap + namespace: {{ NAMESPACE }} + labels: + app: management-deployment +data: + NEST_LOG_LEVEL: "{{ NEST_LOG_LEVEL }}" + EXIT_ON_ERROR: "true" + ENABLE_SYNC_LEGACY_INDEXES_VIA_FEATHERS_SERVICE: "true" diff --git a/ansible/roles/schulcloud-server-init/templates/management-deployment.yml.j2 b/ansible/roles/schulcloud-server-init/templates/management-deployment.yml.j2 index 3f02564879..2b66bfe55a 100644 --- a/ansible/roles/schulcloud-server-init/templates/management-deployment.yml.j2 +++ b/ansible/roles/schulcloud-server-init/templates/management-deployment.yml.j2 @@ -57,6 +57,8 @@ spec: envFrom: - configMapRef: name: api-configmap + - configMapRef: + name: api-management-configmap - secretRef: name: api-secret - secretRef: diff --git a/apps/server/src/apps/management.app.ts b/apps/server/src/apps/management.app.ts index 90af49a26a..04f0a2c59d 100644 --- a/apps/server/src/apps/management.app.ts +++ b/apps/server/src/apps/management.app.ts @@ -4,12 +4,11 @@ import { NestFactory } from '@nestjs/core'; import { ExpressAdapter } from '@nestjs/platform-express'; import express from 'express'; -// register source-map-support for debugging import { install as sourceMapInstall } from 'source-map-support'; - -// application imports import { LegacyLogger } from '@src/core/logger'; import { ManagementServerModule } from '@modules/management'; +import { MikroORM } from '@mikro-orm/core'; +import legacyAppPromise = require('../../../../src/app'); import { createRequestLoggerMiddleware } from './helpers/request-logger-middleware'; import { enableOpenApiDocs } from './helpers'; @@ -21,12 +20,24 @@ async function bootstrap() { const nestExpressAdapter = new ExpressAdapter(nestExpress); const nestApp = await NestFactory.create(ManagementServerModule, nestExpressAdapter); + const orm = nestApp.get(MikroORM); nestApp.use(createRequestLoggerMiddleware()); // WinstonLogger nestApp.useLogger(await nestApp.resolve(LegacyLogger)); + // load the legacy feathers/express server + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const feathersExpress = await legacyAppPromise(orm); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access + await feathersExpress.setup(); + + // set reference to legacy app as an express setting so we can + // access it over the current request within FeathersServiceProvider + // TODO remove if not needed anymore, needed for legacy indexes + nestExpress.set('feathersApp', feathersExpress); + // customize nest app settings nestApp.enableCors(); enableOpenApiDocs(nestApp, 'docs'); @@ -45,8 +56,8 @@ async function bootstrap() { console.log('#################################'); console.log(`### Start Management Server ###`); - console.log(`### Port: ${port} ###`); - console.log(`### Base path: ${basePath} ###`); + console.log(`### Port: ${port} ###`); + console.log(`### Base path: ${basePath} ###`); console.log('#################################'); } void bootstrap(); diff --git a/apps/server/src/infra/feathers/feathers-service.provider.ts b/apps/server/src/infra/feathers/feathers-service.provider.ts index 6efd72aad1..c8456623fc 100644 --- a/apps/server/src/infra/feathers/feathers-service.provider.ts +++ b/apps/server/src/infra/feathers/feathers-service.provider.ts @@ -8,13 +8,13 @@ export interface FeathersService { * * @param id * @param params - * @deprecated Access legacy eathers service get method + * @deprecated Access legacy feathers service get method */ get(id: string, params?: FeathersServiceParams): Promise; /** * * @param params - * @deprecated Access legacy eathers service find method + * @deprecated Access legacy feathers service find method */ find(params?: FeathersServiceParams): Promise; /** diff --git a/apps/server/src/modules/management/controller/database-management.controller.ts b/apps/server/src/modules/management/controller/database-management.controller.ts index 247fc6edc5..60ca9445d3 100644 --- a/apps/server/src/modules/management/controller/database-management.controller.ts +++ b/apps/server/src/modules/management/controller/database-management.controller.ts @@ -1,9 +1,13 @@ import { Controller, Param, Post, All, Query } from '@nestjs/common'; +import { FeathersServiceProvider } from '@infra/feathers'; import { DatabaseManagementUc } from '../uc/database-management.uc'; @Controller('management/database') export class DatabaseManagementController { - constructor(private databaseManagementUc: DatabaseManagementUc) {} + constructor( + private databaseManagementUc: DatabaseManagementUc, + private feathersServiceProvider: FeathersServiceProvider + ) {} @All('seed') async importCollections(@Query('with-indexes') withIndexes: boolean): Promise { @@ -30,7 +34,9 @@ export class DatabaseManagementController { } @Post('sync-indexes') - syncIndexes() { + async syncIndexes() { + // it is absolutely crucial to call the legacy stuff first, otherwise it will drop newly created indexes! + await this.feathersServiceProvider.getService('sync-legacy-indexes').create(); return this.databaseManagementUc.syncIndexes(); } } diff --git a/apps/server/src/modules/management/management.module.ts b/apps/server/src/modules/management/management.module.ts index caa49da568..e24bba8276 100644 --- a/apps/server/src/modules/management/management.module.ts +++ b/apps/server/src/modules/management/management.module.ts @@ -9,6 +9,7 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { createConfigModuleOptions } from '@src/config'; import { LoggerModule } from '@src/core/logger'; +import { FeathersModule } from '@infra/feathers'; import { DatabaseManagementConsole } from './console/database-management.console'; import { DatabaseManagementController } from './controller/database-management.controller'; import { BsonConverter } from './converter/bson.converter'; @@ -20,6 +21,7 @@ const baseImports = [ LoggerModule, ConfigModule.forRoot(createConfigModuleOptions(serverConfig)), EncryptionModule, + FeathersModule, ]; const imports = (Configuration.get('FEATURE_IDENTITY_MANAGEMENT_ENABLED') as boolean) diff --git a/config/default.schema.json b/config/default.schema.json index 196edcfc6b..4b9e52d1e3 100644 --- a/config/default.schema.json +++ b/config/default.schema.json @@ -1675,6 +1675,11 @@ "type": "boolean", "default": "false", "description": "Enables the external system logout feature" + }, + "ENABLE_SYNC_LEGACY_INDEXES_VIA_FEATHERS_SERVICE": { + "type": "boolean", + "default": "false", + "description": "if calling sync legacy indexes is allowed, only management module should have access to this, this should not exist in the long term when all entites and their indexes have been migrated" } }, "required": [] diff --git a/src/services/index.js b/src/services/index.js index 930ad5fde2..b1d4e84db8 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -46,6 +46,7 @@ const etherpad = require('./etherpad'); const storageProvider = require('./storageProvider'); const activation = require('./activation'); const config = require('./config'); +const syncLegacyIndexes = require('./sync-legacy-indexes'); const docs = require('./docs'); module.exports = function initializeServices() { @@ -99,6 +100,7 @@ module.exports = function initializeServices() { app.configure(etherpad); app.configure(storageProvider); app.configure(activation); + app.configure(syncLegacyIndexes); app.configure(config); // initialize events diff --git a/src/services/sync-legacy-indexes/index.js b/src/services/sync-legacy-indexes/index.js new file mode 100644 index 0000000000..5b936117f2 --- /dev/null +++ b/src/services/sync-legacy-indexes/index.js @@ -0,0 +1,43 @@ +const mongoose = require('mongoose'); +const { Configuration } = require('@hpi-schul-cloud/commons'); +const logger = require('../../logger'); + +const getModels = () => Object.entries(mongoose.models); + +class Service { + constructor(options) { + this.options = options || {}; + this.docs = {}; + } + + async create(data, params) { + if (Configuration.get('ENABLE_SYNC_LEGACY_INDEXES_VIA_FEATHERS_SERVICE')) { + const models = getModels(); + for (const [modelName, model] of models) { + logger.alert(`${modelName}.syncIndexes()`); + try { + // eslint-disable-next-line no-await-in-loop + await model.syncIndexes(); + } catch (err) { + logger.alert(err); + } + } + } else { + logger.alert( + 'sync-legacy-indexes has been called without enabling ENABLE_SYNC_LEGACY_INDEXES_VIA_FEATHERS_SERVICE' + ); + } + } + + setup(app) { + this.app = app; + } +} + +module.exports = function () { + const app = this; + + app.use('/sync-legacy-indexes', new Service()); +}; + +module.exports.Service = Service; From 2face7407a30f72ed4b43d7a409d2020bc3d045c Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Thu, 2 Jan 2025 13:39:37 +0100 Subject: [PATCH 2/9] cleanup --- .../templates/configmap_file_init.yml.j2 | 2 - package.json | 1 - scripts/syncIndexes.js | 48 ------------------- 3 files changed, 51 deletions(-) delete mode 100644 scripts/syncIndexes.js diff --git a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 index 0618bf1926..e8ae316161 100644 --- a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 +++ b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 @@ -611,5 +611,3 @@ data: fi # ========== End of TSP system creation - # Database indexes synchronization, it's crucial until we have all the entities in NestJS app. - npm run syncIndexes diff --git a/package.json b/package.json index 06a9cc0204..4dec643c59 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,6 @@ "nest:test:cov": "jest \"^((?!\\.load\\.spec\\.ts).)*\\.spec\\.ts$\" --coverage --force-exit --maxWorkers='50%'", "nest:test:debug": "jest --runInBand", "nest:lint": "eslint apps --ignore-path .gitignore", - "syncIndexes": "node ./scripts/syncIndexes.js", "ensureIndexes": "npm run nest:start:console -- database sync-indexes", "schoolExport": "node ./scripts/schoolExport.js", "schoolImport": "node ./scripts/schoolImport.js", diff --git a/scripts/syncIndexes.js b/scripts/syncIndexes.js deleted file mode 100644 index 1ff5b89ff5..0000000000 --- a/scripts/syncIndexes.js +++ /dev/null @@ -1,48 +0,0 @@ -/* eslint-disable no-underscore-dangle */ -/* eslint-disable no-console */ -const mongoose = require('mongoose'); -const util = require('util'); -const appPromise = require('../src/app'); - -const logger = require('../src/logger'); - -const getModels = () => Object.entries(mongoose.models); - -const extractIndexFromModel = ([modelName, model]) => [modelName, (model.schema || {})._indexes]; - -const formatToLog = (data) => util.inspect(data, { depth: 5, compact: true, breakLength: 120 }); - -const syncIndexes = async () => { - try { - logger.alert('load app...'); - await appPromise(); - logger.alert('start syncIndexes..'); - const models = getModels(); - for (const [modelName, model] of models) { - logger.alert(`${modelName}.syncIndexes()`); - try { - // eslint-disable-next-line no-await-in-loop - await model.syncIndexes(); - } catch (err) { - logger.alert(err); - } - } - - logger.alert('..syncIndex finished!'); - - try { - const indexes = models.map(extractIndexFromModel); - logger.alert(formatToLog(indexes)); - } catch (err) { - logger.alert(err); - } - - logger.alert('..script finished!'); - process.exit(0); - } catch (error) { - logger.error(error); - process.exit(1); - } -}; - -syncIndexes(); From c51833b4915ddbee1370e542a28f9bf955fb2441 Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Thu, 2 Jan 2025 14:03:46 +0100 Subject: [PATCH 3/9] futher cleanup --- .../templates/configmap_file_init.yml.j2 | 12 ------------ .../database-management.controller.spec.ts | 6 ++++++ .../modules/management/uc/database-management.uc.ts | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 index e8ae316161..65fe7cf891 100644 --- a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 +++ b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 @@ -13,18 +13,6 @@ data: cd /schulcloud-server git checkout {{ SCHULCLOUD_SERVER_IMAGE_TAG }} npm ci - until mongosh $DATABASE__URL --eval "print(\"waited for connection\")" - do - sleep 1 - done - mongosh $DATABASE__URL --eval 'rs.initiate({"_id" : "rs0", "members" : [{"_id" : 0, "host" : "localhost:27017"}]})' - sleep 3 - if [[ $(mongosh --quiet --eval "db.isMaster().setName") != rs0 ]] - then - echo "replicaset config failed :(" - else - echo "gg, hacky mongo replicaset" - fi echo "seeding database" curl --retry 360 --retry-all-errors --retry-delay 10 -X POST 'http://mgmt-svc:3333/api/management/database/seed?with-indexes=true' diff --git a/apps/server/src/modules/management/controller/database-management.controller.spec.ts b/apps/server/src/modules/management/controller/database-management.controller.spec.ts index e2461abd5c..cd30f50fb2 100644 --- a/apps/server/src/modules/management/controller/database-management.controller.spec.ts +++ b/apps/server/src/modules/management/controller/database-management.controller.spec.ts @@ -1,6 +1,8 @@ import { Test, TestingModule } from '@nestjs/testing'; +import { createMock } from '@golevelup/ts-jest'; import { DatabaseManagementUc } from '../uc/database-management.uc'; import { DatabaseManagementController } from './database-management.controller'; +import { FeathersServiceProvider } from '@infra/feathers'; describe('DatabaseManagementController', () => { let controller: DatabaseManagementController; @@ -26,6 +28,10 @@ describe('DatabaseManagementController', () => { }, }, }, + { + provide: FeathersServiceProvider, + useValue: createMock(), + }, ], }).compile(); diff --git a/apps/server/src/modules/management/uc/database-management.uc.ts b/apps/server/src/modules/management/uc/database-management.uc.ts index e9422066b6..917507b08d 100644 --- a/apps/server/src/modules/management/uc/database-management.uc.ts +++ b/apps/server/src/modules/management/uc/database-management.uc.ts @@ -44,7 +44,7 @@ export class DatabaseManagementUc { } /** - * absolute path reference for seed data base folder. + * absolute path reference for seed database folder. */ private get baseDir(): string { const folderPath = this.fileSystemAdapter.joinPath(__dirname, this.basePath); From 331e5bebb66df7e234739778fdfafe1ccc54ad6a Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Thu, 2 Jan 2025 14:48:59 +0100 Subject: [PATCH 4/9] fixed tests --- .../api-test/database-management.api.spec.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts b/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts index 6753f6a2b0..01851c664a 100644 --- a/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts +++ b/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts @@ -5,6 +5,8 @@ import { INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { createCollections } from '@shared/testing'; import request from 'supertest'; +import { FeathersServiceProvider } from '@infra/feathers'; +import { createMock } from '@golevelup/ts-jest'; describe('Database Management Controller (API)', () => { let app: INestApplication; @@ -14,7 +16,16 @@ describe('Database Management Controller (API)', () => { beforeAll(async () => { const module: TestingModule = await Test.createTestingModule({ imports: [ManagementServerTestModule], - }).compile(); + providers: [ + { + provide: FeathersServiceProvider, + useValue: createMock(), + }, + ], + }) + .overrideProvider(FeathersServiceProvider) + .useValue(createMock()) + .compile(); app = module.createNestApplication(); await app.init(); @@ -60,7 +71,7 @@ describe('Database Management Controller (API)', () => { expect(result.status).toEqual(201); }); - it('should export a collection to filesystem', async () => { + it('should create indexes', async () => { const result = await request(app.getHttpServer()).post(`/management/database/sync-indexes`); expect(result.status).toEqual(201); From 4645b7862faf72243260ea010c684f85f391b057 Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Thu, 2 Jan 2025 16:43:50 +0100 Subject: [PATCH 5/9] replace node.js scripts/secret.js in init script --- .../templates/configmap_file_init.yml.j2 | 120 ++++++------------ .../src/infra/encryption/encryption.module.ts | 4 +- .../encryption/encryption.service.spec.ts | 6 +- .../infra/encryption/encryption.service.ts | 2 +- .../mapper/identity-provider.mapper.spec.ts | 6 +- .../keycloak-configuration.service.spec.ts | 4 +- ...-identity-management-oauth.service.spec.ts | 4 +- .../services/authentication.service.spec.ts | 4 +- .../database-management.controller.ts | 9 +- .../management/controller/dto/encrypt.dto.ts | 13 ++ .../management/controller/dto/index.ts | 1 + .../uc/database-management.uc.spec.ts | 10 +- .../management/uc/database-management.uc.ts | 6 +- .../oauth/service/hydra.service.spec.ts | 4 +- .../oauth/service/oauth.service.spec.ts | 4 +- config/default.schema.json | 2 +- 16 files changed, 92 insertions(+), 107 deletions(-) create mode 100644 apps/server/src/modules/management/controller/dto/encrypt.dto.ts create mode 100644 apps/server/src/modules/management/controller/dto/index.ts diff --git a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 index 65fe7cf891..b98b565a4b 100644 --- a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 +++ b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 @@ -16,13 +16,43 @@ data: echo "seeding database" curl --retry 360 --retry-all-errors --retry-delay 10 -X POST 'http://mgmt-svc:3333/api/management/database/seed?with-indexes=true' + get_secret() { + local plainText="$1" + local url="http://mgmt-svc:3333/api/management/database/encrypt-plain-text" + + if [[ -z "$plainText" ]]; then + echo "Error: No plainText argument provided." + return 1 + fi + + # Use curl to capture both the response body and status code + local response + local http_code + response=$(curl -s -w "\n%{http_code}" -X POST "$url" \ + -H "Content-Type: text/plain" \ + --data "$plainText") + + # Split the response into body and status code + http_code=$(echo "$response" | tail -n 1) + response_body=$(echo "$response" | head -n -1) + + # Check if the response status code is 200 + if [[ "$http_code" -ne 200 ]]; then + echo "Error: Request failed with status code $http_code." + return 1 + fi + + # Return the response body (presumably the secret) + echo "$response_body" + return 0 + } # Below is a series of a MongoDB-data initializations, meant for the development and testing # purposes on various dev environments - most of them will only work there. # Test OIDC system configuration used in conjunction with OIDCMOCK deployment. - OIDCMOCK_CLIENT_SECRET=$(node scripts/secret.js -s $AES_KEY -e $OIDCMOCK__CLIENT_SECRET) + OIDCMOCK_CLIENT_SECRET=$(get_secret $OIDCMOCK__CLIENT_SECRET) # Test LDAP server (deployed in the sc-common namespace) configuration (stored in the 'systems' collection). - SEARCH_USER_PASSWORD=$(node scripts/secret.js -s $LDAP_PASSWORD_ENCRYPTION_KEY -e $SC_COMMON_LDAP_PASSWORD) + SEARCH_USER_PASSWORD=$(get_secret $SC_COMMON_LDAP_PASSWORD) mongosh $DATABASE__URL --quiet --eval 'db.systems.insertMany([ { "type" : "ldap", @@ -137,7 +167,7 @@ data: } );' # Sanis configuration (stored in the 'systems' collection + some related documents in other collections). - SANIS_CLIENT_SECRET=$(node scripts/secret.js -s $AES_KEY -e $SANIS_CLIENT_SECRET) + SANIS_CLIENT_SECRET=$(get_secret $SANIS_CLIENT_SECRET) SANIS_SYSTEM_ID=0000d186816abba584714c93 if [[ $SC_THEME == "n21" ]]; then mongosh $DATABASE__URL --quiet --eval 'db.schools.updateMany( @@ -211,8 +241,8 @@ data: ISERV_SYSTEM_ID=0000d186816abba584714c92 # Encrypt secrets that contain IServ's OAuth client secret and LDAP server's search user password. - ISERV_OAUTH_CLIENT_SECRET=$(node scripts/secret.js -s $AES_KEY -e $ISERV_OAUTH_CLIENT_SECRET) - ISERV_LDAP_SEARCH_USER_PASSWORD=$(node scripts/secret.js -s $AES_KEY -e $ISERV_LDAP_SEARCH_USER_PASSWORD) + ISERV_OAUTH_CLIENT_SECRET=$(get_secret $ISERV_OAUTH_CLIENT_SECRET) + ISERV_LDAP_SEARCH_USER_PASSWORD=$(get_secret $ISERV_LDAP_SEARCH_USER_PASSWORD) # Add (or replace) document with the Dev IServ configuration. mongosh $DATABASE__URL --quiet --eval 'db.systems.replaceOne( @@ -257,7 +287,7 @@ data: UNIVENTION_LDAP_FEDERAL_STATE_ID=0000b186816abba584714c53 # Encrypt LDAP server's search user password. - UNIVENTION_LDAP_SEARCH_USER_PASSWORD=$(node scripts/secret.js -s $AES_KEY -e $UNIVENTION_LDAP_SEARCH_USER_PASSWORD) + UNIVENTION_LDAP_SEARCH_USER_PASSWORD=$(get_secret $UNIVENTION_LDAP_SEARCH_USER_PASSWORD) # Add (or replace) document with the test BRB Univention LDAP system configuration. mongosh $DATABASE__URL --quiet --eval 'db.systems.replaceOne( @@ -317,40 +347,6 @@ data: # Perform the final Bettermarks config data init if client secret and URL has been properly set. if [ -n "$BETTERMARKS_CLIENT_SECRET" ] && [ -n "$BETTERMARKS_URL" ] && [ -n "$BETTERMARKS_REDIRECT_DOMAIN" ]; then - # Add document to the 'ltitools' collection with Bettermarks tool configuration. - mongosh $DATABASE__URL --quiet --eval 'db.getCollection("ltitools").replaceOne( - { - "name": "bettermarks", - "isTemplate": true - }, - { - "roles": [], - "privacy_permission": "anonymous", - "openNewTab": true, - "name": "bettermarks", - "url": "'$BETTERMARKS_URL'", - "key": null, - "secret": "'$BETTERMARKS_CLIENT_SECRET'", - "logo_url": "'$BETTERMARKS_LOGO_URL'", - "oAuthClientId": "'$BETTERMARKS_OAUTH_CLIENT_ID'", - "isLocal": true, - "resource_link_id": null, - "lti_version": null, - "lti_message_type": null, - "isTemplate": true, - "skipConsent": false, - "customs": [], - "createdAt": new Date(), - "updatedAt": new Date(), - "__v": 0, - "isHidden": false, - "frontchannel_logout_uri": null - }, - { - "upsert": true - } - );' - # The two steps below (Hydra call and MongoDB insert) were added to automate the actions performed inside # the server when Bettermarks' OAuth client configuration is added manually in SuperHero Dashboard. @@ -411,42 +407,6 @@ data: # This configures nextcloud in superhero dashboard as oauth2 tool and also in hydra if [ -n "$NEXTCLOUD_CLIENT_SECRET" ] && [ -n "$NEXTCLOUD_SOCIALLOGIN_OIDC_INTERNAL_NAME" ]; then - echo "Inserting nextcloud to ltitools..." - # Add document to the 'ltitools' collection - mongosh $DATABASE__URL --quiet --eval 'db.getCollection("ltitools").updateOne( - { - "name": "'$NEXTCLOUD_SOCIALLOGIN_OIDC_INTERNAL_NAME'", - "isTemplate": true - }, - { $setOnInsert: { - "roles": [], - "privacy_permission": "anonymous", - "openNewTab": true, - "name": "'$NEXTCLOUD_SOCIALLOGIN_OIDC_INTERNAL_NAME'", - "url": "'$NEXTCLOUD_BASE_URL'", - "key": null, - "secret": "'$NEXTCLOUD_CLIENT_SECRET'", - "logo_url": "", - "oAuthClientId": "'$NEXTCLOUD_CLIENT_ID'", - "isLocal": true, - "resource_link_id": null, - "lti_version": null, - "lti_message_type": null, - "isTemplate": true, - "skipConsent": true, - "customs": [], - "createdAt": new Date(), - "updatedAt": new Date(), - "__v": 0, - "isHidden": true, - "frontchannel_logout_uri": "'$NEXTCLOUD_BASE_URL'apps/schulcloud/logout" - } }, - { - "upsert": true - } - );' - echo "Inserted nextcloud to ltitools." - # Add Nextcloud client in hydra echo "POSTing nextcloud to hydra..." curl --retry 10 --retry-all-errors --retry-delay 10 \ @@ -509,7 +469,7 @@ data: if [ -n "$CTL_SEED_SECRET_ONLINE_DIA_MATHE" ]; then # Encrypt secrets of external tools that contain an lti11 config. - CTL_SEED_SECRET_ONLINE_DIA_MATHE=$(node scripts/secret.js -s $AES_KEY -e $CTL_SEED_SECRET_ONLINE_DIA_MATHE) + CTL_SEED_SECRET_ONLINE_DIA_MATHE=$(get_secret $CTL_SEED_SECRET_ONLINE_DIA_MATHE) mongosh $DATABASE__URL --quiet --eval 'db.getCollection("external-tools").updateOne( { "name": "Product Test Onlinediagnose Grundschule - Mathematik", @@ -524,7 +484,7 @@ data: fi if [ -n "$CTL_SEED_SECRET_ONLINE_DIA_DEUTSCH" ]; then # Encrypt secrets of external tools that contain an lti11 config. - CTL_SEED_SECRET_ONLINE_DIA_DEUTSCH=$(node scripts/secret.js -s $AES_KEY -e $CTL_SEED_SECRET_ONLINE_DIA_DEUTSCH) + CTL_SEED_SECRET_ONLINE_DIA_DEUTSCH=$(get_secret $CTL_SEED_SECRET_ONLINE_DIA_DEUTSCH) mongosh $DATABASE__URL --quiet --eval 'db.getCollection("external-tools").updateOne( { "name": "Product Test Onlinediagnose Grundschule - Deutsch", @@ -539,7 +499,7 @@ data: fi if [ -n "$CTL_SEED_SECRET_MERLIN" ]; then # Encrypt secrets of external tools that contain an lti11 config. - CTL_SEED_SECRET_MERLIN=$(node scripts/secret.js -s $AES_KEY -e $CTL_SEED_SECRET_MERLIN) + CTL_SEED_SECRET_MERLIN=$(get_secret $CTL_SEED_SECRET_MERLIN) mongosh $DATABASE__URL --quiet --eval 'db.getCollection("external-tools").updateOne( { "name": "Merlin Bibliothek", @@ -571,7 +531,7 @@ data: if [[ $SC_THEME == "thr" ]]; then echo "Adding TSP system to systems collection" - TSP_SYSTEM_OAUTH_CLIENT_SECRET=$(node scripts/secret.js -s $AES_KEY -e $TSP_SYSTEM_OAUTH_CLIENT_SECRET) + TSP_SYSTEM_OAUTH_CLIENT_SECRET=$(get_secret $TSP_SYSTEM_OAUTH_CLIENT_SECRET) mongosh $DATABASE__URL --quiet --eval 'db.systems.insertOne( { "_id": ObjectId("66d707f5c5202ba10c5e6256"), diff --git a/apps/server/src/infra/encryption/encryption.module.ts b/apps/server/src/infra/encryption/encryption.module.ts index 816b5b3b94..0b1c990ef7 100644 --- a/apps/server/src/infra/encryption/encryption.module.ts +++ b/apps/server/src/infra/encryption/encryption.module.ts @@ -2,11 +2,11 @@ import { Module } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { LegacyLogger, LoggerModule } from '@src/core/logger'; import { DefaultEncryptionService, LdapEncryptionService } from './encryption.interface'; -import { SymetricKeyEncryptionService } from './encryption.service'; +import { SymmetricKeyEncryptionService } from './encryption.service'; function encryptionProviderFactory(configService: ConfigService, logger: LegacyLogger, aesKey: string) { const key = configService.get(aesKey); - return new SymetricKeyEncryptionService(logger, key); + return new SymmetricKeyEncryptionService(logger, key); } @Module({ diff --git a/apps/server/src/infra/encryption/encryption.service.spec.ts b/apps/server/src/infra/encryption/encryption.service.spec.ts index b972ea50ba..3beb7033e3 100644 --- a/apps/server/src/infra/encryption/encryption.service.spec.ts +++ b/apps/server/src/infra/encryption/encryption.service.spec.ts @@ -1,12 +1,12 @@ import { createMock } from '@golevelup/ts-jest'; import { LegacyLogger } from '@src/core/logger'; -import { SymetricKeyEncryptionService } from './encryption.service'; +import { SymmetricKeyEncryptionService } from './encryption.service'; describe('SymetricKeyEncryptionService', () => { describe('with configure encryption key', () => { const encryptionKey = 'abcdefghijklmnop'; const logger = createMock(); - const encryptionService = new SymetricKeyEncryptionService(logger, encryptionKey); + const encryptionService = new SymmetricKeyEncryptionService(logger, encryptionKey); const testInput = 'testInput'; it('encrypts the input', () => { @@ -33,7 +33,7 @@ describe('SymetricKeyEncryptionService', () => { describe('without configured encryption key', () => { const logger = createMock(); - const encryptionService = new SymetricKeyEncryptionService(logger); + const encryptionService = new SymmetricKeyEncryptionService(logger); const testInput = 'testInput'; beforeEach(() => { diff --git a/apps/server/src/infra/encryption/encryption.service.ts b/apps/server/src/infra/encryption/encryption.service.ts index d23a739567..75619d9891 100644 --- a/apps/server/src/infra/encryption/encryption.service.ts +++ b/apps/server/src/infra/encryption/encryption.service.ts @@ -5,7 +5,7 @@ import { LegacyLogger } from '@src/core/logger'; import { EncryptionService } from './encryption.interface'; @Injectable() -export class SymetricKeyEncryptionService implements EncryptionService { +export class SymmetricKeyEncryptionService implements EncryptionService { constructor(private logger: LegacyLogger, private key?: string) { if (!this.key) { this.logger.warn('No AES key defined. Encryption will no work'); diff --git a/apps/server/src/infra/identity-management/keycloak-configuration/mapper/identity-provider.mapper.spec.ts b/apps/server/src/infra/identity-management/keycloak-configuration/mapper/identity-provider.mapper.spec.ts index cbf443d4d0..abd4b28145 100644 --- a/apps/server/src/infra/identity-management/keycloak-configuration/mapper/identity-provider.mapper.spec.ts +++ b/apps/server/src/infra/identity-management/keycloak-configuration/mapper/identity-provider.mapper.spec.ts @@ -1,5 +1,5 @@ import { createMock } from '@golevelup/ts-jest'; -import { DefaultEncryptionService, SymetricKeyEncryptionService } from '@infra/encryption'; +import { DefaultEncryptionService, SymmetricKeyEncryptionService } from '@infra/encryption'; import IdentityProviderRepresentation from '@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation'; import { OidcConfig } from '@modules/system/domain'; import { Test, TestingModule } from '@nestjs/testing'; @@ -8,7 +8,7 @@ import { OidcIdentityProviderMapper } from './identity-provider.mapper'; describe('OidcIdentityProviderMapper', () => { let module: TestingModule; let mapper: OidcIdentityProviderMapper; - let defaultEncryptionService: SymetricKeyEncryptionService; + let defaultEncryptionService: SymmetricKeyEncryptionService; afterAll(async () => { await module.close(); @@ -19,7 +19,7 @@ describe('OidcIdentityProviderMapper', () => { imports: [], providers: [ OidcIdentityProviderMapper, - { provide: DefaultEncryptionService, useValue: createMock() }, + { provide: DefaultEncryptionService, useValue: createMock() }, ], }).compile(); defaultEncryptionService = module.get(DefaultEncryptionService); diff --git a/apps/server/src/infra/identity-management/keycloak-configuration/service/keycloak-configuration.service.spec.ts b/apps/server/src/infra/identity-management/keycloak-configuration/service/keycloak-configuration.service.spec.ts index 3e18477c5c..c23c6b70b6 100644 --- a/apps/server/src/infra/identity-management/keycloak-configuration/service/keycloak-configuration.service.spec.ts +++ b/apps/server/src/infra/identity-management/keycloak-configuration/service/keycloak-configuration.service.spec.ts @@ -1,5 +1,5 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { SymetricKeyEncryptionService } from '@infra/encryption'; +import { SymmetricKeyEncryptionService } from '@infra/encryption'; import KeycloakAdminClient from '@keycloak/keycloak-admin-client-cjs/keycloak-admin-client-cjs-index'; import IdentityProviderRepresentation from '@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation'; import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; @@ -36,7 +36,7 @@ describe('KeycloakConfigurationService Unit', () => { const kcApiClientMock = createMock(); const kcApiAuthenticationManagementMock = createMock(); const kcApiRealmsMock = createMock(); - const encryptionServiceMock = createMock(); + const encryptionServiceMock = createMock(); const adminUsername = 'admin'; const adminUser: UserRepresentation = { diff --git a/apps/server/src/infra/identity-management/keycloak/service/keycloak-identity-management-oauth.service.spec.ts b/apps/server/src/infra/identity-management/keycloak/service/keycloak-identity-management-oauth.service.spec.ts index acd84025ad..471a791bb2 100644 --- a/apps/server/src/infra/identity-management/keycloak/service/keycloak-identity-management-oauth.service.spec.ts +++ b/apps/server/src/infra/identity-management/keycloak/service/keycloak-identity-management-oauth.service.spec.ts @@ -1,5 +1,5 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { DefaultEncryptionService, EncryptionService, SymetricKeyEncryptionService } from '@infra/encryption'; +import { DefaultEncryptionService, EncryptionService, SymmetricKeyEncryptionService } from '@infra/encryption'; import KeycloakAdminClient from '@keycloak/keycloak-admin-client'; import { HttpService } from '@nestjs/axios'; import { Test, TestingModule } from '@nestjs/testing'; @@ -14,7 +14,7 @@ describe('KeycloakIdentityManagementService', () => { let kcIdmOauthService: KeycloakIdentityManagementOauthService; let kcAdminServiceMock: DeepMocked; let httpServiceMock: DeepMocked; - let oAuthEncryptionService: DeepMocked; + let oAuthEncryptionService: DeepMocked; const clientId = 'TheClientId'; const clientSecret = 'TheClientSecret'; diff --git a/apps/server/src/modules/authentication/services/authentication.service.spec.ts b/apps/server/src/modules/authentication/services/authentication.service.spec.ts index 804e6b3051..35a015c7cd 100644 --- a/apps/server/src/modules/authentication/services/authentication.service.spec.ts +++ b/apps/server/src/modules/authentication/services/authentication.service.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { JwtPayloadFactory } from '@infra/auth-guard'; -import { DefaultEncryptionService, EncryptionService, SymetricKeyEncryptionService } from '@infra/encryption'; +import { DefaultEncryptionService, EncryptionService, SymmetricKeyEncryptionService } from '@infra/encryption'; import { Account, AccountService } from '@modules/account'; import { OauthConfig } from '@modules/system'; import { OauthSessionTokenService } from '@modules/oauth'; @@ -46,7 +46,7 @@ describe(AuthenticationService.name, () => { let configService: DeepMocked; let oauthSessionTokenService: DeepMocked; let httpService: DeepMocked; - let oauthEncryptionService: DeepMocked; + let oauthEncryptionService: DeepMocked; const mockAccount: Account = new Account({ id: 'mockAccountId', diff --git a/apps/server/src/modules/management/controller/database-management.controller.ts b/apps/server/src/modules/management/controller/database-management.controller.ts index 60ca9445d3..7215accde0 100644 --- a/apps/server/src/modules/management/controller/database-management.controller.ts +++ b/apps/server/src/modules/management/controller/database-management.controller.ts @@ -1,5 +1,6 @@ -import { Controller, Param, Post, All, Query } from '@nestjs/common'; +import { Controller, Param, Post, All, Query, Body, HttpCode } from '@nestjs/common'; import { FeathersServiceProvider } from '@infra/feathers'; +import { EncryptDto } from '@modules/management/controller/dto'; import { DatabaseManagementUc } from '../uc/database-management.uc'; @Controller('management/database') @@ -39,4 +40,10 @@ export class DatabaseManagementController { await this.feathersServiceProvider.getService('sync-legacy-indexes').create(); return this.databaseManagementUc.syncIndexes(); } + + @Post('encrypt-plain-text') + @HttpCode(200) + async encryptPlainText(@Body() encryptDto: EncryptDto) { + return this.databaseManagementUc.encryptPlainText(encryptDto.plainText); + } } diff --git a/apps/server/src/modules/management/controller/dto/encrypt.dto.ts b/apps/server/src/modules/management/controller/dto/encrypt.dto.ts new file mode 100644 index 0000000000..cb48a10282 --- /dev/null +++ b/apps/server/src/modules/management/controller/dto/encrypt.dto.ts @@ -0,0 +1,13 @@ +import { IsNotEmpty, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class EncryptDto { + @ApiProperty() + @IsNotEmpty() + @IsString() + public plainText: string; + + constructor(encryptDto: EncryptDto) { + this.plainText = encryptDto.plainText; + } +} diff --git a/apps/server/src/modules/management/controller/dto/index.ts b/apps/server/src/modules/management/controller/dto/index.ts new file mode 100644 index 0000000000..c558cba77a --- /dev/null +++ b/apps/server/src/modules/management/controller/dto/index.ts @@ -0,0 +1 @@ +export * from './encrypt.dto'; diff --git a/apps/server/src/modules/management/uc/database-management.uc.spec.ts b/apps/server/src/modules/management/uc/database-management.uc.spec.ts index 3c627a6ff7..13ba1d9b3b 100644 --- a/apps/server/src/modules/management/uc/database-management.uc.spec.ts +++ b/apps/server/src/modules/management/uc/database-management.uc.spec.ts @@ -1,7 +1,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Configuration } from '@hpi-schul-cloud/commons/lib'; import { DatabaseManagementService } from '@infra/database'; -import { DefaultEncryptionService, LdapEncryptionService, SymetricKeyEncryptionService } from '@infra/encryption'; +import { DefaultEncryptionService, LdapEncryptionService, SymmetricKeyEncryptionService } from '@infra/encryption'; import { FileSystemAdapter } from '@infra/file-system'; import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { SystemEntity } from '@modules/system/entity'; @@ -21,8 +21,8 @@ describe('DatabaseManagementService', () => { let dbService: DeepMocked; let configService: DeepMocked; let logger: DeepMocked; - let defaultEncryptionService: DeepMocked; - let ldapEncryptionService: DeepMocked; + let defaultEncryptionService: DeepMocked; + let ldapEncryptionService: DeepMocked; let bsonConverter: BsonConverter; const configGetSpy = jest.spyOn(Configuration, 'get'); const configHasSpy = jest.spyOn(Configuration, 'has'); @@ -173,11 +173,11 @@ describe('DatabaseManagementService', () => { providers: [ DatabaseManagementUc, BsonConverter, - { provide: DefaultEncryptionService, useValue: createMock() }, + { provide: DefaultEncryptionService, useValue: createMock() }, { provide: ConfigService, useValue: createMock() }, { provide: LegacyLogger, useValue: createMock() }, { provide: EntityManager, useValue: createMock() }, - { provide: LdapEncryptionService, useValue: createMock() }, + { provide: LdapEncryptionService, useValue: createMock() }, { provide: FileSystemAdapter, useValue: createMock({ diff --git a/apps/server/src/modules/management/uc/database-management.uc.ts b/apps/server/src/modules/management/uc/database-management.uc.ts index 917507b08d..cfe488aae3 100644 --- a/apps/server/src/modules/management/uc/database-management.uc.ts +++ b/apps/server/src/modules/management/uc/database-management.uc.ts @@ -374,7 +374,7 @@ export class DatabaseManagementUc { /** * Removes all known secrets (hard coded) from the export. * Manual replacement with the intend placeholders or value is mandatory. - * Currently this affects system and storageproviders collections. + * Currently, this affects system and storageproviders collections. */ private removeSecrets(collectionName: string, jsonDocuments: unknown[]) { if (collectionName === systemsCollectionName) { @@ -418,4 +418,8 @@ export class DatabaseManagementUc { public async migrationPending(): Promise { return this.databaseManagementService.migrationPending(); } + + public async encryptPlainText(plainText: string): Promise { + return this.defaultEncryptionService.encrypt(plainText); + } } diff --git a/apps/server/src/modules/oauth/service/hydra.service.spec.ts b/apps/server/src/modules/oauth/service/hydra.service.spec.ts index 450529bd1a..60a66e706b 100644 --- a/apps/server/src/modules/oauth/service/hydra.service.spec.ts +++ b/apps/server/src/modules/oauth/service/hydra.service.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Configuration } from '@hpi-schul-cloud/commons/lib'; -import { DefaultEncryptionService, SymetricKeyEncryptionService } from '@infra/encryption'; +import { DefaultEncryptionService, SymmetricKeyEncryptionService } from '@infra/encryption'; import { ObjectId } from '@mikro-orm/mongodb'; import { CookiesDto } from '@modules/oauth/service/dto/cookies.dto'; import { HydraRedirectDto } from '@modules/oauth/service/dto/hydra.redirect.dto'; @@ -92,7 +92,7 @@ describe('HydraService', () => { }, { provide: DefaultEncryptionService, - useValue: createMock(), + useValue: createMock(), }, { provide: LegacyLogger, diff --git a/apps/server/src/modules/oauth/service/oauth.service.spec.ts b/apps/server/src/modules/oauth/service/oauth.service.spec.ts index 1a1101c2dc..308a96a095 100644 --- a/apps/server/src/modules/oauth/service/oauth.service.spec.ts +++ b/apps/server/src/modules/oauth/service/oauth.service.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Configuration } from '@hpi-schul-cloud/commons'; -import { DefaultEncryptionService, EncryptionService, SymetricKeyEncryptionService } from '@infra/encryption'; +import { DefaultEncryptionService, EncryptionService, SymmetricKeyEncryptionService } from '@infra/encryption'; import { ObjectId } from '@mikro-orm/mongodb'; import { LegacySchoolService } from '@modules/legacy-school'; import { ProvisioningService } from '@modules/provisioning'; @@ -47,7 +47,7 @@ describe('OAuthService', () => { let module: TestingModule; let service: OAuthService; - let oAuthEncryptionService: DeepMocked; + let oAuthEncryptionService: DeepMocked; let provisioningService: DeepMocked; let userService: DeepMocked; let systemService: DeepMocked; diff --git a/config/default.schema.json b/config/default.schema.json index 4b9e52d1e3..af1954dba9 100644 --- a/config/default.schema.json +++ b/config/default.schema.json @@ -861,7 +861,7 @@ }, "AES_KEY": { "type": "string", - "description": "Symetric encryption key used to encrypt and decrypt secrets.", + "description": "Symmetric encryption key used to encrypt and decrypt secrets.", "pattern": ".{16}.*" }, "FEATURE_ETHERPAD_ENABLED": { From d43b9d01801a88d20b11bdc641ba07bfde599cc0 Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Thu, 2 Jan 2025 16:57:33 +0100 Subject: [PATCH 6/9] remove node and npm --- .../templates/configmap_file_init.yml.j2 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 index b98b565a4b..51f2a1f81a 100644 --- a/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 +++ b/ansible/roles/schulcloud-server-init/templates/configmap_file_init.yml.j2 @@ -8,11 +8,6 @@ metadata: data: update.sh: | #! /bin/bash - # necessary for secret handling and legacy indexes - git clone https://github.com/hpi-schul-cloud/schulcloud-server.git - cd /schulcloud-server - git checkout {{ SCHULCLOUD_SERVER_IMAGE_TAG }} - npm ci echo "seeding database" curl --retry 360 --retry-all-errors --retry-delay 10 -X POST 'http://mgmt-svc:3333/api/management/database/seed?with-indexes=true' From 277f50583bd54a28e92a1842d238f5b274f3639d Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Fri, 3 Jan 2025 10:17:19 +0100 Subject: [PATCH 7/9] linting --- .../controller/database-management.controller.spec.ts | 2 +- .../management/controller/database-management.controller.ts | 2 +- apps/server/src/modules/management/uc/database-management.uc.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/management/controller/database-management.controller.spec.ts b/apps/server/src/modules/management/controller/database-management.controller.spec.ts index cd30f50fb2..bf04549d46 100644 --- a/apps/server/src/modules/management/controller/database-management.controller.spec.ts +++ b/apps/server/src/modules/management/controller/database-management.controller.spec.ts @@ -1,8 +1,8 @@ import { Test, TestingModule } from '@nestjs/testing'; import { createMock } from '@golevelup/ts-jest'; +import { FeathersServiceProvider } from '@infra/feathers'; import { DatabaseManagementUc } from '../uc/database-management.uc'; import { DatabaseManagementController } from './database-management.controller'; -import { FeathersServiceProvider } from '@infra/feathers'; describe('DatabaseManagementController', () => { let controller: DatabaseManagementController; diff --git a/apps/server/src/modules/management/controller/database-management.controller.ts b/apps/server/src/modules/management/controller/database-management.controller.ts index 7215accde0..385c160694 100644 --- a/apps/server/src/modules/management/controller/database-management.controller.ts +++ b/apps/server/src/modules/management/controller/database-management.controller.ts @@ -43,7 +43,7 @@ export class DatabaseManagementController { @Post('encrypt-plain-text') @HttpCode(200) - async encryptPlainText(@Body() encryptDto: EncryptDto) { + encryptPlainText(@Body() encryptDto: EncryptDto) { return this.databaseManagementUc.encryptPlainText(encryptDto.plainText); } } diff --git a/apps/server/src/modules/management/uc/database-management.uc.ts b/apps/server/src/modules/management/uc/database-management.uc.ts index cfe488aae3..88b3bf78fa 100644 --- a/apps/server/src/modules/management/uc/database-management.uc.ts +++ b/apps/server/src/modules/management/uc/database-management.uc.ts @@ -419,7 +419,7 @@ export class DatabaseManagementUc { return this.databaseManagementService.migrationPending(); } - public async encryptPlainText(plainText: string): Promise { + public encryptPlainText(plainText: string): string { return this.defaultEncryptionService.encrypt(plainText); } } From ae1d4ac04d37133378f2eb9d73beeb1542839b80 Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Fri, 3 Jan 2025 11:09:25 +0100 Subject: [PATCH 8/9] test madness --- .../controller/api-test/database-management.api.spec.ts | 8 ++++++++ .../controller/database-management.controller.ts | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts b/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts index 01851c664a..728b22de1d 100644 --- a/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts +++ b/apps/server/src/modules/management/controller/api-test/database-management.api.spec.ts @@ -76,5 +76,13 @@ describe('Database Management Controller (API)', () => { expect(result.status).toEqual(201); }); + it('should encrypt plain text', async () => { + const result = await request(app.getHttpServer()) + .post(`/management/database/encrypt-plain-text`) + .send({ plainText: 'hallo uwe' }); + + expect(result.status).toEqual(200); + expect(result.text).not.toHaveLength(0); + }); }); }); diff --git a/apps/server/src/modules/management/controller/database-management.controller.ts b/apps/server/src/modules/management/controller/database-management.controller.ts index 385c160694..805b0cf932 100644 --- a/apps/server/src/modules/management/controller/database-management.controller.ts +++ b/apps/server/src/modules/management/controller/database-management.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Param, Post, All, Query, Body, HttpCode } from '@nestjs/common'; +import { Controller, Param, Post, All, Query, Body, HttpCode, Header } from '@nestjs/common'; import { FeathersServiceProvider } from '@infra/feathers'; import { EncryptDto } from '@modules/management/controller/dto'; import { DatabaseManagementUc } from '../uc/database-management.uc'; @@ -42,6 +42,7 @@ export class DatabaseManagementController { } @Post('encrypt-plain-text') + @Header('content-type', 'text/plain') @HttpCode(200) encryptPlainText(@Body() encryptDto: EncryptDto) { return this.databaseManagementUc.encryptPlainText(encryptDto.plainText); From 347e03a9bb07fd499e6d55be63b587f192bd30a9 Mon Sep 17 00:00:00 2001 From: Phillip Wirth Date: Fri, 3 Jan 2025 11:26:26 +0100 Subject: [PATCH 9/9] improved test coverage --- .../src/modules/management/controller/dto/encrypt.dto.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/server/src/modules/management/controller/dto/encrypt.dto.ts b/apps/server/src/modules/management/controller/dto/encrypt.dto.ts index cb48a10282..95eb35e0bb 100644 --- a/apps/server/src/modules/management/controller/dto/encrypt.dto.ts +++ b/apps/server/src/modules/management/controller/dto/encrypt.dto.ts @@ -5,9 +5,5 @@ export class EncryptDto { @ApiProperty() @IsNotEmpty() @IsString() - public plainText: string; - - constructor(encryptDto: EncryptDto) { - this.plainText = encryptDto.plainText; - } + public plainText!: string; }