diff --git a/package-lock.json b/package-lock.json index 86d4322..eed9f41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "pinia": "^2.0.13", "prismjs": "^1.29.0", "pug": "^3.0.2", + "uuid": "^13.0.0", "v-network-graph": "^0.9.8", "vite": "^2.8.4", "vue": "^3.2.31", @@ -97,6 +98,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", @@ -1883,6 +1885,7 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz", "integrity": "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==", "hasInstallScript": true, + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.2.0" }, @@ -2802,6 +2805,7 @@ "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3083,6 +3087,7 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.0.tgz", "integrity": "sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w==", "dev": true, + "peer": true, "dependencies": { "@jest/transform": "^28.1.0", "@types/babel__core": "^7.1.14", @@ -3666,6 +3671,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "peer": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", @@ -4073,6 +4079,38 @@ "esbuild-windows-arm64": "0.14.38" } }, + "node_modules/esbuild-android-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz", + "integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz", + "integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/esbuild-darwin-64": { "version": "0.14.38", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz", @@ -4088,6 +4126,278 @@ "node": ">=12" } }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz", + "integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz", + "integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz", + "integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz", + "integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz", + "integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz", + "integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz", + "integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz", + "integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz", + "integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz", + "integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz", + "integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz", + "integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz", + "integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz", + "integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz", + "integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz", + "integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz", + "integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -4133,6 +4443,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", "dev": true, + "peer": true, "dependencies": { "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", @@ -4778,6 +5089,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -4832,6 +5144,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", "dev": true, + "peer": true, "dependencies": { "@babel/runtime": "^7.16.3", "aria-query": "^4.2.2", @@ -4885,6 +5198,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.0.tgz", "integrity": "sha512-RgwH7hjW48BleKsYyHK5vUAvxtE9SMPDKmcPRQgtRCYaZA0XQPt5FSkrU3nhz5ifzMZcA8opwmRJ2cmOO8tr5A==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.5", "array.prototype.flatmap": "^1.3.0", @@ -4913,6 +5227,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz", "integrity": "sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw==", "dev": true, + "peer": true, "engines": { "node": ">=10" }, @@ -6263,6 +6578,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.0.tgz", "integrity": "sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==", "dev": true, + "peer": true, "dependencies": { "@jest/core": "^28.1.0", "import-local": "^3.0.2", @@ -9038,6 +9354,19 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/v-network-graph": { "version": "0.9.8", "resolved": "https://registry.npmjs.org/v-network-graph/-/v-network-graph-0.9.8.tgz", @@ -9081,6 +9410,7 @@ "version": "2.9.15", "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.15.tgz", "integrity": "sha512-fzMt2jK4vQ3yK56te3Kqpkaeq9DkcZfBbzHwYpobasvgYmP2SoAr6Aic05CsB4CzCZbsDv4sujX3pkEGhLabVQ==", + "peer": true, "dependencies": { "esbuild": "^0.14.27", "postcss": "^8.4.13", @@ -9125,6 +9455,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz", "integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.3.4", "@vue/compiler-sfc": "3.3.4", diff --git a/package.json b/package.json index 774542b..15b6b38 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "scripts": { "dev": "vite --host '0.0.0.0'", - "build": "node prebundle.js && vite build", + "build": "node prebundle.js && vite build", "preview": "vite preview --port 5050", "lint": "npx eslint \"./**\"", "lintfix": "npx eslint \"./**\" --fix", @@ -30,6 +30,7 @@ "pinia": "^2.0.13", "prismjs": "^1.29.0", "pug": "^3.0.2", + "uuid": "^13.0.0", "v-network-graph": "^0.9.8", "vite": "^2.8.4", "vue": "^3.2.31", diff --git a/prebundle.js b/prebundle.js index a5f6933..e155f37 100644 --- a/prebundle.js +++ b/prebundle.js @@ -1,17 +1,48 @@ const fs = require('fs-extra'); +const yaml = require('js-yaml'); -console.log('Copying all plugin GUI source files to magma'); +console.log('Copying plugin GUI source files to magma'); -if (fs.existsSync('./src/plugins/')) fs.removeSync('./src/plugins/'); +if (fs.existsSync('./src/plugins/')) { + fs.removeSync('./src/plugins/'); +} -const plugins = fs.readdirSync('../') -plugins.forEach((plugin) => { - // Check to see if gui directory exists +const requestedPlugins = process.argv.slice(2); + +let plugins = []; + +if (requestedPlugins.length > 0) { + // runtime targeted build + plugins = requestedPlugins; + console.log("Building selected plugins:", plugins.join(', ')); + +} else { + // server --build mode + try { + const conf = yaml.load( + fs.readFileSync('../../conf/default.yml', 'utf8') + ); + + plugins = conf.plugins || []; + console.log("Building enabled plugins from config:", plugins.join(', ')); + + } catch (e) { + // fallback for dev mode + plugins = fs.readdirSync('../'); + console.log("Building ALL plugins (fallback)"); + } +} + +plugins.forEach(plugin => { if (!fs.existsSync(`../${plugin}/gui`)) return; - // Copy contents of gui directory to src directory - console.log(`Copying over "${plugin}" files...`) - fs.copySync(`../${plugin}/gui/`, `./src/plugins/${plugin}`, { overwrite: true, recursive: true }) + console.log(`Copying "${plugin}" files...`); + + fs.copySync( + `../${plugin}/gui/`, + `./src/plugins/${plugin}`, + { overwrite: true, recursive: true } + ); }); console.log('Plugin GUI source files copied!'); diff --git a/src/App.vue b/src/App.vue index 40a2310..36f0376 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,34 +1,149 @@ + coreStore.getUserSettings(); +}); + +watch( + () => route.name, + async (name) => { + if (!$api) return; + if (name === "login") return; + if (!authStore.isUserAuthenticated) return; + + await coreStore.getAvailablePlugins($api); + await coreStore.getMainConfig($api); + await authStore.getGroup($api); + }, + { immediate: true } +); + +watch(restarting, (value) => { + if (!value) { + clearInterval(buildPollTimer); + clearInterval(healthPollTimer); + return; + } + + startBuildPolling(); +}); + +function startBuildPolling() { + clearInterval(buildPollTimer); + + buildPollTimer = setInterval(async () => { + try { + const res = await $api.get("/api/v2/plugins/build-status"); + const state = res.data; + + switch (state.status) { + case "installing": + restartMessage.value = + `Installing dependencies for ${state.plugin}…`; + break; + + case "building": + restartMessage.value = + `Building plugin interface for ${state.plugin}…`; + break; + + case "restarting": + restartMessage.value = "Restarting Caldera…"; + clearInterval(buildPollTimer); + startHealthPolling(); + break; + + default: + restartMessage.value = "Preparing plugin…"; + } + } catch { + // backend may be restarting + } + }, 1000); +} + +function startHealthPolling() { + clearInterval(healthPollTimer); + + healthPollTimer = setInterval(async () => { + try { + await $api.get("/api/v2/health", { + params: { t: Date.now() }, + validateStatus: () => true + }); + + clearInterval(healthPollTimer); + window.location.reload(); + } catch { + // still restarting + } + }, 2000); +} +onUnmounted(() => { + clearInterval(buildPollTimer); + clearInterval(healthPollTimer); +}); + diff --git a/src/components/abilities/CreateEditAbility.vue b/src/components/abilities/CreateEditAbility.vue index 3c69833..45d741e 100644 --- a/src/components/abilities/CreateEditAbility.vue +++ b/src/components/abilities/CreateEditAbility.vue @@ -1,293 +1,849 @@ + - + +/** Apply updates to an ability instance within the adversary store. */ +function onUpdateAbility(updatedAbility) { + adversaryStore.updateAbilityInstance(updatedAbility); + + // ✅ force new array ref so DetailsTable watcher fires + adversaryStore.selectedAdversaryAbilities = [ + ...adversaryStore.selectedAdversaryAbilities + ]; + + selectedAbility.value = cloneDeep(updatedAbility); +} + +function removeAbilityFromAdversary(stepUuid) { + selectedAdversaryAbilities.value = + selectedAdversaryAbilities.value.filter(a => a.step_uuid !== stepUuid); +} + + +// ──────────────────────────── +// Lifecycle +// ──────────────────────────── + +/** + * Load initial data (abilities, adversaries, agents) on mount. + */ +onMounted(async () => { + await Promise.all([ + abilityStore.getAbilities($api), + adversaryStore.getAdversaries($api), + agentStore.getAgents($api), + ]); +}); + + + diff --git a/src/views/AdversariesView.vue.bkp b/src/views/AdversariesView.vue.bkp new file mode 100644 index 0000000..0bfc5ad --- /dev/null +++ b/src/views/AdversariesView.vue.bkp @@ -0,0 +1,85 @@ + + + + + diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index 2c8a2c7..4e536b7 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -21,17 +21,28 @@ async function handleLogin(e) { #login.container.content.fullwh.is-flex.is-flex-direction-column.is-align-items-center.is-justify-content-center() img(src="/src/assets/img/caldera-logo.png" alt="Caldera Logo") .p-6 - form + form(@submit.prevent="handleLogin") .field label.label Username .control.has-icons-left - input.input(v-focus v-model="username" type="text" placeholder="username") + input.input( + v-focus + v-model="username" + type="text" + placeholder="username" + autocomplete="username" + ) span.icon.is-small.is-left font-awesome-icon(icon="fas fa-user") .field label.label Password .control.has-icons-left - input.input(v-model="password" type="password" placeholder="password") + input.input( + v-model="password" + type="password" + placeholder="password" + autocomplete="current-password" + ) span.icon.is-small.is-left font-awesome-icon(icon="fas fa-lock") button.button.fancy-button.is-fullwidth(type="submit" @click="handleLogin") Log In diff --git a/vite.config.js b/vite.config.js index 07aa352..8715e93 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,26 +1,54 @@ import { fileURLToPath, URL } from "url"; - -import { defineConfig } from "vite"; +import { defineConfig, loadEnv } from "vite"; import vue from "@vitejs/plugin-vue"; -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()], - server: { - fs: { - allow: ["../"], +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ""); + + // Backend Caldera server + const backend = env.VITE_BACKEND_URL || "http://localhost:8888"; + + return { + plugins: [vue()], + server: { + host: "0.0.0.0", + port: 3000, + fs: { + allow: ["../"], + }, + proxy: { + // 🔐 Auth + "/enter": { + target: backend, + changeOrigin: true, + }, + "/logout": { + target: backend, + changeOrigin: true, + }, + + // 🔌 Core API + "/api": { + target: backend, + changeOrigin: true, + }, + + // 🧩 Plugins + "/plugins": { + target: backend, + changeOrigin: true, + }, + }, + }, + build: { + rollupOptions: { + external: [/gui/], + }, }, - }, - build: { - rollupOptions: { - external: [ - /gui/ - ] - } - }, - resolve: { - alias: { - "@": fileURLToPath(new URL("./src", import.meta.url)) + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, }, - } + }; });