function Console() {} Console.Type = { LOG: "log", DEBUG: "debug", INFO: "info", WARN: "warn", ERROR: "error", GROUP: "group", GROUP_COLLAPSED: "groupCollapsed", GROUP_END: "groupEnd" }; Console.addMessage = function(type, format, args) { chrome.runtime.sendMessage({ command: "sendToConsole", tabId: chrome.devtools.inspectedWindow.tabId, args: escape(JSON.stringify(Array.prototype.slice.call(arguments, 0))) }); }; // Generate Console output methods, i.e. Console.log(), Console.debug() etc. (function() { var console_types = Object.getOwnPropertyNames(Console.Type); for (var type = 0; type < console_types.length; ++type) { var method_name = Console.Type[console_types[type]]; Console[method_name] = Console.addMessage.bind(Console, method_name); } })(); BNPChrome.controller('PanelController', function PanelController($scope, $http, toolbar) { $scope.uniqueid = 1000000; $scope.activeId = null; $scope.requests = {}; $scope.masterRequests = []; $scope.filteredRequests = []; $scope.showAll = true; $scope.limitNetworkRequests = true; $scope.showOriginal = true; $scope.currentDetailTab = "tab-code"; $scope.myCodeMirror = null; $scope.activeCookies = []; $scope.activeHeaders = []; $scope.activePostData = []; $scope.activeRequest = []; $scope.activeResponseData = []; $scope.activeResponseCookies = []; $scope.activeResponseHeaders = []; $scope.activeCode = null; $scope.filter = ""; $scope.showIncomingRequests = true; $scope.init = function(type) { $('#tabs').tabs(); $scope.initChrome(); this.createToolbar(); }; $scope.initChrome = function() { key('⌘+k, ctrl+l', function() { $scope.$apply(function() { $scope.clear(); }); }); chrome.devtools.network.onRequestFinished.addListener(function(request) { // do not show requests to chrome extension resources if (request.request.url.startsWith("chrome-extension://")) { return; } $scope.handleRequest(request); }); }; $scope.filterRequests = function() { // console.debug('Search Filter: ', $scope.filter, $scope.filteredRequests.length, $scope.masterRequests.length); // console.debug("Request", $scope.masterRequests[0]); // console.debug('Requests', $scope.requests); $scope.filteredRequests = $scope.masterRequests.filter(function(x) { if (!$scope.filter) return true; if (x && JSON.stringify(x).toLowerCase().includes($scope.filter.toLowerCase())) return true; }); } $scope.handleRequest = function(har_entry) { const request_method = har_entry.request.method; const request_url = har_entry.request.url; const response_status = har_entry.response.status; $scope.addRequest(har_entry, request_method, request_url, response_status, null); }; $scope.createToolbar = function() { toolbar.createButton('search', 'Search Code', false, function() { // ga('send', 'event', 'button', 'click', 'Search Code'); $scope.$apply(function() { if ($scope.myCodeMirror) { $scope.myCodeMirror.execCommand("find"); } }); }); toolbar.createToggleButton('embed', 'JSON Parsing', false, function() { // ga('send', 'event', 'button', 'click', 'Toggle JSON Parsing'); $scope.$apply(function() { $scope.showOriginal = !$scope.showOriginal; $scope.displayCode(); }); }, false); toolbar.createButton('download3', 'Download', false, function() { // ga('send', 'event', 'button', 'click', 'Download'); $scope.$apply(function() { var blob = new Blob([JSON.stringify($scope.requests)], {type: "application/json;charset=utf-8"}); saveAs(blob, "BNPChromeExport.json"); }); }); toolbar.createButton('upload3', 'Import', true, function() { // ga('send', 'event', 'button', 'click', 'Import'); $scope.$apply(function() { $('#ImportInput').click(); }); }); toolbar.createToggleButton('meter', 'Limit network requests to 500', false, function() { // ga('send', 'event', 'button', 'click', 'Toggle Limit Network Request'); $scope.$apply(function() { $scope.limitNetworkRequests = !$scope.limitNetworkRequests; }); }, true); toolbar.createButton('blocked', 'Clear', false, function() { // ga('send', 'event', 'button', 'click', 'Clear'); $scope.$apply(function() { $scope.clear(); }); }); $('.toolbar').replaceWith(toolbar.render()); //clears the input value so you can reload the same file document.getElementById('ImportInput').addEventListener('click', function() {this.value=null;}, false); document.getElementById('ImportInput').addEventListener('change', readFile, false); function readFile (evt) { const files = evt.target.files; const file = files[0]; const reader = new FileReader(); reader.onload = function() { $scope.importFile(this.result); } reader.readAsText(file) } }; $scope.importFile = function(data) { $scope.$apply(function() { const importHar = JSON.parse(data); for (i in importHar) { $scope.handleRequest(importHar[i]); } }); } $scope.addRequest = function(data, request_method, request_url, response_status) { $scope.$apply(function() { const requestId = $scope.uniqueid; $scope.uniqueid = $scope.uniqueid + 1; if (data.request != null) { data["request_data"] = $scope.createKeypairs(data.request); if (data.request.cookies != null) { data.cookies = $scope.createKeypairsDeep(data.request.cookies); } if (data.request.headers != null) { data.headers = $scope.createKeypairsDeep(data.request.headers); } if (data.request.postData != null) { data.postData = $scope.createKeypairs(data.request.postData); } } if (data.response != null) { data["response_data"] = $scope.createKeypairs(data.response); data.response_data.response_body = "Loading " + requestId; if (data.response.cookies != null) { data["response_cookies"] = $scope.createKeypairsDeep(data.response.cookies); } if (data.response.headers != null) { data["response_headers"] = $scope.createKeypairsDeep(data.response.headers); } } data["request_method"] = request_method; if (request_url.includes('apexremote')) { try { let text = (data && data.request && data.request.postData && data.request.postData.text) ? JSON.parse(data.request.postData.text) : ''; data["request_apex_type"] = (text.data && typeof text.data[1] === 'string') ? text.data[1] : JSON.stringify(text.data); data["request_apex_method"] = text.method || ''; } catch (e) {console.debug('Error', e)} } data["request_url"] = request_url; data["response_status"] = response_status; data["id"] = requestId; $scope.requests[requestId] = data; // master $scope.masterRequests.push(data); $scope.filteredRequests.push(data); data.getContent(function (content, encoding) { try { $scope.requests[requestId].response_data.response_body = JSON.stringify(JSON.parse(content), null, 4); } catch (e) {} }); $scope.cleanRequests(); }); }; $scope.cleanRequests = function() { if ($scope.limitNetworkRequests === true) { if ($scope.masterRequests.length >= 500 ) $scope.masterRequests.shift(); const keys = Object.keys($scope.requests).reverse().slice(500); keys.forEach(function(key) { if ($scope.requests[key]) { delete $scope.requests[key]; } }); } $scope.filterRequests(); } $scope.clear = function() { $scope.requests = {}; $scope.activeId = null; $scope.masterRequests = []; $scope.filteredRequests = []; $scope.activeCookies = []; $scope.activeHeaders = []; $scope.activePostData = []; $scope.activeRequest = []; $scope.activeResponseData = []; $scope.activeResponseDataPreview = ""; $scope.activeResponseCookies = []; $scope.activeResponseHeaders = []; $scope.activeCode = null; $scope.showIncomingRequests = true; document.getElementById("tab-code-codemirror").style.visibility = "hidden"; }; $scope.setActive = function(requestId) { if (!$scope.requests[requestId]) { return; } $scope.activeId = requestId; $scope.activeCookies = $scope.requests[requestId].cookies; $scope.activeHeaders = $scope.requests[requestId].headers; $scope.activePostData = $scope.requests[requestId].postData; $scope.activeRequest = $scope.requests[requestId].request_data; $scope.activeResponseData = $scope.requests[requestId].response_data; $scope.activeResponseDataPreview = $scope.requests[requestId].response_data.response_body; $scope.activeResponseCookies = $scope.requests[requestId].response_cookies; $scope.activeResponseHeaders = $scope.requests[requestId].response_headers; $scope.activeCode = $scope.requests[requestId].response_data.response_body; }; $scope.getClass = function(requestId) { if (requestId === $scope.activeId) { return 'selected'; } else { return ''; } }; $scope.createKeypairs = function(data) { let keypairs = []; if (!(data instanceof Object)) { return keypairs; } $.each(data, function(key, value) { if (!(value instanceof Object)) { keypairs.push({ name: key, value: value }); } }); return keypairs; }; $scope.createKeypairsDeep = function(data) { let keypairs = []; if (!(data instanceof Object)) { return keypairs; } $.each(data, function(key, value) { keypairs.push({ name: value.name, value: value.value }); }); return keypairs; }; $scope.$watch('activeCode', function() { $scope.displayCode(); }); $scope.selectDetailTab = function(tabId) { $scope.currentDetailTab = tabId; if (tabId === "tab-code") { $scope.displayCode(); } } $scope.displayCode = function() { if ($scope.activeCode != null) { document.getElementById("tab-code-codemirror").style.visibility = "visible"; let content = $scope.activeCode; // if (!$scope.showOriginal) { // content = $scope.getPretty(content); // } else { content = JSON.stringify($scope.parse(content), null, 4); // } if ($scope.myCodeMirror) { $scope.myCodeMirror.getDoc().setValue(content); $scope.myCodeMirror.refresh(); return; } document.getElementById("tab-code-codemirror").innerHTML = ""; const myCodeMirror = CodeMirror(document.getElementById("tab-code-codemirror"), { value: content, mode: "application/json", theme: "neat", lineNumbers: true, lineWrapping: false, readOnly: true, foldGutter: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] }); myCodeMirror.setOption("extraKeys", { "Ctrl-F": function(cm) { cm.execCommand('findPersistent'); }, "Ctrl-G": function(cm) { cm.execCommand('findPersistentNext'); }, "Shift-Ctrl-G": function(cm) { cm.execCommand('findPersistentPrev'); } }); $scope.myCodeMirror = myCodeMirror; } } $scope.getPretty = function(source) { let code = $scope.parse(source); const options = { source: code, mode: "beautify", // beautify, diff, minify, parse lang: "auto", inchar: " ", // indent character }; const pd = prettydiff(options); // returns and array: [beautified, report] const pretty = pd[0]; return pretty; } $scope.parse = function(input) { try { // console.warn('Parse Type', typeof input); if (typeof input === 'boolean') return input; if (typeof input === 'number') return input; if (!input) return input; if (typeof input === 'string') { // if string, try to parse // returns the original string if this fails input = JSON.parse(input); // console.debug('Parse String', input); return $scope.parse(input); } if (Array.isArray(input)) { for (let i = 0; i < input.length; i++) { // console.debug('Parse Inner Array', i, input[i]); input[i] = $scope.parse(input[i]); } } if (typeof input === 'object') { // console.debug('Parse Object', input); Object.entries(input).forEach(function([key, value]) { // console.debug('Parse Inner Object', key, value); if (key === "result") input[key] = $scope.parse(value); }) } } catch (e) { // console.info('Error parsing', e, typeof input, input) // console.debug('Parse String Failed', input); return input } // console.debug('Returning', input); return input; } });