Repository: dzt/easy-proxy Branch: master Commit: 8323c70ee480 Files: 16 Total size: 48.9 KB Directory structure: gitextract_h1rwq2co/ ├── .gitignore ├── LICENSE ├── README.md ├── confg/ │ ├── nouserpass/ │ │ └── squid.conf │ └── userpass/ │ └── squid.conf ├── create.js ├── index.js ├── package.json ├── scripts/ │ └── installer.js ├── settings-manager.js └── static/ ├── app.js ├── icons/ │ └── logo.icns ├── index.html ├── main.css ├── settings.html └── settings.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ config.json gs logs *.log npm-debug.log* # Runtime data pids *.pid *.seed package-lock.json # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules jspm_packages # Optional npm cache directory .npm # Optional REPL history .node_repl_history dist out # macOS .DS_Store package-lock.json ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2017 Peter Soboyejo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 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 THE SOFTWARE. ================================================ FILE: README.md ================================================ # easy-proxy Mass proxy distribution made easy with the DigitalOcean API ![screen](https://i.imgur.com/ZIabShH.png) [DOWNLOADS CAN BE FOUND HERE](https://github.com/dzt/easy-proxy/releases) [Community Discord Server](https://discord.gg/BkDxcjT) ### Setup (for development) easy-proxy requires [Node.js](http://nodejs.org/). Development Setup: ```sh $ git clone https://github.com/dzt/easy-proxy.git $ cd easy-proxy $ npm install # sudo npm install if you're on macOS $ npm run dev ``` # Videos [Preview & Explanation Video](https://youtu.be/Uy0EpcAgaAs) [RSA ID Setup on macOS](https://streamable.com/6gnpe) ### Who Written by @dzt, made better by you. ## License ``` The MIT License (MIT) Copyright (c) 2017 Peter Soboyejo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 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 THE SOFTWARE. ``` ================================================ FILE: confg/nouserpass/squid.conf ================================================ http_port 3128 cache deny all hierarchy_stoplist cgi-bin ? access_log none cache_store_log none cache_log /dev/null refresh_pattern ^ftp: 1440 20% 10080 refresh_pattern ^gopher: 1440 0% 1440 refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 refresh_pattern . 0 20% 4320 acl localhost src 127.0.0.1/32 ::1 acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1 acl SSL_ports port 1-65535 acl Safe_ports port 1-65535 acl CONNECT method CONNECT acl siteblacklist dstdomain "/etc/squid/blacklist.acl" http_access allow manager localhost http_access deny manager http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access deny siteblacklist #auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/passwd #auth_param basic children 5 #auth_param basic realm Squid proxy-caching web server #auth_param basic credentialsttl 2 hours #acl password proxy_auth REQUIRED http_access allow localhost http_access allow password http_access allow all forwarded_for off request_header_access Allow allow all request_header_access Authorization allow all request_header_access WWW-Authenticate allow all request_header_access Proxy-Authorization allow all request_header_access Proxy-Authenticate allow all request_header_access Cache-Control allow all request_header_access Content-Encoding allow all request_header_access Content-Length allow all request_header_access Content-Type allow all request_header_access Date allow all request_header_access Expires allow all request_header_access Host allow all request_header_access If-Modified-Since allow all request_header_access Last-Modified allow all request_header_access Location allow all request_header_access Pragma allow all request_header_access Accept allow all request_header_access Accept-Charset allow all request_header_access Accept-Encoding allow all request_header_access Accept-Language allow all request_header_access Content-Language allow all request_header_access Mime-Version allow all request_header_access Retry-After allow all request_header_access Title allow all request_header_access Connection allow all request_header_access Proxy-Connection allow all request_header_access User-Agent allow all request_header_access Cookie allow all request_header_access All deny all ================================================ FILE: confg/userpass/squid.conf ================================================ http_port 3128 cache deny all hierarchy_stoplist cgi-bin ? access_log none cache_store_log none cache_log /dev/null refresh_pattern ^ftp: 1440 20% 10080 refresh_pattern ^gopher: 1440 0% 1440 refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 refresh_pattern . 0 20% 4320 acl localhost src 127.0.0.1/32 ::1 acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1 acl SSL_ports port 1-65535 acl Safe_ports port 1-65535 acl CONNECT method CONNECT acl siteblacklist dstdomain "/etc/squid/blacklist.acl" http_access allow manager localhost http_access deny manager http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access deny siteblacklist auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/passwd auth_param basic children 5 auth_param basic realm Squid proxy-caching web server auth_param basic credentialsttl 2 hours acl password proxy_auth REQUIRED http_access allow localhost http_access allow password http_access deny all forwarded_for off request_header_access Allow allow all request_header_access Authorization allow all request_header_access WWW-Authenticate allow all request_header_access Proxy-Authorization allow all request_header_access Proxy-Authenticate allow all request_header_access Cache-Control allow all request_header_access Content-Encoding allow all request_header_access Content-Length allow all request_header_access Content-Type allow all request_header_access Date allow all request_header_access Expires allow all request_header_access Host allow all request_header_access If-Modified-Since allow all request_header_access Last-Modified allow all request_header_access Location allow all request_header_access Pragma allow all request_header_access Accept allow all request_header_access Accept-Charset allow all request_header_access Accept-Encoding allow all request_header_access Accept-Language allow all request_header_access Content-Language allow all request_header_access Mime-Version allow all request_header_access Retry-After allow all request_header_access Title allow all request_header_access Connection allow all request_header_access Proxy-Connection allow all request_header_access User-Agent allow all request_header_access Cookie allow all request_header_access All deny all ================================================ FILE: create.js ================================================ const randomstring = require('randomstring') const DigitalOcean = require('do-wrapper').default const eSettings = require('electron-settings') const request = require('request') const _ = require('underscore') const ipcMain = require('electron').ipcMain var task = function(win, info, settings, no, callback) { var sender = win.webContents; var ssh_key_id = null; var id = null; var stopped = false; api = new DigitalOcean(eSettings.getSync('do_api_key'), '9999') var host = null; ipcMain.on('stopTasks', function(event) { if (stopped == false) { sender.send('updateMonitor', { no: no, msg: 'Cancelled', username: info.username, password: info.password, ip: 'n/a', error: true }); stopped = true } }); sender.send('updateMonitor', { no: no, msg: 'Started', username: info.username, password: info.password, ip: 'n/a', error: false }); createDroplet(); function createDroplet() { sender.send('updateMonitor', { no: no, msg: `Creating Droplet`, username: info.username, password: info.password, ip: 'n/a', error: false }); var dropletName = randomstring.generate(14) + '-ep'; var dropletData = { name: dropletName, region: info.region, size: '512mb', image: parseInt(info.slug), ssh_keys: [ssh_key_id], monitoring: true, user_data: '#!/bin/bash \n' + 'yum install squid wget httpd-tools -y &&' + 'touch /etc/squid/passwd &&' + `htpasswd -b /etc/squid/passwd ${info.username} ${info.password} &&` + 'wget -O /etc/squid/squid.conf https://raw.githubusercontent.com/dzt/easy-proxy/master/confg/userpass/squid.conf --no-check-certificate &&' + 'touch /etc/squid/blacklist.acl &&' + 'systemctl restart squid.service && systemctl enable squid.service &&' + 'iptables -I INPUT -p tcp --dport 3128 -j ACCEPT &&' + 'iptables-save' }; /* var dropletData = { name: dropletName, region: info.region, size: '512mb', image: parseInt(info.slug), ssh_keys: [ssh_key_id], monitoring: true, user_data: '#!/bin/bash \n' + 'yum install squid wget httpd-tools -y &&' + //'touch /etc/squid/passwd &&' + //`htpasswd -b /etc/squid/passwd ${info.username} ${info.password} &&` + 'wget -O /etc/squid/squid.conf https://raw.githubusercontent.com/dzt/easy-proxy/master/confg/nouserpass/squid.conf --no-check-certificate &&' + 'touch /etc/squid/blacklist.acl &&' + 'systemctl restart squid.service && systemctl enable squid.service &&' + 'iptables -I INPUT -p tcp --dport 3128 -j ACCEPT &&' + 'iptables-save' }; */ console.log(dropletData); api.dropletsCreate(dropletData, function(err, resp, body) { if (err) { sender.send('updateMonitor', { no: no, msg: 'An error occured while trying to create your droplet.', username: info.username, password: info.password, ip: 'n/a', error: true }); console.log(`[${no}] Error creating droplet.`); console.log(err); return callback(null, true); } setTimeout(function() { if (stopped) { destroyDroplet(id, api, function(err, resp) { if (err) { return callback(null, true); } return callback(null, true); }); } api.dropletsGetAll({}, function(err, resp, body) { id = _.findWhere(resp.body.droplets, { name: dropletName }).id host = _.findWhere(resp.body.droplets, { name: dropletName }).networks.v4[0].ip_address var para = null; if (eSettings.getSync('ssh_passphrase') != null) { para = eSettings.getSync('ssh_passphrase'); } if (stopped) { destroyDroplet(id, api, function(err, resp) { if (err) { return callback(null, true); } return callback(null, true); }); } if (stopped) { destroyDroplet(id, api, function(err, resp) { if (err) { return callback(null, true); } return callback(null, true); }); } else { sender.send('updateMonitor', { no: no, msg: `Droplet Created`, username: info.username, password: info.password, ip: host, error: false }); } console.log("http://" + info.username + ":" + info.password + "@" + host + ":" + '3128') var count = 119; for (var i = 0; i < 119; i++) { setTimeout(function() { sender.send('updateMonitor', { no: no, msg: `Testing Proxy in ${count}s`, username: info.username, password: info.password, ip: host, error: false }); count--; }, 1000*i); } setTimeout(function() { request({ method: 'get', url: 'https://google.com/', proxy: "http://" + info.username + ":" + info.password + "@" + host + ":" + '3128', gzip: true, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3107.4 Safari/537.36' } }, (error, resp, body) => { if (error) { console.log(error); sender.send('updateMonitor', { no: no, msg: `Proxy Invalid, destroying droplet.`, username: info.username, password: info.password, ip: host, error: true }); destroyDroplet(id, api, function(err, resp) { if (err) { sender.send('updateMonitor', { no: no, msg: `Error Occured while destroying droplet due to bad proxy Connection.`, username: info.username, password: info.password, ip: host, error: true }); return callback(null, true); } sender.send('updateMonitor', { no: no, msg: `Droplet Destroyed due to bad proxy connection.`, username: info.username, password: info.password, ip: host, error: true }); return callback(null, true); }); } else { sender.send('updateMonitor', { no: no, msg: `Created!`, username: info.username, password: info.password, ip: host, error: false }); console.log(`[${no}] Created!`); return callback(null, true); } }); }, 120000); }); }, 60000); }); } } function destroyDroplet(id, api, cb) { api.dropletsDelete(id, function(err, resp, body) { if (err) { return cb(true, null); } return cb(null, true) }); } module.exports = { task: task }; ================================================ FILE: index.js ================================================ const electron = require('electron') const { app, BrowserWindow, Menu } = electron const settings = require('./settings-manager') const eSettings = require('electron-settings') const create = require('./create') const path = require('path') const async = require('async') const ChildProcess = require('child_process') var DigitalOcean = require('do-wrapper').default, api = null; var win, settingsWin; const debug = /--debug/.test(process.argv[2]) // Launch Menu Spawn System var createShortcut = function(callback) { spawnUpdate([ '--createShortcut', path.basename(process.execPath), '--shortcut-locations', 'StartMenu' ], callback) } var removeShortcut = function(callback) { spawnUpdate([ '--removeShortcut', path.basename(process.execPath) ], callback) } var spawnUpdate = function(args, callback) { var updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe') var stdout = '' var spawned = null try { spawned = ChildProcess.spawn(updateExe, args) } catch (error) { if (error && error.stdout == null) error.stdout = stdout process.nextTick(function() { callback(error) }) return } var error = null spawned.stdout.on('data', function(data) { stdout += data }) spawned.on('error', function(processError) { if (!error) error = processError }) spawned.on('close', function(code, signal) { if (!error && code !== 0) { error = new Error('Command failed: ' + code + ' ' + signal) } if (error && error.code == null) error.code = code if (error && error.stdout == null) error.stdout = stdout callback(error) }) } switch (process.argv[1]) { case '--squirrel-install': createShortcut(function() { app.quit() }); break; case '--squirrel-uninstall': removeShortcut(function() { app.quit(); }); break; case '--squirrel-obsolete': case '--squirrel-updated': app.quit(); break; default: init(); } function init() { app.on('ready', () => { settings.init() app.ep = { settings } win = new BrowserWindow({ width: 750, height: 670, minWidth: 750, minHeight: 670, resizable: true, maxWidth: 750, maxHeight: 640, fullscreenable: false, frame: true, show: true, icon: `${__dirname}/static/icon.png` }) const menuTemplate = [{ label: 'File', submenu: [{ label: 'Settings', click() { initSettings() }, accelerator: 'CmdOrCtrl+,', }, { label: 'Quit', click() { app.quit() }, accelerator: 'CmdOrCtrl+Q', } ] }, { label: 'Edit', submenu: [{ role: 'copy' }, { role: 'paste' }, { role: 'pasteandmatchstyle' }, { role: 'delete' }, { role: 'selectall' } ] }, { label: 'View', submenu: [{ label: 'Reload', accelerator: 'CmdOrCtrl+R', click(item, focusedWindow) { if (focusedWindow) focusedWindow.reload() } }] }, { role: 'window', submenu: [{ role: 'minimize' }, { role: 'close' } ] }, { role: 'help', submenu: [{ label: 'Learn More about EasyProxy', click() { require('electron').shell.openExternal('github.com/dzt/easy-proxy') } }, { label: 'Toggle Developer Tools', accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', click(item, focusedWindow) { if (focusedWindow) focusedWindow.webContents.toggleDevTools() } } ] } ] // If the platform is Mac OS, make some changes to the window management portion of the menu if (process.platform === 'darwin') { menuTemplate[2].submenu = [{ label: 'Close', accelerator: 'CmdOrCtrl+W', role: 'close' }, { label: 'Minimize', accelerator: 'CmdOrCtrl+M', role: 'minimize' }, { label: 'Zoom', role: 'zoom' }, { type: 'separator' }, { label: 'Bring All to Front', role: 'front' } ] } // Set menu template just created as the application menu const mainMenu = Menu.buildFromTemplate(menuTemplate) Menu.setApplicationMenu(mainMenu) win.setMenu(null); win.loadURL(`file://${__dirname}/static/index.html`); }) } electron.ipcMain.on('create', function(event, args) { var tasks = [] args.map(function(task, i) { tasks.push(function(cb) { create.task(win, task, settings, i + 1, (err, response) => { if (err) { return (err) } return cb(null, response) }) }) }) async.parallel(tasks, function(err, res) { if (err) { console.log('err', err) } else { console.log(res) // TODO: When Session Ends win.webContents.send('tasksEnded'); } }); }); electron.ipcMain.on('openSettings', function(event, args) { initSettings(); }); electron.ipcMain.on('open-file-dialog', function(event) { require('electron').dialog.showOpenDialog({ properties: ['openFile'], filters: [{ name: 'All Files', extensions: ['*'] }] }, function(filename) { if (filename) { console.log(filename[0]); event.sender.send('selected-file', filename[0]); } }) }); electron.ipcMain.on('wipeDroplets', function(event) { api = new DigitalOcean(eSettings.getSync('do_api_key')); var droplets = []; api.dropletsGetAll({}, function(err, resp, body) { if (err) { console.log(err); event.sender.send('errDestroy'); } for (var i = 0; i < body.droplets.length; i++) { var id = body.droplets[i].id; var dropletName = body.droplets[i].name; if (dropletName.endsWith('-ep')) { api.dropletsDelete(id, function(err, resp, body) {}); } } event.sender.send('wipe-complete'); //console.log(body); }); }); electron.ipcMain.on('resetApp', (event, args) => { win.close() settingsWin.close() app.quit(); }) electron.ipcMain.on('refreshMainWindow', (event, args) => { win.webContents.send('refreshMain'); }) electron.ipcMain.on('fetchForImages', function(event) { var options = []; var regionDict = []; api = new DigitalOcean(eSettings.getSync('do_api_key')); function fetchFullRegionName(shortName) { for (var i = 0; i < regionDict.length; i++) { if (regionDict[i].slug == shortName) { return regionDict[i].fullName; } } } // Fetch for Regions and Slug Names api.regionsGetAll({}, function(err, resp, body) { if (err) { // Return Error to Window console.log('err', err); win.webContents.send('initError'); return } for (var i = 0; i < body.regions.length; i++) { regionDict.push({ fullName: body.regions[i].name, slug: body.regions[i].slug }) } api.imagesGetAll({type: 'distribution'}, function(err, resp, body) { if (err) { // Return Error to Window win.webContents.send('initError'); return } for (var i = 0; i < body.images.length; i++) { // Look for 64bit versions of CentOS 7 if (body.images[i].distribution.indexOf('CentOS') > -1) { if (body.images[i].name.split(' ')[0].startsWith('7')) { for (var x = 0; x < body.images[i].regions.length; x++) { if (fetchFullRegionName(body.images[i].regions[x]) != undefined) { options.push({ title: `CentOS ${body.images[i].name} - ${body.images[i].id} - (${fetchFullRegionName(body.images[i].regions[x])})`, region: body.images[i].regions[x], slug: body.images[i].id }) } } } } } win.webContents.send('updateOptionList', options); }); }); }); function initSettings() { settingsWin = new electron.BrowserWindow({ backgroundColor: '#ffffff', center: true, fullscreen: false, height: 700, icon: `${__dirname}/static/icon.png`, maximizable: false, minimizable: false, resizable: false, show: false, skipTaskbar: true, title: 'Settings', useContentSize: true, width: 550 }) settingsWin.loadURL(`file://${__dirname}/static/settings.html`); // No menu on the About settingsWindow settingsWin.setMenu(null); //settingsWin.webContents.openDevTools() settingsWin.once('ready-to-show', function() { settingsWin.show() }) settingsWin.once('closed', function() { aboutWin = null }) return settingsWin.show() } ================================================ FILE: package.json ================================================ { "name": "EasyProxy", "version": "2.1.2", "description": "Easy Proxy Creation", "main": "index.js", "scripts": { "start": "electron .", "dev": "electron . --debug", "dist:win": "build --windows --x64 --dir", "dist:mac": "build --mac", "installer": "node scripts/installer.js" }, "author": "Peter Soboyejo ", "license": "MIT", "repository": { "type": "git", "url": "git://github.com/dzt/easy-proxy.git" }, "bugs": { "url": "https://github.com/dzt/easy-proxy/issues" }, "dependencies": { "async": "^2.6.0", "bootstrap": "^3.3.7", "console.table": "^0.8.0", "copy-paste": "^1.3.0", "do-wrapper": "^3.11.1", "electron-config": "^1.0.0", "electron-settings": "^2.2.2", "font-awesome": "^4.7.0", "jquery": "^3.2.1", "object-path": "^0.11.4", "path": "^0.12.7", "prompt": "^1.0.0", "randomstring": "^1.1.5", "request": "^2.83.0", "rimraf": "^2.5.4", "underscore": "^1.8.3" }, "devDependencies": { "electron": "1.3.4", "electron-winstaller": "^2.5.0", "electron-builder": "^19.13.0" }, "build": { "productName": "EasyProxy", "appId": "com.petersoboyejo.easyproxy", "mac": { "target": "default", "icon": "static/icons/logo.icns", "identity": null }, "win": { "publisherName": "EasyProxy", "target": "squirrel", "icon": "static/icons/logo.ico" } } } ================================================ FILE: scripts/installer.js ================================================ const createWindowsInstaller = require('electron-winstaller').createWindowsInstaller const path = require('path') const rimraf = require('rimraf') deleteOutputFolder() .then(getInstallerConfig) .then(createWindowsInstaller) .catch((error) => { console.log('err') console.error(error.message || error) process.exit(1) }) function getInstallerConfig () { const rootPath = path.join(__dirname, '..') const outPath = path.join(rootPath, 'dist') return Promise.resolve({ appDirectory: path.join(outPath, 'win-unpacked'), noMsi: true, outputDirectory: path.join(outPath, 'windows-installer'), setupExe: 'EasyProxySetup.exe', setupIcon: path.join(rootPath, 'static', 'icons', 'logo.ico'), skipUpdateIcon: true }) } function deleteOutputFolder () { return new Promise((resolve, reject) => { rimraf(path.join(__dirname, '..', 'out', 'windows-installer'), (error) => { error ? reject(error) : resolve() }) }) } ================================================ FILE: settings-manager.js ================================================ const homedir = require('os').homedir const app = require('electron').app const settings = require('electron-settings') const objectPath = require('object-path') const DEFAULTS = { filePath: null, do_api_key: null, ip_auth: false, ips: null }; // we need to sync every setting that can be modified externally // e.g. the `openOnStartup` setting can be modified via // macOS' System Preferences.app function sync() { settings.setSync('openOnStartup', app.getLoginItemSettings().openAtLogin); } function init() { settings.defaults(DEFAULTS); settings.applyDefaultsSync(); sync(); } function get(key) { sync(); return objectPath.get(key) || settings.getSync(key); } function getAll() { sync(); return settings.getSync(); } function set(key, value) { settings.setSync(key, value); } function observe(keyPath, handler) { return settings.observe(keyPath, handler); } module.exports = { get: get, getAll: getAll, set: set, observe: observe, init: init }; ================================================ FILE: static/app.js ================================================ require("copy-paste").global() const remote = require('electron').remote const app = remote.app const $ = require('jquery') const ipcRenderer = require('electron').ipcRenderer const settings = require('electron-settings') const randomstring = require('randomstring') var settingsValues = app.ep.settings.getAll(); // Fetch for Images as soon as Window is loaded if (settingsValues.do_api_key == null || settingsValues.do_api_key == "") { $("#fetching").html(''); } else { ipcRenderer.send('fetchForImages'); } ipcRenderer.on('initError', function(event, data) { $("#fetching").html(''); }); // When Images are Fetched return data to DOM ipcRenderer.on('updateOptionList', function(event, data) { if (data.length == 0) { $("#fetching").html(''); } else { for (var i = 0; i < data.length; i++) { $('#sel1').append(``); } $("#fetching").remove(); $("#sel1").prop("disabled", false); $("#createButton").prop("disabled", false); } }); ipcRenderer.on('refreshMain', function(event) { remote.getCurrentWindow().reload(); }); // Create Proxies Button $('#createButton').click(() => { if ($("#count").val() == "") { alert("You must set the number of proxies you want to create before performing this action."); } else if (settingsValues.do_api_key == null) { alert("You're missing crutial settings required to create proxies, please check your settings and try again."); } else { $("#results").empty(); $("#createButton").prop("disabled", true); $("#sel1").prop("disabled", true); $("#count").prop("disabled", true); $("#clearLogsButton").prop("disabled", true); $("#createButton").text('Creating...'); var proxyCount = parseInt($('#count').val()) var tasks = []; for (var i = 0; i < proxyCount; i++) { var username = randomstring.generate({ length: 6, charset: 'alphabetic', capitalization: 'lowercase' }); var password = randomstring.generate({ length: 6, charset: 'alphabetic', capitalization: 'lowercase' }); tasks.push({ username: username, password: password, slug: $('#sel1').find(":selected").attr('slug'), region: $('#sel1').find(":selected").attr('region') }) } ipcRenderer.send('create', tasks); } }); // Update List Items in realtime ipcRenderer.on('updateMonitor', function(event, data) { // TODO: Add Timestamp if ($(`#${data.username}`).length) { // update exisiting item if (data.error) { var newlyAddedUpdate = ` #${data.no} ${data.ip} 3128 ${data.username} ${data.password} ${data.msg} ` } else { var newlyAddedUpdate = ` #${data.no} ${data.ip} 3128 ${data.username} ${data.password} ${data.msg} ` } $(`#${data.username}`).replaceWith(newlyAddedUpdate); } else { var newlyAddedUpdate = ` #${data.no} ${data.ip} 3128 ${data.username} ${data.password} ${data.msg} ` $('#results').append(newlyAddedUpdate); } }); $('#refresh').click(() => { remote.getCurrentWindow().reload(); }); $('#copyToClipboardButton').click(() => { var content = []; $("tr").each(function(i) { if (i != 0) { if ($(this).has(`td:contains('Created!')`).length) { var ip = $(this).find('td').eq(1).text(); var user = $(this).find('td').eq(3).text(); var pass = $(this).find('td').eq(4).text(); content.push(`${ip}:3128:${user}:${pass}`); } } }); // use join function copy(content.join('\n')) }); $('#clearLogsButton').click(() => { $("#results").empty(); }); $('#cancelTasksButton').click(() => { ipcRenderer.send('stopTasks'); }); $('#settingsButton').click(() => { ipcRenderer.send('openSettings'); }); // When all tasks are done doing there thing bring everything back to normal and purge old stuff ipcRenderer.on('tasksEnded', function(event, data) { $("#createButton").prop("disabled", false); $("#sel1").prop("disabled", false); $("#count").prop("disabled", false); $("#clearLogsButton").prop("disabled", false); $("#createButton").text('Create'); }); ================================================ FILE: static/index.html ================================================ EasyProxy






# IP/Host Port Username Password Status


   Refresh
================================================ FILE: static/main.css ================================================ body { background: white; } :not(input):not(textarea), :not(input):not(textarea)::after, :not(input):not(textarea)::before { -webkit-user-select: none; user-select: none; cursor: default; } input, button, textarea, :focus { outline: none; // You should add some other style for :focus to help UX/a11y } a:not([draggable=true]), img:not([draggable=true]) { -webkit-user-drag: none; user-drag: none; /* Technically not supported in Electron yet */ } a[href^="http://"], a[href^="https://"], a[href^="ftp://"] { -webkit-user-drag: auto; user-drag: auto; /* Technically not supported in Electron yet */ } .main footer { position: fixed; right: 0px; bottom: 0px; left: 0px; background-color: #EEEEEE; color: #666; border-style: solid; border-width: 1px; border-color: #fff #fff #fff #fff; font-size: 12px; padding: 9px 24px; overflow: hidden; z-index: 999; } .main footer .status div { display: none; } .main footer .status div:before { content: ''; display: inline-block; width: 9px; height: 9px; background-color: #ccc; border-radius: 100px; margin-right: 6px; } .main footer .status .connected:before { background-color: #66bc66; } .main footer .status .connecting:before, .main footer .status .updating:before { background-color: #f04646; -webkit-animation: 3s indicator infinite; } .main footer .status .disconnected:before { background-color: #de7b7b; } .main footer .update { float: right; } .main footer .update a { display: inline; padding: 3px 9px; } ================================================ FILE: static/settings.html ================================================

Version ()

Written by @dzt


================================================ FILE: static/settings.js ================================================ const remote = require('electron').remote; const app = remote.app; const settings = require('electron-settings'); const $ = require('jquery') const Config = require('electron-config'); const config = new Config(); const dialog = remote.dialog; const ipcRenderer = require('electron').ipcRenderer var settingsValues = app.ep.settings.getAll(); var settingsVal = config.get('settingsVal') var shell = require('electron').shell; $("#filePathBtn").click(function(event){ event.preventDefault(); ipcRenderer.send('open-file-dialog'); }); $('#passphrase').val(settingsValues.ssh_passphrase); $('#doKey').val(settingsValues.do_api_key); $('#filePath').val(settingsValues.filePath); $('#keyName').val(settingsValues.do_ssh_key_name); ipcRenderer.on('selected-file', function(event, filename) { $('#filePath').val(filename); settingsValues.filePath = filename app.ep.settings.set('filePath', filename); }); $('#passphrase').change(function() { settingsValues.ssh_passphrase = $(this).val() app.ep.settings.set('ssh_passphrase', $(this).val()); }); $('#keyName').change(function() { settingsValues.do_ssh_key_name = $(this).val() app.ep.settings.set('do_ssh_key_name', $(this).val()); }); $('#doKey').change(function() { settingsValues.do_api_key = $(this).val() app.ep.settings.set('do_api_key', $(this).val()); }); $('#saveSettings').click(() => { ipcRenderer.send('refreshMainWindow'); }); $('#destroy').click(() => { $("#destroy").prop("disabled", true); if (settingsValues.do_api_key == null || settingsValues.do_api_ke == "") { $('#destroy').text('No API Key was found'); setTimeout(function(){ $('#destroy').text('Destroy'); $("#destroy").prop("disabled", false); }, 5000); } else { $('#destroy').text('Destroying...'); ipcRenderer.send('wipeDroplets'); } }); $('#reset').click(() => { dialog.showMessageBox({ "message": `Are you sure you want to reset?`, "detail": "You will not be able to recover any task data after you perform this action.", "buttons": ["Ok", "Cancel"], }, function(response) { switch (response) { case 0: ok(); case 1: break; } }); function ok() { settings.resetToDefaults() ipcRenderer.send('resetApp'); } }); ipcRenderer.on('errDestroy', function(event, data) { $('#destroy').text('Error Occured while destroying'); setTimeout(function(){ $('#destroy').text('Destroy'); $("#destroy").prop("disabled", false); }, 5000); }); ipcRenderer.on('wipe-complete', function(event, data) { $('#destroy').text('All Droplets have been destroyed'); setTimeout(function(){ $('#destroy').text('Destroy'); $("#destroy").prop("disabled", false); }, 5000); });