diff --git a/configmanager/server.js b/configmanager/server.js
index 712bb14..f3cd72b 100644
--- a/configmanager/server.js
+++ b/configmanager/server.js
@@ -281,7 +281,8 @@ app.get('/throttlelist', (req, res) => {
})
})
// Start the server
-app.listen(3000, () => {
+app.listen(3000, async () => {
+ console.log('Config manager started');
try {
if (!fs.existsSync('/data/cad-default.json')) fs.cpSync('/app/cad-default.json', '/data/cad-default.json');
if (!fs.existsSync('/data/config-default.json')) fs.cpSync('/app/config-default.json', '/data/config-default.json');
@@ -295,5 +296,15 @@ app.listen(3000, () => {
} catch(e) {
console.error(`Could not create blacklist files: ${e}`);
}
- console.log('Config manager started');
+ loop = 0
+ while (loop < 5) {
+ try {
+ await fetch("http://controlpanel-api:8050/configmanager/sync");
+ break;
+ } catch(e) {
+ loop++;
+ await new Promise(resolve => setTimeout(resolve, 5000)); // Wait for 5 seconds before retrying
+ }
+ }
+ if (loop == 5) console.log('Cannot connect to api')
});
diff --git a/controlpanel/api/routes/configmanager.js b/controlpanel/api/routes/configmanager.js
index 60db387..eb452e7 100644
--- a/controlpanel/api/routes/configmanager.js
+++ b/controlpanel/api/routes/configmanager.js
@@ -50,5 +50,15 @@ router.put('/config/:namespace/:application', async (req, res) => {
}
})
+router.get('/sync', async (req, res) => {
+ try {
+ const result = await configmanagerService.sendDataToConfigmanager();
+ return res.status(result.code).send(result);
+ } catch(e) {
+ console.error(e);
+ return res.status(500).send("Server error");
+ }
+})
+
module.exports = router;
\ No newline at end of file
diff --git a/controlpanel/api/server.js b/controlpanel/api/server.js
index 89ecbd3..4136a1c 100644
--- a/controlpanel/api/server.js
+++ b/controlpanel/api/server.js
@@ -3,6 +3,7 @@ const cors = require('cors');
require('dotenv').config({ path: __dirname + '/.env' });
const { CONFIGMANAGER_URL } = require('./util/variables');
const { CONTROLPANEL_URL } = require('./util/variables');
+const { sendDataToConfigmanager } = require('./services/configmanager');
const configmanager = require('./routes/configmanager');
const decoys = require('./routes/decoys');
@@ -39,6 +40,7 @@ app.listen(8050, async () => {
// CONFIGMANAGER URL
await fetch(CONFIGMANAGER_URL);
console.log("Successfully connected to configmanager !")
+ setInterval(async () => await sendDataToConfigmanager(), 60 * 60 * 1000)
} catch(e) {
console.error("Configmanager is not up, please (re)start configmanager");
}
diff --git a/controlpanel/api/services/configmanager.js b/controlpanel/api/services/configmanager.js
index c870345..f600d23 100644
--- a/controlpanel/api/services/configmanager.js
+++ b/controlpanel/api/services/configmanager.js
@@ -1,6 +1,9 @@
const { validateDecoyFilter } = require('../util/decoy-validator');
const { validateConfig } = require('../util/config-validator');
const { CONFIGMANAGER_URL } = require('../util/variables');
+const ProtectedApp = require('../models/ProtectedApp')
+const Config = require('../models/Config-data')
+const Decoy = require('../models/Decoy-data')
const axios = require('axios');
@@ -31,12 +34,13 @@ module.exports = {
* Update decoys list in configmanager
* @param {Object} decoys New list of decoys
*/
- updateDecoysList: async (namespace, application, decoys) => {
+ updateDecoysList: async (namespace, application, decoys) => {
try {
if (!namespace || !application) {
namespace = 'unknown';
application = 'unknown';
}
+ if (!decoys.length) return { type: 'warning', code: 200, message: "Decoys list is empty or full of inactive decoy, cannot sync" };
for (const decoy of decoys) {
if (validateDecoyFilter(decoy).length) return { type: 'error', code: 422, message: "There are errors in one of the decoys, cannot send to configmanager" }
}
@@ -103,4 +107,17 @@ module.exports = {
throw e;
}
},
+
+ sendDataToConfigmanager: async () => {
+ try {
+ const protectedApps = await ProtectedApp.findAll({ include: [{ model: Decoy, as: 'decoys', attributes: ['decoy', 'state'] }, { model: Config, as: 'configs', attributes: ['config'] }] })
+ for (const pa of protectedApps) {
+ module.exports.updateDecoysList(pa.namespace, pa.application, pa.decoys.map(decoyData => decoyData.state == 'active' && decoyData.decoy))
+ module.exports.updateConfig(pa.namespace, pa.application, pa.configs);
+ }
+ return { type: 'success', message: "Successful operation", code: 200 };
+ } catch(e) {
+ return { type: 'error', message: "Server error", data: e, code: 500 };
+ }
+ }
}
\ No newline at end of file
diff --git a/controlpanel/cad/src/app/pages/config/config.component.html b/controlpanel/cad/src/app/pages/config/config.component.html
index c99e8b8..b239f9f 100644
--- a/controlpanel/cad/src/app/pages/config/config.component.html
+++ b/controlpanel/cad/src/app/pages/config/config.component.html
@@ -116,6 +116,7 @@
Config 🔧
{{ config | json }}
+
\ No newline at end of file
diff --git a/controlpanel/cad/src/app/pages/config/config.component.ts b/controlpanel/cad/src/app/pages/config/config.component.ts
index be2dda6..7408941 100644
--- a/controlpanel/cad/src/app/pages/config/config.component.ts
+++ b/controlpanel/cad/src/app/pages/config/config.component.ts
@@ -12,6 +12,7 @@ import { ConfigService } from '../../services/config.service';
import { GlobalStateService } from '../../services/global-state.service';
import { ToastrService } from 'ngx-toastr';
import { isEmptyObject } from '../../utils';
+import { ConfigmanagerApiService } from '../../services/api/configmanager-api.service';
@Component({
selector: 'app-config',
@@ -61,7 +62,7 @@ onLeaveInfo() {
}
//#endregion
- constructor(private configService: ConfigService, private globalState: GlobalStateService, private toastr: ToastrService) {
+ constructor(private configService: ConfigService, private globalState: GlobalStateService, private toastr: ToastrService, private configmanagerApi: ConfigmanagerApiService) {
this.configForm = new FormGroup({
sessionIn: new FormControl(''),
sessionKey: new FormControl(''),
@@ -276,4 +277,10 @@ onLeaveInfo() {
if (apiResponse.type == 'error') this.toastr.error(apiResponse.message, "Error when saving global config");
else this.toastr.success(apiResponse.message, 'Successfully updated global config');
}
+ async sync() {
+ const saveResponse = await this.configmanagerApi.updateConfigmanagerConfig(this.globalState.selectedApp.namespace, this.globalState.selectedApp.application, this.config)
+ if (saveResponse.type == 'error') this.toastr.error(saveResponse.message, "Error Synchronizing");
+ else if (saveResponse.type == 'warning') this.toastr.warning(saveResponse.message, "Warning");
+ else this.toastr.success("Successfully synchronized with configmanager", "Synchronized");
+ }
}
diff --git a/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.html b/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.html
index 685671a..05f791b 100644
--- a/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.html
+++ b/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.html
@@ -64,6 +64,6 @@ Decoys list 🗒️
-
+
\ No newline at end of file
diff --git a/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.ts b/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.ts
index 1cecc1a..d42bacb 100644
--- a/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.ts
+++ b/controlpanel/cad/src/app/pages/list-decoy/list-decoy.component.ts
@@ -10,6 +10,7 @@ import { isProtectedAppEmpty } from '../../models/protected-app';
import { RouterLink } from '@angular/router';
import { UUID } from '../../models/types';
import { Subscription } from 'rxjs';
+import { ConfigmanagerApiService } from '../../services/api/configmanager-api.service';
@Component({
selector: 'app-list-decoy',
@@ -22,7 +23,7 @@ export class ListDecoyComponent implements OnInit, OnDestroy {
decoys: DecoyData[] = [];
globalStateSubscription?: Subscription;
- constructor(private decoyService: DecoyService, private toastr: ToastrService, private globalState: GlobalStateService) { }
+ constructor(private decoyService: DecoyService, private toastr: ToastrService, private globalState: GlobalStateService, private configmanagerApi: ConfigmanagerApiService) { }
async ngOnInit() {
this.globalStateSubscription = this.globalState.selectedApp$.subscribe(data => {
@@ -68,10 +69,11 @@ export class ListDecoyComponent implements OnInit, OnDestroy {
}
}
- // async save() {
- // if (!this.decoys.length) return;
- // const saveResponse = await this.decoyService.updateDecoysState(this.decoys);
- // if (saveResponse.type == 'error') this.toastr.error(saveResponse.message, "Error saving");
- // else this.toastr.success("Successfully saved decoys states", "Saved");
- // }
+ async save() {
+ if (!this.decoys.length) return;
+ const saveResponse = await this.configmanagerApi.updateConfigmanagerDecoys(this.globalState.selectedApp.namespace, this.globalState.selectedApp.application, this.decoys.filter(decoyData => decoyData.state == 'active').map(decoyData => decoyData.decoy))
+ if (saveResponse.type == 'error') this.toastr.error(saveResponse.message, "Error Synchronizing");
+ else if (saveResponse.type == 'warning') this.toastr.warning(saveResponse.message, "Warning");
+ else this.toastr.success("Successfully synchronized with configmanager", "Synchronized");
+ }
}
diff --git a/controlpanel/cad/src/app/services/api/configmanager-api.service.ts b/controlpanel/cad/src/app/services/api/configmanager-api.service.ts
new file mode 100644
index 0000000..a222439
--- /dev/null
+++ b/controlpanel/cad/src/app/services/api/configmanager-api.service.ts
@@ -0,0 +1,41 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { lastValueFrom } from 'rxjs';
+import { ApiResponse } from '../../models/api-response';
+import { GlobalStateService } from '../global-state.service';
+import { Decoy } from '../../models/decoy';
+import { Config } from '../../models/config';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ConfigmanagerApiService {
+
+ constructor(private http: HttpClient, private globalState: GlobalStateService) { }
+
+ async updateConfigmanagerDecoys(namespace: string, application: string, decoys: Decoy[]) {
+ try {
+ return await lastValueFrom(this.http.put(`${this.globalState.API_URL}/configmanager/decoys/${namespace}/${application}`, decoys));
+ } catch (e) {
+ console.error(e);
+ return { message: 'Cannot synchronize decoys with configmanager', type: 'error' };
+ }
+ }
+ async updateConfigmanagerConfig(namespace: string, application: string, config: Config) {
+ try {
+ return await lastValueFrom(this.http.put(`${this.globalState.API_URL}/configmanager/config/${namespace}/${application}`, config));
+ } catch (e) {
+ console.error(e);
+ return { message: 'Cannot synchronize config with configmanager', type: 'error' };
+ }
+ }
+ async getConfigmanagerDecoys(namespace: string, application: string) {
+ try {
+ return await lastValueFrom(this.http.get(`${this.globalState.API_URL}/configmanager/decoys/${namespace}/${application}`));
+ } catch (e) {
+ console.error(e);
+ return { message: 'Cannot synchronize config with configmanager', type: 'error' };
+ }
+ }
+
+}