From a362a0764533ec0a68bf1f586e0e5678de38e886 Mon Sep 17 00:00:00 2001 From: TheTrunk Date: Wed, 13 Dec 2023 16:26:17 +0700 Subject: [PATCH 01/20] my expired apps table --- HomeUI/src/services/AppsService.js | 3 + HomeUI/src/views/apps/GlobalApps.vue | 373 ++++++++++++++++++++++++++- 2 files changed, 375 insertions(+), 1 deletion(-) diff --git a/HomeUI/src/services/AppsService.js b/HomeUI/src/services/AppsService.js index 1869049e2..e882f9299 100644 --- a/HomeUI/src/services/AppsService.js +++ b/HomeUI/src/services/AppsService.js @@ -106,6 +106,9 @@ export default { globalAppSpecifications() { return Api().get('/apps/globalappsspecifications'); }, + permanentMessagesOwner(owner) { + return Api().get(`/apps/permanentmessages?owner=${owner}`); + }, getInstalledAppSpecifics(name) { return Api().get(`/apps/installedapps/${name}`); }, diff --git a/HomeUI/src/views/apps/GlobalApps.vue b/HomeUI/src/views/apps/GlobalApps.vue index 03e00a6d2..2fd7b13ad 100644 --- a/HomeUI/src/views/apps/GlobalApps.vue +++ b/HomeUI/src/views/apps/GlobalApps.vue @@ -340,7 +340,7 @@ - + + + + + + + + + + + + + + + + +
existingApp.appSpecifications.name === appMess.appSpecifications.name); + if (appExists) { + if (appMess.height > appExists.height) { + const index = adjustedPermMessages.findIndex((existingApp) => existingApp.appSpecifications.name === appMess.appSpecifications.name); + if (index > -1) { + adjustedPermMessages.splice(index, 1); + adjustedPermMessages.push(appMess); + } + } + } else { + adjustedPermMessages.push(appMess); + } + } + const expiredApps = []; + // eslint-disable-next-line no-restricted-syntax + for (const appMes of adjustedPermMessages) { + const appAlreadyDeployed = this.allApps.find((existingApp) => existingApp.name.toLowerCase() === appMes.appSpecifications.name.toLowerCase()); + if (!appAlreadyDeployed) { + const app = appMes.appSpecifications; + expiredApps.push(app); + } + } + this.tableconfig.my_expired.apps = expiredApps; + this.tableconfig.my_expired.loading = false; + } catch (error) { + console.log(error); + } + }, + redeployApp(appSpecs) { + console.log(appSpecs); }, openApp(name, _ip, _port) { console.log(name, _ip, _port); From 481f06db3a912d44f05a844638d613a9a97bc019 Mon Sep 17 00:00:00 2001 From: TheTrunk Date: Wed, 13 Dec 2023 16:50:14 +0700 Subject: [PATCH 02/20] continue to reg page --- HomeUI/src/router/routes/apps/apps.js | 2 +- HomeUI/src/views/apps/GlobalApps.vue | 2 +- HomeUI/src/views/apps/RegisterFluxApp.vue | 99 ++++++++++++----------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/HomeUI/src/router/routes/apps/apps.js b/HomeUI/src/router/routes/apps/apps.js index 511c5b247..a2463032d 100644 --- a/HomeUI/src/router/routes/apps/apps.js +++ b/HomeUI/src/router/routes/apps/apps.js @@ -36,7 +36,7 @@ export default [ }, }, { - path: '/apps/registerapp', + path: '/apps/registerapp/:appspecs?', name: 'apps-registerapp', component: () => import('@/views/apps/RegisterFluxApp.vue'), meta: { diff --git a/HomeUI/src/views/apps/GlobalApps.vue b/HomeUI/src/views/apps/GlobalApps.vue index 2fd7b13ad..6439c345a 100644 --- a/HomeUI/src/views/apps/GlobalApps.vue +++ b/HomeUI/src/views/apps/GlobalApps.vue @@ -1237,7 +1237,7 @@ export default { } }, redeployApp(appSpecs) { - console.log(appSpecs); + this.$router.replace({ name: 'apps-registerapp', params: { appspecs: appSpecs } }); }, openApp(name, _ip, _port) { console.log(name, _ip, _port); diff --git a/HomeUI/src/views/apps/RegisterFluxApp.vue b/HomeUI/src/views/apps/RegisterFluxApp.vue index 7a14cfd59..4b168f71e 100644 --- a/HomeUI/src/views/apps/RegisterFluxApp.vue +++ b/HomeUI/src/views/apps/RegisterFluxApp.vue @@ -2425,6 +2425,10 @@ export default { const zelidauth = localStorage.getItem('zelidauth'); const auth = qs.parse(zelidauth); this.appRegistrationSpecification.owner = auth.zelid; + console.log(this.$router.currentRoute.params.appspecs); + if (this.$router.currentRoute.params.appspecs) { + this.appRegistrationSpecification = this.$router.currentRoute.params.appspecs; // TODO this needs adjusting for UI + } }, methods: { onFilteredSelection(filteredItems) { @@ -2571,55 +2575,54 @@ export default { }, async getDaemonInfo() { - const daemonGetInfo = await DaemonService.getInfo(); - if (daemonGetInfo.data.status === 'error') { - this.showToast('danger', daemonGetInfo.data.data.message || daemonGetInfo.data.data); - } else { - this.currentHeight = daemonGetInfo.data.data.blocks; - } - if (this.currentHeight < 1004000) { // fork height for spec v4 - this.specificationVersion = 3; - this.appRegistrationSpecification = this.appRegistrationSpecificationV3Template; + // const daemonGetInfo = await DaemonService.getInfo(); + // if (daemonGetInfo.data.status === 'error') { + // this.showToast('danger', daemonGetInfo.data.data.message || daemonGetInfo.data.data); + // } else { + // this.currentHeight = daemonGetInfo.data.data.blocks; + // } + // if (this.currentHeight < 1004000) { // fork height for spec v4 + // this.specificationVersion = 3; + // this.appRegistrationSpecification = this.appRegistrationSpecificationV3Template; + // const ports = this.getRandomPort(); + // this.appRegistrationSpecification.ports = ports; + // } else if (this.currentHeight < 1142000) { + // this.specificationVersion = 4; + // this.appRegistrationSpecification = this.appRegistrationSpecificationV4Template; + // this.appRegistrationSpecification.compose.forEach((component) => { + // const ports = this.getRandomPort(); + // // eslint-disable-next-line no-param-reassign + // component.ports = ports; + // }); + // } else if (this.currentHeight < 1300000) { + // this.specificationVersion = 5; + // this.appRegistrationSpecification = this.appRegistrationSpecificationV5Template; + // this.appRegistrationSpecification.compose.forEach((component) => { + // const ports = this.getRandomPort(); + // // eslint-disable-next-line no-param-reassign + // component.ports = ports; + // }); + // } else if (this.currentHeight < 1420000) { + // this.specificationVersion = 6; + // this.appRegistrationSpecification = this.appRegistrationSpecificationV6Template; + // this.appRegistrationSpecification.compose.forEach((component) => { + // const ports = this.getRandomPort(); + // // eslint-disable-next-line no-param-reassign + // component.ports = ports; + // // eslint-disable-next-line no-param-reassign + // component.domains = '[""]'; + // }); + // } else { + this.specificationVersion = 7; + this.composeTemplate = this.composeTemplatev7; + this.appRegistrationSpecification = this.appRegistrationSpecificationV7Template; + this.appRegistrationSpecification.compose.forEach((component) => { const ports = this.getRandomPort(); - this.appRegistrationSpecification.ports = ports; - } else if (this.currentHeight < 1142000) { - this.specificationVersion = 4; - this.appRegistrationSpecification = this.appRegistrationSpecificationV4Template; - this.appRegistrationSpecification.compose.forEach((component) => { - const ports = this.getRandomPort(); - // eslint-disable-next-line no-param-reassign - component.ports = ports; - }); - } else if (this.currentHeight < 1300000) { - this.specificationVersion = 5; - this.appRegistrationSpecification = this.appRegistrationSpecificationV5Template; - this.appRegistrationSpecification.compose.forEach((component) => { - const ports = this.getRandomPort(); - // eslint-disable-next-line no-param-reassign - component.ports = ports; - }); - } else if (this.currentHeight < 1420000) { - this.specificationVersion = 6; - this.appRegistrationSpecification = this.appRegistrationSpecificationV6Template; - this.appRegistrationSpecification.compose.forEach((component) => { - const ports = this.getRandomPort(); - // eslint-disable-next-line no-param-reassign - component.ports = ports; - // eslint-disable-next-line no-param-reassign - component.domains = '[""]'; - }); - } else { - this.specificationVersion = 7; - this.composeTemplate = this.composeTemplatev7; - this.appRegistrationSpecification = this.appRegistrationSpecificationV7Template; - this.appRegistrationSpecification.compose.forEach((component) => { - const ports = this.getRandomPort(); - // eslint-disable-next-line no-param-reassign - component.ports = ports; - // eslint-disable-next-line no-param-reassign - component.domains = '[""]'; - }); - } + // eslint-disable-next-line no-param-reassign + component.ports = ports; + // eslint-disable-next-line no-param-reassign + component.domains = '[""]'; + }); const zelidauth = localStorage.getItem('zelidauth'); const auth = qs.parse(zelidauth); this.appRegistrationSpecification.owner = auth.zelid; From b8bc03a33a2435c85d6aa4887e17099fe1f93111 Mon Sep 17 00:00:00 2001 From: David White Date: Wed, 13 Dec 2023 13:37:47 +0000 Subject: [PATCH 03/20] Tidy entrypoints, make UPNP easier (#1173) * Streamline app start The current app.js and apiserver.js are essentially duplicates. This commit removes a lot of that duplication. Also simplifies the way UPnP is loaded, and retests UPnP on every config reload. * Use isUPnP variable instead of testing for userconfig each time * Fix typing for UPnPService * Remove UPnP duplication from serviceManager * Fix UPnP check to match current implementatio If apiPort is set and it's not 16127 - it's a UPnP node If apiPort is set and it's 16127 and routerIP is set - it's UPnP if apiPort is set and it's 16127 and no routerIP set - It's normal If no apiPort is set and no RouterIP is set - it's normal * Remove unneeded term for upnp check --------- Co-authored-by: Tadeas Kmenta --- ZelBack/src/services/appsService.js | 36 +++---- ZelBack/src/services/serviceManager.js | 18 +--- ZelBack/src/services/upnpService.js | 20 ++-- apiServer.js | 58 +++++++---- app.js | 133 ++++++------------------- package.json | 2 +- 6 files changed, 104 insertions(+), 163 deletions(-) diff --git a/ZelBack/src/services/appsService.js b/ZelBack/src/services/appsService.js index e92068bd1..e3f762735 100644 --- a/ZelBack/src/services/appsService.js +++ b/ZelBack/src/services/appsService.js @@ -2106,7 +2106,7 @@ async function appUninstallHard(appName, appId, appSpecifications, isComponent, } } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { // eslint-disable-next-line no-restricted-syntax for (const port of appSpecifications.ports) { // eslint-disable-next-line no-await-in-loop @@ -2120,7 +2120,7 @@ async function appUninstallHard(appName, appId, appSpecifications, isComponent, await fluxNetworkHelper.deleteAllowPortRule(serviceHelper.ensureNumber(appSpecifications.port)); } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { await upnpService.removeMapUpnpPort(serviceHelper.ensureNumber(appSpecifications.port), `Flux_App_${appName}`); } } @@ -2581,7 +2581,7 @@ async function appUninstallSoft(appName, appId, appSpecifications, isComponent, } } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { // eslint-disable-next-line no-restricted-syntax for (const port of appSpecifications.ports) { // eslint-disable-next-line no-await-in-loop @@ -2595,7 +2595,7 @@ async function appUninstallSoft(appName, appId, appSpecifications, isComponent, await fluxNetworkHelper.deleteAllowPortRule(serviceHelper.ensureNumber(appSpecifications.port)); } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { await upnpService.removeMapUpnpPort(serviceHelper.ensureNumber(appSpecifications.port), `Flux_App_${appName}`); } } @@ -3061,7 +3061,7 @@ async function installApplicationHard(appSpecifications, appName, isComponent, r log.info('Firewall not active, application ports are open'); } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { log.info('Custom port specified, mapping ports'); // eslint-disable-next-line no-restricted-syntax for (const port of appSpecifications.ports) { @@ -3100,7 +3100,7 @@ async function installApplicationHard(appSpecifications, appName, isComponent, r log.info('Firewall not active, application ports are open'); } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { log.info('Custom port specified, mapping ports'); const portResponse = await upnpService.mapUpnpPort(serviceHelper.ensureNumber(appSpecifications.port), `Flux_App_${appName}`); if (portResponse === true) { @@ -3468,7 +3468,7 @@ async function installApplicationSoft(appSpecifications, appName, isComponent, r log.info('Firewall not active, application ports are open'); } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { log.info('Custom port specified, mapping ports'); // eslint-disable-next-line no-restricted-syntax for (const port of appSpecifications.ports) { @@ -3507,7 +3507,7 @@ async function installApplicationSoft(appSpecifications, appName, isComponent, r log.info('Firewall not active, application ports are open'); } const isUPNP = upnpService.isUPNP(); - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { log.info('Custom port specified, mapping ports'); const portResponse = await upnpService.mapUpnpPort(serviceHelper.ensureNumber(appSpecifications.port), `Flux_App_${appName}`); if (portResponse === true) { @@ -5738,7 +5738,7 @@ async function restoreFluxPortsSupport() { } // UPNP - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { // map our Flux API, UI and SYNCTHING port await upnpService.setupUPNP(apiPort); } @@ -5769,7 +5769,7 @@ async function restoreAppsPortsSupport() { } // UPNP - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { // map application ports // eslint-disable-next-line no-restricted-syntax for (const application of currentAppsPorts) { @@ -10584,7 +10584,7 @@ async function checkMyAppsAvailability() { checkMyAppsAvailability(); return; } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { iBP = fluxNetworkHelper.isPortUPNPBanned(testingPort); if (iBP) { log.info(`checkMyAppsAvailability - Testing port ${testingPort} is UPNP banned.`); @@ -10617,7 +10617,7 @@ async function checkMyAppsAvailability() { if (firewallActive) { await fluxNetworkHelper.allowPort(testingPort); } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { const upnpMapResult = await upnpService.mapUpnpPort(testingPort, 'Flux_Test_App'); if (!upnpMapResult) { if (lastUPNPMapFailed) { @@ -10703,7 +10703,7 @@ async function checkMyAppsAvailability() { if (firewallActive) { await fluxNetworkHelper.deleteAllowPortRule(testingPort); } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { await upnpService.removeMapUpnpPort(testingPort, 'Flux_Test_App'); } @@ -10737,7 +10737,7 @@ async function checkMyAppsAvailability() { if (firewallActive) { await fluxNetworkHelper.deleteAllowPortRule(testingPort).catch((e) => log.error(e)); } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { await upnpService.removeMapUpnpPort(testingPort, 'Flux_Test_App').catch((e) => log.error(e)); } testingAppserver.shutdown((err) => { @@ -10776,7 +10776,7 @@ async function checkInstallingAppPortAvailable(portsToTest = []) { if (somePortBanned) { return false; } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { somePortBanned = false; portsToTest.forEach((portToTest) => { const iBP = fluxNetworkHelper.isPortUPNPBanned(portToTest); @@ -10796,7 +10796,7 @@ async function checkInstallingAppPortAvailable(portsToTest = []) { // eslint-disable-next-line no-await-in-loop await fluxNetworkHelper.allowPort(portToTest); } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { // eslint-disable-next-line no-await-in-loop const upnpMapResult = await upnpService.mapUpnpPort(portToTest, `Flux_Prelaunch_App_${portToTest}`); if (!upnpMapResult) { @@ -10869,7 +10869,7 @@ async function checkInstallingAppPortAvailable(portsToTest = []) { // eslint-disable-next-line no-await-in-loop await fluxNetworkHelper.deleteAllowPortRule(portToTest); } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { // eslint-disable-next-line no-await-in-loop await upnpService.removeMapUpnpPort(portToTest, `Flux_Prelaunch_App_${portToTest}`); } @@ -10895,7 +10895,7 @@ async function checkInstallingAppPortAvailable(portsToTest = []) { // eslint-disable-next-line no-await-in-loop await fluxNetworkHelper.deleteAllowPortRule(portToTest).catch((e) => log.error(e)); } - if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || isUPNP) { + if (isUPNP) { // eslint-disable-next-line no-await-in-loop await upnpService.removeMapUpnpPort(portToTest, `Flux_Prelaunch_App_${portToTest}`).catch((e) => log.error(e)); } diff --git a/ZelBack/src/services/serviceManager.js b/ZelBack/src/services/serviceManager.js index 934279c27..80b87fa18 100644 --- a/ZelBack/src/services/serviceManager.js +++ b/ZelBack/src/services/serviceManager.js @@ -27,24 +27,14 @@ async function startFluxFunctions() { log.error(`Flux port ${apiPort} is not supported. Shutting down.`); process.exit(); } - const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); - if (userconfig.initial.apiport && (userconfig.initial.apiport !== config.server.apiport || userconfig.initial.routerIP)) { - log.info('FluxOS is configured to run under UPNP'); - if (verifyUpnp !== true) { - log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to verify support. Shutting down.`); - process.exit(); - } - const setupUpnp = await upnpService.setupUPNP(apiPort); - if (setupUpnp !== true) { - log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to map to api or home port. Shutting down.`); - process.exit(); - } + + // User configured UPnP node, UPnP has already been verified and setup + if (userconfig.initial.apiport || userconfig.initial.routerIP) { setInterval(() => { upnpService.adjustFirewallForUPNP(); }, 2 * 60 * 60 * 1000); // every 2 hours - } else { - upnpService.setupUPNP(apiPort); } + fluxNetworkHelper.installNetcat(); log.info('Initiating MongoDB connection'); await dbHelper.initiateDB(); // either true or throws error diff --git a/ZelBack/src/services/upnpService.js b/ZelBack/src/services/upnpService.js index 83d9e0891..304cfd53a 100644 --- a/ZelBack/src/services/upnpService.js +++ b/ZelBack/src/services/upnpService.js @@ -24,7 +24,7 @@ function isUPNP() { /** * To check if a firewall is active. - * @returns {boolean} True if a firewall is active. Otherwise false. + * @returns {Promise} True if a firewall is active. Otherwise false. */ async function isFirewallActive() { try { @@ -74,7 +74,7 @@ async function adjustFirewallForUPNP() { /** * To verify that a port has UPnP (Universal Plug and Play) support. * @param {number} apiport Port number. - * @returns {boolean} True if port mappings can be set. Otherwise false. + * @returns {Promise} True if port mappings can be set. Otherwise false. */ async function verifyUPNPsupport(apiport = config.server.apiport) { try { @@ -134,7 +134,7 @@ async function verifyUPNPsupport(apiport = config.server.apiport) { /** * To set up UPnP (Universal Plug and Play) support. * @param {number} apiport Port number. - * @returns {boolean} True if port mappings can be set. Otherwise false. + * @returns {Promise} True if port mappings can be set. Otherwise false. */ async function setupUPNP(apiport = config.server.apiport) { try { @@ -173,7 +173,7 @@ async function setupUPNP(apiport = config.server.apiport) { * To create mappings for UPnP (Universal Plug and Play) port. * @param {number} port Port number. * @param {string} description Port description. - * @returns {boolean} True if port mappings can be created for both TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) protocols. Otherwise false. + * @returns {Promise} True if port mappings can be created for both TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) protocols. Otherwise false. */ async function mapUpnpPort(port, description) { try { @@ -201,7 +201,7 @@ async function mapUpnpPort(port, description) { /** * To remove TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) port mappings from UPnP (Universal Plug and Play) port. * @param {number} port Port number. - * @returns {boolean} True if port mappings have been removed for both TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) protocols. Otherwise false. + * @returns {Promise} True if port mappings have been removed for both TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) protocols. Otherwise false. */ async function removeMapUpnpPort(port) { try { @@ -223,7 +223,7 @@ async function removeMapUpnpPort(port) { /** * To map a specified port and show a message if successfully mapped. Only accessible by admins and Flux team members. * @param {object} req Request. - * @param {object} res Response. + * @param {Promise} res Response. */ async function mapPortApi(req, res) { try { @@ -269,7 +269,7 @@ async function mapPortApi(req, res) { /** * To unmap a specified port and show a message if successfully unmapped. Only accessible by admins and Flux team members. * @param {object} req Request. - * @param {object} res Response. + * @param {Promise} res Response. */ async function removeMapPortApi(req, res) { try { @@ -309,7 +309,7 @@ async function removeMapPortApi(req, res) { /** * To show a message with mappings. Only accessible by admins and Flux team members. * @param {object} req Request. - * @param {object} res Response. + * @param {Promise} res Response. */ async function getMapApi(req, res) { try { @@ -336,7 +336,7 @@ async function getMapApi(req, res) { /** * To show a message with IP address. Only accessible by admins and Flux team members. * @param {object} req Request. - * @param {object} res Response. + * @param {Promise} res Response. */ async function getIpApi(req, res) { try { @@ -363,7 +363,7 @@ async function getIpApi(req, res) { /** * To show a message with gateway address. Only accessible by admins and Flux team members. * @param {object} req Request. - * @param {object} res Response. + * @param {Promise} res Response. */ async function getGatewayApi(req, res) { try { diff --git a/apiServer.js b/apiServer.js index c0d0b6ee7..4c8df27f2 100644 --- a/apiServer.js +++ b/apiServer.js @@ -19,9 +19,33 @@ const { watch } = require('fs/promises'); const cmdAsync = util.promisify(nodecmd.get); const apiPort = userconfig.initial.apiport || config.server.apiport; -const apiPortHttps = apiPort + 1; +const apiPortHttps = +apiPort + 1; let initialHash = hash(fs.readFileSync(path.join(__dirname, '/config/userconfig.js'))); +async function loadUpnpIfRequired() { + // direct node (non UPnP) + if (userconfig.initial.apiport === config.server.apiport && !userconfig.initial.routerIP) { + return; + } + // User configured UPnP node + if (userconfig.initial.apiport) { + if (!userconfig.initial.routerIP) { + log.error(`Flux UPnP port and RouterIP must both be set if running UPnP. Apiport: ${userconfig.initial.apiport}, RouterIP: ${userconfig.initial.routerIP}. Shutting down.`); + process.exit(); + } + const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); + if (verifyUpnp !== true) { + log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to verify support. Shutting down.`); + process.exit(); + } + const setupUpnp = await upnpService.setupUPNP(apiPort); + if (setupUpnp !== true) { + log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to map to api or home port. Shutting down.`); + process.exit(); + } + } +} + async function configReload() { try { const watcher = watch(path.join(__dirname, '/config')); @@ -37,6 +61,7 @@ async function configReload() { delete require.cache[require.resolve('./config/userconfig')]; // eslint-disable-next-line userconfig = require('./config/userconfig'); + await loadUpnpIfRequired(); } } } catch (error) { @@ -44,27 +69,21 @@ async function configReload() { } } -setInterval(async () => { - configReload(); -}, 2 * 1000); - +/** + * + * @returns {Promise} + */ async function initiate() { if (!config.server.allowedPorts.includes(+apiPort)) { log.error(`Flux port ${apiPort} is not supported. Shutting down.`); process.exit(); } - if (userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) { - const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); - if (verifyUpnp !== true) { - log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to verify support. Shutting down.`); - process.exit(); - } - const setupUpnp = await upnpService.setupUPNP(apiPort); - if (setupUpnp !== true) { - log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to map to api or home port. Shutting down.`); - process.exit(); - } - } + + await loadUpnpIfRequired(); + + setInterval(async () => { + configReload(); + }, 2 * 1000); const server = app.listen(apiPort, () => { log.info(`Flux listening on port ${apiPort}!`); @@ -90,6 +109,9 @@ async function initiate() { } catch (error) { log.error(error); } + return apiPort; } -initiate(); +module.exports = { + initiate +} diff --git a/app.js b/app.js index ca9be80e8..2e35b8d7d 100644 --- a/app.js +++ b/app.js @@ -1,118 +1,47 @@ -/* global userconfig */ -global.userconfig = require('./config/userconfig'); - process.env.NODE_CONFIG_DIR = `${__dirname}/ZelBack/config/`; -// Flux configuration -const config = require('config'); -const compression = require('compression'); -const fs = require('fs'); -const https = require('https'); + +const { parseArgs } = require('node:util'); +const log = require('./ZelBack/src/lib/log'); const path = require('path'); -const util = require('util'); -const nodecmd = require('node-cmd'); +const compression = require('compression'); const express = require('express'); -const app = require('./ZelBack/src/lib/server'); -const log = require('./ZelBack/src/lib/log'); -const socket = require('./ZelBack/src/lib/socket'); -const serviceManager = require('./ZelBack/src/services/serviceManager'); -const upnpService = require('./ZelBack/src/services/upnpService'); -const hash = require('object-hash'); -const { watch } = require('fs/promises'); - -const cmdAsync = util.promisify(nodecmd.get); -const apiPort = userconfig.initial.apiport || config.server.apiport; -const homePort = +apiPort - 1; -const apiPortHttps = +apiPort + 1; -let initialHash = hash(fs.readFileSync(path.join(__dirname, '/config/userconfig.js'))); - -async function configReload() { - try { - const watcher = watch(path.join(__dirname, '/config')); - // eslint-disable-next-line - for await (const event of watcher) { - if (event.eventType === 'change' && event.filename === 'userconfig.js') { - const hashCurrent = hash(fs.readFileSync(path.join(__dirname, '/config/userconfig.js'))); - if (hashCurrent === initialHash) { - return; - } - initialHash = hashCurrent; - log.info(`Config file changed, reloading ${event.filename}...`); - delete require.cache[require.resolve('./config/userconfig')]; - // eslint-disable-next-line - userconfig = require('./config/userconfig'); - } +const apiServer = require('./apiServer'); + +const args = parseArgs({ + options: { + apiServer: { + type: "boolean", + short: "a", + default: false } - } catch (error) { - log.error(`Error watching files: ${error}`); } -} - -setInterval(async () => { - configReload(); -}, 2 * 1000); +}, process.argv.slice(2)); async function initiate() { - if (!config.server.allowedPorts.includes(+apiPort)) { - log.error(`Flux port ${apiPort} is not supported. Shutting down.`); - process.exit(); - } - if (userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) { - const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); - if (verifyUpnp !== true) { - log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to verify support. Shutting down.`); - process.exit(); - } - const setupUpnp = await upnpService.setupUPNP(apiPort); - if (setupUpnp !== true) { - log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to map to api or home port. Shutting down.`); - process.exit(); - } - } + const apiPort = await apiServer.initiate(); - const server = app.listen(apiPort, () => { - log.info(`Flux running on port ${apiPort}!`); - serviceManager.startFluxFunctions(); - }); + if (!args.values.apiServer) { + const homePort = +apiPort - 1; + // Flux Home configuration + const home = path.join(__dirname, './HomeUI/dist'); - socket.initIO(server); + const homeApp = express(); + homeApp.use(compression()); + homeApp.use(express.static(home)); - try { - const certExists = fs.existsSync(path.join(__dirname, './certs/v1.key')); - if (!certExists) { - const nodedpath = path.join(__dirname, './helpers'); - const exec = `cd ${nodedpath} && bash createSSLcert.sh`; - await cmdAsync(exec); - } - const key = fs.readFileSync(path.join(__dirname, './certs/v1.key'), 'utf8'); - const cert = fs.readFileSync(path.join(__dirname, './certs/v1.crt'), 'utf8'); - const credentials = { key, cert }; - const httpsServer = https.createServer(credentials, app); - httpsServer.listen(apiPortHttps, () => { - log.info(`Flux https listening on port ${apiPortHttps}!`); + homeApp.get('/robots.txt', (req, res) => { + res.type('text/plain'); + res.send('User-agent: *\nDisallow: /'); }); - } catch (error) { - log.error(error); - } - - // Flux Home configuration - const home = path.join(__dirname, './HomeUI/dist'); - const homeApp = express(); - homeApp.use(compression()); - homeApp.use(express.static(home)); - - homeApp.get('/robots.txt', (req, res) => { - res.type('text/plain'); - res.send('User-agent: *\nDisallow: /'); - }); - - homeApp.get('*', (req, res) => { - res.sendFile(path.join(home, 'index.html')); - }); + homeApp.get('*', (req, res) => { + res.sendFile(path.join(home, 'index.html')); + }); - homeApp.listen(homePort, () => { - log.info(`Flux Home running on port ${homePort}!`); - }); + homeApp.listen(homePort, () => { + log.info(`Flux Home running on port ${homePort}!`); + }); + } } initiate(); diff --git a/package.json b/package.json index cda0975c6..c0dcc20d2 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "homedev": "vue-cli-service serve --port 16126", "homeprod": "nodemon homeServer.js", "homebuild": "vue-cli-service build", - "fluxdev": "nodemon apiServer.js", + "fluxdev": "nodemon app.js --apiServer", "flux": "nodemon app.js", "start": "npm install --production && node init.js && npm run flux", "dev": "node init.js && concurrently \"npm run fluxdev\" \"npm run homedev\"", From 22c9af61ce6477bad157524da93525c5b534d3aa Mon Sep 17 00:00:00 2001 From: Cabecinha84 Date: Wed, 13 Dec 2023 13:42:28 +0000 Subject: [PATCH 04/20] adjust startup --- ZelBack/src/services/serviceManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ZelBack/src/services/serviceManager.js b/ZelBack/src/services/serviceManager.js index 80b87fa18..acc72ad82 100644 --- a/ZelBack/src/services/serviceManager.js +++ b/ZelBack/src/services/serviceManager.js @@ -29,10 +29,10 @@ async function startFluxFunctions() { } // User configured UPnP node, UPnP has already been verified and setup - if (userconfig.initial.apiport || userconfig.initial.routerIP) { + if (userconfig.initial.routerIP) { setInterval(() => { upnpService.adjustFirewallForUPNP(); - }, 2 * 60 * 60 * 1000); // every 2 hours + }, 1 * 60 * 60 * 1000); // every 1 hours } fluxNetworkHelper.installNetcat(); From 22d816acc866a4df9a75e97df4f00e5183159373 Mon Sep 17 00:00:00 2001 From: Cabecinha84 Date: Wed, 13 Dec 2023 13:44:19 +0000 Subject: [PATCH 05/20] adjust calling adjustFirewallForUPNP --- ZelBack/src/services/upnpService.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ZelBack/src/services/upnpService.js b/ZelBack/src/services/upnpService.js index 304cfd53a..5bf9d5665 100644 --- a/ZelBack/src/services/upnpService.js +++ b/ZelBack/src/services/upnpService.js @@ -78,7 +78,9 @@ async function adjustFirewallForUPNP() { */ async function verifyUPNPsupport(apiport = config.server.apiport) { try { - await adjustFirewallForUPNP(); + if (userconfig.initial.routerIP) { + await adjustFirewallForUPNP(); + } // run test on apiport + 1 await client.getPublicIp(); } catch (error) { From f489f52c1aefd086d081ffa4edf2a65083a246f3 Mon Sep 17 00:00:00 2001 From: Cabecinha84 Date: Wed, 13 Dec 2023 13:47:10 +0000 Subject: [PATCH 06/20] fix eslint and fix assumption that routerIP is mandatory for upnp --- apiServer.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apiServer.js b/apiServer.js index 4c8df27f2..def3a658c 100644 --- a/apiServer.js +++ b/apiServer.js @@ -29,10 +29,6 @@ async function loadUpnpIfRequired() { } // User configured UPnP node if (userconfig.initial.apiport) { - if (!userconfig.initial.routerIP) { - log.error(`Flux UPnP port and RouterIP must both be set if running UPnP. Apiport: ${userconfig.initial.apiport}, RouterIP: ${userconfig.initial.routerIP}. Shutting down.`); - process.exit(); - } const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); if (verifyUpnp !== true) { log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to verify support. Shutting down.`); @@ -113,5 +109,5 @@ async function initiate() { } module.exports = { - initiate -} + initiate, +}; From 7e13cedd5c1c2611e58422f295c3b4bd46116278 Mon Sep 17 00:00:00 2001 From: Cabecinha84 Date: Wed, 13 Dec 2023 13:58:22 +0000 Subject: [PATCH 07/20] fix to make it compatible with first versions of UPNP support --- apiServer.js | 3 +++ homeServer.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apiServer.js b/apiServer.js index def3a658c..880faa780 100644 --- a/apiServer.js +++ b/apiServer.js @@ -24,6 +24,9 @@ let initialHash = hash(fs.readFileSync(path.join(__dirname, '/config/userconfig. async function loadUpnpIfRequired() { // direct node (non UPnP) + if (userconfig.initial.apiport) { + await upnpService.setupUPNP(apiPort); + } if (userconfig.initial.apiport === config.server.apiport && !userconfig.initial.routerIP) { return; } diff --git a/homeServer.js b/homeServer.js index a1a40e875..c595d5d60 100644 --- a/homeServer.js +++ b/homeServer.js @@ -32,6 +32,9 @@ async function initiate() { log.error(`Flux port ${apiPort} is not supported. Shutting down.`); process.exit(); } + if (userconfig.initial.apiport) { + await upnpService.setupUPNP(apiPort); + } if (userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) { const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); if (verifyUpnp !== true) { From 97826d53ae137e530b28a75e52befaa6e5b47219 Mon Sep 17 00:00:00 2001 From: Cabecinha84 Date: Wed, 13 Dec 2023 14:05:57 +0000 Subject: [PATCH 08/20] fix app.js --- app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app.js b/app.js index 2e35b8d7d..d69e0d0ce 100644 --- a/app.js +++ b/app.js @@ -10,11 +10,11 @@ const apiServer = require('./apiServer'); const args = parseArgs({ options: { apiServer: { - type: "boolean", - short: "a", - default: false - } - } + type: 'boolean', + short: 'a', + default: false, + }, + }, }, process.argv.slice(2)); async function initiate() { From a60b305b216aad362886b18a9c041a7967cf31f1 Mon Sep 17 00:00:00 2001 From: Cabecinha84 Date: Wed, 13 Dec 2023 14:21:10 +0000 Subject: [PATCH 09/20] fix --- app.js | 54 +++++++++++++++++++--------------------------------- package.json | 2 +- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/app.js b/app.js index d69e0d0ce..bcb9ca0eb 100644 --- a/app.js +++ b/app.js @@ -1,47 +1,33 @@ process.env.NODE_CONFIG_DIR = `${__dirname}/ZelBack/config/`; -const { parseArgs } = require('node:util'); const log = require('./ZelBack/src/lib/log'); const path = require('path'); const compression = require('compression'); const express = require('express'); const apiServer = require('./apiServer'); -const args = parseArgs({ - options: { - apiServer: { - type: 'boolean', - short: 'a', - default: false, - }, - }, -}, process.argv.slice(2)); - async function initiate() { const apiPort = await apiServer.initiate(); - - if (!args.values.apiServer) { - const homePort = +apiPort - 1; - // Flux Home configuration - const home = path.join(__dirname, './HomeUI/dist'); - - const homeApp = express(); - homeApp.use(compression()); - homeApp.use(express.static(home)); - - homeApp.get('/robots.txt', (req, res) => { - res.type('text/plain'); - res.send('User-agent: *\nDisallow: /'); - }); - - homeApp.get('*', (req, res) => { - res.sendFile(path.join(home, 'index.html')); - }); - - homeApp.listen(homePort, () => { - log.info(`Flux Home running on port ${homePort}!`); - }); - } + const homePort = +apiPort - 1; + // Flux Home configuration + const home = path.join(__dirname, './HomeUI/dist'); + + const homeApp = express(); + homeApp.use(compression()); + homeApp.use(express.static(home)); + + homeApp.get('/robots.txt', (req, res) => { + res.type('text/plain'); + res.send('User-agent: *\nDisallow: /'); + }); + + homeApp.get('*', (req, res) => { + res.sendFile(path.join(home, 'index.html')); + }); + + homeApp.listen(homePort, () => { + log.info(`Flux Home running on port ${homePort}!`); + }); } initiate(); diff --git a/package.json b/package.json index c0dcc20d2..d0c949880 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "homedev": "vue-cli-service serve --port 16126", "homeprod": "nodemon homeServer.js", "homebuild": "vue-cli-service build", - "fluxdev": "nodemon app.js --apiServer", + "fluxdev": "nodemon app.js", "flux": "nodemon app.js", "start": "npm install --production && node init.js && npm run flux", "dev": "node init.js && concurrently \"npm run fluxdev\" \"npm run homedev\"", From d4a11c47413325e87659c5344113cddfd0019d08 Mon Sep 17 00:00:00 2001 From: Cabecinha84 Date: Wed, 13 Dec 2023 14:47:57 +0000 Subject: [PATCH 10/20] fix upnp check --- apiServer.js | 16 +++++++--------- homeServer.js | 11 +++++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apiServer.js b/apiServer.js index 880faa780..cbe9dc493 100644 --- a/apiServer.js +++ b/apiServer.js @@ -23,21 +23,19 @@ const apiPortHttps = +apiPort + 1; let initialHash = hash(fs.readFileSync(path.join(__dirname, '/config/userconfig.js'))); async function loadUpnpIfRequired() { - // direct node (non UPnP) + let verifyUpnp = false; + let setupUpnp = false; if (userconfig.initial.apiport) { - await upnpService.setupUPNP(apiPort); - } - if (userconfig.initial.apiport === config.server.apiport && !userconfig.initial.routerIP) { - return; + verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); + if (verifyUpnp) { + setupUpnp = await upnpService.setupUPNP(apiPort); + } } - // User configured UPnP node - if (userconfig.initial.apiport) { - const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); + if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || userconfig.initial.routerIP) { if (verifyUpnp !== true) { log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to verify support. Shutting down.`); process.exit(); } - const setupUpnp = await upnpService.setupUPNP(apiPort); if (setupUpnp !== true) { log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to map to api or home port. Shutting down.`); process.exit(); diff --git a/homeServer.js b/homeServer.js index c595d5d60..ce634707f 100644 --- a/homeServer.js +++ b/homeServer.js @@ -32,16 +32,19 @@ async function initiate() { log.error(`Flux port ${apiPort} is not supported. Shutting down.`); process.exit(); } + let verifyUpnp = false; + let setupUpnp = false; if (userconfig.initial.apiport) { - await upnpService.setupUPNP(apiPort); + verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); + if (verifyUpnp) { + setupUpnp = await upnpService.setupUPNP(apiPort); + } } - if (userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) { - const verifyUpnp = await upnpService.verifyUPNPsupport(apiPort); + if ((userconfig.initial.apiport && userconfig.initial.apiport !== config.server.apiport) || userconfig.initial.routerIP) { if (verifyUpnp !== true) { log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to verify support. Shutting down.`); process.exit(); } - const setupUpnp = await upnpService.setupUPNP(apiPort); if (setupUpnp !== true) { log.error(`Flux port ${userconfig.initial.apiport} specified but UPnP failed to map to api or home port. Shutting down.`); process.exit(); From f71d65fe8b6e9f4475d852908f325304e2dd3356 Mon Sep 17 00:00:00 2001 From: TheTrunk Date: Wed, 13 Dec 2023 22:05:05 +0700 Subject: [PATCH 11/20] finalise redeploy posibility --- HomeUI/src/views/apps/GlobalApps.vue | 2 +- HomeUI/src/views/apps/Management.vue | 7 +- HomeUI/src/views/apps/RegisterFluxApp.vue | 151 +++++++++++++++++++++- 3 files changed, 155 insertions(+), 5 deletions(-) diff --git a/HomeUI/src/views/apps/GlobalApps.vue b/HomeUI/src/views/apps/GlobalApps.vue index 6439c345a..b15630350 100644 --- a/HomeUI/src/views/apps/GlobalApps.vue +++ b/HomeUI/src/views/apps/GlobalApps.vue @@ -1237,7 +1237,7 @@ export default { } }, redeployApp(appSpecs) { - this.$router.replace({ name: 'apps-registerapp', params: { appspecs: appSpecs } }); + this.$router.replace({ name: 'apps-registerapp', params: { appspecs: JSON.stringify(appSpecs) } }); }, openApp(name, _ip, _port) { console.log(name, _ip, _port); diff --git a/HomeUI/src/views/apps/Management.vue b/HomeUI/src/views/apps/Management.vue index a570187b0..20bd6f18f 100644 --- a/HomeUI/src/views/apps/Management.vue +++ b/HomeUI/src/views/apps/Management.vue @@ -4828,8 +4828,13 @@ export default { this.appUpdateSpecification.geolocation = this.ensureString([]); if (this.appUpdateSpecification.version >= 5) { this.appUpdateSpecification.contacts = this.ensureString(specs.contacts || []); - this.decodeGeolocation(specs.geolocation || []); this.appUpdateSpecification.geolocation = this.ensureString(specs.geolocation || []); + try { + this.decodeGeolocation(specs.geolocation || []); + } catch (error) { + console.log(error); + this.appUpdateSpecification.geolocation = this.ensureString([]); + } } this.appUpdateSpecification.compose.forEach((component) => { // eslint-disable-next-line no-param-reassign diff --git a/HomeUI/src/views/apps/RegisterFluxApp.vue b/HomeUI/src/views/apps/RegisterFluxApp.vue index 4b168f71e..73f4038d7 100644 --- a/HomeUI/src/views/apps/RegisterFluxApp.vue +++ b/HomeUI/src/views/apps/RegisterFluxApp.vue @@ -1979,7 +1979,7 @@ export default { registrationHash: '', registrationtype: 'fluxappregister', currentHeight: 1350000, - specificationVersion: 6, + specificationVersion: 7, appRegistrationSpecification: {}, appRegistrationSpecificationV3Template: { version: 3, @@ -2413,7 +2413,7 @@ export default { }, }, beforeMount() { - this.appRegistrationSpecification = this.appRegistrationSpecificationV5Template; + this.appRegistrationSpecification = this.appRegistrationSpecificationV7Template; }, mounted() { this.getGeolocationData(); @@ -2427,7 +2427,95 @@ export default { this.appRegistrationSpecification.owner = auth.zelid; console.log(this.$router.currentRoute.params.appspecs); if (this.$router.currentRoute.params.appspecs) { - this.appRegistrationSpecification = this.$router.currentRoute.params.appspecs; // TODO this needs adjusting for UI + const specs = JSON.parse(this.$router.currentRoute.params.appspecs); + console.log(specs); + this.appRegistrationSpecification = JSON.parse(this.$router.currentRoute.params.appspecs); + + this.appRegistrationSpecification.instances = specs.instances || 3; + if (this.appRegistrationSpecification.version <= 3) { + this.appRegistrationSpecification.version = 3; // enforce specs version 3 + this.appRegistrationSpecification.ports = specs.port || this.ensureString(specs.ports); // v1 compatibility + this.appRegistrationSpecification.domains = this.ensureString(specs.domains); + this.appRegistrationSpecification.enviromentParameters = this.ensureString(specs.enviromentParameters); + this.appRegistrationSpecification.commands = this.ensureString(specs.commands); + this.appRegistrationSpecification.containerPorts = specs.containerPort || this.ensureString(specs.containerPorts); // v1 compatibility + } else { + if (this.appRegistrationSpecification.version <= 7) { + this.appRegistrationSpecification.version = 7; + } + this.appRegistrationSpecification.contacts = this.ensureString([]); + this.appRegistrationSpecification.geolocation = this.ensureString([]); + if (this.appRegistrationSpecification.version >= 5) { + this.appRegistrationSpecification.contacts = this.ensureString(specs.contacts || []); + this.appRegistrationSpecification.geolocation = this.ensureString(specs.geolocation || []); + try { + this.decodeGeolocation(specs.geolocation || []); + } catch (error) { + console.log(error); + this.appRegistrationSpecification.geolocation = this.ensureString([]); + } + } + this.appRegistrationSpecification.compose.forEach((component) => { + // eslint-disable-next-line no-param-reassign + component.ports = this.ensureString(component.ports); + // eslint-disable-next-line no-param-reassign + component.domains = this.ensureString(component.domains); + // eslint-disable-next-line no-param-reassign + component.environmentParameters = this.ensureString(component.environmentParameters); + // eslint-disable-next-line no-param-reassign + component.commands = this.ensureString(component.commands); + // eslint-disable-next-line no-param-reassign + component.containerPorts = this.ensureString(component.containerPorts); + // eslint-disable-next-line no-param-reassign + component.secrets = this.ensureString(component.secrets || ''); + // eslint-disable-next-line no-param-reassign + component.repoauth = this.ensureString(component.repoauth || ''); + }); + if (this.appRegistrationSpecification.version >= 6) { + this.appRegistrationSpecification.expire = this.ensureNumber(specs.expire || 22000); + this.expirePosition = this.getExpirePosition(this.appRegistrationSpecification.expire); + } + if (this.appRegistrationSpecification.version >= 7) { + this.appRegistrationSpecification.staticip = this.appRegistrationSpecification.staticip ?? false; + this.appRegistrationSpecification.nodes = this.appRegistrationSpecification.nodes || []; + if (this.appRegistrationSpecification.nodes && this.appRegistrationSpecification.nodes.length) { + this.isPrivateApp = true; + } + // fetch information about enterprise nodes, pgp keys + this.appRegistrationSpecification.nodes.forEach(async (node) => { + if (!this.enterpriseNodes) { + await this.getEnterpriseNodes(); + } + // fetch pgp key + const keyExists = this.enterprisePublicKeys.find((key) => key.nodeip === node); + if (!keyExists) { + const pgpKey = await this.fetchEnterpriseKey(node); + if (pgpKey) { + const pair = { + nodeip: node.ip, + nodekey: pgpKey, + }; + const keyExistsB = this.enterprisePublicKeys.find((key) => key.nodeip === node); + if (!keyExistsB) { + this.enterprisePublicKeys.push(pair); + } + } + } + }); + this.selectedEnterpriseNodes = []; + this.appRegistrationSpecification.nodes.forEach((node) => { + // add to selected node list + if (this.enterpriseNodes) { + const nodeFound = this.enterpriseNodes.find((entNode) => entNode.ip === node || node === `${entNode.txhash}:${entNode.outidx}`); + if (nodeFound) { + this.selectedEnterpriseNodes.push(nodeFound); + } + } else { + this.showToast('danger', 'Failed to load Enterprise Node List'); + } + }); + } + } } }, methods: { @@ -2436,6 +2524,63 @@ export default { this.entNodesSelectTable.totalRows = filteredItems.length; this.entNodesSelectTable.currentPage = 1; }, + getExpirePosition(value) { + const position = this.expireOptions.findIndex((opt) => opt.value === value); + if (position || position === 0) { + return position; + } + return 2; + }, + decodeGeolocation(existingGeolocation) { + // decode geolocation and push it properly numberOfGeolocations, numberOfNegativeGeolocations + // selectedContinent1, selectedCountry1, selectedRegion1 + // existingGeolocation is an array that can contain older specs of a, b OR can contain new specs of ac (a!c); + console.log(existingGeolocation); + let isOldSpecs = false; + existingGeolocation.forEach((location) => { + if (location.startsWith('b')) { + isOldSpecs = true; + } + if (location.startsWith('a') && location.startsWith('ac') && location.startsWith('a!c')) { + isOldSpecs = true; + } + }); + let updatedNewSpecGeo = existingGeolocation; + if (isOldSpecs) { + const continentEncoded = existingGeolocation.find((location) => location.startsWith('a') && location.startsWith('ac') && location.startsWith('a!c')); + const countryEncoded = existingGeolocation.find((location) => location.startsWith('b')); + let newSpecLocation = `ac${continentEncoded.slice(1)}`; + if (countryEncoded) { + newSpecLocation += `_${countryEncoded.slice(1)}`; + } + updatedNewSpecGeo = [newSpecLocation]; + } + // updatedNewSpecGeo is now geolocation according to new specs + const allowedLocations = updatedNewSpecGeo.filter((locations) => locations.startsWith('ac')); + const forbiddenLocations = updatedNewSpecGeo.filter((locations) => locations.startsWith('a!c')); + for (let i = 1; i < allowedLocations.length + 1; i += 1) { + this.numberOfGeolocations = i; + const specifiedLocation = allowedLocations[i - 1].slice(2); + const locations = specifiedLocation.split('_'); + const continentCode = locations[0]; + const countryCode = locations[1]; + const regionName = locations[2]; + this.allowedGeolocations[`selectedContinent${i}`] = continentCode; + this.allowedGeolocations[`selectedCountry${i}`] = countryCode || 'ALL'; + this.allowedGeolocations[`selectedRegion${i}`] = regionName || 'ALL'; + } + for (let i = 1; i < forbiddenLocations.length + 1; i += 1) { + this.numberOfNegativeGeolocations = i; + const specifiedLocation = forbiddenLocations[i - 1].slice(3); + const locations = specifiedLocation.split('_'); + const continentCode = locations[0]; + const countryCode = locations[1]; + const regionName = locations[2]; + this.forbiddenGeolocations[`selectedContinent${i}`] = continentCode; + this.forbiddenGeolocations[`selectedCountry${i}`] = countryCode || 'NONE'; + this.forbiddenGeolocations[`selectedRegion${i}`] = regionName || 'NONE'; + } + }, async getFluxnodeStatus() { try { const fluxnodeStatus = await DaemonService.getFluxNodeStatus(); From 427108ea3fa0a918467237e7d42982587ec04b26 Mon Sep 17 00:00:00 2001 From: TheTrunk Date: Fri, 15 Dec 2023 15:25:22 +0700 Subject: [PATCH 12/20] add marketplace deployments tab --- HomeUI/src/views/apps/GlobalApps.vue | 355 +++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) diff --git a/HomeUI/src/views/apps/GlobalApps.vue b/HomeUI/src/views/apps/GlobalApps.vue index b15630350..c5e80b988 100644 --- a/HomeUI/src/views/apps/GlobalApps.vue +++ b/HomeUI/src/views/apps/GlobalApps.vue @@ -340,6 +340,342 @@ + + + + + + + + + + + + + + + { + if (app.name.length >= 14) { + const possibleDateString = app.name.substring(app.name.length - 13, app.name.length); + const possibleDate = Number(possibleDateString); + if (!Number.isNaN(possibleDate)) return true; + } + return false; + }); this.tableconfig.active.loading = false; this.loadPermanentMessages(); }, @@ -1202,6 +1556,7 @@ export default { const zelidauth = localStorage.getItem('zelidauth'); const auth = qs.parse(zelidauth); if (!auth.zelid) { + this.tableconfig.my_expired.loading = false; return; } const response = await AppsService.permanentMessagesOwner(auth.zelid); From 8b4865d1dc1baf7a2598bad554d5fad96ce721db Mon Sep 17 00:00:00 2001 From: TheTrunk Date: Fri, 15 Dec 2023 15:56:07 +0700 Subject: [PATCH 13/20] copy of specs, deploy myself button --- HomeUI/src/views/apps/GlobalApps.vue | 62 ++++++++++++++++++++++- HomeUI/src/views/apps/RegisterFluxApp.vue | 5 ++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/HomeUI/src/views/apps/GlobalApps.vue b/HomeUI/src/views/apps/GlobalApps.vue index c5e80b988..29d097337 100644 --- a/HomeUI/src/views/apps/GlobalApps.vue +++ b/HomeUI/src/views/apps/GlobalApps.vue @@ -39,6 +39,31 @@ @@ -1970,6 +1994,8 @@ export default { }, data() { return { + importAppSpecs: false, + importedSpecs: '', timeoptions, version: 1, websocket: null, @@ -2425,97 +2451,8 @@ export default { const zelidauth = localStorage.getItem('zelidauth'); const auth = qs.parse(zelidauth); this.appRegistrationSpecification.owner = auth.zelid; - console.log(this.$router.currentRoute.params.appspecs); if (this.$router.currentRoute.params.appspecs) { - const specs = JSON.parse(this.$router.currentRoute.params.appspecs); - console.log(specs); - this.appRegistrationSpecification = JSON.parse(this.$router.currentRoute.params.appspecs); - - this.appRegistrationSpecification.instances = specs.instances || 3; - if (this.appRegistrationSpecification.version <= 3) { - this.appRegistrationSpecification.version = 3; // enforce specs version 3 - this.appRegistrationSpecification.ports = specs.port || this.ensureString(specs.ports); // v1 compatibility - this.appRegistrationSpecification.domains = this.ensureString(specs.domains); - this.appRegistrationSpecification.enviromentParameters = this.ensureString(specs.enviromentParameters); - this.appRegistrationSpecification.commands = this.ensureString(specs.commands); - this.appRegistrationSpecification.containerPorts = specs.containerPort || this.ensureString(specs.containerPorts); // v1 compatibility - } else { - if (this.appRegistrationSpecification.version <= 7) { - this.appRegistrationSpecification.version = 7; - } - this.appRegistrationSpecification.contacts = this.ensureString([]); - this.appRegistrationSpecification.geolocation = this.ensureString([]); - if (this.appRegistrationSpecification.version >= 5) { - this.appRegistrationSpecification.contacts = this.ensureString(specs.contacts || []); - this.appRegistrationSpecification.geolocation = this.ensureString(specs.geolocation || []); - try { - this.decodeGeolocation(specs.geolocation || []); - } catch (error) { - console.log(error); - this.appRegistrationSpecification.geolocation = this.ensureString([]); - } - } - this.appRegistrationSpecification.compose.forEach((component) => { - // eslint-disable-next-line no-param-reassign - component.ports = this.ensureString(component.ports); - // eslint-disable-next-line no-param-reassign - component.domains = this.ensureString(component.domains); - // eslint-disable-next-line no-param-reassign - component.environmentParameters = this.ensureString(component.environmentParameters); - // eslint-disable-next-line no-param-reassign - component.commands = this.ensureString(component.commands); - // eslint-disable-next-line no-param-reassign - component.containerPorts = this.ensureString(component.containerPorts); - // eslint-disable-next-line no-param-reassign - component.secrets = this.ensureString(component.secrets || ''); - // eslint-disable-next-line no-param-reassign - component.repoauth = this.ensureString(component.repoauth || ''); - }); - if (this.appRegistrationSpecification.version >= 6) { - this.appRegistrationSpecification.expire = this.ensureNumber(specs.expire || 22000); - this.expirePosition = this.getExpirePosition(this.appRegistrationSpecification.expire); - } - if (this.appRegistrationSpecification.version >= 7) { - this.appRegistrationSpecification.staticip = this.appRegistrationSpecification.staticip ?? false; - this.appRegistrationSpecification.nodes = this.appRegistrationSpecification.nodes || []; - if (this.appRegistrationSpecification.nodes && this.appRegistrationSpecification.nodes.length) { - this.isPrivateApp = true; - } - // fetch information about enterprise nodes, pgp keys - this.appRegistrationSpecification.nodes.forEach(async (node) => { - if (!this.enterpriseNodes) { - await this.getEnterpriseNodes(); - } - // fetch pgp key - const keyExists = this.enterprisePublicKeys.find((key) => key.nodeip === node); - if (!keyExists) { - const pgpKey = await this.fetchEnterpriseKey(node); - if (pgpKey) { - const pair = { - nodeip: node.ip, - nodekey: pgpKey, - }; - const keyExistsB = this.enterprisePublicKeys.find((key) => key.nodeip === node); - if (!keyExistsB) { - this.enterprisePublicKeys.push(pair); - } - } - } - }); - this.selectedEnterpriseNodes = []; - this.appRegistrationSpecification.nodes.forEach((node) => { - // add to selected node list - if (this.enterpriseNodes) { - const nodeFound = this.enterpriseNodes.find((entNode) => entNode.ip === node || node === `${entNode.txhash}:${entNode.outidx}`); - if (nodeFound) { - this.selectedEnterpriseNodes.push(nodeFound); - } - } else { - this.showToast('danger', 'Failed to load Enterprise Node List'); - } - }); - } - } + this.importSpecs(this.$router.currentRoute.params.appspecs); } if (auth.zelid) { this.appRegistrationSpecification.owner = auth.zelid; @@ -3479,6 +3416,113 @@ export default { this.showToast('danger', error.message); } }, + importSpecs(appSpecs) { + try { + JSON.parse(appSpecs); + } catch (error) { + this.showToast('error', 'Invalid Application Specifications'); + return; + } + const zelidauth = localStorage.getItem('zelidauth'); + const auth = qs.parse(zelidauth); + if (appSpecs) { + const specs = JSON.parse(appSpecs); + console.log(specs); + this.appRegistrationSpecification = JSON.parse(appSpecs); + + this.appRegistrationSpecification.instances = specs.instances || 3; + if (this.appRegistrationSpecification.version <= 3) { + this.appRegistrationSpecification.version = 3; // enforce specs version 3 + this.appRegistrationSpecification.ports = specs.port || this.ensureString(specs.ports); // v1 compatibility + this.appRegistrationSpecification.domains = this.ensureString(specs.domains); + this.appRegistrationSpecification.enviromentParameters = this.ensureString(specs.enviromentParameters); + this.appRegistrationSpecification.commands = this.ensureString(specs.commands); + this.appRegistrationSpecification.containerPorts = specs.containerPort || this.ensureString(specs.containerPorts); // v1 compatibility + } else { + if (this.appRegistrationSpecification.version <= 7) { + this.appRegistrationSpecification.version = 7; + } + this.appRegistrationSpecification.contacts = this.ensureString([]); + this.appRegistrationSpecification.geolocation = this.ensureString([]); + if (this.appRegistrationSpecification.version >= 5) { + this.appRegistrationSpecification.contacts = this.ensureString(specs.contacts || []); + this.appRegistrationSpecification.geolocation = this.ensureString(specs.geolocation || []); + try { + this.decodeGeolocation(specs.geolocation || []); + } catch (error) { + console.log(error); + this.appRegistrationSpecification.geolocation = this.ensureString([]); + } + } + this.appRegistrationSpecification.compose.forEach((component) => { + // eslint-disable-next-line no-param-reassign + component.ports = this.ensureString(component.ports); + // eslint-disable-next-line no-param-reassign + component.domains = this.ensureString(component.domains); + // eslint-disable-next-line no-param-reassign + component.environmentParameters = this.ensureString(component.environmentParameters); + // eslint-disable-next-line no-param-reassign + component.commands = this.ensureString(component.commands); + // eslint-disable-next-line no-param-reassign + component.containerPorts = this.ensureString(component.containerPorts); + // eslint-disable-next-line no-param-reassign + component.secrets = this.ensureString(component.secrets || ''); + // eslint-disable-next-line no-param-reassign + component.repoauth = this.ensureString(component.repoauth || ''); + }); + if (this.appRegistrationSpecification.version >= 6) { + this.appRegistrationSpecification.expire = this.ensureNumber(specs.expire || 22000); + this.expirePosition = this.getExpirePosition(this.appRegistrationSpecification.expire); + } + if (this.appRegistrationSpecification.version >= 7) { + this.appRegistrationSpecification.staticip = this.appRegistrationSpecification.staticip ?? false; + this.appRegistrationSpecification.nodes = this.appRegistrationSpecification.nodes || []; + if (this.appRegistrationSpecification.nodes && this.appRegistrationSpecification.nodes.length) { + this.isPrivateApp = true; + } + // fetch information about enterprise nodes, pgp keys + this.appRegistrationSpecification.nodes.forEach(async (node) => { + if (!this.enterpriseNodes) { + await this.getEnterpriseNodes(); + } + // fetch pgp key + const keyExists = this.enterprisePublicKeys.find((key) => key.nodeip === node); + if (!keyExists) { + const pgpKey = await this.fetchEnterpriseKey(node); + if (pgpKey) { + const pair = { + nodeip: node.ip, + nodekey: pgpKey, + }; + const keyExistsB = this.enterprisePublicKeys.find((key) => key.nodeip === node); + if (!keyExistsB) { + this.enterprisePublicKeys.push(pair); + } + } + } + }); + this.selectedEnterpriseNodes = []; + this.appRegistrationSpecification.nodes.forEach((node) => { + // add to selected node list + if (this.enterpriseNodes) { + const nodeFound = this.enterpriseNodes.find((entNode) => entNode.ip === node || node === `${entNode.txhash}:${entNode.outidx}`); + if (nodeFound) { + this.selectedEnterpriseNodes.push(nodeFound); + } + } else { + this.showToast('danger', 'Failed to load Enterprise Node List'); + } + }); + } + } + } + if (auth.zelid) { + this.appRegistrationSpecification.owner = auth.zelid; + } else { + this.appRegistrationSpecification.owner = ''; + this.showToast('warning', 'Please log in first before registering an application'); + } + }, }, }; @@ -3540,4 +3584,9 @@ a:hover img { filter: opacity(70%); transform: scale(1.1); } + +.importSpecsButton { + float: right; + margin-top: -50px; +} From d27a70069913b6f708384ff1b51bb894fb37bb3e Mon Sep 17 00:00:00 2001 From: TheTrunk Date: Sat, 16 Dec 2023 13:32:31 +0700 Subject: [PATCH 15/20] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d0c949880..c0a59cc23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flux", - "version": "4.22.0", + "version": "4.23.0", "description": "Flux, Your Gateway to a Decentralized World", "repository": { "type": "git", From 435bf677f28fd791d4c3a0d3ec45f6d2ce8affe6 Mon Sep 17 00:00:00 2001 From: TheTrunk Date: Sat, 16 Dec 2023 13:40:59 +0700 Subject: [PATCH 16/20] rebuild home --- HomeUI/dist/css/chunk-10dffc21.css | 1 - ...{chunk-71da22eb.css => chunk-5ddea72d.css} | 0 HomeUI/dist/css/chunk-7c2fa3b6.css | 1 + ...{chunk-fab32434.css => chunk-fc566620.css} | 0 HomeUI/dist/index.html | 2 +- HomeUI/dist/js/chunk-1d6cd7cd.js | 2 +- .../{chunk-71da22eb.js => chunk-5ddea72d.js} | 10 ++++----- .../{chunk-10dffc21.js => chunk-7c2fa3b6.js} | 22 +++++++++---------- HomeUI/dist/js/chunk-a3518802.js | 2 +- HomeUI/dist/js/chunk-a91dae36.js | 2 +- .../{chunk-fab32434.js => chunk-fc566620.js} | 12 +++++----- HomeUI/dist/js/index.js | 2 +- 12 files changed, 28 insertions(+), 28 deletions(-) delete mode 100644 HomeUI/dist/css/chunk-10dffc21.css rename HomeUI/dist/css/{chunk-71da22eb.css => chunk-5ddea72d.css} (100%) create mode 100644 HomeUI/dist/css/chunk-7c2fa3b6.css rename HomeUI/dist/css/{chunk-fab32434.css => chunk-fc566620.css} (100%) rename HomeUI/dist/js/{chunk-71da22eb.js => chunk-5ddea72d.js} (70%) rename HomeUI/dist/js/{chunk-10dffc21.js => chunk-7c2fa3b6.js} (62%) rename HomeUI/dist/js/{chunk-fab32434.js => chunk-fc566620.js} (68%) diff --git a/HomeUI/dist/css/chunk-10dffc21.css b/HomeUI/dist/css/chunk-10dffc21.css deleted file mode 100644 index e26a18d8d..000000000 --- a/HomeUI/dist/css/chunk-10dffc21.css +++ /dev/null @@ -1 +0,0 @@ -.popover{max-width:400px}.confirm-dialog-250{width:250px}.confirm-dialog-275{width:275px}.confirm-dialog-300{width:300px}.confirm-dialog-350{width:350px}.confirm-dialog-400{width:400px}.inline[data-v-1417792e]{display:inline}[dir=ltr] .inline[data-v-1417792e]{padding-left:5px}[dir=rtl] .inline[data-v-1417792e]{padding-right:5px}.loginRow[data-v-1417792e]{display:flex;flex-direction:row;justify-content:space-around;align-items:center}[dir] .loginRow[data-v-1417792e]{margin-bottom:10px}.zelidLogin[data-v-1417792e]{height:90px}[dir] .zelidLogin[data-v-1417792e]{padding:10px}[dir=ltr] .zelidLogin[data-v-1417792e]{margin-left:5px}[dir=rtl] .zelidLogin[data-v-1417792e]{margin-right:5px}.zelidLogin img[data-v-1417792e]{-webkit-app-region:no-drag;transition:.1s}.walletconnectLogin[data-v-1417792e]{height:100px}[dir] .walletconnectLogin[data-v-1417792e]{padding:10px}.walletconnectLogin img[data-v-1417792e]{-webkit-app-region:no-drag;transition:.1s}.metamaskLogin[data-v-1417792e]{height:80px}[dir] .metamaskLogin[data-v-1417792e]{padding:10px}.metamaskLogin img[data-v-1417792e]{-webkit-app-region:no-drag;transition:.1s}.sspLogin[data-v-1417792e]{height:90px}[dir] .sspLogin[data-v-1417792e]{padding:10px}[dir=ltr] .sspLogin[data-v-1417792e]{margin-left:5px}[dir=rtl] .sspLogin[data-v-1417792e]{margin-right:5px}.sspLogin img[data-v-1417792e]{-webkit-app-region:no-drag;transition:.1s}a img[data-v-1417792e]{transition:all .05s ease-in-out}a:hover img[data-v-1417792e]{filter:opacity(70%)}[dir] a:hover img[data-v-1417792e]{transform:scale(1.1)} \ No newline at end of file diff --git a/HomeUI/dist/css/chunk-71da22eb.css b/HomeUI/dist/css/chunk-5ddea72d.css similarity index 100% rename from HomeUI/dist/css/chunk-71da22eb.css rename to HomeUI/dist/css/chunk-5ddea72d.css diff --git a/HomeUI/dist/css/chunk-7c2fa3b6.css b/HomeUI/dist/css/chunk-7c2fa3b6.css new file mode 100644 index 000000000..6fda4f641 --- /dev/null +++ b/HomeUI/dist/css/chunk-7c2fa3b6.css @@ -0,0 +1 @@ +.popover{max-width:400px}.confirm-dialog-250{width:250px}.confirm-dialog-275{width:275px}.confirm-dialog-300{width:300px}.confirm-dialog-350{width:350px}.confirm-dialog-400{width:400px}.inline[data-v-37ae21fa]{display:inline}[dir=ltr] .inline[data-v-37ae21fa]{padding-left:5px}[dir=rtl] .inline[data-v-37ae21fa]{padding-right:5px}.loginRow[data-v-37ae21fa]{display:flex;flex-direction:row;justify-content:space-around;align-items:center}[dir] .loginRow[data-v-37ae21fa]{margin-bottom:10px}.zelidLogin[data-v-37ae21fa]{height:90px}[dir] .zelidLogin[data-v-37ae21fa]{padding:10px}[dir=ltr] .zelidLogin[data-v-37ae21fa]{margin-left:5px}[dir=rtl] .zelidLogin[data-v-37ae21fa]{margin-right:5px}.zelidLogin img[data-v-37ae21fa]{-webkit-app-region:no-drag;transition:.1s}.walletconnectLogin[data-v-37ae21fa]{height:100px}[dir] .walletconnectLogin[data-v-37ae21fa]{padding:10px}.walletconnectLogin img[data-v-37ae21fa]{-webkit-app-region:no-drag;transition:.1s}.metamaskLogin[data-v-37ae21fa]{height:80px}[dir] .metamaskLogin[data-v-37ae21fa]{padding:10px}.metamaskLogin img[data-v-37ae21fa]{-webkit-app-region:no-drag;transition:.1s}.sspLogin[data-v-37ae21fa]{height:90px}[dir] .sspLogin[data-v-37ae21fa]{padding:10px}[dir=ltr] .sspLogin[data-v-37ae21fa]{margin-left:5px}[dir=rtl] .sspLogin[data-v-37ae21fa]{margin-right:5px}.sspLogin img[data-v-37ae21fa]{-webkit-app-region:no-drag;transition:.1s}a img[data-v-37ae21fa]{transition:all .05s ease-in-out}a:hover img[data-v-37ae21fa]{filter:opacity(70%)}[dir] a:hover img[data-v-37ae21fa]{transform:scale(1.1)}[dir] .importSpecsButton[data-v-37ae21fa]{margin-top:-50px}[dir=ltr] .importSpecsButton[data-v-37ae21fa]{float:right}[dir=rtl] .importSpecsButton[data-v-37ae21fa]{float:left} \ No newline at end of file diff --git a/HomeUI/dist/css/chunk-fab32434.css b/HomeUI/dist/css/chunk-fc566620.css similarity index 100% rename from HomeUI/dist/css/chunk-fab32434.css rename to HomeUI/dist/css/chunk-fc566620.css diff --git a/HomeUI/dist/index.html b/HomeUI/dist/index.html index 6d7c4e096..18328c96f 100644 --- a/HomeUI/dist/index.html +++ b/HomeUI/dist/index.html @@ -83,7 +83,7 @@ transform: rotate(1turn); opacity: 1; } - }FluxOS Dashboard