├── .babelrc ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.md ├── files └── GeoLite2-City.mmdb ├── package.json ├── postcss.config.js ├── public ├── fonts │ ├── Lato-Black.ttf │ ├── Lato-BlackItalic.ttf │ ├── Lato-Bold.ttf │ ├── Lato-BoldItalic.ttf │ ├── Lato-Hairline.ttf │ ├── Lato-HairlineItalic.ttf │ ├── Lato-Italic.ttf │ ├── Lato-Light.ttf │ ├── Lato-LightItalic.ttf │ └── Lato-Regular.ttf ├── icons │ ├── Logo-ProxyScrape-colored.png │ ├── Logo-ProxyScrape-colored.svg │ ├── Logo-ProxyScrape-white.png │ ├── Logo-ProxyScrape-white.svg │ ├── icon.ico │ └── icon.png ├── index.html └── styles │ ├── Checking.postcss │ ├── Counter.postcss │ ├── Elements.postcss │ ├── Footer.postcss │ ├── Icons.postcss │ ├── Info.postcss │ ├── Input.postcss │ ├── Main.postcss │ ├── Modal.postcss │ ├── Notification.postcss │ ├── OverlayIp.postcss │ ├── OverlayJudges.postcss │ ├── Result.postcss │ ├── ResultCountries.postcss │ ├── ResultExport.postcss │ ├── ResultItemsHeader.postcss │ ├── Settings.postcss │ ├── Titlebar.postcss │ └── Update.postcss ├── src ├── actions │ ├── BlacklistActions.js │ ├── CheckingActions.js │ ├── CoreActions.js │ ├── InputActions.js │ ├── IpActions.js │ ├── JudgesActions.js │ ├── MainActions.js │ ├── OverlayIpActions.js │ ├── OverlayJudgesActions.js │ ├── ResultActions.js │ └── UpdateActions.js ├── components │ ├── BlacklistAddNew.jsx │ ├── BlacklistItem.jsx │ ├── Counter.jsx │ ├── CounterProtocol.jsx │ ├── Footer.jsx │ ├── Info.jsx │ ├── JudgesAddNew.jsx │ ├── JudgesItem.jsx │ ├── LicenseModal.jsx │ ├── Main.jsx │ ├── Notification.jsx │ ├── OverlayIp.jsx │ ├── OverlayJudges.jsx │ ├── ResultBlacklist.jsx │ ├── ResultBlacklistItem.jsx │ ├── ResultCountries.jsx │ ├── ResultCountriesItem.jsx │ ├── ResultExport.jsx │ ├── ResultItemData.jsx │ ├── ResultItemsHeader.jsx │ ├── ResultListItem.jsx │ ├── Settings.jsx │ └── ui │ │ ├── CheckIcon.jsx │ │ ├── Checkbox.jsx │ │ ├── CloseIcon.jsx │ │ ├── DocIcon.jsx │ │ ├── DropDocIcon.jsx │ │ ├── FillPlusIcon.jsx │ │ ├── GitIcon.jsx │ │ ├── LicenseIcon.jsx │ │ ├── LogoIcon.jsx │ │ ├── PlusIcon.jsx │ │ ├── SearchBarIcon.jsx │ │ ├── SearchIcon.jsx │ │ ├── SortIcon.jsx │ │ ├── TimeIcon.jsx │ │ └── XIcon.jsx ├── constants │ ├── ActionTypes.js │ ├── AppConstants.js │ ├── SettingsConstants.js │ └── UpdateConstants.js ├── containers │ ├── Blacklist.jsx │ ├── Checking.jsx │ ├── Core.jsx │ ├── Input.jsx │ ├── Ip.jsx │ ├── Judges.jsx │ ├── Main.jsx │ ├── Overlay.jsx │ ├── Result.jsx │ ├── Titlebar.jsx │ └── Update.jsx ├── core │ ├── blacklist.js │ ├── checker.js │ ├── country.js │ ├── index.js │ ├── ip.js │ ├── judges.js │ ├── misc.js │ ├── settings.js │ └── updater.js ├── index.js ├── misc │ ├── FindMixedProxies.js │ ├── array.js │ ├── other.js │ ├── regexes.js │ ├── text.js │ └── wait.js ├── renderer.dev.js ├── renderer.js └── store │ ├── index.js │ ├── reducers │ ├── blacklist.js │ ├── checking.js │ ├── core.js │ ├── index.js │ ├── input.js │ ├── ip.js │ ├── judges.js │ ├── main.js │ ├── overlay.js │ ├── result.js │ └── update.js │ └── selectors │ └── getFilteredProxies.js ├── webpack.config.base.js ├── webpack.config.main.babel.js └── webpack.config.renderer.babel.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/env", { "targets": { "electron": "20.1.3" } }], "@babel/react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-transform-runtime", ["@babel/plugin-proposal-object-rest-spread", { "useBuiltIns": false }]], 4 | "env": { 5 | "development": { 6 | "plugins": ["react-hot-loader/babel"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | public/styles/* linguist-vendored -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Additional context** 14 | Add any other context about the problem here. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: new feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | settings.proxyscrape.checker.json 4 | /public/*.js 5 | /.vscode 6 | dist 7 | package-lock.json 8 | tests 9 | yarn.lock 10 | yarn-error.log -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 assnctr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 |
5 |
6 |

7 | 8 | 9 | ![](https://cdn.proxyscrape.com/img/proxy-checker/proxy-results.png) 10 | 11 | Full description & Documentation for [Proxy Checker](https://proxyscrape.com/proxy-checker) 12 | 13 | #### ProxyScrape 14 | [Premium](https://proxyscrape.com/premium) - ProxyScrape premium 15 | [Free Proxy List](https://proxyscrape.com/free-proxy-list) - Free proxy list updated every 5 minutes 16 | -------------------------------------------------------------------------------- /files/GeoLite2-City.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/files/GeoLite2-City.mmdb -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proxyscrape-proxy-checker", 3 | "version": "1.1.0", 4 | "main": "public/main.js", 5 | "license": "MIT", 6 | "author": { 7 | "name": "ProxyScrape", 8 | "email": "support@proxyscrape.com", 9 | "url": "https://proxyscrape.com/home" 10 | }, 11 | "keywords": [ 12 | "ProxyScrape", 13 | "proxy", 14 | "checker" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/ProxyScrape/proxy-checker" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/ProxyScrape/proxy-checker/issues" 22 | }, 23 | "homepage": "https://proxyscrape.com/proxy-checker", 24 | "scripts": { 25 | "build": "run-p build:*", 26 | "build:main": "cross-env NODE_ENV=production webpack -p --config webpack.config.main.babel.js", 27 | "build:renderer": "cross-env NODE_ENV=production webpack -p --config webpack.config.renderer.babel.js", 28 | "start": "run-p start:*", 29 | "start:main": "electron --require @babel/register src/index", 30 | "start:renderer": "cross-env NODE_ENV=development webpack-dev-server -d --config webpack.config.renderer.babel.js", 31 | "package": "npm run build && electron-builder --win", 32 | "package-linux": "npm run build && electron-builder --linux", 33 | "publish": "npm run build && electron-builder --win --publish always", 34 | "publish-linux": "npm run build && electron-builder --linux --publish always" 35 | }, 36 | "devDependencies": { 37 | "@babel/cli": "^7.18.10", 38 | "@babel/core": "^7.19.1", 39 | "@babel/plugin-proposal-class-properties": "^7.18.6", 40 | "@babel/plugin-proposal-object-rest-spread": "^7.18.9", 41 | "@babel/plugin-transform-runtime": "^7.19.1", 42 | "@babel/preset-env": "^7.19.1", 43 | "@babel/preset-react": "^7.18.6", 44 | "@babel/register": "^7.18.9", 45 | "@babel/runtime": "^7.19.0", 46 | "babel-loader": "^8.2.5", 47 | "cross-env": "^7.0.3", 48 | "css-loader": "^3.2.0", 49 | "electron": "^20.1.4", 50 | "electron-builder": "^23.3.3", 51 | "electron-devtools-installer": "^3.2.0", 52 | "electron-react-devtools": "^0.5.3", 53 | "electron-updater": "^5.2.1", 54 | "fast-sort": "^3.2.0", 55 | "file-loader": "^4.2.0", 56 | "ip": "^1.1.5", 57 | "js-flock": "^3.14.0", 58 | "maxmind": "^3.1.2", 59 | "npm-run-all": "^4.1.5", 60 | "postcss-color-function": "^4.1.0", 61 | "postcss-css-variables": "^0.13.0", 62 | "postcss-easings": "^2.0.0", 63 | "postcss-loader": "^3.0.0", 64 | "postcss-preset-env": "^6.7.0", 65 | "react": "^18.2.0", 66 | "react-dom": "^18.2.0", 67 | "react-hot-loader": "^4.13.1", 68 | "react-markdown": "^4.2.2", 69 | "react-redux": "^8.0.2", 70 | "react-tabs": "^3.0.0", 71 | "redux": "^4.2.0", 72 | "redux-thunk": "^2.4.1", 73 | "request": "^2.88.2", 74 | "request-promise": "^4.2.6", 75 | "reselect": "^4.1.6", 76 | "socks-proxy-agent": "^4.0.2", 77 | "style-loader": "^1.0.0", 78 | "url-loader": "^2.1.0", 79 | "webpack": "^4.25.1", 80 | "webpack-cli": "^3.1.2", 81 | "webpack-dev-server": "^3.1.10", 82 | "axios": "^1.2.0", 83 | "electron-packager": "^17.1.1", 84 | "uuid": "^9.0.0" 85 | }, 86 | "build": { 87 | "win": { 88 | "target": [ 89 | { 90 | "target": "nsis", 91 | "arch": [ 92 | "x64", 93 | "ia32" 94 | ] 95 | }, 96 | { 97 | "target": "portable", 98 | "arch": [ 99 | "x64", 100 | "ia32" 101 | ] 102 | } 103 | ], 104 | "icon": "/public/icons/icon.ico", 105 | "artifactName": "${name}-v${version}-${arch}-${os}-installer.${ext}" 106 | }, 107 | "linux": { 108 | "icon": "./public/icons/icon.png", 109 | "target": [ 110 | "AppImage" 111 | ], 112 | "category": "Network", 113 | "artifactName": "${name}-v${version}-${arch}-${os}.${ext}" 114 | }, 115 | "publish": [ 116 | { 117 | "provider": "github", 118 | "owner": "ProxyScrape", 119 | "repo": "proxyscrape-proxy-checker", 120 | "private": false 121 | } 122 | ], 123 | "productName": "ProxyScrape Proxy Checker", 124 | "copyright": "ProxyScrape", 125 | "extraResources": [ 126 | "./files/**" 127 | ], 128 | "portable": { 129 | "artifactName": "${name}-v${version}-${arch}-${os}-portable.${ext}" 130 | }, 131 | "nsis": { 132 | "oneClick": false, 133 | "perMachine": true, 134 | "allowToChangeInstallationDirectory": true, 135 | "differentialPackage": true 136 | } 137 | }, 138 | "dependencies": { 139 | "bootstrap": "4.3.1", 140 | "electron-dl": "^3.5.0", 141 | "electron-squirrel-startup": "^1.0.0", 142 | "react-bootstrap": "^2.7.0" 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'postcss-css-variables': { 4 | variables: { 5 | '--green-color': { 6 | value: '#31bc86' 7 | }, 8 | '--blue-color': { 9 | value: '#5396d8' 10 | }, 11 | '--grey-color': { 12 | value: '#424a60' 13 | }, 14 | '--red-color': { 15 | value: '#e74856' 16 | }, 17 | '--back-black-color': { 18 | value: '#1e272e' 19 | }, 20 | '--neo-black-color': { 21 | value: '#2C3A47' 22 | }, 23 | '--white-color': { 24 | value: '#f5f6fa' 25 | }, 26 | '--white-color-back': { 27 | value: '#f0f2fa' 28 | } 29 | } 30 | }, 31 | 'postcss-preset-env': { 32 | stage: 4, 33 | features: { 34 | 'nesting-rules': true 35 | } 36 | }, 37 | 'postcss-color-function': {}, 38 | 'postcss-easings': { 39 | easings: { easeOne: 'cubic-bezier(0.23, 1, 0.32, 1)' } 40 | } 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /public/fonts/Lato-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-Black.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-BlackItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-Bold.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-BoldItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-Hairline.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-Hairline.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-HairlineItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-HairlineItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-Italic.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-Light.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-LightItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/fonts/Lato-Regular.ttf -------------------------------------------------------------------------------- /public/icons/Logo-ProxyScrape-colored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/icons/Logo-ProxyScrape-colored.png -------------------------------------------------------------------------------- /public/icons/Logo-ProxyScrape-colored.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/icons/Logo-ProxyScrape-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/icons/Logo-ProxyScrape-white.png -------------------------------------------------------------------------------- /public/icons/Logo-ProxyScrape-white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/icons/icon.ico -------------------------------------------------------------------------------- /public/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxyScrape/proxyscrape-proxy-checker/e94e876fe8d319a1112dde333a5ef7355698b63e/public/icons/icon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ProxyScrape Proxy Checker 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/styles/Checking.postcss: -------------------------------------------------------------------------------- 1 | .checking-page { 2 | position: fixed; 3 | display: flex; 4 | visibility: hidden; 5 | flex-flow: column wrap; 6 | align-items: center; 7 | justify-content: center; 8 | width: 100%; 9 | height: calc(100% - 2em); 10 | top: 2em; 11 | opacity: 0; 12 | background-color: color(var(--white-color) alpha(95%)); 13 | transition: all 0.5s easeOne; 14 | 15 | &.opened { 16 | visibility: visible; 17 | opacity: 1; 18 | } 19 | 20 | & .preparing-results { 21 | position: fixed; 22 | top: 0; 23 | left: 0; 24 | width: 100%; 25 | height: 100%; 26 | z-index: 1; 27 | display: flex; 28 | align-items: center; 29 | cursor: default; 30 | user-select: none; 31 | font-weight: 700; 32 | color: color(var(--grey-color) alpha(85%)); 33 | opacity: 0; 34 | visibility: hidden; 35 | justify-content: center; 36 | background-color: var(--white-color); 37 | transition: all 0.5s easeOne; 38 | 39 | &.active { 40 | visibility: visible; 41 | opacity: 1; 42 | } 43 | } 44 | } 45 | 46 | .container.dark .checking-page { 47 | background-color: color(var(--neo-black-color) alpha(95%)); 48 | 49 | & .preparing-results { 50 | color: #3464E0; 51 | background-color: color(var(--neo-black-color) alpha(98%)); 52 | } 53 | } -------------------------------------------------------------------------------- /public/styles/Counter.postcss: -------------------------------------------------------------------------------- 1 | .counter-container { 2 | display: flex; 3 | flex-flow: row wrap; 4 | width: 75%; 5 | max-width: 1600px; 6 | margin: auto; 7 | justify-content: center; 8 | background: #fff; 9 | border-radius: 10px; 10 | position: absolute; 11 | top: 5%; 12 | padding: 15px 25px 30px 25px; 13 | 14 | & .protocol-wrap { 15 | display: flex; 16 | width: 100%; 17 | 18 | & .protocol { 19 | display: inline-flex; 20 | margin-right: 80px; 21 | 22 | & .type { 23 | font-size: 12px; 24 | font-weight: 600; 25 | color: #757DA1; 26 | } 27 | 28 | & .count { 29 | margin-left: 20px; 30 | font-weight: 700; 31 | font-size: 13px; 32 | &:empty { 33 | padding: 0; 34 | margin-left: 0; 35 | } 36 | } 37 | } 38 | } 39 | 40 | & .progress { 41 | position: relative; 42 | width: 80%; 43 | height: 34px; 44 | margin-top: 30px; 45 | border-radius: 10px; 46 | overflow: hidden; 47 | background: #84AEFF; 48 | border: 1px solid #3464E0; 49 | 50 | & .bar { 51 | position: absolute; 52 | height: 100%; 53 | top: 0; 54 | left: 0; 55 | border-radius: 10px; 56 | transition: width 0.7s easeOne; 57 | background-color: #3464E0; 58 | } 59 | 60 | & h1 { 61 | display: flex; 62 | margin: 0; 63 | height: 100%; 64 | justify-content: center; 65 | align-items: center; 66 | position: absolute; 67 | width: 100%; 68 | font-size: 0.9em; 69 | color: var(--white-color); 70 | text-align: center; 71 | } 72 | } 73 | 74 | & button { 75 | margin: 30px 0 0 20px; 76 | width: calc(20% - 20px); 77 | } 78 | } 79 | 80 | .container.dark .counter-container { 81 | & .protocol { 82 | &.http.active { 83 | color: color(var(--grey-color) alpha(95%)); 84 | } 85 | 86 | &.socks.active { 87 | color: color(var(--grey-color) alpha(95%)); 88 | } 89 | } 90 | 91 | & .progress { 92 | & .bar { 93 | background-color: color(#ddd alpha(15%)); 94 | } 95 | 96 | & h1 { 97 | color: var(--neo-black-color); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /public/styles/Elements.postcss: -------------------------------------------------------------------------------- 1 | /* -------------------------------- 2 | Buttons section 3 | -------------------------------- */ 4 | 5 | button { 6 | font-weight: 700; 7 | font-size: 14px; 8 | border-radius: 10px; 9 | outline: 0; 10 | border: 0; 11 | cursor: pointer; 12 | padding: 0.5em 1.5em; 13 | margin-right: 2em; 14 | background-color: #3464E0; 15 | color: #fff; 16 | transition: color 0.3s easeOne, background-color 0.3s easeOne; 17 | margin-top: 20px; 18 | 19 | &.less { 20 | padding: 0; 21 | background-color: transparent; 22 | color: color(var(--blue-color) alpha(60%)); 23 | 24 | &:hover { 25 | color: #3464E0; 26 | } 27 | } 28 | 29 | &:not(.less):hover { 30 | color: color(var(--white-color) alpha(85%)); 31 | background-color: #3464E0; 32 | } 33 | } 34 | button.check-button{ 35 | width: 100%; 36 | margin-top: 20px; 37 | } 38 | 39 | /* -------------------------------- 40 | Inputs section 41 | -------------------------------- */ 42 | 43 | textarea { 44 | font-weight: 400; 45 | border-radius: 0.5em; 46 | border: 0; 47 | outline: 0; 48 | padding: 1em; 49 | width: 100%; 50 | font-size: 1em; 51 | background-color: color(var(--blue-color) alpha(5%)); 52 | color: var(--blue-color); 53 | resize: vertical; 54 | } 55 | 56 | input.field { 57 | width: 100%; 58 | border: 0; 59 | outline: 0; 60 | background-color: #84AEFF; 61 | font-weight: 600; 62 | padding: 4px 12px; 63 | border-radius: 10px; 64 | line-height: 24px; 65 | font-size: 12px; 66 | color: #fff; 67 | transition: color 0.5s easeOne, background-color 0.5s easeOne; 68 | 69 | &::-webkit-input-placeholder { 70 | color: #fff; 71 | } 72 | 73 | &:not([value='']) { 74 | background-color: #84AEFF; 75 | } 76 | 77 | &:focus { 78 | color: var(--white-color); 79 | background-color: #3464E0; 80 | 81 | &::-webkit-input-placeholder { 82 | color: transparent; 83 | } 84 | } 85 | } 86 | 87 | input[type='range'] { 88 | width: 100%; 89 | 90 | } 91 | 92 | /* -------------------------------- 93 | Checkboxes section 94 | -------------------------------- */ 95 | 96 | .checkbox { 97 | display: inline-flex; 98 | margin: auto; 99 | user-select: none; 100 | cursor: pointer; 101 | padding-top: 30px; 102 | padding-right: 2em; 103 | 104 | &:last-child { 105 | padding-right: 0; 106 | } 107 | 108 | & span.count { 109 | margin-left: 0.5em; 110 | transition: color 0.3s easeOne; 111 | color: color(var(--grey-color) alpha(25%)); 112 | } 113 | 114 | & span:not(.count) { 115 | display: inline-block; 116 | vertical-align: middle; 117 | font-weight: 900; 118 | transform: translate3d(0, 0, 0); 119 | color: #3A4368; 120 | transition: all 0.3s easeOne; 121 | 122 | &:first-child { 123 | position: relative; 124 | width: 20px; 125 | height: 20px; 126 | border-radius: 1.25em; 127 | vertical-align: middle; 128 | transition: all 0.3s easeOne; 129 | border: 1px solid #3464E0; 130 | 131 | & svg { 132 | position: absolute; 133 | top: 3px; 134 | left: 2px; 135 | fill: none; 136 | stroke: var(--white-color); 137 | stroke-width: 1.1; 138 | stroke-linecap: round; 139 | stroke-linejoin: round; 140 | stroke-dasharray: 1em; 141 | stroke-dashoffset: 1em; 142 | transition: all 0.3s easeOne; 143 | transform: translate3d(0, 0, 0); 144 | } 145 | 146 | &:before { 147 | content: ''; 148 | width: 100%; 149 | height: 100%; 150 | background-color: var(--blue-color); 151 | display: block; 152 | transform: scale(0); 153 | opacity: 1; 154 | border-radius: 50%; 155 | } 156 | } 157 | 158 | &:last-child { 159 | padding-left: 0.5em; 160 | font-size: 14px; 161 | } 162 | } 163 | 164 | &:hover span:first-child { 165 | border-color: var(--blue-color); 166 | } 167 | } 168 | 169 | .input-checkbox { 170 | display: none; 171 | } 172 | 173 | .input-checkbox:checked + .checkbox span.count { 174 | color: color(var(--grey-color) alpha(75%)); 175 | } 176 | 177 | .input-checkbox:checked + .checkbox span:not(.count) { 178 | color: #3A4368; 179 | font-size: 14px; 180 | font-weight: 700; 181 | 182 | &:first-child { 183 | background-color: #3464E0; 184 | border-color: #3464E0; 185 | 186 | & svg { 187 | stroke-dashoffset: 0; 188 | } 189 | 190 | &:before { 191 | transform: scale(3.5); 192 | opacity: 0; 193 | transition: all 0.7s easeOne; 194 | } 195 | } 196 | } 197 | 198 | .container.dark { 199 | & ::-webkit-scrollbar-thumb { 200 | background-color: color(var(--neo-black-color) alpha(75%)); 201 | } 202 | 203 | & ::-webkit-scrollbar-track { 204 | background-color: color(var(--back-black-color) alpha(15%)); 205 | } 206 | 207 | & .checkbox span:not(.count):first-child svg { 208 | stroke: color(var(--neo-black-color) alpha(75%)); 209 | } 210 | 211 | & span.count { 212 | color: color(#ddd alpha(25%)); 213 | } 214 | 215 | & .input-checkbox:checked + .checkbox span.count { 216 | color: color(#ddd alpha(65%)); 217 | } 218 | } 219 | .block-list-btn{ 220 | 221 | margin: 0; 222 | padding: 0 3px; 223 | } -------------------------------------------------------------------------------- /public/styles/Footer.postcss: -------------------------------------------------------------------------------- 1 | footer { 2 | padding-top: 30px; 3 | padding-left: 50px; 4 | padding-right: 50px; 5 | display: flex; 6 | flex-flow: row wrap; 7 | width: 100%; 8 | margin: auto; 9 | background-color: #E9F6FF; 10 | position: fixed; 11 | bottom: 0; 12 | font-size: 12px; 13 | & .links { 14 | margin-right: 1.5em; 15 | display: flex; 16 | flex-flow: row wrap; 17 | align-items: center; 18 | 19 | & a { 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | margin-right: 2em; 24 | color: color(var(--grey-color) alpha(80%)); 25 | text-decoration: none; 26 | 27 | &:hover { 28 | color: var(--grey-color); 29 | 30 | } 31 | 32 | & span { 33 | font-weight: 600; 34 | margin-left: 0.5em; 35 | transition: color 0.5s easeOne; 36 | } 37 | 38 | & svg { 39 | width: 20px; 40 | height: 20px; 41 | fill: #3464E0; 42 | transition: fill 0.5s easeOne; 43 | } 44 | } 45 | } 46 | 47 | & .get-em { 48 | display: flex; 49 | align-items: center; 50 | margin-left: auto; 51 | animation: fade-footer-get-em 0.7s easeOne both; 52 | 53 | & p { 54 | margin: 0; 55 | border-radius: 1.25em; 56 | color: var(--grey-color); 57 | 58 | & a { 59 | display: inline-flex; 60 | align-items: center; 61 | margin: 0 0.25em; 62 | text-decoration: underline; 63 | font-weight: 700; 64 | transition: color 0.5s easeOne; 65 | color: #3464E0; 66 | 67 | &:hover { 68 | color: var(--blue-color); 69 | 70 | & svg { 71 | fill: var(--blue-color); 72 | } 73 | } 74 | 75 | & svg { 76 | width: 1em; 77 | height: 1em; 78 | margin-left: 0.35em; 79 | transition: fill 0.5s easeOne; 80 | fill: color(var(--blue-color) alpha(70%)); 81 | } 82 | } 83 | } 84 | } 85 | 86 | & .ops { 87 | display: flex; 88 | width: 100%; 89 | margin: 20px auto 0 auto; 90 | padding: 10px 30px; 91 | font-weight: 600; 92 | border-top-left-radius: 10px; 93 | border-top-right-radius: 10px; 94 | position: relative; 95 | color: #f0f2fa; 96 | background: #3A4368; 97 | align-items: center; 98 | justify-content: space-between; 99 | flex-direction: row-reverse; 100 | 101 | 102 | & .d { 103 | margin-left: auto; 104 | } 105 | 106 | &:before { 107 | content: attr(data-version); 108 | color: #fff; 109 | font-size: 12px; 110 | } 111 | 112 | & a { 113 | text-decoration: none; 114 | color: #f0f2fa; 115 | transition: color 0.5s cubic-bezier(0.23, 1, 0.32, 1); 116 | font-size: 15px; 117 | font-weight: 700; 118 | 119 | &:nth-child(1):hover { 120 | color: var(--blue-color); 121 | 122 | & svg { 123 | fill: var(--blue-color); 124 | } 125 | } 126 | 127 | &:nth-child(2):hover { 128 | color: var(--blue-color); 129 | 130 | & svg { 131 | fill: var(--blue-color); 132 | } 133 | } 134 | 135 | & svg { 136 | transition: fill 0.5s easeOne; 137 | fill: var(--white-color-back); 138 | } 139 | } 140 | } 141 | } 142 | 143 | @keyframes fade-footer-get-em { 144 | from { 145 | opacity: 0; 146 | transform: translateX(15%); 147 | } 148 | to { 149 | opacity: 1; 150 | transform: translateX(0); 151 | } 152 | } 153 | 154 | .container.dark footer { 155 | & .ops:before { 156 | background-color: color(var(--back-black-color) alpha(85%)); 157 | } 158 | 159 | & .ops a { 160 | color: var(--back-black-color); 161 | 162 | &:nth-child(1):hover { 163 | color: var(--blue-color); 164 | 165 | & svg { 166 | fill: var(--blue-color); 167 | } 168 | } 169 | 170 | &:nth-child(2):hover { 171 | color: var(--blue-color); 172 | 173 | & svg { 174 | fill: var(--blue-color); 175 | } 176 | } 177 | 178 | & svg { 179 | fill: var(--back-black-color); 180 | } 181 | } 182 | 183 | & .links a { 184 | color: color(var(--blue-color) alpha(60%)); 185 | 186 | &:hover { 187 | color: #3464E0; 188 | 189 | & svg { 190 | fill: var(--blue-color); 191 | } 192 | } 193 | 194 | & svg { 195 | fill: color(var(--blue-color) alpha(60%)); 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /public/styles/Input.postcss: -------------------------------------------------------------------------------- 1 | .proxy-input { 2 | display: flex; 3 | flex-flow: column wrap; 4 | border-top: 1px solid var(--white-color-back); 5 | 6 | & section.load-file-area { 7 | display: flex; 8 | justify-content: space-between; 9 | user-select: none; 10 | margin-bottom: 20px; 11 | align-items: center; 12 | width: 76%; 13 | background: #fff; 14 | padding: 15px 25px 30px 25px; 15 | border-radius: 10px; 16 | font-size: 14px; 17 | @media screen and (max-width: 960px) { 18 | width: 100%; 19 | } 20 | 21 | & .wrap { 22 | width: calc(50% - 1em); 23 | & .title { 24 | color: #757DA1; 25 | padding-bottom: 30px; 26 | font-size: 12px; 27 | font-weight: 700; 28 | } 29 | & .text-underline{ 30 | text-decoration: underline; 31 | } 32 | & .from-clipboard { 33 | padding: 8px; 34 | border-radius: 0.5rem; 35 | font-weight: 700; 36 | color: var(--white-color); 37 | white-space: nowrap; 38 | background-color: #84AEFF; 39 | margin-bottom: 20px; 40 | cursor: pointer; 41 | text-align: center; 42 | transition: background-color 0.5s easeOne, color 0.5s easeOne; 43 | 44 | &:hover { 45 | color: color(var(--white-color) alpha(95%)); 46 | background-color: #3464E0; 47 | 48 | & svg { 49 | fill: color(var(--white-color) alpha(95%)); 50 | } 51 | } 52 | } 53 | 54 | & .select-event { 55 | min-height: 11em; 56 | display: flex; 57 | background-color: #84AEFF; 58 | justify-content: center; 59 | align-items: center; 60 | border-radius: 0.5em; 61 | color: var(--white-color); 62 | font-weight: 700; 63 | cursor: pointer; 64 | transition: background-color 0.5s easeOne, color 0.5s easeOne; 65 | 66 | &:hover { 67 | color: color(var(--white-color) alpha(95%)); 68 | background-color: #3464E0; 69 | 70 | & svg { 71 | fill: color(var(--white-color) alpha(95%)); 72 | } 73 | } 74 | 75 | & svg { 76 | fill: var(--white-color); 77 | margin-right: 1em; 78 | transition: fill 0.5s easeOne; 79 | } 80 | } 81 | } 82 | 83 | & .data { 84 | width: calc(50% - 1em); 85 | animation: fade-left 0.7s easeOne both; 86 | overflow: hidden; 87 | 88 | & .stat { 89 | margin-top: 1em; 90 | 91 | & .item { 92 | padding-bottom: 0.5em; 93 | 94 | &:last-child { 95 | padding-bottom: 0; 96 | } 97 | 98 | & div { 99 | 100 | font-size: 0.95em; 101 | 102 | 103 | 104 | white-space: nowrap; 105 | 106 | &:last-child { 107 | overflow: hidden; 108 | white-space: nowrap; 109 | text-overflow: ellipsis; 110 | } 111 | 112 | &:nth-child(1) { 113 | margin-right: 0.5em; 114 | color: #757DA1; 115 | } 116 | 117 | &:nth-child(2) { 118 | color: #3464E0; 119 | font-weight: 700; 120 | font-size: 1em; 121 | 122 | } 123 | } 124 | } 125 | } 126 | 127 | & label.checkbox { 128 | padding: 0; 129 | } 130 | } 131 | 132 | & svg.metrics-svg { 133 | width: 20px; 134 | height: 20px; 135 | margin: auto; 136 | fill: #3464E0; 137 | } 138 | 139 | & .preview { 140 | width: calc(50% - 1em); 141 | } 142 | } 143 | } 144 | 145 | @keyframes fade-left { 146 | from { 147 | opacity: 0; 148 | transform: translateX(-5%); 149 | } 150 | to { 151 | opacity: 1; 152 | transform: translateX(0); 153 | } 154 | } 155 | 156 | .container.dark .proxy-input { 157 | border-top: 1px solid color(var(--white-color) alpha(5%)); 158 | 159 | & section.load-file-area { 160 | & .from-clipboard { 161 | color: color(var(--neo-black-color) alpha(75%)); 162 | 163 | &:hover { 164 | color: color(var(--neo-black-color) alpha(95%)); 165 | } 166 | } 167 | 168 | & .select-event { 169 | color: color(var(--neo-black-color) alpha(75%)); 170 | 171 | &:hover { 172 | color: color(var(--neo-black-color) alpha(95%)); 173 | 174 | & svg { 175 | fill: color(var(--neo-black-color) alpha(95%)); 176 | } 177 | } 178 | 179 | & svg { 180 | fill: color(var(--neo-black-color) alpha(75%)); 181 | } 182 | } 183 | 184 | & .data .stat .item span { 185 | color: color(var(--neo-black-color) alpha(85%)); 186 | 187 | &:nth-child(2) { 188 | color: color(var(--blue-color) alpha(80%)); 189 | background-color: color(var(--grey-color) alpha(35%)); 190 | } 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /public/styles/Main.postcss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Lato'; 3 | font-style: normal; 4 | font-weight: 300; 5 | font-display: auto; 6 | src: local('Lato Light'), local('Lato-Light'), url('../fonts/Lato-Light.ttf') format('truetype'); 7 | } 8 | 9 | @font-face { 10 | font-family: 'Lato'; 11 | font-style: normal; 12 | font-weight: 400; 13 | font-display: auto; 14 | src: local('Lato Regular'), local('Lato-Regular'), url('../fonts/Lato-Regular.ttf') format('truetype'); 15 | } 16 | 17 | @font-face { 18 | font-family: 'Lato'; 19 | font-style: normal; 20 | font-weight: 700; 21 | font-display: auto; 22 | src: local('Lato Bold'), local('Lato-Bold'), url('../fonts/Lato-Bold.ttf') format('truetype'); 23 | } 24 | 25 | body { 26 | margin: 0; 27 | font-family: 'Lato', monospace; 28 | text-rendering: geometricPrecision; 29 | -webkit-font-smoothing: antialiased; 30 | counter-reset: items-counter; 31 | } 32 | 33 | .no-select { 34 | user-select: none; 35 | } 36 | 37 | input, 38 | textarea, 39 | button { 40 | font-family: 'Lato', monospace; 41 | text-rendering: geometricPrecision; 42 | -webkit-font-smoothing: antialiased; 43 | } 44 | 45 | *, 46 | :after, 47 | :before { 48 | -webkit-box-sizing: border-box; 49 | -moz-box-sizing: border-box; 50 | box-sizing: border-box; 51 | } 52 | 53 | #root { 54 | position: relative; 55 | overflow: hidden; 56 | } 57 | 58 | .container { 59 | background-color: var(--white-color-back); 60 | } 61 | 62 | .main-page-container { 63 | width: 100%; 64 | height: calc(100% - 2em); 65 | top: 2em; 66 | left: 0; 67 | overflow-y: hidden; 68 | overflow-x: hidden; 69 | background-color: var(--white-color-back); 70 | 71 | & .main-page-content { 72 | width: 100%; 73 | margin-bottom: 105.25px; 74 | overflow-y: auto; 75 | height: calc(100vh - 2rem - 105.25px); 76 | padding: 50px 40px 0 40px; 77 | background-color: #f5f6fa; 78 | border-radius: 0 0 1em 1em; 79 | } 80 | } 81 | 82 | .container.dark { 83 | background-color: var(--grey-color); 84 | 85 | & .main-page-container { 86 | background-color: var(--back-black-color); 87 | 88 | & .main-page-content { 89 | background-color: var(--neo-black-color); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /public/styles/Modal.postcss: -------------------------------------------------------------------------------- 1 | .modal-info-wrap { 2 | position: fixed; 3 | width: 100%; 4 | height: calc(100% - 2em); 5 | top: 2em; 6 | left: 0; 7 | opacity: 0; 8 | visibility: hidden; 9 | overflow: auto; 10 | z-index: 5; 11 | background: rgba(0, 0, 0, 0.5); 12 | transition: opacity 0.7s easeOne, visibility 0.7s easeOne; 13 | 14 | &.active { 15 | opacity: 1; 16 | visibility: visible; 17 | 18 | & .modal-content { 19 | transform: translateX(0); 20 | opacity: 1; 21 | } 22 | } 23 | 24 | & .modal-content { 25 | 26 | width: 80%; 27 | position: absolute; 28 | transition: transform 0.5s easeOne, opacity 0.5s easeOne; 29 | transform: translateX(50px); 30 | opacity: 1; 31 | background: #fff; 32 | padding: 6em 2em 2em 2em; 33 | top: 5%; 34 | left: 10%; 35 | border-radius: 10px; 36 | 37 | & .close-svg { 38 | width: 20px; 39 | height: 20px; 40 | margin-right: 0.5em; 41 | fill: #3464E0; 42 | position:absolute; 43 | right: 20px; 44 | top: 20px; 45 | 46 | &:hover { 47 | cursor: pointer; 48 | } 49 | } 50 | 51 | & .section { 52 | align-items: center; 53 | margin: 0 auto 2em auto; 54 | float: left; 55 | color: #3A4368; 56 | font-size: 14px; 57 | &.rel { 58 | margin-top: 6em; 59 | } 60 | 61 | & svg { 62 | width: 3em; 63 | height: 3em; 64 | margin-right: 0.5em; 65 | fill: #3464E0; 66 | } 67 | & .title{ 68 | display:flex; 69 | font-size: 12px; 70 | } 71 | & .title-name{ 72 | font-size: 16px; 73 | font-weight: 700; 74 | color: black; 75 | } 76 | 77 | & .content{ 78 | margin-top: 20px; 79 | } 80 | & .item-list{ 81 | display: flex; 82 | padding: 3px; 83 | 84 | & div{ 85 | margin-top: -3px; 86 | } 87 | } 88 | } 89 | & .section-description{ 90 | width: 30%; 91 | 92 | } 93 | & .section-permissions{ 94 | width: 20%; 95 | margin-left: 5%; 96 | 97 | & svg { 98 | width: 20px; 99 | height: 20px; 100 | min-width: 20px; 101 | margin-right: 8px; 102 | fill: none; 103 | stroke: #3464E0; 104 | stroke-width: 1.5; 105 | stroke-linecap: round; 106 | stroke-linejoin: round; 107 | stroke-dashoffset: 10px; 108 | } 109 | } 110 | & .section-limitations{ 111 | width: 15%; 112 | margin-left: 5%; 113 | & svg { 114 | width: 20px; 115 | height: 20px; 116 | min-width: 20px; 117 | margin-right: 8px; 118 | fill: #3A4368; 119 | } 120 | } 121 | & .section-conditions{ 122 | width: 20%; 123 | margin-left: 5%; 124 | & svg { 125 | width: 20px; 126 | height: 20px; 127 | min-width: 20px; 128 | margin-right: 8px; 129 | fill: #3464E0; 130 | } 131 | } 132 | 133 | & .section-footer{ 134 | overflow-y: scroll; 135 | padding: 25px; 136 | margin-top: 20px; 137 | max-height: 250px; 138 | background: #3A4368; 139 | color: #fff; 140 | border-radius: 10px; 141 | } 142 | 143 | } 144 | } -------------------------------------------------------------------------------- /public/styles/Notification.postcss: -------------------------------------------------------------------------------- 1 | .modal-notification-wrap { 2 | position: fixed; 3 | width: 350px; 4 | height: 150px; 5 | bottom: 50px; 6 | right: 50px; 7 | opacity: 0; 8 | visibility: hidden; 9 | overflow: auto; 10 | z-index: 5; 11 | background: #c1c1c1; 12 | border-radius: 10px; 13 | transition: opacity 0.7s easeOne, visibility 0.7s easeOne; 14 | padding: 10px 20px 0 20px; 15 | 16 | &.active { 17 | opacity: 1; 18 | visibility: visible; 19 | 20 | } 21 | 22 | & .modal-header{ 23 | padding: 10px; 24 | } 25 | & .close-svg { 26 | width: 20px; 27 | with: 20px; 28 | position: absolute; 29 | top: 10px; 30 | right: 20px; 31 | fill: #3464E0; 32 | cursor: pointer; 33 | } 34 | & .modal-content { 35 | font-size: 14px; 36 | } 37 | 38 | & .modal-footer { 39 | & button{ 40 | margin-right: 0; 41 | } 42 | 43 | & .disable-check{ 44 | cursor: pointer; 45 | padding: 7px 20px; 46 | font-size: 14px; 47 | text-align: center; 48 | } 49 | } 50 | 51 | 52 | } -------------------------------------------------------------------------------- /public/styles/OverlayIp.postcss: -------------------------------------------------------------------------------- 1 | .ip-lookup { 2 | position: fixed; 3 | visibility: hidden; 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | opacity: 0; 8 | width: 100%; 9 | height: calc(100% - 2em); 10 | top: 2em; 11 | left: 0; 12 | transition: visibility 0.5s easeOne, opacity 0.5s easeOne; 13 | background-color: color(var(--white-color) alpha(85%)); 14 | 15 | &.opened { 16 | visibility: visible; 17 | opacity: 1; 18 | } 19 | 20 | & .checking-status { 21 | font-weight: 700; 22 | color: var(--white-color); 23 | 24 | & svg { 25 | margin: 1.25em; 26 | fill: color(var(--blue-color) alpha(65%)); 27 | width: 1.5em; 28 | height: 1.5em; 29 | } 30 | 31 | &.done { 32 | & .ip-address { 33 | opacity: 1; 34 | transform: translateY(0); 35 | } 36 | } 37 | 38 | & .ip-address { 39 | opacity: 0; 40 | padding: 1em 2em; 41 | border-radius: 1.5em; 42 | background-color: color(var(--blue-color) alpha(35%)); 43 | transform: translateY(-10%); 44 | transition: opacity 0.87s easeOne, transform 0.87s easeOne; 45 | } 46 | } 47 | } 48 | 49 | .container.dark .ip-lookup { 50 | background-color: color(var(--neo-black-color) alpha(95%)); 51 | 52 | & .ip-address { 53 | color: color(var(--neo-black-color) alpha(85%)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /public/styles/OverlayJudges.postcss: -------------------------------------------------------------------------------- 1 | .ping-judges-container { 2 | position: fixed; 3 | display: flex; 4 | flex-flow: column nowrap; 5 | align-items: center; 6 | padding: 2em; 7 | width: 100%; 8 | height: calc(100% - 2em); 9 | top: 2em; 10 | left: 0; 11 | overflow-y: auto; 12 | background-color: color(var(--white-color) alpha(95%)); 13 | transition: opacity 0.7s easeOne, visibility 0.7s easeOne, z-index 0.7s easeOne; 14 | opacity: 0; 15 | visibility: hidden; 16 | z-index: -1; 17 | 18 | &.opened { 19 | opacity: 1; 20 | z-index: 3; 21 | visibility: visible; 22 | 23 | & .ping-judges-content { 24 | visibility: visible; 25 | opacity: 1; 26 | transform: translateY(0%); 27 | } 28 | } 29 | 30 | & .ping-judges-content { 31 | width: 80%; 32 | opacity: 0; 33 | transform: translateY(-10%); 34 | background: #fff; 35 | border-radius: 10px; 36 | padding: 15px 25px 10px 25px; 37 | 38 | & .ping-progress { 39 | display: inline-flex; 40 | font-size: 12px; 41 | font-weight: 600; 42 | user-select: none; 43 | border-radius: 10px; 44 | border: 1px solid transparent; 45 | color: #757DA1; 46 | 47 | & .ping-counter { 48 | padding: 0 20px; 49 | font-size: 13px; 50 | font-weight: 700; 51 | color: #3A4368; 52 | } 53 | } 54 | 55 | & .items { 56 | margin-top: 30px; 57 | } 58 | 59 | & .item { 60 | font-size: 14px; 61 | display: flex; 62 | flex-flow: row wrap; 63 | padding: 1.15em 0; 64 | height: 4em; 65 | align-items: center; 66 | font-weight: 700; 67 | transition: color 0.7s easeOne; 68 | color: color(var(--grey-color) alpha(65%)); 69 | border-bottom: 1px dotted #C1C1C1; 70 | 71 | & svg { 72 | width: 24px; 73 | height: 24px; 74 | margin-right: 0.75em; 75 | fill: color(var(--grey-color) alpha(65%)); 76 | transition: fill 0.7s easeOne; 77 | } 78 | 79 | &.success { 80 | color: #3464E0; 81 | 82 | & svg { 83 | fill: #3464E0; 84 | } 85 | 86 | & .response { 87 | color: var(--white-color); 88 | background-color: #3464E0; 89 | } 90 | } 91 | 92 | &.error { 93 | color: #3A4368; 94 | 95 | & svg { 96 | fill: #3A4368; 97 | } 98 | 99 | & .response { 100 | color: var(--white-color); 101 | background-color: #3A4368; 102 | } 103 | } 104 | 105 | &:last-child { 106 | border-bottom: none; 107 | } 108 | 109 | & .url { 110 | white-space: nowrap; 111 | overflow: hidden; 112 | text-overflow: ellipsis; 113 | margin-top: -9px; 114 | } 115 | 116 | & .status { 117 | margin-left: auto; 118 | 119 | & svg path { 120 | fill: color(var(--grey-color) alpha(65%)); 121 | } 122 | 123 | & .response { 124 | display: inline-block; 125 | padding: 2px 20px; 126 | border-radius: 10px; 127 | font-size: 12px; 128 | line-height: 24px; 129 | font-weight: 700; 130 | animation: fade-judge-status 0.7s easeOne; 131 | text-align: center; 132 | } 133 | } 134 | } 135 | } 136 | } 137 | 138 | @keyframes fade-judge-status { 139 | from { 140 | opacity: 0; 141 | transform: translateY(50%); 142 | } 143 | to { 144 | opacity: 1; 145 | transform: translateY(0); 146 | } 147 | } 148 | 149 | .container.dark .ping-judges-container { 150 | background-color: color(var(--neo-black-color) alpha(95%)); 151 | 152 | & .ping-judges-content { 153 | & .ping-progress { 154 | color: color(#ddd alpha(50%)); 155 | background-color: #fff; 156 | } 157 | 158 | & .items { 159 | border-top: 1px solid color(var(--white-color) alpha(5%)); 160 | } 161 | 162 | & .item { 163 | color: color(#ddd alpha(50%)); 164 | border-bottom: 1px solid color(var(--white-color) alpha(5%)); 165 | 166 | &:last-child { 167 | border-bottom: none; 168 | } 169 | 170 | & svg { 171 | fill: color(#ddd alpha(50%)); 172 | } 173 | 174 | &.success { 175 | color: color(var(--blue-color) alpha(65%)); 176 | 177 | & svg { 178 | fill: color(var(--blue-color) alpha(65%)); 179 | } 180 | } 181 | 182 | &.error { 183 | color: color(var(--red-color) alpha(65%)); 184 | 185 | & svg { 186 | fill: color(var(--red-color) alpha(65%)); 187 | } 188 | } 189 | } 190 | 191 | & .response { 192 | color: color(var(--neo-black-color) alpha(85%)); 193 | } 194 | 195 | & .status svg path { 196 | fill: color(#ddd alpha(50%)); 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /public/styles/ResultItemsHeader.postcss: -------------------------------------------------------------------------------- 1 | .result-container .result-list-header { 2 | display: flex; 3 | flex-flow: row nowrap; 4 | align-items: center; 5 | color: #757DA2; 6 | font-weight: 600; 7 | font-size: 12px; 8 | line-height: 24px; 9 | user-select: none; 10 | margin: 35px 0; 11 | 12 | & span { 13 | white-space: nowrap; 14 | text-overflow: ellipsis; 15 | 16 | &.main { 17 | display: flex; 18 | flex-flow: row nowrap; 19 | align-content: center; 20 | align-items: center; 21 | cursor: pointer; 22 | height: 4em; 23 | 24 | & span { 25 | transition: color 0.3s easeOne; 26 | } 27 | 28 | & svg.sort-svg { 29 | opacity: 0; 30 | transform: translateY(-35%); 31 | margin-left: 0.75em; 32 | transition: opacity 0.5s easeOne, transform 0.5s easeOne; 33 | } 34 | 35 | &:hover { 36 | color: #3464E0; 37 | 38 | & svg.sort-svg { 39 | opacity: 1; 40 | transform: translateY(0%); 41 | 42 | & path { 43 | fill: #3464E0; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | & svg.count { 51 | width: 1.25em; 52 | height: 1.25em; 53 | fill: color(var(--grey-color) alpha(75%)); 54 | } 55 | 56 | & svg { 57 | width: 1em; 58 | height: 1em; 59 | 60 | & path, 61 | & rect { 62 | transition: fill 0.5s easeOne; 63 | fill: color(var(--grey-color) alpha(75%)); 64 | } 65 | } 66 | 67 | & .blacklist svg, 68 | & .timeout svg { 69 | width: 1.5em; 70 | height: 1.5em; 71 | } 72 | 73 | & .count { 74 | width: 5%; 75 | height: 4em; 76 | display: flex; 77 | align-items: center; 78 | } 79 | 80 | & .ip { 81 | width: 15%; 82 | } 83 | 84 | & .port { 85 | width: 10%; 86 | } 87 | 88 | & .protocols { 89 | width: 12.5%; 90 | } 91 | 92 | & .anon { 93 | width: 12.5%; 94 | } 95 | 96 | & .country { 97 | width: 20%; 98 | } 99 | 100 | & .empty-blacklist-placeholder { 101 | width: 5%; 102 | } 103 | 104 | & .blacklist { 105 | width: 5%; 106 | height: 4em; 107 | cursor: pointer; 108 | display: flex; 109 | align-items: center; 110 | 111 | &:hover { 112 | & svg path:nth-child(1) { 113 | fill: #f3705a; 114 | } 115 | 116 | & svg path:nth-child(2) { 117 | fill: #ffd15c; 118 | } 119 | } 120 | } 121 | 122 | & .empty-keep-alive-placeholder { 123 | width: 5%; 124 | } 125 | 126 | & .k-a { 127 | width: 5%; 128 | 129 | & svg { 130 | width: 20px; 131 | height: 20px; 132 | 133 | & path:nth-child(2) { 134 | fill: color(var(--grey-color) alpha(65%)); 135 | } 136 | } 137 | 138 | &:hover path:nth-child(1) { 139 | fill: color(var(--blue-color) alpha(25%)); 140 | } 141 | } 142 | 143 | & .server { 144 | width: 7.5%; 145 | } 146 | 147 | & .timeout { 148 | width: 7.5%; 149 | margin-left: auto; 150 | 151 | & svg { 152 | margin-left: auto; 153 | } 154 | 155 | &:hover { 156 | & svg path:nth-child(1) { 157 | fill: #7383bf; 158 | } 159 | 160 | & svg path:nth-child(2), 161 | & svg rect:nth-child(3), 162 | & svg rect:nth-child(5) { 163 | fill: #424a60; 164 | } 165 | 166 | & svg path:nth-child(4), 167 | & svg path:nth-child(6) { 168 | fill: #556080; 169 | } 170 | 171 | & svg path:nth-child(7), 172 | & svg path:nth-child(8) { 173 | fill: #7fabda; 174 | } 175 | } 176 | } 177 | } 178 | 179 | .container.dark .result-container .result-list-header { 180 | border-top: 1px solid color(var(--white-color) alpha(5%)); 181 | 182 | & span.main { 183 | color: color(#ddd alpha(65%)); 184 | 185 | &:hover { 186 | color: #3464E0; 187 | } 188 | } 189 | 190 | & svg.count { 191 | width: 1.25em; 192 | height: 1.25em; 193 | fill: color(#ddd alpha(65%)); 194 | } 195 | 196 | & svg { 197 | & path, 198 | & rect { 199 | fill: color(#ddd alpha(65%)); 200 | } 201 | } 202 | 203 | & .k-a svg path:nth-child(2) { 204 | fill: color(var(--grey-color) alpha(95%)); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /public/styles/Titlebar.postcss: -------------------------------------------------------------------------------- 1 | .titlebar { 2 | background-color: var(--white-color-back); 3 | height: 2em; 4 | display: flex; 5 | align-items: center; 6 | position: relative; 7 | z-index: 5; 8 | -webkit-app-region: drag; 9 | user-select: none; 10 | padding-left: 1em; 11 | color: var(--grey-color); 12 | 13 | &.dark { 14 | background-color: var(--back-black-color); 15 | } 16 | 17 | & svg { 18 | color: #4888C7; 19 | fill: #4888C7; 20 | } 21 | 22 | & span.title { 23 | font-size: 15px; 24 | display: inline-flex; 25 | animation: color-change 6s infinite; 26 | font-weight: 700; 27 | } 28 | 29 | & .misc { 30 | display: flex; 31 | align-items: center; 32 | height: 100%; 33 | margin-left: auto; 34 | } 35 | & ul.buttons { 36 | display: flex; 37 | list-style: none; 38 | height: 100%; 39 | position: absolute; 40 | right: 0; 41 | 42 | & svg { 43 | height: 0.75em; 44 | 45 | &.minimize { 46 | padding: 0.15em; 47 | } 48 | } 49 | 50 | & li { 51 | align-items: center; 52 | display: flex; 53 | justify-content: center; 54 | -webkit-app-region: no-drag; 55 | width: 3em; 56 | 57 | &:hover { 58 | background-color: color(var(--grey-color) a(5%)); 59 | } 60 | 61 | &:nth-child(3):hover { 62 | background-color: color(var(--red-color)); 63 | 64 | & svg polygon { 65 | fill: var(--white-color-back) !important; 66 | } 67 | } 68 | } 69 | } 70 | 71 | &.dark ul.buttons li { 72 | &:hover { 73 | background-color: color(var(--grey-color) a(35%)) !important; 74 | } 75 | 76 | &:nth-child(3):hover { 77 | background-color: color(var(--red-color)) !important; 78 | 79 | & svg polygon { 80 | fill: var(--back-black-color) !important; 81 | } 82 | } 83 | } 84 | } 85 | 86 | @keyframes color-change { 87 | 0% { 88 | color: #3A4368; 89 | fill: #3A4368; 90 | } 91 | 50% { 92 | color: #5396d8; 93 | fill: #5396d8; 94 | } 95 | 100% { 96 | color: #4888C7; 97 | fill: #4888C7; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /public/styles/Update.postcss: -------------------------------------------------------------------------------- 1 | .update-notify { 2 | position: fixed; 3 | width: 100%; 4 | display: flex; 5 | flex-flow: column nowrap; 6 | align-items: center; 7 | justify-content: center; 8 | left: 0; 9 | height: calc(100% - 2em); 10 | top: 2em; 11 | overflow: auto; 12 | opacity: 1; 13 | transition: opacity 0.7s easeOne, visibility 0.7s easeOne; 14 | background-color: var(--white-color-back); 15 | 16 | &.closed { 17 | opacity: 0; 18 | visibility: hidden; 19 | } 20 | 21 | &.checking { 22 | width: 100%; 23 | height: 100%; 24 | left: 0; 25 | top: 0; 26 | 27 | & .lds-ripple { 28 | opacity: 1; 29 | } 30 | } 31 | 32 | & .lds-ripple { 33 | opacity: 0; 34 | position: fixed; 35 | width: 58px; 36 | height: 58px; 37 | left: calc(50% - 29px); 38 | top: calc(50% - 29px); 39 | border-radius: 100%; 40 | 41 | & div { 42 | position: absolute; 43 | border: 4px solid color(var(--blue-color) alpha(80%)); 44 | opacity: 1; 45 | border-radius: 50%; 46 | animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite; 47 | 48 | &:nth-child(2) { 49 | animation-delay: -0.5s; 50 | } 51 | } 52 | } 53 | 54 | & .transition-wrap { 55 | animation: fade-one 0.7s easeOne; 56 | 57 | & .update-container { 58 | width: 300px; 59 | align-items: center; 60 | justify-content: center; 61 | transform: translateY(0); 62 | border-radius: 0.75em; 63 | background-color: var(--white-color); 64 | background: #E9F6FE; 65 | opacity: 1; 66 | transition: transform 0.7s easeOne; 67 | padding: 2em; 68 | animation: background-color-change 6s infinite; 69 | 70 | & a { 71 | font-weight: 700; 72 | text-decoration: none; 73 | color: color(var(--blue-color) alpha(75%)); 74 | background-color: color(var(--blue-color) alpha(25%)); 75 | transition: color 0.7s easeOne, background-color 0.7s easeOne; 76 | border-radius: 1.25em; 77 | padding: 0.5em 1.25em; 78 | 79 | &:hover { 80 | color: var(--white-color); 81 | background-color: color(var(--blue-color) alpha(80%)); 82 | } 83 | } 84 | 85 | & svg { 86 | width: 1.75em; 87 | height: 1.75em; 88 | margin-right: 0.75em; 89 | fill: var(--white-color); 90 | } 91 | 92 | & span { 93 | padding: 0.25em 1em; 94 | border-radius: 1em; 95 | font-weight: 700; 96 | background: linear-gradient(107deg, color(var(--white-color) alpha(10%)), transparent); 97 | color: var(--white-color); 98 | } 99 | 100 | & .update-info{ 101 | display: block; 102 | width: 100%; 103 | padding: 10px 0; 104 | color: #424a60; 105 | font-size: 1rem; 106 | } 107 | 108 | & .update-label{ 109 | font-size: .75rem; 110 | } 111 | 112 | & .update-progress{ 113 | display: block; 114 | width: 100%; 115 | position: relative; 116 | 117 | & .progress { 118 | display: flex; 119 | overflow: hidden; 120 | font-size: .75rem; 121 | background-color: #e9ecef; 122 | border-radius: 0.25rem; 123 | 124 | & .progress-bar { 125 | display: flex; 126 | flex-direction: column; 127 | justify-content: center; 128 | color: #ffffff; 129 | text-align: center; 130 | white-space: nowrap; 131 | background-color: #3464E0; 132 | transition: width .6s ease; 133 | } 134 | } 135 | } 136 | } 137 | } 138 | } 139 | 140 | @keyframes lds-ripple { 141 | 0% { 142 | top: 28px; 143 | left: 28px; 144 | width: 0; 145 | height: 0; 146 | opacity: 1; 147 | } 148 | 100% { 149 | top: -1px; 150 | left: -1px; 151 | width: 58px; 152 | height: 58px; 153 | opacity: 0; 154 | } 155 | } 156 | 157 | @keyframes background-color-change { 158 | 0% { 159 | background-color: color(var(--blue-color) alpha(35%)); 160 | } 161 | 50% { 162 | background-color: color(var(--blue-color) alpha(35%)); 163 | } 164 | 100% { 165 | background-color: color(var(--blue-color) alpha(35%)); 166 | } 167 | } 168 | 169 | .container.dark .update-notify { 170 | background-color: var(--back-black-color); 171 | } 172 | -------------------------------------------------------------------------------- /src/actions/BlacklistActions.js: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron'; 2 | import { BLACKLIST_CHANGE_ITEM_PATH, BLACKLIST_ADD_ITEM, BLACKLIST_REMOVE_ITEM, BLACKLIST_TOGGLE_OPTION, BLACKLIST_SET_ACTIVE_ITEM } from '../constants/ActionTypes'; 3 | 4 | export const changePath = (title, path) => ({ 5 | type: BLACKLIST_CHANGE_ITEM_PATH, 6 | title, 7 | path 8 | }); 9 | 10 | export const selectPath = title => async dispatch => { 11 | const path = await ipcRenderer.invoke('choose-path', 'open'); 12 | 13 | if (path) { 14 | dispatch(changePath(title, path)); 15 | } 16 | }; 17 | 18 | export const add = (title, path) => ({ 19 | type: BLACKLIST_ADD_ITEM, 20 | title, 21 | path 22 | }); 23 | 24 | export const setActive = (title, active) => ({ 25 | type: BLACKLIST_SET_ACTIVE_ITEM, 26 | title, 27 | active 28 | }); 29 | 30 | export const remove = title => ({ 31 | type: BLACKLIST_REMOVE_ITEM, 32 | title 33 | }); 34 | 35 | export const toggleOption = e => ({ 36 | type: BLACKLIST_TOGGLE_OPTION, 37 | target: e.target.name 38 | }); 39 | -------------------------------------------------------------------------------- /src/actions/CheckingActions.js: -------------------------------------------------------------------------------- 1 | import Core from '../core'; 2 | import Judges from '../core/judges'; 3 | import { wait } from '../misc/wait'; 4 | import { shuffle } from '../misc/array'; 5 | import { isURL, isIP, isPath } from '../misc/regexes'; 6 | import { IpLookup } from './OverlayIpActions'; 7 | import Blacklist from '../core/blacklist'; 8 | import { CHECKING_UP_COUNTER_STATUS, CHECKING_OPEN, CHECKING_OTHER_CHANGES } from '../constants/ActionTypes'; 9 | 10 | const validateJudges = (judges, targetProtocols) => { 11 | if (targetProtocols.includes('https') && !judges.some(({ url }) => url.match(/https:\/\//))) { 12 | throw new Error('You have no judges for HTTPS'); 13 | } 14 | 15 | if (targetProtocols.some(protocol => ['http'].includes(protocol)) && !judges.some(({ url }) => !url.match(/https:\/\//))) { 16 | throw new Error('You have no judges for HTTP'); 17 | } 18 | 19 | if (judges.filter(({ active }) => active).length == 0) { 20 | throw new Error('You have no active judges'); 21 | } 22 | 23 | if (judges.every(({ url }) => isURL(url))) { 24 | return true; 25 | } 26 | 27 | throw new Error('Judge URL is not correct'); 28 | }; 29 | 30 | const validateBlacklist = items => { 31 | if (items.every(({ path }) => isURL(path) || isPath(path))) { 32 | return true; 33 | } 34 | 35 | throw new Error('Blacklist path must be an local path or URL'); 36 | }; 37 | 38 | const validateInput = list => { 39 | if (list.length > 0) { 40 | return true; 41 | } 42 | 43 | throw new Error('No proxies found'); 44 | }; 45 | 46 | const transformProtocols = protocols => { 47 | const enabledProtocols = Object.keys(protocols).filter(protocol => protocols[protocol]); 48 | 49 | if (enabledProtocols.length > 0) { 50 | return enabledProtocols; 51 | } 52 | 53 | throw new Error('Select protocols'); 54 | }; 55 | 56 | export const start = () => async (dispatch, getState) => { 57 | try { 58 | const { core, judges, blacklist, ip, input, checking, overlay } = getState(); 59 | 60 | if (overlay.judges.locked || overlay.ip.locked || checking.isOpened) { 61 | return; 62 | } 63 | 64 | const protocols = transformProtocols(core.protocols); 65 | const activeJudges = judges.items.filter(item => item.active); 66 | 67 | validateInput(input.list); 68 | validateJudges(activeJudges, protocols); 69 | 70 | if (blacklist.filter) { 71 | validateBlacklist(blacklist.items); 72 | } 73 | 74 | const proxyList = core.shuffle ? shuffle([...input.list]) : [...input.list]; 75 | const initBlacklist = blacklist.filter ? await new Blacklist(blacklist.items) : false; 76 | const initJudges = await new Judges({ swap: judges.swap, items: activeJudges }, protocols); 77 | 78 | if (!initJudges) return; 79 | 80 | const chainCheck = ip => Core.start(proxyList, core, initJudges, protocols, ip, initBlacklist); 81 | 82 | if (isIP(ip.current)) { 83 | chainCheck(ip.current); 84 | } else { 85 | dispatch(IpLookup(chainCheck)); 86 | } 87 | } catch (error) { 88 | alert(error); 89 | } 90 | }; 91 | 92 | export const stop = () => async (dispatch, getState) => { 93 | const { checking } = getState(); 94 | 95 | if (checking.preparing) { 96 | return; 97 | } 98 | 99 | dispatch( 100 | otherChanges({ 101 | preparing: true 102 | }) 103 | ); 104 | 105 | await wait(300); 106 | 107 | Core.stop(); 108 | }; 109 | 110 | export const otherChanges = state => ({ 111 | type: CHECKING_OTHER_CHANGES, 112 | state 113 | }); 114 | 115 | export const openChecking = counter => ({ 116 | type: CHECKING_OPEN, 117 | counter 118 | }); 119 | 120 | export const upCounterStatus = counter => ({ 121 | type: CHECKING_UP_COUNTER_STATUS, 122 | counter 123 | }); 124 | -------------------------------------------------------------------------------- /src/actions/CoreActions.js: -------------------------------------------------------------------------------- 1 | import { CORE_CHANGE_OPTION, CORE_TOGGLE_OPTION, CORE_TOGGLE_PROTOCOL } from '../constants/ActionTypes'; 2 | import { getMaxThreads } from '../misc/other'; 3 | 4 | export const changeOption = e => ({ 5 | type: CORE_CHANGE_OPTION, 6 | target: e.target.name, 7 | value: e.target.value 8 | }); 9 | 10 | export const toggleOption = e => ({ 11 | type: CORE_TOGGLE_OPTION, 12 | target: e.target.name 13 | }); 14 | 15 | export const toggleProtocol = e => (dispatch, getState) => { 16 | dispatch({ 17 | type: CORE_TOGGLE_PROTOCOL, 18 | protocol: e.target.name 19 | }); 20 | 21 | const { core } = getState(); 22 | const maxThreads = getMaxThreads(core.protocols); 23 | 24 | if (core.threads > maxThreads) { 25 | dispatch( 26 | changeOption({ 27 | target: { 28 | name: 'threads', 29 | value: maxThreads 30 | } 31 | }) 32 | ); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/actions/InputActions.js: -------------------------------------------------------------------------------- 1 | import findMixedProxies from '../misc/FindMixedProxies.js'; 2 | import { readFile } from 'fs/promises'; 3 | import { ipcRenderer } from 'electron'; 4 | import { uniq } from '../misc/array'; 5 | import { INPUT_SET_LOADED_FILE_DATA } from '../constants/ActionTypes'; 6 | import { parse } from 'path'; 7 | 8 | export const setLoadedData = nextState => ({ 9 | type: INPUT_SET_LOADED_FILE_DATA, 10 | nextState 11 | }); 12 | 13 | const getResult = (text, event, getState) => { 14 | try { 15 | // if (event.ctrlKey) { 16 | // const { input } = getState(); 17 | 18 | // const totalLines = text.split(/\r?\n/).filter(item => item.length > 0); 19 | // const uniqueLines = uniq([...totalLines, ...input.list]); 20 | // console.log(uniqueLines); 21 | // const { successed: list, failed: errors } = findMixedProxies(uniqueLines); 22 | 23 | // return { 24 | // list, 25 | // errors, 26 | // total: totalLines.length + input.list.length, 27 | // unique: uniqueLines.length 28 | // }; 29 | // } 30 | 31 | const totalLines = text.split(/\r?\n/).filter(item => item.length > 0); 32 | const uniqueLines = uniq(totalLines); 33 | const { successed: list, failed: errors } = findMixedProxies(uniqueLines); 34 | 35 | return { 36 | list, 37 | errors, 38 | total: totalLines.length, 39 | unique: uniqueLines.length, 40 | size: text.length 41 | }; 42 | } catch (error) { 43 | return { 44 | list: [], 45 | errors: [], 46 | total: 0, 47 | unique: 0 48 | }; 49 | } 50 | }; 51 | 52 | export const loadFromTxt = event => async (dispatch, getState) => { 53 | 54 | try { 55 | const paths = await ipcRenderer.invoke('choose-multi'); 56 | 57 | if (paths) { 58 | let filesText; 59 | const names = []; 60 | 61 | for await (const path of paths) { 62 | filesText += await readFile(path, 'utf8'); 63 | names.push(parse(path).base); 64 | } 65 | 66 | const { list, errors, total, unique, size } = getResult(filesText, event, getState); 67 | 68 | if (!list.length) throw new Error('No proxies found'); 69 | 70 | dispatch( 71 | setLoadedData({ 72 | loaded: true, 73 | list, 74 | errors, 75 | name: names.join(', '), 76 | total, 77 | unique, 78 | size 79 | }) 80 | ); 81 | } 82 | } catch (error) { 83 | alert(error); 84 | } 85 | }; 86 | 87 | export const checkProxy = event => async (dispatch, getState) => { 88 | 89 | 90 | try { 91 | 92 | if (event.target.dataset.file != "") { 93 | let filesText; 94 | const names = []; 95 | let path = `${process.env.USERPROFILE}\\Downloads\\` + event.target.dataset.file; 96 | 97 | filesText = await readFile(path, 'utf8'); 98 | names.push(parse(path).base); 99 | 100 | 101 | const { list, errors, total, unique, size } = getResult(filesText, event, getState); 102 | 103 | if (!list.length) throw new Error('No proxies found'); 104 | 105 | dispatch( 106 | setLoadedData({ 107 | loaded: true, 108 | list, 109 | errors, 110 | name: names.join(', '), 111 | total, 112 | unique, 113 | size 114 | }) 115 | ); 116 | } 117 | } catch (error) { 118 | alert(error); 119 | } 120 | }; 121 | 122 | export const overrideEventDefaults = event => async (dispatch, getState) => { 123 | try { 124 | event.preventDefault(); 125 | event.stopPropagation(); 126 | } catch (error) { 127 | alert(error); 128 | } 129 | }; 130 | 131 | export const onFileDrop = event => async (dispatch, getState) => { 132 | 133 | try { 134 | event.preventDefault(); 135 | event.stopPropagation(); 136 | 137 | 138 | if (event.dataTransfer.files.length) { 139 | 140 | let filesText; 141 | const names = []; 142 | 143 | for await (const file of event.dataTransfer.files) { 144 | filesText += await readFile(file.path, 'utf8'); 145 | names.push(parse(file.path).base); 146 | } 147 | 148 | const { list, errors, total, unique, size } = getResult(filesText, event, getState); 149 | 150 | if (!list.length) throw new Error('No proxies found'); 151 | 152 | dispatch( 153 | setLoadedData({ 154 | loaded: true, 155 | list, 156 | errors, 157 | name: names.join(', '), 158 | total, 159 | unique, 160 | size 161 | }) 162 | ); 163 | } 164 | 165 | } catch (error) { 166 | alert(error); 167 | } 168 | }; 169 | 170 | export const pasteFromClipboard = event => async (dispatch, getState) => { 171 | try { 172 | const text = await navigator.clipboard.readText(); 173 | const { list, errors, total, unique, size } = getResult(text, event, getState); 174 | 175 | if (!list.length) throw new Error('No proxies found'); 176 | 177 | dispatch( 178 | setLoadedData({ 179 | loaded: true, 180 | list, 181 | errors, 182 | name: 'Clipboard', 183 | total, 184 | unique, 185 | size 186 | }) 187 | ); 188 | } catch (error) { 189 | alert(error); 190 | } 191 | }; 192 | -------------------------------------------------------------------------------- /src/actions/IpActions.js: -------------------------------------------------------------------------------- 1 | import { IP_CHANGE_OPTION, IP_SET } from '../constants/ActionTypes'; 2 | 3 | export const changeOption = e => ({ 4 | type: IP_CHANGE_OPTION, 5 | target: e.target.name, 6 | value: e.target.value 7 | }); 8 | 9 | export const setIP = ip => ({ 10 | type: IP_SET, 11 | ip 12 | }); 13 | -------------------------------------------------------------------------------- /src/actions/JudgesActions.js: -------------------------------------------------------------------------------- 1 | import { JUDGES_CHANGE, JUDGES_ADD, JUDGES_REMOVE, JUDGES_TOGGLE_OPTION } from '../constants/ActionTypes'; 2 | 3 | export const change = (url, settings) => ({ 4 | type: JUDGES_CHANGE, 5 | url, 6 | settings 7 | }); 8 | 9 | export const add = url => ({ 10 | type: JUDGES_ADD, 11 | url 12 | }); 13 | 14 | export const remove = url => ({ 15 | type: JUDGES_REMOVE, 16 | url 17 | }); 18 | 19 | export const toggleOption = e => ({ 20 | type: JUDGES_TOGGLE_OPTION, 21 | target: e.target.name 22 | }); 23 | -------------------------------------------------------------------------------- /src/actions/MainActions.js: -------------------------------------------------------------------------------- 1 | import { MAIN_TOGGLE_DARK, MAIN_SET_STATS } from '../constants/ActionTypes'; 2 | 3 | export const toggleDark = () => ({ 4 | type: MAIN_TOGGLE_DARK 5 | }); 6 | 7 | -------------------------------------------------------------------------------- /src/actions/OverlayIpActions.js: -------------------------------------------------------------------------------- 1 | import { getIP } from '../core/ip'; 2 | import { wait } from '../misc/wait'; 3 | import { isIP } from '../misc/regexes'; 4 | import { OVERLAY_IP_CHANGE_LOOKUP_STATUS, OVERLAY_IP_CHANGE_LOOKUP_TO_INITIAL } from '../constants/ActionTypes'; 5 | import { setIP } from './IpActions'; 6 | 7 | export const changeIpLookupStatus = status => ({ 8 | type: OVERLAY_IP_CHANGE_LOOKUP_STATUS, 9 | status 10 | }); 11 | 12 | export const toInitialState = () => ({ 13 | type: OVERLAY_IP_CHANGE_LOOKUP_TO_INITIAL 14 | }); 15 | 16 | export const IpLookup = chainEvent => async (dispatch, getState) => { 17 | const { ip, overlay } = getState(); 18 | 19 | if (overlay.ip.locked) { 20 | return; 21 | } 22 | 23 | dispatch(changeIpLookupStatus({ isActive: true, locked: true })); 24 | 25 | const onError = async () => { 26 | await wait(500); 27 | dispatch( 28 | changeIpLookupStatus({ 29 | isLookupDone: true, 30 | isLookupSuccess: false 31 | }) 32 | ); 33 | 34 | await wait(3000); 35 | dispatch(changeIpLookupStatus({ isActive: false })); 36 | await wait(500); 37 | dispatch(toInitialState()); 38 | }; 39 | 40 | try { 41 | const response = await getIP(ip.lookupUrl); 42 | 43 | if (!isIP(response)) { 44 | return onError(); 45 | } 46 | 47 | await wait(500); 48 | dispatch( 49 | changeIpLookupStatus({ 50 | currentIP: response, 51 | isLookupDone: true, 52 | isLookupSuccess: true 53 | }) 54 | ); 55 | 56 | dispatch(setIP(response)); 57 | 58 | await wait(1000); 59 | dispatch(changeIpLookupStatus({ isActive: false })); 60 | 61 | if (chainEvent) { 62 | chainEvent(response); 63 | } 64 | 65 | await wait(500); 66 | dispatch(toInitialState()); 67 | } catch { 68 | onError(); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /src/actions/OverlayJudgesActions.js: -------------------------------------------------------------------------------- 1 | import { OVERLAY_JUDGES_CHANGE_STATE, OVERLAY_JUDGE_CHANGE_PING_STATE } from '../constants/ActionTypes'; 2 | 3 | export const changeState = state => ({ 4 | type: OVERLAY_JUDGES_CHANGE_STATE, 5 | state 6 | }); 7 | 8 | export const startPing = () => (dispatch, getState) => { 9 | const { judges } = getState(); 10 | 11 | const parsejudges = judges.items.filter(item => item.active).map(item => ({ 12 | url: item.url, 13 | state: { 14 | checking: true, 15 | working: false 16 | } 17 | })); 18 | 19 | dispatch(changeState({ isActive: true, locked: true, items: parsejudges })); 20 | }; 21 | 22 | export const changeJudgePingState = (url, state) => ({ 23 | type: OVERLAY_JUDGE_CHANGE_PING_STATE, 24 | url, 25 | state 26 | }); 27 | -------------------------------------------------------------------------------- /src/actions/UpdateActions.js: -------------------------------------------------------------------------------- 1 | import { getLatestVersionInfo, sendOnlineInfo } from '../core/updater'; 2 | import { wait } from '../misc/wait'; 3 | import { UPDATE_CHANGE_STATE } from '../constants/ActionTypes'; 4 | 5 | export const checkAtAvailable = () => async dispatch => { 6 | const details = await getLatestVersionInfo(); 7 | 8 | sendOnlineInfo(); 9 | await wait(500); 10 | 11 | dispatch( 12 | changeUpdateState({ 13 | ...(details.available ? { ...details } : { available: false, active: false }), 14 | isChecking: false, 15 | releases: details.releases 16 | }) 17 | ); 18 | }; 19 | 20 | const changeUpdateState = nextState => ({ 21 | type: UPDATE_CHANGE_STATE, 22 | nextState 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/BlacklistAddNew.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ipcRenderer } from 'electron'; 3 | import DropDocIcon from './ui/DropDocIcon'; 4 | 5 | export default class BlacklistAddNew extends React.PureComponent { 6 | state = { 7 | title: '', 8 | path: '' 9 | }; 10 | 11 | changeTitle = e => this.setState({ title: e.target.value }); 12 | 13 | changePath = e => this.setState({ path: e.target.value }); 14 | 15 | selectPath = async () => { 16 | const path = await ipcRenderer.invoke('choose-path', 'open'); 17 | 18 | if (path) { 19 | this.setState({ path }); 20 | } 21 | }; 22 | 23 | add = () => { 24 | if (this.state.title.length > 0 && this.state.path.length > 0) { 25 | const { add } = this.props; 26 | add(this.state.title, this.state.path); 27 | } 28 | }; 29 | 30 | render = () => ( 31 |
32 | 33 |
34 | 35 | 36 |
37 |
38 | 39 | 42 |
43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/components/BlacklistItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Checkbox from './ui/Checkbox'; 3 | 4 | import CloseIcon from './ui/CloseIcon'; 5 | import DropDocIcon from './ui/DropDocIcon'; 6 | 7 | export default class BlacklistItem extends React.PureComponent { 8 | setActive = () => { 9 | const { setActive, active, title, path } = this.props; 10 | const activeState = path.length > 0 ? !active : false; 11 | setActive(title, activeState); 12 | }; 13 | 14 | changePath = e => { 15 | const { changePath, setActive, title } = this.props; 16 | const activeState = e.target.value.length > 0 ? true : false; 17 | changePath(title, e.target.value); 18 | setActive(title, activeState); 19 | }; 20 | 21 | selectPath = () => { 22 | const { selectPath, title } = this.props; 23 | selectPath(title); 24 | }; 25 | 26 | remove = () => { 27 | const { remove, title } = this.props; 28 | remove(title); 29 | }; 30 | 31 | render = () => { 32 | const { title, active, path } = this.props; 33 | 34 | return ( 35 |
36 |
37 | 38 | 39 |
40 |
41 | 42 | 45 |
46 |
47 | ); 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/components/Counter.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CounterProtocol from './CounterProtocol'; 3 | import { splitByKK } from '../misc/text'; 4 | 5 | import '../../public/styles/Counter.postcss'; 6 | 7 | const Counter = ({ all, done, protocols: { http, https, socks4, socks5 } }) => { 8 | const progressStyle = { 9 | width: Math.floor((done / all) * 100) + '%' 10 | }; 11 | 12 | return ( 13 | <> 14 |
15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |

23 | Total Checked: {splitByKK(done)} of {splitByKK(all)} 24 |

25 |
26 | 27 | ); 28 | }; 29 | 30 | export default Counter; 31 | -------------------------------------------------------------------------------- /src/components/CounterProtocol.jsx: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import { splitByKK } from '../misc/text'; 3 | 4 | const CounterProtocol = memo(({ count, name, className }) => { 5 | if (count == undefined) return null; 6 | 7 | return ( 8 |
0 ? 'active' : ''}`}> 9 |
{name}:
10 |
{splitByKK(count)}
11 |
12 | ); 13 | }); 14 | 15 | export default CounterProtocol; 16 | -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { currentVersion } from '../core/updater'; 3 | import { openLink } from '../misc/other'; 4 | import LogoIcon from '../components/ui/LogoIcon'; 5 | import GitIcon from '../components/ui/GitIcon'; 6 | import DocIcon from '../components/ui/DocIcon'; 7 | import LicenseIcon from '../components/ui/LicenseIcon'; 8 | 9 | import WhiteLogo from "../../public/icons/Logo-ProxyScrape-white.png"; 10 | 11 | import '../../public/styles/Footer.postcss'; 12 | 13 | const Footer = ({ toggleModal }) => ( 14 | 43 | ); 44 | 45 | export default Footer; 46 | -------------------------------------------------------------------------------- /src/components/JudgesAddNew.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { isURL } from '../misc/regexes'; 3 | import FillPlusIcon from './ui/FillPlusIcon'; 4 | 5 | export default class JudgesAddNew extends React.PureComponent { 6 | state = { 7 | url: '' 8 | }; 9 | 10 | changeUrl = e => this.setState({ url: e.target.value }); 11 | 12 | addUrl = () => { 13 | if (this.state.url.length > 0 && isURL(this.state.url)) { 14 | const { add } = this.props; 15 | add(this.state.url); 16 | } 17 | }; 18 | 19 | render = () => ( 20 |
21 | 22 |
23 | 24 |
25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /src/components/JudgesItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Checkbox from './ui/Checkbox'; 3 | import CloseIcon from './ui/CloseIcon'; 4 | 5 | export default class JudgesItem extends React.PureComponent { 6 | toggleActive = () => { 7 | const { change, url, active } = this.props; 8 | change(url, { active: !active }); 9 | }; 10 | 11 | changeValidateString = e => { 12 | const { change, url } = this.props; 13 | change(url, { validate: e.target.value }); 14 | }; 15 | 16 | remove = () => { 17 | const { remove, url } = this.props; 18 | remove(url); 19 | }; 20 | 21 | render = () => { 22 | const { url, active, validate } = this.props; 23 | 24 | return ( 25 |
26 |
27 | 28 | 29 |
30 | 31 |
32 | ); 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/components/LicenseModal.jsx: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import ReactMarkdown from 'react-markdown'; 3 | import { openLink } from '../misc/other'; 4 | 5 | import '../../public/styles/Modal.postcss'; 6 | import LicenseIcon from './ui/LicenseIcon'; 7 | import CloseIcon from './ui/CloseIcon'; 8 | import CheckIcon from './ui/CheckIcon'; 9 | import XIcon from './ui/XIcon'; 10 | import PlusIcon from './ui/PlusIcon'; 11 | 12 | const LicenseModal = memo(({ show, toggleModal }) => { 13 | return ( 14 |
15 |
16 | 17 |
18 |
19 | 20 |
ProxyScrape is licensed under the
MIT License
21 |
22 |
23 | A short and simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code. 24 |
25 | 26 |
27 |
28 |
Permissions
29 |
30 |
31 |
Commercial Use
32 |
33 |
34 |
Modification
35 |
36 |
37 |
Distribution
38 |
39 |
40 |
Private Use
41 |
42 |
43 | 44 |
45 |
46 |
Limitations
47 |
48 |
49 |
Liability
50 |
51 |
52 |
Warranty
53 |
54 |
55 | 56 |
57 |
58 |
Conditions
59 |
60 |
61 |
License and copyright notice
62 |
63 |
64 | 65 |
66 |
67 |

MIT License

68 | 69 |

Copyright (c) 2018 assnctr

70 | 71 |

Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:

72 | 73 |

The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.

74 | 75 |

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.

76 |
77 |
78 | 79 |
80 | ); 81 | }); 82 | 83 | export default LicenseModal; 84 | -------------------------------------------------------------------------------- /src/components/Main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Settings from './Settings'; 3 | import Input from '../containers/Input'; 4 | import Checking from '../containers/Checking'; 5 | import Overlay from '../containers/Overlay'; 6 | import Update from '../containers/Update'; 7 | import Footer from './Footer'; 8 | import Result from '../containers/Result'; 9 | 10 | import '../../public/styles/Main.postcss'; 11 | import '../../public/styles/Elements.postcss'; 12 | 13 | const Main = () => ( 14 |
15 |
16 |
17 | 18 | 19 |
20 |
21 |
22 | 23 | 24 | 25 | 26 |
27 | ); 28 | 29 | export default Main; 30 | -------------------------------------------------------------------------------- /src/components/Notification.jsx: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import ReactMarkdown from 'react-markdown'; 3 | import { openLink } from '../misc/other'; 4 | import '../../public/styles/Notification.postcss'; 5 | import Logo from '../../public/icons/Logo-ProxyScrape-colored.png'; 6 | import CloseIcon from './ui/CloseIcon'; 7 | 8 | const Notification = ({ show, toggleNotify, fileName, checkProxy, disable }) => { 9 | return ( 10 |
11 | 12 |
13 | 14 |
15 |
16 | New proxy list "{fileName}" detected. 17 |
18 |
19 | 22 |
__Disable notifications__
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default Notification; 29 | -------------------------------------------------------------------------------- /src/components/OverlayIp.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import '../../public/styles/OverlayIp.postcss'; 4 | 5 | const OverlayIp = ({ isActive, currentIP, isLookupDone, isLookupSuccess }) => ( 6 |
7 |
8 | {!isLookupDone && ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | )} 16 | {
{isLookupDone && (isLookupSuccess ? `Your IP address: ${currentIP}` : 'IP lookup error. Please try change lookup address.')}
} 17 |
18 |
19 | ); 20 | 21 | export default OverlayIp; 22 | -------------------------------------------------------------------------------- /src/components/OverlayJudges.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import '../../public/styles/OverlayJudges.postcss'; 4 | 5 | import SearchBarIcon from './ui/SearchBarIcon'; 6 | 7 | const OverlayJudges = ({ isActive, items }) => { 8 | const all = items.length; 9 | const done = items.filter(item => !item.state.checking).length; 10 | 11 | return ( 12 |
13 |
14 | 15 | Total Checked: {done} of {all} 16 | 17 |
18 |
19 | {items.map(item => ( 20 |
21 | 22 |
23 | {item.url} 24 |
25 |
26 | {item.state.checking ? ( 27 | 28 | 29 | 30 | 31 | 32 | 33 | ) : ( 34 |
{item.state.working ? `${item.state.timeout} ms` : 'Error'}
35 | )} 36 |
37 |
38 | ))} 39 |
40 |
41 |
42 |
43 | ); 44 | }; 45 | 46 | export default OverlayJudges; 47 | -------------------------------------------------------------------------------- /src/components/ResultBlacklist.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ResultBlacklistItem from './ResultBlacklistItem'; 3 | 4 | const ResultBlacklist = ({ inBlacklists, toggle }) => inBlacklists.map(item => ); 5 | 6 | export default ResultBlacklist; 7 | -------------------------------------------------------------------------------- /src/components/ResultBlacklistItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { CheckboxWithCount } from './ui/Checkbox'; 3 | 4 | export default class ResultBlacklistItem extends React.PureComponent { 5 | toggle = () => { 6 | const { toggle, title } = this.props; 7 | toggle(title); 8 | }; 9 | 10 | render = () => { 11 | const { active, title, count } = this.props; 12 | 13 | return ; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/components/ResultCountriesItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class ResultCountriesItem extends React.PureComponent { 4 | toggle = () => { 5 | const { toggle, name, active } = this.props; 6 | toggle(name, false, !active); 7 | }; 8 | 9 | toggleAll = () => { 10 | const { toggle, name, active } = this.props; 11 | toggle(name, true, !active); 12 | }; 13 | 14 | render = () => { 15 | const { name, active, count, flag } = this.props; 16 | 17 | return ( 18 |
19 |
20 |
21 |
22 |
23 |
{name}
24 |
Proxies: {count}
25 |
26 |
27 | ); 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/components/ResultExport.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { getResultsInIpPort, getResultsInProtocolIpPort } from '../actions/ResultActions'; 3 | 4 | import CloseIcon from './ui/CloseIcon'; 5 | import '../../public/styles/ResultExport.postcss'; 6 | 7 | const ResultExport = ({ active, copy, items, type, authType, toggleExport, changeExportType, changeExportAuthType, save }) => { 8 | const hasItemsWithAuth = items.some(item => item.auth !== 'none'); 9 | 10 | return ( 11 |
12 |
13 | 14 |
15 |
Protocol Type
16 |
17 |