fix vpn servers

This commit is contained in:
kandrusyak
2022-12-05 19:45:45 +03:00
parent 3e8a0e2233
commit 9c331789b3
8 changed files with 514 additions and 186 deletions

18
package-lock.json generated
View File

@@ -26,6 +26,7 @@
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
"querystring-es3": "^0.2.1", "querystring-es3": "^0.2.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-country-flag": "^3.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-flatpickr": "^3.10.7", "react-flatpickr": "^3.10.7",
"react-loader-spinner": "^5.2.0", "react-loader-spinner": "^5.2.0",
@@ -6829,6 +6830,17 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-country-flag": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/react-country-flag/-/react-country-flag-3.0.2.tgz",
"integrity": "sha512-JPaz+q3QD0/nZtHBKj5x3O7r/SgSG9kxbymdaIU0RqlDAcorJIe4KV0DFhWIdKh69q5cPVkIVERcMYGZdvXgAA==",
"engines": {
"node": ">=12"
},
"peerDependencies": {
"react": ">=16"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@@ -13837,6 +13849,12 @@
"object-assign": "^4.1.1" "object-assign": "^4.1.1"
} }
}, },
"react-country-flag": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/react-country-flag/-/react-country-flag-3.0.2.tgz",
"integrity": "sha512-JPaz+q3QD0/nZtHBKj5x3O7r/SgSG9kxbymdaIU0RqlDAcorJIe4KV0DFhWIdKh69q5cPVkIVERcMYGZdvXgAA==",
"requires": {}
},
"react-dom": { "react-dom": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",

View File

@@ -25,6 +25,7 @@
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
"querystring-es3": "^0.2.1", "querystring-es3": "^0.2.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-country-flag": "^3.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-flatpickr": "^3.10.7", "react-flatpickr": "^3.10.7",
"react-loader-spinner": "^5.2.0", "react-loader-spinner": "^5.2.0",

View File

@@ -32,6 +32,10 @@ const App = observer(() => {
document.querySelector('html').style.scrollBehavior = ''; document.querySelector('html').style.scrollBehavior = '';
}, [location.pathname]); // triggered on route change }, [location.pathname]); // triggered on route change
if (!store.nodeInfo.networkIdentifier) {
return <LoadingOverlay />;
}
return ( return (
<> <>
{store.loading && <LoadingOverlay />} {store.loading && <LoadingOverlay />}

View File

@@ -6,33 +6,45 @@ import { QRCodeSVG } from 'qrcode.react';
import VPNServeIcon from '../../images/vpn_server_icon.png'; import VPNServeIcon from '../../images/vpn_server_icon.png';
import { Filters } from '../../components/Filters'; import { Filters } from '../../components/Filters';
import { observer } from 'mobx-react-lite';
import ReactCountryFlag from 'react-country-flag';
const filters = { const filters = {
'View All': '', 'View All': 'all',
Active: 'Active', Active: true,
Offline: 'Offline', Offline: false,
}; };
function VPNServers() { const VPNServers = observer(() => {
const [sidebarOpen, setSidebarOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false);
const [selectedServer, setSelectedServer] = useState(0); const [selectedServer, setSelectedServer] = useState(0);
const [currentFilter, setCurrentFilter] = useState('View All'); const [currentFilter, setCurrentFilter] = useState('View All');
const servers = useMemo(() => {
if (filters[currentFilter] === 'all') return store.vpnServers;
return store.vpnServers.filter((e) => e.state === filters[currentFilter]);
}, [store.vpnServers, currentFilter]);
const qrContent = useMemo( const qrContent = useMemo(
() => ` () => `
[Interface] [Interface]
PrivateKey = ${store.vpnPrivateKey} PrivateKey = ${store.vpnPrivateKey}
Address = ${store.vpnServers?.[selectedServer]?.address} Address = ${servers?.[selectedServer]?.address}
DNS = ${store.vpnServers?.[selectedServer]?.dns} DNS = ${servers?.[selectedServer]?.dns}
[Peer] [Peer]
PublicKey = ${store.vpnServers?.[selectedServer]?.publicKey} PublicKey = ${servers?.[selectedServer]?.serverPublickKey}
AllowedIPs = 0.0.0.0/0 AllowedIPs = 0.0.0.0/0
Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint} Endpoint = ${servers?.[selectedServer]?.endpoint}
PersistentKeepalive = 25
`, `,
[store.vpnServers, store.vpnPrivateKey] [store.vpnServers, store.vpnPrivateKey, selectedServer]
); );
useEffect(() => {
setSelectedServer(0);
}, [currentFilter]);
const downloadTxtFile = () => { const downloadTxtFile = () => {
const element = document.createElement('a'); const element = document.createElement('a');
const file = new Blob([qrContent], { type: 'text/plain' }); const file = new Blob([qrContent], { type: 'text/plain' });
@@ -59,7 +71,7 @@ Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
<main> <main>
<div className="lg:relative lg:flex"> <div className="lg:relative lg:flex">
{/* Content */} {/* Content */}
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto"> <div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl">
{/* Page header */} {/* Page header */}
<div className="sm:flex sm:justify-between sm:items-center mb-5"> <div className="sm:flex sm:justify-between sm:items-center mb-5">
{/* Left: Title */} {/* Left: Title */}
@@ -79,7 +91,7 @@ Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
{/* Credit cards */} {/* Credit cards */}
<div className="space-y-2"> <div className="space-y-2">
{store.vpnServers?.map((e, i) => ( {servers?.map((e, i) => (
<label <label
className="relative block cursor-pointer text-left w-full" className="relative block cursor-pointer text-left w-full"
onClick={() => setSelectedServer(i)} onClick={() => setSelectedServer(i)}
@@ -96,28 +108,35 @@ Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
<div className="grid grid-cols-12 items-center gap-x-2"> <div className="grid grid-cols-12 items-center gap-x-2">
{/* Card */} {/* Card */}
<div className="col-span-6 order-1 sm:order-none sm:col-span-3 flex items-center space-x-4 lg:sidebar-expanded:col-span-6 xl:sidebar-expanded:col-span-3"> <div className="col-span-6 order-1 sm:order-none sm:col-span-3 flex items-center space-x-4 lg:sidebar-expanded:col-span-6 xl:sidebar-expanded:col-span-3">
<img <ReactCountryFlag
src={VPNServeIcon} countryCode={e.country}
width="36" svg
height="36" style={{ width: '36px', height: 'auto' }}
alt="VPN Country"
/> />
<div> <div>
<div className="text-sm font-medium text-slate-800"> <div className="text-sm font-medium text-slate-800">
{e.endpoint} {e.endpoint}
</div> </div>
<div className="text-xs">{e.publicKey}</div> <div className="text-xs">{e.serverPublickKey}</div>
</div> </div>
</div> </div>
{/* Card limits */} {/* Card limits */}
<div className="col-span-6 order-1 sm:order-none sm:col-span-4 text-right sm:text-center lg:sidebar-expanded:col-span-6 xl:sidebar-expanded:col-span-6"> <div className="col-span-6 order-1 sm:order-none sm:col-span-4 text-right sm:text-center lg:sidebar-expanded:col-span-6 xl:sidebar-expanded:col-span-6">
<div className="text-sm">4673,00 Mb / 473,00 Mb</div> <div className="text-sm">
{e.transferSum} / 50.00 GB
</div>
</div> </div>
{/* Card status */} {/* Card status */}
<div className="col-span-6 order-2 sm:order-none sm:col-span-2 text-right lg:sidebar-expanded:hidden xl:sidebar-expanded:block"> <div className="col-span-6 order-2 sm:order-none sm:col-span-2 text-right lg:sidebar-expanded:hidden xl:sidebar-expanded:block">
{store.vpnServers?.[selectedServer]?.state ? (
<div className="text-xs inline-flex font-medium bg-emerald-100 text-emerald-600 rounded-full text-center px-2.5 py-1"> <div className="text-xs inline-flex font-medium bg-emerald-100 text-emerald-600 rounded-full text-center px-2.5 py-1">
Active Active
</div> </div>
) : (
<div className="text-xs inline-flex font-medium bg-amber-100 text-amber-600 rounded-full text-center px-2.5 py-1">
Offline
</div>
)}
</div> </div>
</div> </div>
</div> </div>
@@ -131,6 +150,7 @@ Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
</div> </div>
{/* Sidebar */} {/* Sidebar */}
{servers?.length > 0 && (
<div> <div>
<div className="lg:sticky lg:top-16 bg-slate-50 lg:overflow-x-hidden lg:overflow-y-auto no-scrollbar lg:shrink-0 border-t lg:border-t-0 lg:border-l border-slate-200 lg:w-[390px] lg:h-[calc(100vh-64px)]"> <div className="lg:sticky lg:top-16 bg-slate-50 lg:overflow-x-hidden lg:overflow-y-auto no-scrollbar lg:shrink-0 border-t lg:border-t-0 lg:border-l border-slate-200 lg:w-[390px] lg:h-[calc(100vh-64px)]">
<div className="py-8 px-4 lg:px-8 h-full"> <div className="py-8 px-4 lg:px-8 h-full">
@@ -159,16 +179,27 @@ Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
<li className="flex items-center justify-between py-3 border-b border-slate-200"> <li className="flex items-center justify-between py-3 border-b border-slate-200">
<div className="text-sm">Server address</div> <div className="text-sm">Server address</div>
<div className="text-sm font-medium text-slate-800 ml-2"> <div className="text-sm font-medium text-slate-800 ml-2">
{store.vpnServers?.[selectedServer]?.endpoint} {servers?.[selectedServer]?.endpoint}
</div> </div>
</li> </li>
<li className="flex items-center justify-between py-3 border-b border-slate-200"> <li className="flex items-center justify-between py-3 border-b border-slate-200">
<div className="text-sm">Status</div> <div className="text-sm">Status</div>
<div className="flex items-center whitespace-nowrap"> <div className="flex items-center whitespace-nowrap">
{servers?.[selectedServer]?.state ? (
<>
<div className="w-2 h-2 rounded-full bg-emerald-500 mr-2" /> <div className="w-2 h-2 rounded-full bg-emerald-500 mr-2" />
<div className="text-sm font-medium text-slate-800"> <div className="text-sm font-medium text-slate-800">
Active Active
</div> </div>
</>
) : (
<>
<div className="w-2 h-2 rounded-full mr-2 bg-amber-500" />
<div className="text-sm font-medium text-slate-800">
Offline
</div>
</>
)}
</div> </div>
</li> </li>
</ul> </ul>
@@ -183,16 +214,18 @@ Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
<div className="flex justify-between text-sm mb-2"> <div className="flex justify-between text-sm mb-2">
<div>Spent This Month</div> <div>Spent This Month</div>
<div className="italic"> <div className="italic">
4673,00 Mb{' '} {servers?.[selectedServer]?.transferSum}{' '}
<span className="text-slate-400">/</span> 46730,00 <span className="text-slate-400">/</span> 50.00
Mb GB
</div> </div>
</div> </div>
<div className="relative w-full h-2 bg-slate-300"> <div className="relative w-full h-2 bg-slate-300">
<div <div
className="absolute inset-0 bg-indigo-500" className="absolute inset-0 bg-indigo-500"
aria-hidden="true" aria-hidden="true"
style={{ width: '10%' }} style={{
width: `${servers?.[selectedServer]?.trafficUsed}%`,
}}
/> />
</div> </div>
</div> </div>
@@ -216,11 +249,12 @@ Endpoint = ${store.vpnServers?.[selectedServer]?.endpoint}
</div> </div>
</div> </div>
</div> </div>
)}
</div> </div>
</main> </main>
</div> </div>
</div> </div>
); );
} });
export default VPNServers; export default VPNServers;

View File

@@ -3,27 +3,30 @@ import {
makeAutoObservable, makeAutoObservable,
onBecomeObserved, onBecomeObserved,
onBecomeUnobserved, onBecomeUnobserved,
} from "mobx"; } from 'mobx';
import { cryptography } from "@liskhq/lisk-client"; import { cryptography } from '@liskhq/lisk-client';
import { passphrase } from "@liskhq/lisk-client"; import { passphrase } from '@liskhq/lisk-client';
import { getNodeInfo } from "../api/node"; import { getNodeInfo } from '../api/node';
import { fetchWrapper } from "../shared/fetchWrapper"; import { fetchWrapper } from '../shared/fetchWrapper';
import { labelMap } from "../shared/labelMap"; import { labelMap } from '../shared/labelMap';
import { statusMap } from "../shared/statusMap"; import { statusMap } from '../shared/statusMap';
import { generateSvgAvatar } from "../images/GenerateOnboardingSvg/GenerateSvg"; import { generateSvgAvatar } from '../images/GenerateOnboardingSvg/GenerateSvg';
import { decryptedData } from "../utils/decryptedData"; import { decryptedData } from '../utils/decryptedData';
import { import {
bytesToMbytes,
encryptAccountData, encryptAccountData,
encryptSharedData, encryptSharedData,
formatBytes,
generateTransaction, generateTransaction,
hashAccountData, hashAccountData,
} from "../utils/Utils"; } from '../utils/Utils';
import sodium from "sodium-universal"; import sodium from 'sodium-universal';
import { countryCodes } from '../utils/countryCodes';
class Store { class Store {
_accountData = []; _accountData = [];
_passPhrase = ""; _passPhrase = '';
_nodeInfo = {}; _nodeInfo = {};
@@ -63,18 +66,18 @@ class Store {
() => this.address, () => this.address,
() => this.fetchAccountInfo() () => this.fetchAccountInfo()
); );
onBecomeObserved(this, "decryptedAccountData", () => onBecomeObserved(this, 'decryptedAccountData', () =>
this.fetchNewAccountData() this.fetchNewAccountData()
); );
onBecomeUnobserved(this, "decryptedAccountData", () => onBecomeUnobserved(this, 'decryptedAccountData', () =>
this.unobservedAccountData() this.unobservedAccountData()
); );
onBecomeObserved(this, "sharedData", () => this.fetchKeysArray()); onBecomeObserved(this, 'sharedData', () => this.fetchKeysArray());
onBecomeUnobserved(this, "sharedData", () => this.unobservedSharedData()); onBecomeUnobserved(this, 'sharedData', () => this.unobservedSharedData());
onBecomeObserved(this, "transactionsInfo", () => onBecomeObserved(this, 'transactionsInfo', () =>
this.fetchTransactionsInfo() this.fetchTransactionsInfo()
); );
onBecomeUnobserved(this, "transactionsInfo", () => onBecomeUnobserved(this, 'transactionsInfo', () =>
this.unobservedTransactionsInfo() this.unobservedTransactionsInfo()
); );
@@ -83,7 +86,7 @@ class Store {
fetchVPNServers() { fetchVPNServers() {
fetchWrapper fetchWrapper
.getAuth("vpn/servers", { .getAuth('vpn/servers', {
networkIdentifier: this.nodeInfo.networkIdentifier, networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID, lastBlockID: this.nodeInfo.lastBlockID,
}) })
@@ -97,18 +100,13 @@ class Store {
} }
fetchNewAccountData() { fetchNewAccountData() {
getNodeInfo()
.then((info) => {
this.fetchNodeInfoSuccess(info);
fetchWrapper fetchWrapper
.getAuth("data/private", { .getAuth('data/private', {
networkIdentifier: this.nodeInfo.networkIdentifier, networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID, lastBlockID: this.nodeInfo.lastBlockID,
}) })
.then((res) => this.accountDataFetchChange(res)) .then((res) => this.accountDataFetchChange(res))
.catch((err) => this.throwError(err)); .catch((err) => this.throwError(err));
})
.catch((err) => this.throwError(err));
} }
fetchAccountInfo() { fetchAccountInfo() {
@@ -123,7 +121,7 @@ class Store {
.then((info) => { .then((info) => {
this.fetchNodeInfoSuccess(info); this.fetchNodeInfoSuccess(info);
fetchWrapper fetchWrapper
.getAuth("data/shared/", { .getAuth('data/shared/', {
networkIdentifier: this.nodeInfo.networkIdentifier, networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID, lastBlockID: this.nodeInfo.lastBlockID,
}) })
@@ -144,13 +142,13 @@ class Store {
fetchTempTransactions() { fetchTempTransactions() {
fetchWrapper fetchWrapper
.get("node/transactions") .get('node/transactions')
.then((res) => this.fetchTempTransactionsSuccess(res)) .then((res) => this.fetchTempTransactionsSuccess(res))
.catch((err) => this.throwError(err)); .catch((err) => this.throwError(err));
} }
fetchPassPhrase() { fetchPassPhrase() {
this._passPhrase = sessionStorage.getItem("passPhrase") || ""; this._passPhrase = sessionStorage.getItem('passPhrase') || '';
} }
fetchSharedData() { fetchSharedData() {
@@ -173,7 +171,7 @@ class Store {
if (data.length > 0) { if (data.length > 0) {
fetchWrapper fetchWrapper
.postAuth( .postAuth(
"data/shared", 'data/shared',
{ {
networkIdentifier: this.nodeInfo.networkIdentifier, networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID, lastBlockID: this.nodeInfo.lastBlockID,
@@ -190,7 +188,7 @@ class Store {
pushAccountData(data = this.accountData) { pushAccountData(data = this.accountData) {
fetchWrapper fetchWrapper
.postAuth( .postAuth(
"data/private", 'data/private',
{ {
networkIdentifier: this.nodeInfo.networkIdentifier, networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID, lastBlockID: this.nodeInfo.lastBlockID,
@@ -221,7 +219,7 @@ class Store {
if (changed.length !== 0) signedTx = builder.update(changed); if (changed.length !== 0) signedTx = builder.update(changed);
if (signedTx) { if (signedTx) {
fetchWrapper fetchWrapper
.post("transactions", {}, signedTx) .post('transactions', {}, signedTx)
.then(() => this.fetchTempTransactions()) .then(() => this.fetchTempTransactions())
.catch((err) => this.throwError(err)); .catch((err) => this.throwError(err));
this.accountInfo.sequence.nonce++; this.accountInfo.sequence.nonce++;
@@ -240,7 +238,7 @@ class Store {
if (signedTx) { if (signedTx) {
fetchWrapper fetchWrapper
.post("transactions", {}, signedTx) .post('transactions', {}, signedTx)
.then(() => this.fetchTempTransactions()) .then(() => this.fetchTempTransactions())
.catch((err) => this.throwError(err)); .catch((err) => this.throwError(err));
this.accountInfo.sequence.nonce++; this.accountInfo.sequence.nonce++;
@@ -262,7 +260,7 @@ class Store {
if (signedTx) { if (signedTx) {
fetchWrapper fetchWrapper
.post("transactions", {}, signedTx) .post('transactions', {}, signedTx)
.then(() => this.fetchTempTransactions()) .then(() => this.fetchTempTransactions())
.catch((err) => this.throwError(err)); .catch((err) => this.throwError(err));
this.accountInfo.sequence.nonce++; this.accountInfo.sequence.nonce++;
@@ -271,12 +269,12 @@ class Store {
generatePassPhrase() { generatePassPhrase() {
this._passPhrase = passphrase.Mnemonic.generateMnemonic(); this._passPhrase = passphrase.Mnemonic.generateMnemonic();
sessionStorage.setItem("passPhrase", this._passPhrase); sessionStorage.setItem('passPhrase', this._passPhrase);
} }
savePastPassPhrase(phrase) { savePastPassPhrase(phrase) {
this._passPhrase = phrase; this._passPhrase = phrase;
sessionStorage.setItem("passPhrase", this._passPhrase); sessionStorage.setItem('passPhrase', this._passPhrase);
} }
unobservedTransactionsInfo() { unobservedTransactionsInfo() {
@@ -398,12 +396,12 @@ class Store {
} }
get firstName() { get firstName() {
return this.decryptedAccountData.find((item) => item.key === "firstname") return this.decryptedAccountData.find((item) => item.key === 'firstname')
?.value; ?.value;
} }
get lastName() { get lastName() {
return this.decryptedAccountData.find((item) => item.key === "secondname") return this.decryptedAccountData.find((item) => item.key === 'secondname')
?.value; ?.value;
} }
@@ -444,27 +442,27 @@ class Store {
let x25519_sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES); let x25519_sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES);
sodium.crypto_sign_ed25519_sk_to_curve25519( sodium.crypto_sign_ed25519_sk_to_curve25519(
x25519_sk, x25519_sk,
Buffer.from(this.privateKey, "hex") Buffer.from(this.privateKey, 'hex')
); );
return x25519_sk.toString("Base64"); return x25519_sk.toString('Base64');
} }
get pubKey() { get pubKey() {
return this.addressAndPubKey.publicKey.toString("hex"); return this.addressAndPubKey.publicKey.toString('hex');
} }
get address() { get address() {
return this.addressAndPubKey.address.toString("hex"); return this.addressAndPubKey.address.toString('hex');
} }
get tokenKey() { get tokenKey() {
const stringToSign = const stringToSign =
this.nodeInfo.networkIdentifier + this.nodeInfo.lastBlockID; this.nodeInfo.networkIdentifier + this.nodeInfo.lastBlockID;
if (!stringToSign) return ""; if (!stringToSign) return '';
const sign = cryptography const sign = cryptography
.signDataWithPassphrase(Buffer.from(stringToSign, "hex"), this.passPhrase) .signDataWithPassphrase(Buffer.from(stringToSign, 'hex'), this.passPhrase)
.toString("hex"); .toString('hex');
return this.pubKey + ":" + sign; return this.pubKey + ':' + sign;
} }
get accountIdentity() { get accountIdentity() {
@@ -598,7 +596,19 @@ class Store {
} }
get vpnServers() { get vpnServers() {
return this._vpnServers; return this._vpnServers?.map((server) => ({
...server,
transferSum: formatBytes(
Number(server.transferTx || 0) + Number(server.transferRx || 0)
),
trafficUsed: Math.floor(
((Number(server.transferTx || 0) + Number(server.transferRx || 0)) /
(50 * 1024 * 1024 * 1024)) *
100
),
state: server.state === '1',
country: countryCodes[server.country] || 'US',
}));
} }
get canVPN() { get canVPN() {
@@ -611,13 +621,13 @@ class Store {
let amount = this.processedVotes[address]; let amount = this.processedVotes[address];
if (amount) return "Pending"; if (amount) return 'Pending';
amount = this.accountSentVotes[address]; amount = this.accountSentVotes[address];
if (amount) return "Unvote"; if (amount) return 'Unvote';
return "Vote"; return 'Vote';
}; };
return this._delegates.data.map((delegate) => ({ return this._delegates.data.map((delegate) => ({

View File

@@ -139,6 +139,18 @@ export const hashValue = (value = '', seed = '') =>
Buffer.concat([Buffer.from(seed, 'utf8'), cryptography.hash(value, 'utf8')]) Buffer.concat([Buffer.from(seed, 'utf8'), cryptography.hash(value, 'utf8')])
); );
export const formatBytes = (bytes, decimals = 2) => {
if (!+bytes) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
};
export const generateTransaction = ( export const generateTransaction = (
nonce = BigInt(0), nonce = BigInt(0),
senderPublicKey = '', senderPublicKey = '',

252
src/utils/countryCodes.js Normal file
View File

@@ -0,0 +1,252 @@
export const countryCodes = {
BGD: 'BD',
BEL: 'BE',
BFA: 'BF',
BGR: 'BG',
BIH: 'BA',
BRB: 'BB',
WLF: 'WF',
BLM: 'BL',
BMU: 'BM',
BRN: 'BN',
BOL: 'BO',
BHR: 'BH',
BDI: 'BI',
BEN: 'BJ',
BTN: 'BT',
JAM: 'JM',
BVT: 'BV',
BWA: 'BW',
WSM: 'WS',
BES: 'BQ',
BRA: 'BR',
BHS: 'BS',
JEY: 'JE',
BLR: 'BY',
BLZ: 'BZ',
RUS: 'RU',
RWA: 'RW',
SRB: 'RS',
TLS: 'TL',
REU: 'RE',
TKM: 'TM',
TJK: 'TJ',
ROU: 'RO',
TKL: 'TK',
GNB: 'GW',
GUM: 'GU',
GTM: 'GT',
SGS: 'GS',
GRC: 'GR',
GNQ: 'GQ',
GLP: 'GP',
JPN: 'JP',
GUY: 'GY',
GGY: 'GG',
GUF: 'GF',
GEO: 'GE',
GRD: 'GD',
GBR: 'GB',
GAB: 'GA',
SLV: 'SV',
GIN: 'GN',
GMB: 'GM',
GRL: 'GL',
GIB: 'GI',
GHA: 'GH',
OMN: 'OM',
TUN: 'TN',
JOR: 'JO',
HRV: 'HR',
HTI: 'HT',
HUN: 'HU',
HKG: 'HK',
HND: 'HN',
HMD: 'HM',
VEN: 'VE',
PRI: 'PR',
PSE: 'PS',
PLW: 'PW',
PRT: 'PT',
SJM: 'SJ',
PRY: 'PY',
IRQ: 'IQ',
PAN: 'PA',
PYF: 'PF',
PNG: 'PG',
PER: 'PE',
PAK: 'PK',
PHL: 'PH',
PCN: 'PN',
POL: 'PL',
SPM: 'PM',
ZMB: 'ZM',
ESH: 'EH',
EST: 'EE',
EGY: 'EG',
ZAF: 'ZA',
ECU: 'EC',
ITA: 'IT',
VNM: 'VN',
SLB: 'SB',
ETH: 'ET',
SOM: 'SO',
ZWE: 'ZW',
SAU: 'SA',
ESP: 'ES',
ERI: 'ER',
MNE: 'ME',
MDA: 'MD',
MDG: 'MG',
MAF: 'MF',
MAR: 'MA',
MCO: 'MC',
UZB: 'UZ',
MMR: 'MM',
MLI: 'ML',
MAC: 'MO',
MNG: 'MN',
MHL: 'MH',
MKD: 'MK',
MUS: 'MU',
MLT: 'MT',
MWI: 'MW',
MDV: 'MV',
MTQ: 'MQ',
MNP: 'MP',
MSR: 'MS',
MRT: 'MR',
IMN: 'IM',
UGA: 'UG',
TZA: 'TZ',
MYS: 'MY',
MEX: 'MX',
ISR: 'IL',
FRA: 'FR',
IOT: 'IO',
SHN: 'SH',
FIN: 'FI',
FJI: 'FJ',
FLK: 'FK',
FSM: 'FM',
FRO: 'FO',
NIC: 'NI',
NLD: 'NL',
NOR: 'NO',
NAM: 'NA',
VUT: 'VU',
NCL: 'NC',
NER: 'NE',
NFK: 'NF',
NGA: 'NG',
NZL: 'NZ',
NPL: 'NP',
NRU: 'NR',
NIU: 'NU',
COK: 'CK',
XKX: 'XK',
CIV: 'CI',
CHE: 'CH',
COL: 'CO',
CHN: 'CN',
CMR: 'CM',
CHL: 'CL',
CCK: 'CC',
CAN: 'CA',
COG: 'CG',
CAF: 'CF',
COD: 'CD',
CZE: 'CZ',
CYP: 'CY',
CXR: 'CX',
CRI: 'CR',
CUW: 'CW',
CPV: 'CV',
CUB: 'CU',
SWZ: 'SZ',
SYR: 'SY',
SXM: 'SX',
KGZ: 'KG',
KEN: 'KE',
SSD: 'SS',
SUR: 'SR',
KIR: 'KI',
KHM: 'KH',
KNA: 'KN',
COM: 'KM',
STP: 'ST',
SVK: 'SK',
KOR: 'KR',
SVN: 'SI',
PRK: 'KP',
KWT: 'KW',
SEN: 'SN',
SMR: 'SM',
SLE: 'SL',
SYC: 'SC',
KAZ: 'KZ',
CYM: 'KY',
SGP: 'SG',
SWE: 'SE',
SDN: 'SD',
DOM: 'DO',
DMA: 'DM',
DJI: 'DJ',
DNK: 'DK',
VGB: 'VG',
DEU: 'DE',
YEM: 'YE',
DZA: 'DZ',
USA: 'US',
URY: 'UY',
MYT: 'YT',
UMI: 'UM',
LBN: 'LB',
LCA: 'LC',
LAO: 'LA',
TUV: 'TV',
TWN: 'TW',
TTO: 'TT',
TUR: 'TR',
LKA: 'LK',
LIE: 'LI',
LVA: 'LV',
TON: 'TO',
LTU: 'LT',
LUX: 'LU',
LBR: 'LR',
LSO: 'LS',
THA: 'TH',
ATF: 'TF',
TGO: 'TG',
TCD: 'TD',
TCA: 'TC',
LBY: 'LY',
VAT: 'VA',
VCT: 'VC',
ARE: 'AE',
AND: 'AD',
ATG: 'AG',
AFG: 'AF',
AIA: 'AI',
VIR: 'VI',
ISL: 'IS',
IRN: 'IR',
ARM: 'AM',
ALB: 'AL',
AGO: 'AO',
ATA: 'AQ',
ASM: 'AS',
ARG: 'AR',
AUS: 'AU',
AUT: 'AT',
ABW: 'AW',
IND: 'IN',
ALA: 'AX',
AZE: 'AZ',
IRL: 'IE',
IDN: 'ID',
UKR: 'UA',
QAT: 'QA',
MOZ: 'MZ',
};

View File

@@ -1,19 +1,19 @@
const path = require("path"); const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin"); const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require("webpack"); const webpack = require('webpack');
const plugins = [ const plugins = [
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
favicon: "./public/favicon.ico", favicon: './public/favicon.ico',
template: "./public/index.html", template: './public/index.html',
}), }),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"], Buffer: ['buffer', 'Buffer'],
}), }),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
process: "process/browser", process: 'process/browser',
}), }),
require("tailwindcss"), require('tailwindcss'),
new webpack.ContextReplacementPlugin(/sodium/, (data) => { new webpack.ContextReplacementPlugin(/sodium/, (data) => {
delete data.dependencies[0].critical; delete data.dependencies[0].critical;
return data; return data;
@@ -21,86 +21,83 @@ const plugins = [
]; ];
module.exports = (env, argv) => ({ module.exports = (env, argv) => ({
entry: "./src/main.jsx", entry: './src/main.jsx',
mode: argv.mode || "development", mode: argv.mode || 'development',
devtool: argv.mode === "production" ? false : "eval-source-map", devtool: argv.mode === 'production' ? false : 'eval-source-map',
plugins, plugins,
output: { output: {
clean: true, clean: true,
path: path.resolve(__dirname, "build"), path: path.resolve(__dirname, 'build'),
assetModuleFilename: "assets/[fullhash:12][ext]", assetModuleFilename: 'assets/[fullhash:12][ext]',
filename: "main.[fullhash:8].js", filename: 'main.[fullhash:8].js',
}, },
devServer: { devServer: {
open: true, open: true,
static: { static: {
directory: path.join(__dirname, "public"), directory: path.join(__dirname, 'public'),
}, },
compress: true, compress: true,
port: "auto", port: 'auto',
hot: true, hot: true,
client: { client: {
progress: true, progress: true,
}, },
proxy: { proxy: {
"/api/**": { '/api/**': {
target: "https://tn-alpha.idntty.org:8080/", target: 'https://tn-alpha.idntty.org:8080/',
secure: false, secure: false,
changeOrigin: true, changeOrigin: true,
}, },
}, },
}, },
ignoreWarnings: [() => false],
module: { module: {
rules: [ rules: [
{ test: /\.(html)$/, use: ["html-loader"] }, { test: /\.(html)$/, use: ['html-loader'] },
{ {
test: /\.m?jsx?$/, test: /\.m?jsx?$/,
exclude: /(node_modules|bower_components)/, exclude: /(node_modules|bower_components)/,
use: { use: {
loader: "babel-loader", loader: 'babel-loader',
}, },
}, },
{ {
test: /\.scss$/, test: /\.scss$/,
use: [ use: [
{ {
loader: "style-loader", loader: 'style-loader',
}, },
{ {
loader: "css-loader", loader: 'css-loader',
}, },
{ {
loader: "postcss-loader", loader: 'postcss-loader',
}, },
{ {
loader: "sass-loader", loader: 'sass-loader',
}, },
], ],
}, },
{ {
test: /\.(png|svg|jpg|gif)$/, test: /\.(png|svg|jpg|gif)$/,
loader: "file-loader", loader: 'file-loader',
options: { options: {
outputPath: "assets", outputPath: 'assets',
}, },
}, },
], ],
}, },
resolve: { resolve: {
extensions: [".js", ".jsx"], extensions: ['.js', '.jsx'],
fallback: { fallback: {
path: require.resolve("path-browserify"), path: require.resolve('path-browserify'),
os: require.resolve("os-browserify/browser"), os: require.resolve('os-browserify/browser'),
querystring: require.resolve("querystring-es3"), querystring: require.resolve('querystring-es3'),
crypto: require.resolve("crypto-browserify"), crypto: require.resolve('crypto-browserify'),
util: require.resolve("util/"), util: require.resolve('util/'),
stream: require.resolve("stream-browserify"), stream: require.resolve('stream-browserify'),
url: require.resolve("url/"), url: require.resolve('url/'),
buffer: require.resolve("buffer/"), buffer: require.resolve('buffer/'),
fs: false, fs: false,
}, },
}, },