Skip to content

Commit

Permalink
Merge pull request #222 from zelcash/development
Browse files Browse the repository at this point in the history
v1.10.0
  • Loading branch information
TheTrunk authored Feb 7, 2021
2 parents d21edd8 + abd2666 commit cf99a57
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 83 deletions.
45 changes: 26 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

[![DeepScan grade](https://deepscan.io/api/teams/6436/projects/8442/branches/100920/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=6436&pid=8442&bid=100920) [![CodeFactor](https://www.codefactor.io/repository/github/zelcash/zelflux/badge)](https://www.codefactor.io/repository/github/zelcash/zelflux)[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/zelcash/zelflux.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/zelcash/zelflux/context:javascript)

Flux is available on domains, load balancing the entire Flux network. You can access both UI and API on following main domain

[Flux](https://home.runonflux.io)

[API](https://api.runonflux.io)

## API Documentation

[API documentation](https://zelcash.github.io/zelfluxdocs/)
Expand All @@ -20,28 +26,28 @@ This application communicates locally with the ZelCash Daemon (zelcashd), ZelBen

### Backend Solution - zelback

- Provide communication with zelcashd
- Providing private API, and public API, ZelNode team API (limited!)
- Listen and handel frontend requests
- Requests signing and authenticity verifying
- Handel communication with other zelnode daemons (Flux solution)
- Manage ZelNode applications - smart spawning, distributing workload, termination depending of application subscription.
- and more!
- Provide communication with zelcashd
- Providing private API, and public API, ZelNode team API (limited!)
- Listen and handle frontend requests
- Requests signing and authenticity verifying
- Handle communication with other zelnode daemons (Flux solution)
- Manage ZelNode applications - smart spawning, distributing workload, termination depending of application subscription.
- and more!

### Frontend Solution - zelfront

- Display ZelNode status information
- Display Zel Network information
- Display ZelCash status information
- Display ZelCash network information
- Display Specific application information
- Provide API access
- Login into private API part (frontend part)
- Login into ZelNode team API part (frontend part)
- Private: Management of ZelNode
- Private: Management of ZelCash
- Private: Update, status information
- and more!
- Display ZelNode status information
- Display Zel Network information
- Display ZelCash status information
- Display ZelCash network information
- Display Specific application information
- Provide API access
- Login into private API part (frontend part)
- Login into ZelNode team API part (frontend part)
- Private: Management of ZelNode
- Private: Management of ZelCash
- Private: Update, status information
- and more!

This application is open source and distributed under the GNU AGPLv3 licence

Expand All @@ -50,6 +56,7 @@ This application is open source and distributed under the GNU AGPLv3 licence
Flux needs Zelcashd to be ruuning, to setup Zelcashd follow [these instructions.](https://github.com/zelcash/ZelNodeInstallv3)

build-essential is a recommended dependency

```bash

sudo apt-get build-essential
Expand Down
114 changes: 69 additions & 45 deletions ZelBack/src/services/zelfluxCommunication.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const LRUoptions = {

const myCache = new LRU(LRUoptions);
const myMessageCache = new LRU(250);
const blockedPubKeysCache = new LRU(LRUoptions);

let addingNodesToCache = false;

// basic check for a version of other flux.
async function isFluxAvailable(ip) {
Expand Down Expand Up @@ -91,6 +94,11 @@ async function myZelNodeIP() {
// filter can only be a publicKey!
async function deterministicZelNodeList(filter) {
try {
if (addingNodesToCache === true) {
// prevent several instances filling the cache at the same time.
await serviceHelper.delay(100);
return deterministicZelNodeList(filter);
}
const request = {
params: {},
query: {},
Expand All @@ -103,6 +111,7 @@ async function deterministicZelNodeList(filter) {
}
if (!zelnodeList) {
// not present in cache lets get zelnodelist again and cache it.
addingNodesToCache = true;
const zelcashZelNodeList = await zelcashService.viewDeterministicZelNodeList(request);
if (zelcashZelNodeList.status === 'success') {
zelnodeList = zelcashZelNodeList.data || [];
Expand All @@ -111,6 +120,7 @@ async function deterministicZelNodeList(filter) {
});
myCache.set('zelnodeList', zelnodeList);
}
addingNodesToCache = false;
if (filter) {
zelnodeList = myCache.get(`zelnodeList${serviceHelper.ensureString(filter)}`);
}
Expand Down Expand Up @@ -151,7 +161,7 @@ async function verifyFluxBroadcast(data, obtainedZelNodeList, currentTimeStamp)
const { timestamp } = dataObj; // ms
const { signature } = dataObj;
const { version } = dataObj;
// onle version 1 is active
// only version 1 is active
if (version !== 1) {
return false;
}
Expand Down Expand Up @@ -189,7 +199,7 @@ async function verifyFluxBroadcast(data, obtainedZelNodeList, currentTimeStamp)
return false;
}

// extends verifyFluxBroadcast by not allowing request older than 5 secs.
// extends verifyFluxBroadcast by not allowing request older than 5 mins.
async function verifyOriginalFluxBroadcast(data, obtainedZelNodeList, currentTimeStamp) {
// eslint-disable-next-line no-param-reassign
const dataObj = serviceHelper.ensureObject(data);
Expand All @@ -209,7 +219,7 @@ async function verifyTimestampInFluxBroadcast(data, currentTimeStamp) {
const { timestamp } = dataObj; // ms
// eslint-disable-next-line no-param-reassign
currentTimeStamp = currentTimeStamp || Date.now(); // ms
if (currentTimeStamp < (timestamp + 300000)) { // bigger than 5 secs
if (currentTimeStamp < (timestamp + 300000)) { // bigger than 5 mins
return true;
}
return false;
Expand Down Expand Up @@ -458,63 +468,77 @@ function handleIncomingConnection(ws, req, expressWS) {
incomingPeers.push(peer);
// verify data integrity, if not signed, close connection
ws.on('message', async (msg) => {
const dataObj = serviceHelper.ensureObject(msg);
const { pubKey } = dataObj;
if (blockedPubKeysCache.has(pubKey)) {
try {
ws.close(1008); // close as of policy violation?
} catch (e) {
console.error(e);
}
return;
}
const currentTimeStamp = Date.now(); // ms
const messageOK = await verifyFluxBroadcast(msg, undefined, currentTimeStamp);
const timestampOK = await verifyTimestampInFluxBroadcast(msg, currentTimeStamp);
if (messageOK === true && timestampOK === true) {
try {
const msgObj = serviceHelper.ensureObject(msg);
if (msgObj.data.type === 'zelappregister' || msgObj.data.type === 'zelappupdate') {
handleZelAppMessages(msgObj, peer.ip);
} else if (msgObj.data.type === 'zelapprequest') {
respondWithAppMessage(msgObj, ws);
} else if (msgObj.data.type === 'zelapprunning') {
handleZelAppRunningMessage(msgObj, ws);
} else if (msgObj.data.type === 'HeartBeat' && msgObj.data.message === 'ping') { // we know that data exists
const newMessage = msgObj.data;
newMessage.message = 'pong';
const pongResponse = await serialiseAndSignZelFluxBroadcast(newMessage);
try {
ws.send(pongResponse);
} catch (error) {
console.log(error);
}
} else if (msgObj.data.type === 'HeartBeat' && msgObj.data.message === 'pong') { // we know that data exists. This is measuring rtt from incoming conn
const newerTimeStamp = Date.now(); // ms, get a bit newer time that has passed verification of broadcast
const rtt = newerTimeStamp - msgObj.data.timestamp;
const ip = ws._socket.remoteAddress;
const foundPeer = incomingPeers.find((mypeer) => mypeer.ip === ip);
if (foundPeer) {
const peerIndex = incomingPeers.indexOf(foundPeer);
if (peerIndex > -1) {
incomingPeers[peerIndex].rtt = rtt;
if (messageOK === true) {
const timestampOK = await verifyTimestampInFluxBroadcast(msg, currentTimeStamp);
if (timestampOK === true) {
try {
const msgObj = serviceHelper.ensureObject(msg);
if (msgObj.data.type === 'zelappregister' || msgObj.data.type === 'zelappupdate') {
handleZelAppMessages(msgObj, peer.ip);
} else if (msgObj.data.type === 'zelapprequest') {
respondWithAppMessage(msgObj, ws);
} else if (msgObj.data.type === 'zelapprunning') {
handleZelAppRunningMessage(msgObj, ws);
} else if (msgObj.data.type === 'HeartBeat' && msgObj.data.message === 'ping') { // we know that data exists
const newMessage = msgObj.data;
newMessage.message = 'pong';
const pongResponse = await serialiseAndSignZelFluxBroadcast(newMessage);
try {
ws.send(pongResponse);
} catch (error) {
console.log(error);
}
} else if (msgObj.data.type === 'HeartBeat' && msgObj.data.message === 'pong') { // we know that data exists. This is measuring rtt from incoming conn
const newerTimeStamp = Date.now(); // ms, get a bit newer time that has passed verification of broadcast
const rtt = newerTimeStamp - msgObj.data.timestamp;
const ip = ws._socket.remoteAddress;
const foundPeer = incomingPeers.find((mypeer) => mypeer.ip === ip);
if (foundPeer) {
const peerIndex = incomingPeers.indexOf(foundPeer);
if (peerIndex > -1) {
incomingPeers[peerIndex].rtt = rtt;
}
}
} else {
try {
ws.send(`Flux ${userconfig.initial.ipaddress} says message received!`);
} catch (error) {
console.log(error);
}
}
} else {
try {
ws.send(`Flux ${userconfig.initial.ipaddress} says message received!`);
} catch (error) {
console.log(error);
}
} catch (e) {
log.error(e);
}
} catch (e) {
log.error(e);
}
// try rebroadcasting to all outgoing peers
// try {
// sendToAllPeers(msg);
// } catch (e) {
// log.error(e);
// }
} else if (messageOK === true) {
try {
ws.send(`Flux ${userconfig.initial.ipaddress} says message received but your message is outdated!`);
} catch (e) {
console.error(e);
} else {
try {
ws.send(`Flux ${userconfig.initial.ipaddress} says message received but your message is outdated!`);
} catch (e) {
console.error(e);
}
}
} else {
// we dont like this peer as it sent wrong message. Lets close the connection
// and add him to blocklist
try {
blockedPubKeysCache.set(pubKey, pubKey);
ws.close(1008); // close as of policy violation?
} catch (e) {
console.error(e);
Expand Down
41 changes: 39 additions & 2 deletions ZelFront/src/components/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<div>
<a
@click="initiateLoginWS"
:href="'zel:?action=sign&message=' + loginPhrase + '&icon=https%3A%2F%2Fraw.githubusercontent.com%2Fzelcash%2Fzelflux%2Fmaster%2FZelFront%2Fsrc%2Fassets%2Fimg%2FzelID.svg&callback=http%3A%2F%2F' + userconfig.externalip + ':' + config.apiPort + '%2Fzelid%2Fverifylogin%2F'"
:href="'zel:?action=sign&message=' + loginPhrase + '&icon=https%3A%2F%2Fraw.githubusercontent.com%2Fzelcash%2Fzelflux%2Fmaster%2FZelFront%2Fsrc%2Fassets%2Fimg%2FzelID.svg&callback=' + callbackValue"
>
<img
class="zelidLogin"
Expand Down Expand Up @@ -68,6 +68,7 @@ import Vue from 'vue';
import zelIDService from '@/services/ZelIDService';
const qs = require('qs');
const store = require('store');
Vue.use(Vuex);
const vue = new Vue();
Expand All @@ -91,6 +92,25 @@ export default {
'config',
'userconfig',
]),
callbackValue() {
const { protocol, hostname } = window.location;
let mybackend = '';
mybackend += protocol;
mybackend += '//';
const regex = /[A-Za-z]/g;
if (hostname.match(regex)) {
const names = hostname.split('.');
names[0] = 'api';
mybackend += names.join('.');
} else {
mybackend += this.userconfig.externalip;
mybackend += ':';
mybackend += this.config.apiPort;
}
const backendURL = store.get('backendURL') || mybackend;
const url = `${backendURL}/zelid/verifylogin`;
return encodeURI(url);
},
},
mounted() {
const isChrome = !!window.chrome;
Expand Down Expand Up @@ -173,7 +193,24 @@ export default {
},
initiateLoginWS() {
const self = this;
const wsuri = `ws://${this.userconfig.externalip}:${this.config.apiPort}/ws/zelid/${this.loginPhrase}`;
const { protocol, hostname } = window.location;
let mybackend = '';
mybackend += protocol;
mybackend += '//';
const regex = /[A-Za-z]/g;
if (hostname.match(regex)) {
const names = hostname.split('.');
names[0] = 'api';
mybackend += names.join('.');
} else {
mybackend += this.userconfig.externalip;
mybackend += ':';
mybackend += this.config.apiPort;
}
let backendURL = store.get('backendURL') || mybackend;
backendURL = backendURL.replace('https://', 'wss://');
backendURL = backendURL.replace('http://', 'ws://');
const wsuri = `${backendURL}/ws/zelid/${this.loginPhrase}`;
const websocket = new WebSocket(wsuri);
this.websocket = websocket;
Expand Down
Loading

0 comments on commit cf99a57

Please sign in to comment.