diff --git a/src/fireedge/config.yml b/src/fireedge/config.yml
index 59a5d05776..a499f4f78a 100644
--- a/src/fireedge/config.yml
+++ b/src/fireedge/config.yml
@@ -20,4 +20,9 @@ TOKEN_SECRET: secret_token
# JWT life time (days)
LIMIT_TOKEN:
MIN: 14
- MAX: 30
\ No newline at end of file
+ MAX: 30
+
+# VMRC
+VMRC:
+ TARGET: 'http://opennebula.io'
+ TOKENS_PATH: '/var/lib/one/sunstone_vnc_tokens/vmrc'
diff --git a/src/fireedge/genPotFile.js b/src/fireedge/genPotFile.js
deleted file mode 100644
index e274759488..0000000000
--- a/src/fireedge/genPotFile.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const { createReadStream, generateFile } = require('fireedge-genpotfile');
-const constants = require('./src/utils/constants');
-const clientConstants = require('./src/public/constants');
-
-const testFolder = './src/public';
-const exportFile = 'test.po';
-const definitions = { ...constants, ...clientConstants };
-
-// function Tr()
-const optsFunc = {
- regex: /Tr(\("|\('|\()[a-zA-Z0-9_ ]*("\)|'\)|\))/g,
- removeStart: /Tr(\()/g,
- removeEnd: /(\))/g,
- regexTextCaptureIndex: 0,
- definitions
-};
-
-// React component
-const optsComponent = {
- regex: //g,
- removeStart: //g,
- regexTextCaptureIndex: 0,
- definitions
-};
-
-createReadStream(testFolder, optsFunc);
-createReadStream(testFolder, optsComponent);
-
-generateFile(exportFile);
diff --git a/src/fireedge/package.json b/src/fireedge/package.json
index 898b77ecc3..d0f0888827 100644
--- a/src/fireedge/package.json
+++ b/src/fireedge/package.json
@@ -12,7 +12,8 @@
"start": "node dist/index",
"cypress:open": "cypress open",
"cypress:run": "cypress run --headless --browser chrome --spec \"cypress/integration/**/*.spec.js\"",
- "genPot": "node genPotFile.js",
+ "pot": "node potfile.js",
+ "po2json": "node po2json.js",
"copy_static_assets": "node copyStaticAssets.js"
},
"keywords": [
@@ -41,11 +42,11 @@
"concurrently": "^5.2.0",
"cors": "^2.8.5",
"express": "^4.17.1",
- "fireedge-genpotfile": "^1.0.0",
"fs-extra": "^9.0.1",
"fuse.js": "^6.4.1",
"helmet": "^3.23.3",
"http": "0.0.1-security",
+ "http-proxy-middleware": "^1.0.5",
"immutable": "^4.0.0-rc.12",
"intersection-observer": "^0.11.0",
"jsonschema": "^1.2.6",
@@ -101,20 +102,17 @@
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-cypress": "^2.11.1",
"file-loader": "^6.0.0",
+ "fireedge-genpotfile": "^1.0.0",
+ "fireedge-pojson": "^1.0.1",
"jloboescalona-eslint-config": "^1.1.0",
"node-sass": "^4.12.0",
"nodemon": "^1.18.10",
- "once": "^1.4.0",
+ "path": "^0.12.7",
"react-addons-test-utils": "^15.6.2",
- "readdirp": "^3.4.0",
- "split": "^1.0.1",
- "stream-combiner": "^0.2.2",
"style-loader": "^1.0.0",
- "through2": "^4.0.2",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.7",
"webpack-livereload-plugin": "^2.3.0",
- "webpack-node-externals": "^1.7.2",
- "xgettext-regex": "^0.3.0"
+ "webpack-node-externals": "^1.7.2"
}
}
diff --git a/src/fireedge/po2json.js b/src/fireedge/po2json.js
new file mode 100644
index 0000000000..6969fae4ac
--- /dev/null
+++ b/src/fireedge/po2json.js
@@ -0,0 +1,22 @@
+/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
+/* not use this file except in compliance with the License. You may obtain */
+/* a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+/* -------------------------------------------------------------------------- */
+
+const { createReadStream, generateFile } = require('fireedge-pojson');
+
+const testFolder = './src/public/assets/languages';
+
+createReadStream(testFolder, { exportPath: testFolder });
+
+generateFile();
diff --git a/src/fireedge/potfile.js b/src/fireedge/potfile.js
new file mode 100644
index 0000000000..998ecdf38b
--- /dev/null
+++ b/src/fireedge/potfile.js
@@ -0,0 +1,45 @@
+/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
+/* not use this file except in compliance with the License. You may obtain */
+/* a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+/* -------------------------------------------------------------------------- */
+
+const { createReadStream, generateFile } = require('fireedge-genpotfile');
+const constants = require('./src/utils/constants');
+const clientConstants = require('./src/public/constants');
+
+const testFolder = './src/public';
+const exportFile = './src/public/assets/languages/messages.pot';
+const definitions = { ...constants, ...clientConstants };
+
+// function Tr()
+const optsFunc = {
+ regex: /Tr(\("|\('|\()[a-zA-Z0-9_ ]*("\)|'\)|\))/g,
+ removeStart: /Tr(\()/g,
+ removeEnd: /(\))/g,
+ regexTextCaptureIndex: 0,
+ definitions
+};
+
+// React component
+const optsComponent = {
+ regex: //g,
+ removeStart: //g,
+ regexTextCaptureIndex: 0,
+ definitions
+};
+
+createReadStream(testFolder, optsFunc);
+createReadStream(testFolder, optsComponent);
+
+generateFile(exportFile);
diff --git a/src/fireedge/src/index.js b/src/fireedge/src/index.js
index 5178be1dca..c8b4b52f56 100644
--- a/src/fireedge/src/index.js
+++ b/src/fireedge/src/index.js
@@ -19,7 +19,6 @@ const helmet = require('helmet');
const express = require('express');
const morgan = require('morgan');
const path = require('path');
-const socketIO = require('socket.io');
const cors = require('cors');
const {
accessSync,
@@ -33,7 +32,8 @@ const bodyParser = require('body-parser');
const {
defaultConfigLogPath,
defaultConfigLogFile,
- defaultTypeLog
+ defaultTypeLog,
+ defaultPort
} = require('./utils/constants/defaults');
const { validateServerIsSecure, getCert, getKey } = require('./utils/server');
const {
@@ -41,13 +41,15 @@ const {
entrypointApi,
entrypointApp
} = require('./routes/entrypoints');
-const { messageTerminal, addWsServer, getConfig } = require('./utils');
+const { oneHooks } = require('./routes/websockets/zeromq');
+const { vmrcUpgrade } = require('./routes/websockets/vmrc');
+const { messageTerminal, getConfig } = require('./utils');
const app = express();
// settings
const appConfig = getConfig();
-const port = appConfig.PORT || 3000;
+const port = appConfig.PORT || defaultPort;
const userLog = appConfig.LOG || 'dev';
let log = morgan('dev');
@@ -102,9 +104,7 @@ const appServer = validateServerIsSecure()
)
: unsecureServer(app);
-// connect to websocket
-const io = socketIO.listen(appServer);
-addWsServer(io);
+oneHooks(appServer);
appServer.listen(port, () => {
const config = {
@@ -114,3 +114,4 @@ appServer.listen(port, () => {
};
messageTerminal(config);
});
+vmrcUpgrade(appServer);
diff --git a/src/fireedge/src/public/containers/Websocket/index.js b/src/fireedge/src/public/containers/Webconsole/index.js
similarity index 88%
rename from src/fireedge/src/public/containers/Websocket/index.js
rename to src/fireedge/src/public/containers/Webconsole/index.js
index b3abc623a0..02e46e545f 100644
--- a/src/fireedge/src/public/containers/Websocket/index.js
+++ b/src/fireedge/src/public/containers/Webconsole/index.js
@@ -15,18 +15,20 @@
import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';
-import { findStorageData } from '../../../utils';
+import { findStorageData } from 'client/utils';
import constants from 'client/constants';
+import { defaultPort } from 'server/utils/constants/defaults';
const { jwtName } = constants;
-const ENDPOINT = 'http://127.0.0.1:3000';
+const ENDPOINT = `http://127.0.0.1:${defaultPort}`;
-function Webconsole() {
+const Webconsole = () => {
const [response, setResponse] = useState({});
useEffect(() => {
const socket = io(ENDPOINT, {
+ path: '/zeromq',
query: {
token: findStorageData(jwtName)
}
@@ -37,6 +39,5 @@ function Webconsole() {
}, []);
console.log('-->', response);
return
;
-}
-
+};
export default Webconsole;
diff --git a/src/fireedge/src/public/containers/Websocket/WSConsole.js b/src/fireedge/src/public/containers/Websocket/WSConsole.js
deleted file mode 100644
index 937f547bc0..0000000000
--- a/src/fireedge/src/public/containers/Websocket/WSConsole.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
-/* */
-/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
-/* not use this file except in compliance with the License. You may obtain */
-/* a copy of the License at */
-/* */
-/* http://www.apache.org/licenses/LICENSE-2.0 */
-/* */
-/* Unless required by applicable law or agreed to in writing, software */
-/* distributed under the License is distributed on an "AS IS" BASIS, */
-/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
-/* See the License for the specific language governing permissions and */
-/* limitations under the License. */
-/* -------------------------------------------------------------------------- */
-
-import React, { Component } from 'react';
-import { w3cwebsocket as W3CWebSocket } from 'websocket';
-import JSONPretty from 'react-json-pretty';
-import { messageTerminal } from '../../../utils/general';
-
-class WSConsole extends Component {
- constructor(props) {
- super(props);
- this.state = {
- data: ''
- };
- }
-
- componentWillMount() {
- const client = new W3CWebSocket(
- 'ws://127.0.0.1:3000?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIwIiwiYXVkIjoib25lYWRtaW4iLCJqdGkiOiJkYzNjMmJkMDhlODM3MmU0NWY5MDVmNjE0ZjdkMDE0YmQ2ZmE3ZTVjYjlmNjU1OTRjNjRjYzMzZjNiYmYxY2IyIiwiaWF0IjoxNTY5MjIxOTgwLCJleHAiOjE1NzA0MzE1ODB9.ESxu8xeGNVQCAJ2T5-93y2cWofXCNxvsAdT0Jt5Qt5I'
- );
-
- client.onopen = () => {
- const config = {
- color: 'green',
- type: 'ERROR',
- message: 'WebSocket Client Connected'
- };
- messageTerminal(config);
- };
-
- client.onmessage = message => {
- if (message && message.data) {
- this.setState({
- data: JSON.parse(message.data)
- });
- }
- };
- }
-
- render() {
- const { data } = this.state;
- return ;
- }
-}
-
-export default WSConsole;
diff --git a/src/fireedge/src/public/router/endpoints.js b/src/fireedge/src/public/router/endpoints.js
index 9fe66c77e6..a9d4401808 100644
--- a/src/fireedge/src/public/router/endpoints.js
+++ b/src/fireedge/src/public/router/endpoints.js
@@ -26,6 +26,7 @@ import Login from 'client/containers/Login';
import Dashboard from 'client/containers/Dashboard';
import Settings from 'client/containers/Settings';
import TestApi from 'client/containers/TestApi';
+import Webconsole from 'client/containers/Webconsole';
import {
ApplicationCreate,
ApplicationDeploy,
@@ -74,6 +75,14 @@ const ENDPOINTS = [
icon: BallotIcon,
component: TestApi
},
+ {
+ label: 'Webconsole',
+ path: '/webconsole',
+ authenticated: true,
+ devMode: true,
+ icon: BallotIcon,
+ component: Webconsole
+ },
{
label: 'Create Application',
path: PATH.APPLICATION.CREATE,
diff --git a/src/fireedge/src/routes/api/routes/2fa/functions.js b/src/fireedge/src/routes/api/routes/2fa/functions.js
new file mode 100644
index 0000000000..773463af1d
--- /dev/null
+++ b/src/fireedge/src/routes/api/routes/2fa/functions.js
@@ -0,0 +1,279 @@
+/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
+/* not use this file except in compliance with the License. You may obtain */
+/* a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+/* -------------------------------------------------------------------------- */
+
+const speakeasy = require('speakeasy');
+const qrcode = require('qrcode');
+const { httpResponse } = require('../../../../utils/server');
+const { getConfig } = require('../../../../utils/yml');
+const {
+ httpMethod,
+ defaultMethodUserInfo,
+ defaultMethodUserUpdate,
+ default2FAIssuer,
+ default2FAOpennebulaVar,
+ default2FAOpennebulaTmpVar
+} = require('../../../../utils/constants/defaults');
+
+const { POST, GET } = httpMethod;
+const {
+ responseOpennebula,
+ checkOpennebulaCommand,
+ generateNewTemplate,
+ check2Fa
+} = require('../../../../utils/opennebula');
+const { from: fromData } = require('../../../../utils/constants/defaults');
+const {
+ ok,
+ unauthorized,
+ internalServerError
+} = require('../../../../utils/constants/http-codes');
+
+// user config
+const appConfig = getConfig();
+
+const twoFactorAuthIssuer =
+ appConfig.TWO_FACTOR_AUTH_ISSUER || default2FAIssuer;
+
+const getUserInfoAuthenticated = (connect, userId, callback, next) => {
+ if (
+ connect &&
+ !!userId &&
+ callback &&
+ next &&
+ typeof connect === 'function' &&
+ typeof callback === 'function' &&
+ typeof next === 'function' &&
+ defaultMethodUserInfo
+ ) {
+ const connectOpennebula = connect();
+ const dataUser = {};
+ // empty positions for validate...
+ dataUser[fromData.resource] = {};
+ dataUser[fromData.query] = {};
+ dataUser[fromData.postBody] = {};
+ dataUser[fromData.resource].id = userId;
+ const getOpennebulaMethod = checkOpennebulaCommand(
+ defaultMethodUserInfo,
+ GET
+ );
+ connectOpennebula(
+ defaultMethodUserInfo,
+ getOpennebulaMethod(dataUser),
+ (err, value) => {
+ responseOpennebula(
+ () => undefined,
+ err,
+ value,
+ info => {
+ if (info !== undefined && info !== null) {
+ callback(info);
+ } else {
+ next();
+ }
+ },
+ next
+ );
+ }
+ );
+ }
+};
+
+const generateQR = (req, res, next, connect, userId) => {
+ const secret = speakeasy.generateSecret({
+ length: 10,
+ name: twoFactorAuthIssuer
+ });
+ if (secret && secret.otpauth_url && secret.base32) {
+ const { otpauth_url: otpURL, base32 } = secret;
+ qrcode.toDataURL(otpURL, (err, dataURL) => {
+ if (err) {
+ res.locals.httpCode = httpResponse(internalServerError);
+ next();
+ } else {
+ const connectOpennebula = connect();
+ getUserInfoAuthenticated(
+ connect,
+ userId,
+ info => {
+ if (info && info.USER && info.USER.TEMPLATE && req) {
+ const dataUser = Map(req).toObject();
+ const emptyTemplate = {};
+ emptyTemplate[default2FAOpennebulaTmpVar] = base32;
+
+ dataUser[fromData.resource].id = userId;
+ dataUser[fromData.postBody].template = generateNewTemplate(
+ info.USER.TEMPLATE.SUNSTONE || {},
+ emptyTemplate,
+ [default2FAOpennebulaVar]
+ );
+ const getOpennebulaMethod = checkOpennebulaCommand(
+ defaultMethodUserUpdate,
+ POST
+ );
+ connectOpennebula(
+ defaultMethodUserUpdate,
+ getOpennebulaMethod(dataUser),
+ (error, value) => {
+ responseOpennebula(
+ () => undefined,
+ error,
+ value,
+ pass => {
+ if (pass !== undefined && pass !== null) {
+ res.locals.httpCode = httpResponse(ok, {
+ img: dataURL
+ });
+ next();
+ } else {
+ next();
+ }
+ },
+ next
+ );
+ }
+ );
+ } else {
+ next();
+ }
+ },
+ next
+ );
+ }
+ });
+ } else {
+ next();
+ }
+};
+
+const twoFactorSetup = (req, res, next, connect, userId) => {
+ const connectOpennebula = connect();
+ getUserInfoAuthenticated(
+ connect,
+ userId,
+ info => {
+ if (
+ info &&
+ info.USER &&
+ info.USER.TEMPLATE &&
+ info.USER.TEMPLATE.SUNSTONE &&
+ info.USER.TEMPLATE.SUNSTONE[default2FAOpennebulaTmpVar] &&
+ fromData &&
+ fromData.postBody &&
+ req &&
+ req[fromData.postBody] &&
+ req[fromData.postBody].token
+ ) {
+ const sunstone = info.USER.TEMPLATE.SUNSTONE;
+ const token = req[fromData.postBody].token;
+ const secret = sunstone[default2FAOpennebulaTmpVar];
+ if (check2Fa(secret, token)) {
+ const emptyTemplate = {};
+ emptyTemplate[default2FAOpennebulaVar] = secret;
+
+ const dataUser = Map(req).toObject();
+ dataUser[fromData.resource].id = userId;
+ dataUser[fromData.postBody].template = generateNewTemplate(
+ sunstone || {},
+ emptyTemplate,
+ [default2FAOpennebulaTmpVar]
+ );
+ const getOpennebulaMethodUpdate = checkOpennebulaCommand(
+ defaultMethodUserUpdate,
+ POST
+ );
+ connectOpennebula(
+ defaultMethodUserUpdate,
+ getOpennebulaMethodUpdate(dataUser),
+ (err, value) => {
+ responseOpennebula(
+ () => undefined,
+ err,
+ value,
+ pass => {
+ if (pass !== undefined && pass !== null) {
+ res.locals.httpCode = httpResponse(ok);
+ }
+ next();
+ },
+ next
+ );
+ }
+ );
+ } else {
+ res.locals.httpCode = httpResponse(unauthorized);
+ next();
+ }
+ } else {
+ next();
+ }
+ },
+ next
+ );
+};
+const twoFactorDelete = (req, res, next, connect, userId) => {
+ const connectOpennebula = connect();
+ getUserInfoAuthenticated(
+ connect,
+ userId,
+ info => {
+ if (
+ info &&
+ info.USER &&
+ info.USER.TEMPLATE &&
+ info.USER.TEMPLATE.SUNSTONE
+ ) {
+ const emptyTemplate = {};
+ const dataUser = Map(req).toObject();
+ dataUser[fromData.resource].id = userId;
+ dataUser[fromData.postBody].template = generateNewTemplate(
+ info.USER.TEMPLATE.SUNSTONE || {},
+ emptyTemplate,
+ [default2FAOpennebulaTmpVar, default2FAOpennebulaVar]
+ );
+ const getOpennebulaMethodUpdate = checkOpennebulaCommand(
+ defaultMethodUserUpdate,
+ POST
+ );
+ connectOpennebula(
+ defaultMethodUserUpdate,
+ getOpennebulaMethodUpdate(dataUser),
+ (err, value) => {
+ responseOpennebula(
+ () => undefined,
+ err,
+ value,
+ pass => {
+ if (pass !== undefined && pass !== null) {
+ res.locals.httpCode = httpResponse(ok);
+ }
+ next();
+ },
+ next
+ );
+ }
+ );
+ } else {
+ next();
+ }
+ },
+ next
+ );
+};
+module.exports = {
+ getUserInfoAuthenticated,
+ generateQR,
+ twoFactorSetup,
+ twoFactorDelete
+};
diff --git a/src/fireedge/src/routes/api/routes/2fa/index.js b/src/fireedge/src/routes/api/routes/2fa/index.js
index 730b366b5c..26a4f59e80 100644
--- a/src/fireedge/src/routes/api/routes/2fa/index.js
+++ b/src/fireedge/src/routes/api/routes/2fa/index.js
@@ -13,283 +13,31 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
-const { Map } = require('immutable');
-const speakeasy = require('speakeasy');
-const qrcode = require('qrcode');
-const { getConfig } = require('../../../../utils/yml');
-const {
- httpMethod,
- defaultMethodUserInfo,
- defaultMethodUserUpdate,
- default2FAIssuer,
- default2FAOpennebulaVar,
- default2FAOpennebulaTmpVar
-} = require('../../../../utils/constants/defaults');
+const { generateQR, twoFactorSetup, twoFactorDelete } = require('./functions');
+const { httpMethod } = require('../../../../utils/constants/defaults');
const {
TWO_FACTOR_QR,
TWO_FACTOR_DELETE,
TWO_FACTOR_SETUP
} = require('./string-routes');
-const {
- ok,
- unauthorized,
- internalServerError
-} = require('../../../../utils/constants/http-codes');
-const { from: fromData } = require('../../../../utils/constants/defaults');
-const {
- responseOpennebula,
- checkOpennebulaCommand,
- generateNewTemplate,
- check2Fa
-} = require('../../../../utils/opennebula');
-const { httpResponse } = require('../../../../utils/server');
-// user config
-const appConfig = getConfig();
-
-const twoFactorAuthIssuer =
- appConfig.TWO_FACTOR_AUTH_ISSUER || default2FAIssuer;
-
-const { POST, GET, DELETE } = httpMethod;
-
-const getUserInfoAuthenticated = (connect, userId, callback, next) => {
- if (
- connect &&
- !!userId &&
- callback &&
- next &&
- typeof connect === 'function' &&
- typeof callback === 'function' &&
- typeof next === 'function' &&
- defaultMethodUserInfo
- ) {
- const connectOpennebula = connect();
- const dataUser = {};
- // empty positions for validate...
- dataUser[fromData.resource] = {};
- dataUser[fromData.query] = {};
- dataUser[fromData.postBody] = {};
- dataUser[fromData.resource].id = userId;
- const getOpennebulaMethod = checkOpennebulaCommand(
- defaultMethodUserInfo,
- GET
- );
- connectOpennebula(
- defaultMethodUserInfo,
- getOpennebulaMethod(dataUser),
- (err, value) => {
- responseOpennebula(
- () => undefined,
- err,
- value,
- info => {
- if (info !== undefined && info !== null) {
- callback(info);
- } else {
- next();
- }
- },
- next
- );
- }
- );
- }
-};
+const { POST, DELETE } = httpMethod;
const privateRoutes = [
{
httpMethod: POST,
endpoint: TWO_FACTOR_QR,
- action: (req, res, next, connect, userId) => {
- const secret = speakeasy.generateSecret({
- length: 10,
- name: twoFactorAuthIssuer
- });
- if (secret && secret.otpauth_url && secret.base32) {
- const { otpauth_url: otpURL, base32 } = secret;
- qrcode.toDataURL(otpURL, (err, dataURL) => {
- if (err) {
- res.locals.httpCode = httpResponse(internalServerError);
- next();
- } else {
- const connectOpennebula = connect();
- getUserInfoAuthenticated(
- connect,
- userId,
- info => {
- if (info && info.USER && info.USER.TEMPLATE && req) {
- const dataUser = Map(req).toObject();
- const emptyTemplate = {};
- emptyTemplate[default2FAOpennebulaTmpVar] = base32;
-
- dataUser[fromData.resource].id = userId;
- dataUser[
- fromData.postBody
- ].template = generateNewTemplate(
- info.USER.TEMPLATE.SUNSTONE || {},
- emptyTemplate,
- [default2FAOpennebulaVar]
- );
- const getOpennebulaMethod = checkOpennebulaCommand(
- defaultMethodUserUpdate,
- POST
- );
- connectOpennebula(
- defaultMethodUserUpdate,
- getOpennebulaMethod(dataUser),
- (error, value) => {
- responseOpennebula(
- () => undefined,
- error,
- value,
- pass => {
- if (pass !== undefined && pass !== null) {
- res.locals.httpCode = httpResponse(ok, {
- img: dataURL
- });
- next();
- } else {
- next();
- }
- },
- next
- );
- }
- );
- } else {
- next();
- }
- },
- next
- );
- }
- });
- } else {
- next();
- }
- }
+ action: generateQR
},
{
httpMethod: POST,
endpoint: TWO_FACTOR_SETUP,
- action: (req, res, next, connect, userId) => {
- const connectOpennebula = connect();
- getUserInfoAuthenticated(
- connect,
- userId,
- info => {
- if (
- info &&
- info.USER &&
- info.USER.TEMPLATE &&
- info.USER.TEMPLATE.SUNSTONE &&
- info.USER.TEMPLATE.SUNSTONE[default2FAOpennebulaTmpVar] &&
- fromData &&
- fromData.postBody &&
- req &&
- req[fromData.postBody] &&
- req[fromData.postBody].token
- ) {
- const sunstone = info.USER.TEMPLATE.SUNSTONE;
- const token = req[fromData.postBody].token;
- const secret = sunstone[default2FAOpennebulaTmpVar];
- if (check2Fa(secret, token)) {
- const emptyTemplate = {};
- emptyTemplate[default2FAOpennebulaVar] = secret;
-
- const dataUser = Map(req).toObject();
- dataUser[fromData.resource].id = userId;
- dataUser[
- fromData.postBody
- ].template = generateNewTemplate(sunstone || {}, emptyTemplate, [
- default2FAOpennebulaTmpVar
- ]);
- const getOpennebulaMethodUpdate = checkOpennebulaCommand(
- defaultMethodUserUpdate,
- POST
- );
- connectOpennebula(
- defaultMethodUserUpdate,
- getOpennebulaMethodUpdate(dataUser),
- (err, value) => {
- responseOpennebula(
- () => undefined,
- err,
- value,
- pass => {
- if (pass !== undefined && pass !== null) {
- res.locals.httpCode = httpResponse(ok);
- }
- next();
- },
- next
- );
- }
- );
- } else {
- res.locals.httpCode = httpResponse(unauthorized);
- next();
- }
- } else {
- next();
- }
- },
- next
- );
- }
+ action: twoFactorSetup
},
{
httpMethod: DELETE,
endpoint: TWO_FACTOR_DELETE,
- action: (req, res, next, connect, userId) => {
- const connectOpennebula = connect();
- getUserInfoAuthenticated(
- connect,
- userId,
- info => {
- if (
- info &&
- info.USER &&
- info.USER.TEMPLATE &&
- info.USER.TEMPLATE.SUNSTONE
- ) {
- const emptyTemplate = {};
- const dataUser = Map(req).toObject();
- dataUser[fromData.resource].id = userId;
- dataUser[fromData.postBody].template = generateNewTemplate(
- info.USER.TEMPLATE.SUNSTONE || {},
- emptyTemplate,
- [default2FAOpennebulaTmpVar, default2FAOpennebulaVar]
- );
- const getOpennebulaMethodUpdate = checkOpennebulaCommand(
- defaultMethodUserUpdate,
- POST
- );
- connectOpennebula(
- defaultMethodUserUpdate,
- getOpennebulaMethodUpdate(dataUser),
- (err, value) => {
- responseOpennebula(
- () => undefined,
- err,
- value,
- pass => {
- if (pass !== undefined && pass !== null) {
- res.locals.httpCode = httpResponse(ok);
- }
- next();
- },
- next
- );
- }
- );
- } else {
- next();
- }
- },
- next
- );
- }
+ action: twoFactorDelete
}
];
diff --git a/src/fireedge/src/routes/api/routes/2fa/string-routes.js b/src/fireedge/src/routes/api/routes/2fa/string-routes.js
index 2474f4a544..9995646411 100644
--- a/src/fireedge/src/routes/api/routes/2fa/string-routes.js
+++ b/src/fireedge/src/routes/api/routes/2fa/string-routes.js
@@ -1,3 +1,18 @@
+/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
+/* not use this file except in compliance with the License. You may obtain */
+/* a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+/* -------------------------------------------------------------------------- */
+
const TWO_FACTOR_SETUP = '2fsetup';
const TWO_FACTOR_QR = '2fqr';
const TWO_FACTOR_DELETE = '2fdelete';
diff --git a/src/fireedge/src/routes/api/routes/auth/index.js b/src/fireedge/src/routes/api/routes/auth/index.js
index efcb84d01e..7847e5f6d0 100644
--- a/src/fireedge/src/routes/api/routes/auth/index.js
+++ b/src/fireedge/src/routes/api/routes/auth/index.js
@@ -14,9 +14,7 @@
/* -------------------------------------------------------------------------- */
const { Map } = require('immutable');
-const {
- AUTH,
-} = require('./string-routes');
+const { AUTH } = require('./string-routes');
const {
httpMethod,
defaultMethodLogin
diff --git a/src/fireedge/src/routes/api/routes/auth/string-routes.js b/src/fireedge/src/routes/api/routes/auth/string-routes.js
index 485ce0dcd0..8c294217dd 100644
--- a/src/fireedge/src/routes/api/routes/auth/string-routes.js
+++ b/src/fireedge/src/routes/api/routes/auth/string-routes.js
@@ -1,3 +1,18 @@
+/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
+/* not use this file except in compliance with the License. You may obtain */
+/* a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+/* -------------------------------------------------------------------------- */
+
const AUTH = 'auth';
const Actions = {
diff --git a/src/fireedge/src/routes/api/routes/oneflow/string-routes.js b/src/fireedge/src/routes/api/routes/oneflow/string-routes.js
index 5d3f59da23..259a60db97 100644
--- a/src/fireedge/src/routes/api/routes/oneflow/string-routes.js
+++ b/src/fireedge/src/routes/api/routes/oneflow/string-routes.js
@@ -1,3 +1,18 @@
+/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
+/* not use this file except in compliance with the License. You may obtain */
+/* a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+/* -------------------------------------------------------------------------- */
+
const SERVICE = 'service';
const SERVICE_ACTION = 'service-action';
const SERVICE_SCALE = 'service-scale';
diff --git a/src/fireedge/src/routes/websockets/vmrc/index.js b/src/fireedge/src/routes/websockets/vmrc/index.js
new file mode 100644
index 0000000000..c336c928af
--- /dev/null
+++ b/src/fireedge/src/routes/websockets/vmrc/index.js
@@ -0,0 +1,74 @@
+/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
+/* not use this file except in compliance with the License. You may obtain */
+/* a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+/* -------------------------------------------------------------------------- */
+const { createProxyMiddleware } = require('http-proxy-middleware');
+const { readFileSync } = require('fs-extra');
+const { getConfig } = require('../../../utils/yml');
+const { messageTerminal } = require('../../../utils/general');
+const { console } = require('window-or-global');
+
+const appConfig = getConfig();
+const vmrcData = appConfig.VMRC || {};
+
+const endpoint = '/vmrc';
+const url = vmrcData.TARGET || '';
+const vmrcProxy = createProxyMiddleware(endpoint, {
+ target: url,
+ changeOrigin: false,
+ ws: true,
+ secure: /^(https):\/\/[^ "]+$/.test(url),
+ logLevel: 'debug',
+ pathRewrite: path => path.replace(endpoint, '/ticket'),
+ router: req => {
+ if (req && req.url) {
+ const ticket = req.url.split('/')[2];
+ try {
+ const esxi = readFileSync(
+ `${vmrcData.TOKENS_PATH || ''}/${ticket}`
+ ).toString();
+ return esxi;
+ } catch (error) {
+ const config = {
+ color: 'red',
+ type: error.message,
+ message: 'Error read vmrc token: %s'
+ };
+ messageTerminal(config);
+ }
+ }
+ }
+});
+
+const vmrc = appServer => {
+ if (appServer) {
+ appServer(endpoint, vmrcProxy);
+ }
+};
+const vmrcUpgrade = appServer => {
+ if (
+ appServer &&
+ appServer.on &&
+ appServer.constructor &&
+ appServer.constructor.name &&
+ appServer.constructor.name === 'Server'
+ ) {
+ appServer.on('upgrade', vmrcProxy.upgrade);
+ }
+};
+
+module.exports = {
+ endpoint,
+ vmrc,
+ vmrcUpgrade
+};
diff --git a/src/fireedge/src/utils/ws-zeromq.js b/src/fireedge/src/routes/websockets/zeromq/index.js
similarity index 85%
rename from src/fireedge/src/utils/ws-zeromq.js
rename to src/fireedge/src/routes/websockets/zeromq/index.js
index 2a22c2e01d..3c34b40294 100644
--- a/src/fireedge/src/utils/ws-zeromq.js
+++ b/src/fireedge/src/routes/websockets/zeromq/index.js
@@ -14,14 +14,13 @@
/* -------------------------------------------------------------------------- */
const atob = require('atob');
-
+const socketIO = require('socket.io');
const { socket: socketZeroMQ } = require('zeromq');
const xml2js = require('xml2js');
-const { messageTerminal } = require('./general');
-const { getConfig } = require('./yml');
-const { validateAuth } = require('./jwt');
-// const { unauthorized } = require('./constants/http-codes');
+const { messageTerminal } = require('../../../utils/general');
+const { getConfig } = require('../../../utils/yml');
+const { validateAuth } = require('../../../utils/jwt');
// user config
const appConfig = getConfig();
@@ -30,7 +29,8 @@ const zeromqType = appConfig.ZEROTYPE || 'tcp';
const zeromqPort = appConfig.ZEROPORT || 2101;
const zeromqHost = appConfig.ZEROHOST || '127.0.0.1';
-const addWsServer = appServer => {
+const endpoint = '/zeromq';
+const oneHooksEmits = appServer => {
// connect to zeromq
const zeromqSock = socketZeroMQ('sub');
const address = `${zeromqType}://${zeromqHost}:${zeromqPort}`;
@@ -86,11 +86,6 @@ const addWsServer = appServer => {
);
}
});
-
- /* socketServer.on('disconnect', () => {
- console.log('Client disconnected');
- clearInterval(interval);
- }); */
});
} catch (error) {
const configErrorZeroMQ = {
@@ -102,6 +97,19 @@ const addWsServer = appServer => {
}
};
-module.exports = {
- addWsServer
+const oneHooks = appServer => {
+ if (
+ appServer &&
+ appServer.constructor &&
+ appServer.constructor.name &&
+ appServer.constructor.name === 'Server'
+ ) {
+ const io = socketIO({ path: endpoint }).listen(appServer);
+ oneHooksEmits(io);
+ }
+};
+
+module.exports = {
+ endpoint,
+ oneHooks
};
diff --git a/src/fireedge/src/utils/constants/defaults.js b/src/fireedge/src/utils/constants/defaults.js
index 6bd072ce3a..f7ae577a92 100644
--- a/src/fireedge/src/utils/constants/defaults.js
+++ b/src/fireedge/src/utils/constants/defaults.js
@@ -63,6 +63,7 @@ const defaults = {
defaultLang: 'en_US',
defaultIP: defaultIp,
defaultProtocolHotReload: 'http',
+ defaultPort: 2616,
defaultPortHotReload: '3001',
translations: {
en_US: 'English',
diff --git a/src/fireedge/src/utils/index.js b/src/fireedge/src/utils/index.js
index c9cdec2b7e..19289e2413 100644
--- a/src/fireedge/src/utils/index.js
+++ b/src/fireedge/src/utils/index.js
@@ -20,7 +20,6 @@ const functionRoutes = require('../routes/api');
const { validateAuth } = require('./jwt');
const { httpResponse } = require('./server');
const { messageTerminal, addPrintf } = require('./general');
-const { addWsServer } = require('./ws-zeromq');
const { getConfig } = require('./yml');
// user config
@@ -127,7 +126,6 @@ const checkIfIsARouteFunction = (route, httpMethod) => {
};
module.exports = {
- addWsServer,
validateAuth,
createParamsState,
getAllowedQueryParams,