diff --git a/CHANGELOG.md b/CHANGELOG.md index 98420f55..5f127468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ All notable changes to this project will be documented in this file. +## [3.0.5](https://github.com/Netflix-Skunkworks/stethoscope-app/tree/v3.0.5) + +### Fixed +- kmd requiring node to be installed on user's machine +- Lack of proper error handling when scan fails +- Timing destructuring error +- Issue reading logs when files haven't been created +- Update Electron to 2.0.18 to fix security issue +- Semver parsing issue + +### Added +- Debugger app link - [stethoscope://debugger](stethoscope://debugger) +- AWS Workspace support +- Auto-expand first failing item + +---- + +## [3.0.1](https://github.com/Netflix-Skunkworks/stethoscope-app/tree/v3.0.1) + +### Removed +- OSquery dependency, it's been a good run, but not a great fit for our use-case. We switched to [`kmd`](https://github.com/Netflix-Skunkworks/kmd) + +---- + ## [2.1.0](https://github.com/Netflix-Skunkworks/stethoscope-app/tree/v2.1.0) ### Fixed diff --git a/package.json b/package.json index cdcf95a4..e5b1b03b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Stethoscope", - "version": "3.0.4", + "version": "3.0.5", "private": true, "homepage": "./", "author": "Netflix", @@ -107,11 +107,12 @@ "build": "rm -r dist/; react-scripts build && electron-builder -mwl", "postinstall": "electron-builder install-app-deps", "build:react": "react-scripts build && node update-download-page.js", - "build:mac": "rm -r dist/; npm run build:react && npm run build:electron -m && npm run test:spectron", - "build:windows": " npm run build:react && npm run build:electron -w && npm run test:spectron", + "build:clean": "rm -r dist/", + "build:mac": "npm run build:react && npm run build:electron -m && npm run test:spectron", + "build:windows": "npm run build:react && npm run build:electron -w && npm run test:spectron", "build:electron": "cross-env ELECTRON_BUILDER_COMPRESSION_LEVEL=9 electron-builder", "test:spectron": "node src/__tests__/test-build.js", - "build:linux": "rm -r dist/ ; react-scripts build && electron-builder -l", + "build:linux": "react-scripts build && electron-builder -l", "lint": "standard --fix src/*.js src/**/*.js resolvers/*.js sources/*.js server.js" }, "dependencies": { @@ -140,7 +141,7 @@ "helmet": "^3.9.0", "isomorphic-fetch": "^2.2.1", "js-yaml": "^3.10.0", - "kmd-script": "^0.0.7", + "kmd-script": "^0.0.8", "marked": "^0.3.7", "moment": "^2.19.3", "node-powershell": "^3.3.1", diff --git a/practices/policy.yaml b/practices/policy.yaml index e4f1ca27..5786591f 100644 --- a/practices/policy.yaml +++ b/practices/policy.yaml @@ -1,7 +1,7 @@ osVersion: darwin: # High Sierra - ok: ">=10.14.3" + ok: ">=10.14.4" # Sierra nudge: ">=10.12.6" win32: diff --git a/resolvers/platform/WindowsSecurity.js b/resolvers/platform/WindowsSecurity.js index 35c70754..886c4e87 100644 --- a/resolvers/platform/WindowsSecurity.js +++ b/resolvers/platform/WindowsSecurity.js @@ -37,6 +37,9 @@ const WindowsSecurity = { const { chargingTimeout, batteryTimeout } = kmdResponse return ( + // According to Windows: 0 = Never + chargingTimeout !== 0 && + batteryTimeout !== 0 && chargingTimeout <= windowsMaxScreenLockTimeout && batteryTimeout <= windowsMaxScreenLockTimeout ) diff --git a/server.js b/server.js index 8d65b3cd..840054a8 100644 --- a/server.js +++ b/server.js @@ -13,6 +13,7 @@ const fetch = require('isomorphic-fetch') const yaml = require('js-yaml') const { compile, run, setKmdEnv } = require('kmd-script/src') const glob = require('fast-glob') +const pkg = require('./package.json') const { performance } = require('perf_hooks') const { graphql } = require('graphql') @@ -29,7 +30,8 @@ const io = require('socket.io')(http, { wsEngine: 'ws' }) setKmdEnv({ NODE_ENV: process.env.STETHOSCOPE_ENV, - FILE_BASE_PATH: process.resourcesPath + path.sep + FILE_BASE_PATH: process.resourcesPath + path.sep, + NODE_PATH: process.execPath }) function precompile () { @@ -108,6 +110,30 @@ module.exports = async function startServer (env, log, language = 'en-US', appAc platform: process.platform || os.platform() } + app.get('/debugger', cors(corsOptions), (req, res) => { + appActions.enableDebugger() + appActions.requestLogPermission(req.get('origin')).then(async () => { + const file = fs.readFileSync(log.getLogFile()) + const checkData = await Promise.all(checks.map(async script => { + try { return await run(script) } + catch (e) { return '' } + })) + const noColor = String(file).replace(/\[[\d]+m?:?/g, '') + const out = `Stethoscope version: ${pkg.version} + +LOGS +============================== +${noColor} +DEVICE DATA +============================== +${JSON.stringify(extend(true, {}, ...checkData), null, 3)}` + + res.send(out) + }).catch(() => { + res.status(403).send('ACCESS DENIED') + }) + }) + app.use(['/scan', '/graphql'], cors(corsOptions), async (req, res) => { // set upper boundary on scan time const MAX_SCAN_SECONDS = 45 diff --git a/sources/win32/screenlock.sh b/sources/win32/screenlock.sh index d53ec8d8..eca912ae 100644 --- a/sources/win32/screenlock.sh +++ b/sources/win32/screenlock.sh @@ -7,12 +7,12 @@ template powercfg /query '{_activePowerGUID}' 7516b95f-f776-4464-8c53-06167f40cc exec trim save _output -extract Current AC Power Setting Index: 0x([\d]+) +extract Current AC Power Setting Index: 0x([0-9a-fA-F]+) parseInt 16 save chargingTimeout load _output -extract Current DC Power Setting Index: 0x([\d]+) +extract Current DC Power Setting Index: 0x([0-9a-fA-F]+) parseInt 16 save batteryTimeout diff --git a/src/App.js b/src/App.js index c81e627f..ba811858 100644 --- a/src/App.js +++ b/src/App.js @@ -94,7 +94,7 @@ class App extends Component { // setup a socket io listener to refresh the app when a scan is performed socket.on('scan:complete', this.onScanComplete) // TODO handle errors that happen on local scans - // socket.on('scan:error', this.onScanError) + socket.on('scan:error', this.onScanError) // the focus/blur handlers are used to update the last scanned time window.addEventListener('focus', () => this.setState({ focused: true })) window.addEventListener('blur', () => this.setState({ focused: false })) @@ -131,6 +131,7 @@ class App extends Component { onScanError = ({ error }) => { this.errorThrown = true + log.error("Scan error", error) throw new Error(error) } diff --git a/src/lib/Stethoscope.js b/src/lib/Stethoscope.js index 0c1ffc64..2b7b55bf 100644 --- a/src/lib/Stethoscope.js +++ b/src/lib/Stethoscope.js @@ -138,7 +138,8 @@ export default class Stethoscope { return res } }) - .then(({ errors, data = {}, extensions: { timing } }) => { + .then(({ errors, data = {}, extensions = {} }) => { + const { timing = { total: 0 }} = extensions const { policy, device } = data if (errors) { reject({ errors }) diff --git a/src/lib/logger.js b/src/lib/logger.js index 9dd43d1a..1872d63e 100644 --- a/src/lib/logger.js +++ b/src/lib/logger.js @@ -1,15 +1,7 @@ -/** - * Global Logger, pipes appropriate logs to file in dev and production incl. - * auto-rotation. - * - * // visible in dev - * log.info('foo', true, { hello: 'world' }) - * // visible in dev and prod - * log.error(new Error("ohnos")) - */ const { app } = require('electron') const winston = require('winston') const path = require('path') +const moment = require('moment') const chalk = require('chalk') require('winston-daily-rotate-file') const IS_DEV = process.env.STETHOSCOPE_ENV === 'development' @@ -30,14 +22,13 @@ const logColors = ['red', 'yellow', 'cyan', 'magenta'] // change if you want more than 'error' and 'warn' const productionLogs = logLevels.slice(0, 2) - - if (!global.log) { + const filename = `${envPrefix}application-%DATE%.log` log = winston.createLogger({ format: winston.format.simple(), transports: [ new (winston.transports.DailyRotateFile)({ - filename: `${envPrefix}application-%DATE%.log`, + filename, datePattern: 'YYYY-MM-DD', dirname: path.resolve(userDataPath), zippedArchive: true, @@ -47,6 +38,13 @@ if (!global.log) { ] }) + log.getLogFile = function() { + return path.join( + path.resolve(userDataPath), + filename.replace('%DATE%', moment().format('YYYY-MM-DD')) + ) + } + // support multiple arguments to winston logger const wrapper = ( original, level ) => { return (...args) => original(args.map(o => { diff --git a/src/start.js b/src/start.js index dae3e5c0..7dd79bbf 100644 --- a/src/start.js +++ b/src/start.js @@ -40,6 +40,7 @@ let appStartTime = Date.now() let server let updater let launchIntoUpdater = false +let launchIntoDebugger = false let deeplinkingUrl let isLaunching = true let isFirstLaunch = false @@ -72,7 +73,7 @@ const BASE_URL = process.env.ELECTRON_START_URL || url.format({ }) // process command line arguments -const enableDebugger = process.argv.find(arg => arg.includes('enableDebugger')) +let enableDebugger = process.argv.find(arg => arg.includes('enableDebugger')) const DEBUG_MODE = !!process.env.STETHOSCOPE_DEBUG const focusOrCreateWindow = () => { @@ -138,6 +139,9 @@ async function createWindow () { if (isLaunching) { updater.checkForUpdates({}, {}, {}, true) + // check for updates in background + const EVERY_DAY = 86400 * 1000 + setInterval(() => updater.checkForUpdates({}, {}, {}, true), EVERY_DAY) isLaunching = false } @@ -176,6 +180,23 @@ async function createWindow () { }, requestUpdate () { updater.checkForUpdates() + }, + enableDebugger: enableAppDebugger, + requestLogPermission(origin) { + return new Promise((resolve, reject) => { + dialog.showMessageBox({ + type: 'info', + title: 'Allow Access', + message: `Will you allow your Stethoscope log files to be sent to ${origin}?`, + buttons: ['Yes', 'No'] + }, (buttonIndex) => { + if (buttonIndex === 0) { + resolve() + } else { + reject() + } + }) + }) } } @@ -261,6 +282,13 @@ async function createWindow () { global.app = app +function enableAppDebugger() { + if (mainWindow) { + mainWindow.webContents.openDevTools() + mainWindow.setResizable(true) + } +} + // wrap ready callback in 0-delay setTimeout to reduce serious jank // issues on Windows app.on('ready', () => setTimeout(() => { @@ -304,6 +332,15 @@ app.on('open-url', (event, url) => { launchIntoUpdater = true } + if (url.includes('debugger')) { + if (!mainWindow) { + enableDebugger = true + createWindow() + } else { + enableAppDebugger() + } + } + if (mainWindow) { if (mainWindow.isMinimized()) { mainWindow.restore()