UNPKG

wanami-browser

Version:
1,633 lines (1,406 loc) 55 kB
module.exports = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./main/background.js"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./main/background.js": /*!****************************!*\ !*** ./main/background.js ***! \****************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const path = __webpack_require__(/*! path */ "path"); const os = __webpack_require__(/*! os */ "os"); const envPath = path.resolve(process.cwd(), 'config/.env'); __webpack_require__(/*! dotenv */ "dotenv").config({ path: envPath }); const electron = __webpack_require__(/*! electron */ "electron"); const { app } = electron; const serve = __webpack_require__(/*! electron-serve */ "electron-serve"); const { createTaskbar } = __webpack_require__(/*! ./views/taskbar */ "./main/views/taskbar/index.js"); const { createContentView } = __webpack_require__(/*! ./views/content */ "./main/views/content/index.js"); const { createPasswordView } = __webpack_require__(/*! ./views/password */ "./main/views/password/index.js"); const { createMainWindow, attachViews } = __webpack_require__(/*! ./windows/main */ "./main/windows/main/index.js"); const { attachIPCListeners } = __webpack_require__(/*! ./communication/ipc */ "./main/communication/ipc/index.js"); const { isProduction, platform } = __webpack_require__(/*! ./utility/env_config */ "./main/utility/env_config.js"); const { passwords } = __webpack_require__(/*! ./services */ "./main/services/index.js"); const { log } = __webpack_require__(/*! ./utility/logger */ "./main/utility/logger.js"); // References to prevent garbage collection global.electronRefs = { windows: { mainWindow: null, taskbarWindow: null }, views: { taskbarView: null, contentView: null, passwordView: null } }; global.appName = app.name; if (isProduction) { serve({ directory: 'app' }); } else { app.setPath('userData', `${app.getPath('userData')} (development)`); } const initialize = () => { app.dock.setIcon(electron.nativeImage.createFromPath(app.getAppPath() + "/resources/icons/linux/icon_256x256.png")); createTaskbar(app); createContentView(app); createPasswordView(app); createMainWindow(app); attachViews([global.electronRefs.views.contentView, global.electronRefs.views.taskbarView, global.electronRefs.views.passwordView]); attachIPCListeners(); loadWindowContents(); }; const clearViewContent = () => { global.electronRefs.views.taskbarView.webContents.loadFile(''); global.electronRefs.views.contentView.webContents.loadFile(''); }; const loadPasswordPage = () => { const port = process.argv[2]; if (isProduction) { global.electronRefs.views.passwordView.webContents.loadURL('app://./password.html'); } else { global.electronRefs.views.passwordView.webContents.loadURL(`http://localhost:${port}/password`); } }; const loadCreatePasswordPage = () => { const port = process.argv[2]; if (isProduction) { global.electronRefs.views.passwordView.webContents.loadURL('app://./create-password.html'); } else { global.electronRefs.views.passwordView.webContents.loadURL(`http://localhost:${port}/create-password`); } }; const loadTaskbar = () => { const port = process.argv[2]; if (isProduction) { global.electronRefs.views.taskbarView.webContents.loadURL('app://./home.html'); } else { global.electronRefs.views.taskbarView.webContents.loadURL(`http://localhost:${port}/home`); } }; const loadHomepage = () => { global.electronRefs.views.contentView.webContents.loadURL('https://www.google.com/'); // if(!isProduction){ // global.electronRefs.views.contentView.webContents.openDevTools({ mode: 'detach' }); // } }; const loadWindowContents = () => { global.electronRefs.views.contentView.setBackgroundColor('#2B2E3B'); passwords.getPassword('app:global').then(data => data ? loadPasswordPage() : loadCreatePasswordPage()).catch(error => { loadCreatePasswordPage(); }); global.electronRefs.views.passwordView.webContents.once('did-finish-load', () => { setTimeout(() => { loadTaskbar(); global.electronRefs.views.taskbarView.webContents.once('did-finish-load', () => { // if(!isProduction){ // global.electronRefs.views.taskbarView.webContents.openDevTools({ mode: 'detach' }); // } loadHomepage(); }); }, 2000); }); }; app.on('ready', () => initialize()); // (macOS) app icon clicked in dock app.on('activate', () => initialize()); app.on('window-all-closed', () => { global.electronRefs.views.contentView.webContents.clearHistory(); clearViewContent(); if (platform !== 'darwin') app.quit(); }); app.on('browser-window-blur', e => log.info('app::', 'Focus Lost')); app.on('browser-window-focus', e => log.info('app::', 'Focus Gained')); app.on('before-quit', e => log.info('app::', 'About to Quit')); /***/ }), /***/ "./main/communication/ipc/index.js": /*!*****************************************!*\ !*** ./main/communication/ipc/index.js ***! \*****************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { ipcMain } = __webpack_require__(/*! electron */ "electron"); const domainParser = __webpack_require__(/*! psl */ "psl"); const { loadNewPage } = __webpack_require__(/*! ../../views/content/controller */ "./main/views/content/controller.js"); const { uplead, otp, passwords } = __webpack_require__(/*! ../../services */ "./main/services/index.js"); const { sleep, validURL, checkForUpdates } = __webpack_require__(/*! ../../utility/helper */ "./main/utility/helper.js"); const { log } = __webpack_require__(/*! ../../utility/logger */ "./main/utility/logger.js"); const attachIPCListeners = () => { if (attachIPCListeners.singleton) return; ipcMain.handle('taskbar::navigate', (e, { protocol, url }) => { let toLoadURL = validURL(protocol, url) || validURL('https://', `duckduckgo.com/?q=${encodeURI(url)}`); try { log.info('taskbar::navigate', toLoadURL); loadNewPage(toLoadURL); } catch (err) { console.error('app::navigate', protocol, url); } return { toLoadURL }; }); ipcMain.handle('taskbar::open', () => { const { width, height } = global.electronRefs.windows.mainWindow.getBounds(); global.electronRefs.views.taskbarView.setBounds({ x: 0, y: 0, width, height }); }); ipcMain.handle('taskbar::close', () => { const { width } = global.electronRefs.windows.mainWindow.getBounds(); global.electronRefs.views.taskbarView.setBounds({ x: 0, y: 0, width, height: 56 }); }); ipcMain.handle('taskbar::reload', () => { global.electronRefs.views.contentView.webContents.reload(); }); ipcMain.handle('taskbar::back', () => { if (global.electronRefs.views.contentView.webContents.canGoBack()) { global.electronRefs.views.contentView.webContents.goBack(); } }); ipcMain.handle('taskbar::forward', () => { if (global.electronRefs.views.contentView.webContents.canGoForward()) { global.electronRefs.views.contentView.webContents.goForward(); } }); ipcMain.handle('taskbar::company-info', async (e, url) => { try { const justDomain = domainParser.get(url); const { data } = await uplead.getCompanyInfo(justDomain); log.info('app::getCompanyInfo', data); return data; } catch (error) { log.info('app::getCompanyInfo', error); } }); ipcMain.handle('taskbar::otp-capture', async (e, navigation) => { const nativeImage = await global.electronRefs.views.contentView.webContents.capturePage(); const jpegData = nativeImage.toJPEG(100); const otpObj = otp.handleOTP(jpegData, navigation); if (otpObj) { otpObj.navigation = navigation; const response = { issuer: otpObj.issuer, label: otpObj.label, digits: otpObj.digits, navigation }; log.info(otpObj); return response; } return null; }); ipcMain.handle('taskbar::otp-codes', async e => { return otp.getCodes(); }); ipcMain.handle('password::enter', async (e, input) => { await sleep(2000); if (await passwords.verifyPassword('app:global', input)) { log.info('app::password', 'Password Success'); setTimeout(() => { global.electronRefs.windows.mainWindow.removeBrowserView(global.electronRefs.views.passwordView); global.electronRefs.views.passwordView.destroy(); global.electronRefs.views.passwordView = null; }, 500); otp.initializeStore(input); checkForUpdates(); return true; } log.error('app::password', 'Password Failure'); return false; }); ipcMain.handle('password::create', async (e, { password, confirmedPassword }) => { await sleep(2000); if (password === confirmedPassword) { return passwords.setPassword('app:global', password).then(data => { log.info('app::password', 'Create Password Success'); setTimeout(() => { global.electronRefs.windows.mainWindow.removeBrowserView(global.electronRefs.views.passwordView); global.electronRefs.views.passwordView.destroy(); global.electronRefs.views.passwordView = null; }, 500); otp.initializeStore(password); return true; }).catch(error => { console.error('app::password', error); return false; }); } else { log.error('app::password', 'Create Password Failure'); return false; } }); attachIPCListeners.singleton = true; }; module.exports = { attachIPCListeners }; /***/ }), /***/ "./main/services/apivoid/index.js": /*!****************************************!*\ !*** ./main/services/apivoid/index.js ***! \****************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const axios = __webpack_require__(/*! axios */ "axios"); const memo = __webpack_require__(/*! memoizee */ "memoizee"); const token = process.env['APIVOID_API_TOKEN']; const { log } = __webpack_require__(/*! ../../utility/logger */ "./main/utility/logger.js"); const uplead = axios.create({ baseURL: 'https://endpoint.apivoid.com/urlrep/v1/pay-as-you-go', timeout: 1500 }); const getSecurityInfo = async url => { log.info('app::getSecurityInfo', `Fetching ${url}`); const response = await uplead.get('/', { params: { key: token, url } }).catch(e => { console.error('app::getSecurityInfo', e); }); return response && response.data; }; module.exports = { getSecurityInfo: memo(getSecurityInfo) }; /***/ }), /***/ "./main/services/index.js": /*!********************************!*\ !*** ./main/services/index.js ***! \********************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const uplead = __webpack_require__(/*! ./uplead */ "./main/services/uplead/index.js"); const apivoid = __webpack_require__(/*! ./apivoid */ "./main/services/apivoid/index.js"); const otp = __webpack_require__(/*! ./otp */ "./main/services/otp/index.js"); const passwords = __webpack_require__(/*! ./passwords */ "./main/services/passwords/index.js"); module.exports = { uplead, apivoid, otp, passwords }; /***/ }), /***/ "./main/services/otp/index.js": /*!************************************!*\ !*** ./main/services/otp/index.js ***! \************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const fs = __webpack_require__(/*! fs */ "fs"); const jsQR = __webpack_require__(/*! jsqr */ "jsqr"); const jpeg = __webpack_require__(/*! jpeg-js */ "jpeg-js"); const OTPAuth = __webpack_require__(/*! otpauth */ "otpauth"); const Store = __webpack_require__(/*! electron-store */ "electron-store"); let store = null; let otp = []; const handleOTP = (data, metadata = false) => { const code = extractQRCode(data); const otpConfig = code && parseOTPLink(code.data); const otpItem = createOTP(otpConfig); if (otpItem) { store.set(`${otpItem.issuer}-${otpItem.label}`, { otp: otpItem.toString(), metadata }); restoreItems(); } return otpItem; }; const extractQRCode = rawJpegData => { try { const { data, width, height } = jpeg.decode(rawJpegData, { useTArray: true }); return jsQR(data, width, height); } catch (err) { console.error(err); return null; } }; const parseOTPLink = uri => { try { return OTPAuth.URI.parse(uri); } catch (err) { console.error(err); return null; } }; const createOTP = otpObject => { if (otpObject instanceof OTPAuth.TOTP) { return new OTPAuth.TOTP(otpObject); } else if (otpObject instanceof OTPAuth.HOTP) { return OTPAuth.HOTP(otpObject); } else { return null; } }; const restoreItems = () => { otp = []; for (let x of store) { if (x[1]) otp.push({ otp: createOTP(parseOTPLink(x[1].otp)), metadata: x[1].metadata }); } }; const getCodes = () => { return otp.map(x => { return { issuer: x.otp.issuer, label: x.otp.label, digits: x.otp.digits, code: x.otp.generate(), hostname: x.metadata.hostname }; }); }; const seedStore = () => { // Example of a TOTP URI // otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example const sample = ['otpauth://totp/Google:alice@wanamibrowser.com?secret=JBSWY3DPEHPK3PXP&issuer=Google', 'otpauth://totp/Facebook:alice@wanamibrowser.com?secret=JBSWY3DPEHPK3PXW&issuer=Facebook', 'otpauth://totp/Twitter:alice@wanamibrowser.com?secret=JBSWY3DPEHPK3PXF&issuer=Twitter']; for (let link of sample) { const otpConfig = parseOTPLink(link); const otpItem = createOTP(otpConfig); if (otpItem) { store.set(`${otpItem.issuer}-${otpItem.label}`, { otp: otpItem.toString(), metadata: { hostname: 'Sample' } }); } } restoreItems(); }; const initializeStore = encryptionKey => { store = new Store({ name: 'otp-mfa-store', accessPropertiesByDotNotation: false, encryptionKey }); // seedStore(); // For demo purposes restoreItems(); }; module.exports = { handleOTP, getCodes, restoreItems, initializeStore }; /***/ }), /***/ "./main/services/passwords/index.js": /*!******************************************!*\ !*** ./main/services/passwords/index.js ***! \******************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const keytar = __webpack_require__(/*! keytar */ "keytar"); const argon2 = __webpack_require__(/*! argon2 */ "argon2"); const getPassword = async account => { return await keytar.getPassword(global.appName, account); }; const verifyPassword = async (account, password) => { try { const hash = await getPassword(account); return await argon2.verify(hash, password); } catch (error) { console.error('passwords::verify', error); return false; } }; const setPassword = async (account, password) => { try { const hash = await argon2.hash(password); await keytar.setPassword(global.appName, account, hash); return true; } catch (error) { console.error('passwords::set', error); return false; } }; module.exports = { getPassword, verifyPassword, setPassword }; /***/ }), /***/ "./main/services/uplead/index.js": /*!***************************************!*\ !*** ./main/services/uplead/index.js ***! \***************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const axios = __webpack_require__(/*! axios */ "axios"); const memo = __webpack_require__(/*! memoizee */ "memoizee"); const token = process.env['UPLEAD_API_TOKEN']; const uplead = axios.create({ baseURL: 'https://api.uplead.com/v2/', timeout: 1000, headers: { 'Authorization': token } }); const getCompanyInfo = async domain => { if (process.env['ENABLE_COMPANY_DATA'] === 'true') { const data = await uplead.get('company-search', { params: { domain } }).catch(e => { console.error('app::getCompanyInfo', e); }); return data && data.data; } return {}; }; module.exports = { getCompanyInfo: memo(getCompanyInfo) }; /***/ }), /***/ "./main/utility/certificates.js": /*!**************************************!*\ !*** ./main/utility/certificates.js ***! \**************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const https = __webpack_require__(/*! https */ "https"); const Joi = __webpack_require__(/*! joi */ "joi"); const certificateSchema = Joi.object({ subject: Joi.object({ CN: Joi.optional(), O: Joi.optional(), C: Joi.optional() }).optional(), subjectaltname: Joi.optional(), valid_to: Joi.optional(), issuer: Joi.object({ CN: Joi.optional(), O: Joi.optional(), C: Joi.optional() }).optional() }).options({ stripUnknown: true }); const fetchCertificate = options => { let config = { agent: false, ciphers: 'ALL', method: 'GET', rejectUnauthorized: true, ...options }; return new Promise(function (resolve, reject) { const req = https.request(config, function (res) { const certificate = res.socket.getPeerCertificate(); if (typeof certificate === 'undefined' || certificate === null) { reject({ message: 'The website did not provide a valid certificate', error: '' }); } else { resolve(certificate); } }); req.end(); req.on('error', error => { reject({ message: 'The website did not provide a valid certificate', error }); }); }); }; const parseCertificate = certificate => { return certificateSchema.validate(certificate); }; module.exports = { fetchCertificate, parseCertificate }; /***/ }), /***/ "./main/utility/env_config.js": /*!************************************!*\ !*** ./main/utility/env_config.js ***! \************************************/ /*! no static exports found */ /***/ (function(module, exports) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const isProduction = "development" === 'production'; const platform = process.platform; module.exports = { isProduction, platform }; /***/ }), /***/ "./main/utility/helper.js": /*!********************************!*\ !*** ./main/utility/helper.js ***! \********************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const normalizeUrl = __webpack_require__(/*! normalize-url */ "normalize-url"); const versionCheck = __webpack_require__(/*! github-version-checker */ "github-version-checker"); const domainParser = __webpack_require__(/*! psl */ "psl"); const { URL } = __webpack_require__(/*! url */ "url"); const pkg = __webpack_require__(/*! ../../package.json */ "./package.json"); const { navigateNotification } = __webpack_require__(/*! ../windows/generic/notifications */ "./main/windows/generic/notifications.js"); const { log } = __webpack_require__(/*! ./logger */ "./main/utility/logger.js"); const getPropertySafe = (func, defaultValue) => { try { return func(); } catch (e) { return defaultValue; } }; const sleep = ms => { return new Promise(resolve => setTimeout(resolve, ms)); }; const validURL = (protocol, url) => { try { log.info('app::url-check', url); const urlObj = new URL(normalizeUrl(url, { forceHttps: true })); const validDomain = domainParser.get(urlObj.hostname); const remProto = normalizeUrl(url, { stripProtocol: true }); return validDomain && normalizeUrl(`${protocol}${remProto}`); } catch (error) { console.error('app::url-check', url, error); return false; } }; const checkForUpdates = () => { versionCheck({ repo: pkg.name, owner: pkg.repository.owner, currentVersion: pkg.version }, function (error, update) { if (error) { log.error('app::', 'Unable to Check for Available', error); } else if (update) { log.info('app::', 'Update Available', JSON.stringify(update)); if (!update.isPrerelease) { navigateNotification({ subtitle: 'Update Available!', body: `Version ${update.name} is available on GitHub`, urgency: 'normal' }, update.url); } } else { log.info('app::', 'No Update Available'); } }); }; module.exports = { getPropertySafe, sleep, validURL, checkForUpdates }; /***/ }), /***/ "./main/utility/logger.js": /*!********************************!*\ !*** ./main/utility/logger.js ***! \********************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const log = __webpack_require__(/*! electron-log */ "electron-log"); module.exports = { log }; /***/ }), /***/ "./main/views/content/controller.js": /*!******************************************!*\ !*** ./main/views/content/controller.js ***! \******************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const urlParser = __webpack_require__(/*! url */ "url"); const { fetchCertificate, parseCertificate } = __webpack_require__(/*! ../../utility/certificates */ "./main/utility/certificates.js"); const { apivoid } = __webpack_require__(/*! ../../services */ "./main/services/index.js"); const { launchNotification } = __webpack_require__(/*! ../../windows/generic/notifications */ "./main/windows/generic/notifications.js"); const { log } = __webpack_require__(/*! ../../utility/logger */ "./main/utility/logger.js"); const completedNavigation = url => { let parsedURL = urlParser.parse(url); let certificateError = null; fetchCertificate({ hostname: parsedURL.hostname }).then(function (certificate) { const { error, value } = parseCertificate(certificate); log.info('app::certificate', error, value); if (!error) { global.electronRefs.views.taskbarView.webContents.send("organization::certificate", value); } }).catch(error => { log.info('app::certificate', error); certificateError = error; }).finally(() => { if (parsedURL.protocol === 'http:' || certificateError !== null) { parsedURL.protocol = 'http:'; launchNotification({ subtitle: 'Security Warning!', body: 'Review the secuity panel for more information.', urgency: 'critical' }); } global.electronRefs.views.taskbarView.webContents.send('navigate::new', parsedURL); }); if (process.env['ENABLE_URL_CHECK'] === 'true') { log.info('app::getSecurityInfo', 'Fetching URL Info'); apivoid.getSecurityInfo(url).then(({ data }) => { log.info('app::getSecurityInfo', data); const response = { detections: data.report.domain_blacklist.detections, risk: data.report.risk_score.result, security_checks: data.report.security_checks }; const securityScore = Object.values(response.security_checks).reduce((accumulator, currentValue) => { if (!currentValue) { return accumulator + 1; } }); response.warning = response.risk > 75 && response.detections > 10 && securityScore > 5; if (response.warning) { launchNotification({ subtitle: 'Security Warning!', body: 'Review the secuity panel for more information.', urgency: 'critical' }); } global.electronRefs.views.taskbarView.webContents.send("security::checkup", response); }).catch(function (error) { console.error('app::getSecurityInfo', error); }); } else { log.info('app::getSecurityInfo', 'Skipping Security Checks'); } }; const loadNewPage = url => { global.electronRefs.views.contentView.webContents.loadURL(url); }; module.exports = { completedNavigation, loadNewPage }; /***/ }), /***/ "./main/views/content/index.js": /*!*************************************!*\ !*** ./main/views/content/index.js ***! \*************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { BrowserView } = __webpack_require__(/*! electron */ "electron"); const urlParser = __webpack_require__(/*! url */ "url"); const { completedNavigation, loadNewPage } = __webpack_require__(/*! ./controller */ "./main/views/content/controller.js"); const { log } = __webpack_require__(/*! ../../utility/logger */ "./main/utility/logger.js"); const setViewBoundsContent = (width, height) => { global.electronRefs.views.contentView.setBounds({ x: 0, y: 52, width, height: height - 72 }); }; const createContentView = app => { if (global.electronRefs.views.contentView !== null) return null; global.electronRefs.views.contentView = new BrowserView({ webPreferences: { nodeIntegration: false, contextIsolation: true, sandbox: true, enableRemoteModule: false, backgroundThrottling: false } }); attachListeners(); }; const attachListeners = () => { if (attachListeners.singleton) return; global.electronRefs.views.contentView.webContents.on('console-message', (e, level, message) => { log.info('Content::console-message', level, message); }); global.electronRefs.views.contentView.webContents.on('page-title-updated', (e, title) => { log.info('Content::page-title-updated', title); }); global.electronRefs.views.contentView.webContents.on('did-navigate', async (e, url) => { log.info('Content::did-navigate', url); completedNavigation(url); }); global.electronRefs.views.contentView.webContents.on('did-navigate-in-page', async (e, url, isMainFrame) => { log.info('Content::did-navigate-in-page', url, isMainFrame); if (isMainFrame) { completedNavigation(url); } }); global.electronRefs.views.contentView.webContents.on('did-stop-loading', () => { log.info('Content::did-stop-loading'); }); global.electronRefs.views.contentView.webContents.on('did-start-loading', () => { log.info('Content::did-start-loading'); }); global.electronRefs.views.contentView.webContents.on('did-start-navigation', async (e, ...args) => { log.info('Content::did-start-navigation'); }); global.electronRefs.views.contentView.webContents.on('new-window', async (e, url, frameName, disposition) => { e.preventDefault(); log.info('Content::new-window', url, frameName, disposition); loadNewPage(url); }); global.electronRefs.views.contentView.webContents.on('did-fail-load', (e, errorCode, errorDescription, validatedURL, isMainFrame) => { log.info('Content::did-fail-load', errorCode, errorDescription, validatedURL, isMainFrame); }); global.electronRefs.views.contentView.webContents.on('page-favicon-updated', async (e, favicons) => { log.info('Content::page-favicon-updated', favicons); }); global.electronRefs.views.contentView.webContents.on('certificate-error', (event, url, error, certificate, callback) => { // log.info('Content::certificate-error', url, error, certificate); event.preventDefault(); callback(true); }); global.electronRefs.views.contentView.webContents.on('render-process-gone', (event, details) => { log.info('Content::render-process-gone', details); }); global.electronRefs.views.contentView.webContents.on('unresponsive', event => { log.info('Content::unresponsive'); }); global.electronRefs.views.contentView.webContents.on('destroyed', event => { log.info('Content::destroyed'); }); attachListeners.singleton = true; }; module.exports = { createContentView, setViewBoundsContent }; /***/ }), /***/ "./main/views/password/index.js": /*!**************************************!*\ !*** ./main/views/password/index.js ***! \**************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { BrowserView } = __webpack_require__(/*! electron */ "electron"); const { log } = __webpack_require__(/*! ../../utility/logger */ "./main/utility/logger.js"); const setViewBoundsPassword = (width, height) => { global.electronRefs.views.passwordView.setBounds({ x: 0, y: 0, width, height }); }; const createPasswordView = app => { if (global.electronRefs.views.passwordView !== null) return null; global.electronRefs.views.passwordView = new BrowserView({ webPreferences: { nodeIntegration: true, enableRemoteModule: true, backgroundThrottling: false } }); attachListeners(); }; const attachListeners = () => { if (attachListeners.singleton) return; global.electronRefs.views.passwordView.webContents.on('console-message', (e, level, message) => { log.info('Taskbar::log', level, message); }); attachListeners.singleton = true; }; module.exports = { createPasswordView, setViewBoundsPassword }; /***/ }), /***/ "./main/views/taskbar/index.js": /*!*************************************!*\ !*** ./main/views/taskbar/index.js ***! \*************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { BrowserView } = __webpack_require__(/*! electron */ "electron"); const { isProduction } = __webpack_require__(/*! ../../utility/env_config */ "./main/utility/env_config.js"); const { log } = __webpack_require__(/*! ../../utility/logger */ "./main/utility/logger.js"); const setViewBoundsTaskbar = (width, height) => { global.electronRefs.views.taskbarView.setBounds({ x: 0, y: 0, width, height: 56 }); }; const createTaskbar = app => { if (global.electronRefs.views.taskbarView !== null) return null; global.electronRefs.views.taskbarView = new BrowserView({ webPreferences: { nodeIntegration: true, enableRemoteModule: true, backgroundThrottling: false } }); attachListeners(); }; const attachListeners = () => { if (attachListeners.singleton) return; global.electronRefs.views.taskbarView.webContents.on('console-message', (e, level, message) => { log.info('Taskbar::log', level, message); }); attachListeners.singleton = true; }; module.exports = { createTaskbar, setViewBoundsTaskbar }; /***/ }), /***/ "./main/windows/generic/create_window.js": /*!***********************************************!*\ !*** ./main/windows/generic/create_window.js ***! \***********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { screen, BrowserWindow, Menu, Tray } = __webpack_require__(/*! electron */ "electron"); const Store = __webpack_require__(/*! electron-store */ "electron-store"); const { menubar, contextMenu } = __webpack_require__(/*! ./menu */ "./main/windows/generic/menu.js"); let trayMenu = null; function createWindow(windowName, options) { const key = 'window-state'; const name = `window-state-${windowName}`; const store = new Store({ name }); const defaultSize = { width: options.width, height: options.height }; let state = {}; let win; const restore = () => store.get(key, defaultSize); const getCurrentPosition = () => { const position = win.getPosition(); const size = win.getSize(); return { x: position[0], y: position[1], width: size[0], height: size[1] }; }; const windowWithinBounds = (windowState, bounds) => { return windowState.x >= bounds.x && windowState.y >= bounds.y && windowState.x + windowState.width <= bounds.x + bounds.width && windowState.y + windowState.height <= bounds.y + bounds.height; }; const resetToDefaults = () => { const bounds = screen.getPrimaryDisplay().bounds; return Object.assign({}, defaultSize, { x: (bounds.width - defaultSize.width) / 2, y: (bounds.height - defaultSize.height) / 2 }); }; const ensureVisibleOnSomeDisplay = windowState => { const visible = screen.getAllDisplays().some(display => { return windowWithinBounds(windowState, display.bounds); }); if (!visible) { // Window is partially or fully not visible now. // Reset it to safe defaults. return resetToDefaults(); } return windowState; }; const saveState = () => { if (!win.isMinimized() && !win.isMaximized()) { Object.assign(state, getCurrentPosition()); } store.set(key, state); }; state = ensureVisibleOnSomeDisplay(restore()); win = new BrowserWindow({ ...options, ...state, webPreferences: { ...options.webPreferences } }); tray = new Tray(`${__dirname}/../resources/icons/linux/icon_16x16.png`); tray.setToolTip(windowName); tray.on('click', e => win.show()); tray.on('right-click', e => { trayMenu = Menu.buildFromTemplate([{ role: 'quit' }]); tray.setContextMenu(trayMenu); tray.popUpContextMenu(trayMenu); }); const mainMenu = Menu.buildFromTemplate(menubar); const context = Menu.buildFromTemplate(contextMenu); Menu.setApplicationMenu(mainMenu); win.on('close', saveState); win.webContents.on('context-menu', e => { context.popup(); }); return win; } ; module.exports = { createWindow }; /***/ }), /***/ "./main/windows/generic/menu.js": /*!**************************************!*\ !*** ./main/windows/generic/menu.js ***! \**************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { platform } = __webpack_require__(/*! ../../utility/env_config */ "./main/utility/env_config.js"); const { shell } = __webpack_require__(/*! electron */ "electron"); const openAboutWindow = __webpack_require__(/*! electron-about-window */ "electron-about-window").default; const { join } = __webpack_require__(/*! path */ "path"); const menubar = [...(platform === 'darwin' ? [{ label: 'Wanami Browser', submenu: [{ label: 'About Wanami Browser', click: () => { // TODO: Figure out why this does not work. openAboutWindow({ icon_path: join(__dirname, '../../../resources/icons/linux/icon_256x256.png'), copyright: 'Copyright © 2020 Stephen Mendez', package_json_dir: join(__dirname, '../../../'), open_devtools: "development" !== 'production', win_options: { webPreferences: { nodeIntegration: true } } }); } }, { type: 'separator' }, { role: 'services' }, { type: 'separator' }, { role: 'hide' }, { role: 'hideothers' }, { role: 'unhide' }, { type: 'separator' }, { role: 'quit' }] }] : []), { role: 'fileMenu' }, { role: 'editMenu' }, { role: 'viewMenu' }, { role: 'windowMenu' }, { role: 'help', submenu: [{ label: 'Learn More', click: () => { shell.openExternal('https://github.com/401unauthorized/wanami-browser'); } }] }]; const contextMenu = [{ role: 'editMenu' }]; module.exports = { menubar, contextMenu }; /***/ }), /***/ "./main/windows/generic/notifications.js": /*!***********************************************!*\ !*** ./main/windows/generic/notifications.js ***! \***********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { Notification } = __webpack_require__(/*! electron */ "electron"); const { loadNewPage } = __webpack_require__(/*! ../../views/content/controller */ "./main/views/content/controller.js"); const launchNotification = options => { let notification = new Notification({ title: global.appName, ...options }); notification.show(); notification.on('click', e => { if (!global.electronRefs.windows.mainWindow.isVisible()) { global.electronRefs.windows.mainWindow.show(); } }); }; const navigateNotification = (options, url) => { let notification = new Notification({ title: global.appName, ...options }); notification.show(); notification.on('click', e => { if (!global.electronRefs.windows.mainWindow.isVisible()) { global.electronRefs.windows.mainWindow.show(); } global.electronRefs.views.contentView.webContents.loadURL(url); }); }; module.exports = { launchNotification, navigateNotification }; /***/ }), /***/ "./main/windows/main/index.js": /*!************************************!*\ !*** ./main/windows/main/index.js ***! \************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* Copyright (c) 2020 Stephen Mendez. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const { createWindow } = __webpack_require__(/*! ../generic/create_window */ "./main/windows/generic/create_window.js"); const { setViewBoundsTaskbar } = __webpack_require__(/*! ../../views/taskbar */ "./main/views/taskbar/index.js"); const { setViewBoundsContent } = __webpack_require__(/*! ../../views/content */ "./main/views/content/index.js"); const { setViewBoundsPassword } = __webpack_require__(/*! ../../views/password */ "./main/views/password/index.js"); const resizeInnerContents = () => { const { width, height } = global.electronRefs.windows.mainWindow.getBounds(); setViewBoundsTaskbar(width, height); setViewBoundsContent(width, height); setViewBoundsPassword(width, height); }; const attachViews = views => { for (let v of views) { global.electronRefs.windows.mainWindow.addBrowserView(v); } resizeInnerContents(); }; const createMainWindow = app => { if (global.electronRefs.windows.mainWindow !== null) return null; global.electronRefs.windows.mainWindow = createWindow(app.name, { title: app.name, icon: `${__dirname}/../../../resources/icons/mac/wanami.icns`, resizable: true, backgroundColor: '#2B2E3B', opacity: 1, width: 1000, height: 800, minWidth: 520, minHeight: 360, webPreferences: { nodeIntegration: true, backgroundThrottling: false } }); global.electronRefs.windows.mainWindow.on('resize', resizeInnerContents); global.electronRefs.windows.mainWindow.on('closed', () => { global.electronRefs.windows.mainWindow = null; }); }; module.exports = { createMainWindow, attachViews }; /***/ }), /***/ "./package.json": /*!**********************!*\ !*** ./package.json ***! \**********************/ /*! exports provided: name, productName, description, version, keywords, author, bugs, repository, license, main, scripts, dependencies, devDependencies, funding, default */ /***/ (function(module) { module.exports = JSON.parse("{\"name\":\"wanami-browser\",\"productName\":\"Wanami Browser\",\"description\":\"A simple, cybersecurity focused web browser.\",\"version\":\"1.0.0\",\"keywords\":[\"wanami\",\"wahoo\",\"namaste\",\"web\",\"browser\",\"cybersecurity\",\"phishing\",\"electron\",\"react\"],\"author\":\"Stephen Mendez <git@stephenmendez.dev> (https://www.stephenmendez.dev)\",\"bugs\":\"https://github.com/401unauthorized/wanami-browser/issues\",\"repository\":{\"type\":\"git\",\"url\":\"https://github.com/401unauthorized/wanami-browser.git\",\"owner\":\"401Unauthorized\"},\"license\":\"MPL-2.0\",\"main\":\"app/background.js\",\"scripts\":{\"dev\":\"nextron\",\"build\":\"nextron build\",\"postinstall\":\"electron-builder install-app-deps\",\"package-mac\":\"electron-packager ./main --overwrite --platform=darwin --arch=x64 --icon=resources/icons/mac/icon.icns --prune=true --out=release-builds\",\"package-win\":\"electron-packager ./main --overwrite --platform=win32 --arch=ia32 --icon=resources/icons/win/icon.ico --prune=false --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\\\"Wanami Browser\\\"\",\"package-linux\":\"electron-packager ./main --overwrite --platform=linux --arch=x64 --icon=resources/icons/linux/icon.png --prune=false --out=release-builds\"},\"dependencies\":{\"argon2\":\"^0.27.0\",\"axios\":\"^0.21.0\",\"copy-to-clipboard\":\"^3.3.1\",\"dotenv\":\"^8.2.0\",\"electron-about-window\":\"^1.13.4\",\"electron-log\":\"^4.3.0\",\"electron-serve\":\"^1.0.0\",\"electron-store\":\"^6.0.1\",\"framer-motion\":\"^2.9.4\",\"github-version-checker\":\"^2.2.0\",\"joi\":\"^17.3.0\",\"jpeg-js\":\"^0.4.2\",\"jsqr\":\"^1.3.1\",\"keytar\":\"^7.0.0\",\"memoizee\":\"^0.4.14\",\"moment\":\"^2.29.1\",\"normalize-url\":\"^5.3.0\",\"otpauth\":\"^6.1.0\",\"psl\":\"^1.8.0\",\"semantic-ui-css\":\"^2.4.1\",\"semantic-ui-react\":\"^2.0.1\"},\"devDependencies\":{\"@babel/core\":\"^7.11.6\",\"babel-loader\":\"^8.1.0\",\"electron\":\"^10.1.5\",\"electron-builder\":\"^22.9.1\",\"electron-packager\":\"^15.1.0\",\"next\":\"^10.0.2\",\"nextron\":\"^5.15.11\",\"react\":\"^16.14.0\",\"react-dom\":\"^16.14.0\",\"webpack\":\"^4.44.2\"},\"funding\":{\"type\":\"individual\",\"url\":\"https://paypal.me/stephenmendez401\"}}"); /***/ }), /***/ "argon2": /*!*************************!*\ !*** external "argon2" ***! \*************************/ /*! no static exports found */ /***/