1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

F OpenNebula/one#2312: Fireedge VMRC proxy (#225)

* add vmrc proxy
* fix zeromq and vmrc
* organizate code websockets
* catch error vmrc

Signed-off-by: Jorge Lobo <jlobo@opennebula.io>
This commit is contained in:
Jorge Miguel Lobo Escalona 2020-09-18 11:07:23 +02:00 committed by GitHub
parent 22debd99e3
commit 169b072a32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 530 additions and 386 deletions

View File

@ -20,4 +20,9 @@ TOKEN_SECRET: secret_token
# JWT life time (days)
LIMIT_TOKEN:
MIN: 14
MAX: 30
MAX: 30
# VMRC
VMRC:
TARGET: 'http://opennebula.io'
TOKENS_PATH: '/var/lib/one/sunstone_vnc_tokens/vmrc'

View File

@ -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 <Translate word="word"/>
const optsComponent = {
regex: /<Translate word=('|"|{|{'|{")[a-zA-Z0-9_ ]*('|"|}|'}|"}) \/>/g,
removeStart: /<Translate word=('|"|{|{'|{")/g,
removeEnd: /('|"|}|'}|"}) \/>/g,
regexTextCaptureIndex: 0,
definitions
};
createReadStream(testFolder, optsFunc);
createReadStream(testFolder, optsComponent);
generateFile(exportFile);

View File

@ -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"
}
}

22
src/fireedge/po2json.js Normal file
View File

@ -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();

45
src/fireedge/potfile.js Normal file
View File

@ -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 <Translate word="word"/>
const optsComponent = {
regex: /<Translate word=('|"|{|{'|{")[a-zA-Z0-9_ ]*('|"|}|'}|"}) \/>/g,
removeStart: /<Translate word=('|"|{|{'|{")/g,
removeEnd: /('|"|}|'}|"}) \/>/g,
regexTextCaptureIndex: 0,
definitions
};
createReadStream(testFolder, optsFunc);
createReadStream(testFolder, optsComponent);
generateFile(exportFile);

View File

@ -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);

View File

@ -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 <p />;
}
};
export default Webconsole;

View File

@ -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 <JSONPretty id="json-pretty" data={data} />;
}
}
export default WSConsole;

View File

@ -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,

View File

@ -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
};

View File

@ -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
}
];

View File

@ -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';

View File

@ -14,9 +14,7 @@
/* -------------------------------------------------------------------------- */
const { Map } = require('immutable');
const {
AUTH,
} = require('./string-routes');
const { AUTH } = require('./string-routes');
const {
httpMethod,
defaultMethodLogin

View File

@ -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 = {

View File

@ -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';

View File

@ -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
};

View File

@ -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
};

View File

@ -63,6 +63,7 @@ const defaults = {
defaultLang: 'en_US',
defaultIP: defaultIp,
defaultProtocolHotReload: 'http',
defaultPort: 2616,
defaultPortHotReload: '3001',
translations: {
en_US: 'English',

View File

@ -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,