├── Images
└── HowToInstall.gif
├── LICENSE
├── README.md
└── extension
├── icon128.png
├── icon16.png
├── icon48.png
├── js
├── background.js
├── contentscript.js
├── menu.js
└── web
│ ├── accessibility
│ ├── highlightElementsWithTheSameId.js
│ ├── highlightImagesWithoutAltTags.js
│ ├── highlightInputsWithoutLabel.js
│ ├── removeElementsWithTheSameId.js
│ ├── removeImagesWithoutAltTags.js
│ ├── removeInputsWithoutLabel.js
│ ├── removeStyleSheets.js
│ └── visualiseTabFlow.js
│ ├── exploits
│ ├── sql.js
│ └── xss.js
│ ├── styling
│ ├── increaseAllElementsText.js
│ ├── increaseButtonsText.js
│ ├── increaseLabelsText.js
│ ├── increaseLinksText.js
│ └── increasePagesText.js
│ ├── utilities
│ ├── decodeBase64ToConsole.js
│ ├── documentDesignModeOff.js
│ ├── documentDesignModeOn.js
│ ├── encodeBase64ToConsole.js
│ ├── forEveryDoThis.js
│ ├── linkchecker.js
│ └── prettyPrintJsonToConsole.js
│ └── validation
│ ├── changeInputTypesToText.js
│ ├── removeMaxLength.js
│ ├── removePasteRestrictions.js
│ └── removeRequired.js
└── manifest.json
/Images/HowToInstall.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eviltester/usefuljssnippetextension/acc84ade54a0722b0c83ec4d5b43b142bb20f750/Images/HowToInstall.gif
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Alan Richardson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #  Useful Snippets Extension
2 |
3 | A Chrome Extension with Useful JavaScript snippets for testing.
4 |
5 | Feel free to contribute to this set of snippets.
6 |
7 | What we are looking for are short JavaScript snippets that can run from a popup menu and provide small useful aids to support testing.
8 |
9 | The snippets should also be small enough that they provide useful examples of using JavaScript from the console or as Bookmarklets and help people learn to use JavaScript in their testing.
10 |
11 | ## Basic Install Instructions
12 |
13 | - Download and extract this repository somewhere
14 | - Navigate to `chrome://extensions` within Chrome
15 | - Ensure to switch 'Developer mode' on (a toggle at the top right of the page)
16 | - Select 'Load unpacked' and then navigate to the `/extension` folder
17 | - Navigate to a website and then right click it to access the `Useful Snippets` context menu
18 | - After executing a snippet you can see the bot code and get the code as a bookmarklet by viewing the DevTools console
19 |
20 | 
21 |
22 | ## Current Snippets
23 | Below is a list of snippets currently available with this extension. Have an idea? Want to contribute? Please feel free to fork this repository, add snippets and then create a pull request.
24 |
25 | ### Accessibility
26 | * Remove images which do not have alt tags
27 | * Show images which do not have alt tags
28 | * Remove inputs which do not have matching `for` labels
29 | * Show inputs which do not have matching `for` labels
30 | * Remove elements with duplicate `id`'s
31 | * Show elements with duplicate `id`'s
32 | * Remove page style sheets
33 | * Visualise page tab flow
34 |
35 | ### Exploits
36 | * Insert JS Script Injection in all inputs
37 | * Insert SQL Injection in all inputs
38 |
39 | ### Styling
40 | * Check label text overflow
41 | * Check button text overflow
42 | * Check link text overflow
43 | * Check page text overflow
44 | * Check all elements text overflow
45 |
46 | ### Utilities
47 | * Switch document edit mode on
48 | * Switch document edit mode off
49 | * Pretty print a JSON string
50 | * Encode a string as Base64
51 | * Decode a Base64 string
52 | * For Every _element_ Do _this_
53 | * will prompt twice, first for a CSS selector, next for some javascript to execute against the _element_ variable.
54 | * e.g. "p" and then "console.log(element.innerText)" would write out the text of all paragraphs to the console
55 | * e.g. "[role='checkbox']" and then "element.click()" would toggle all checkboxes
56 | * Link Checker
57 | * A simple link checker - all CORS and mixed content errors are displayed in console, console.table used for report output
58 |
59 | ### Validation (Client side)
60 | * Remove max length attributes from fields
61 | * Remove required field attributes from fields
62 | * Remove paste restrictions from fields
63 | * Change all inputs types to text
64 |
65 | ## Contributors
66 |
67 | See commit history for the authorship of the ongoing snippets.
68 |
69 | - [Alan Richardson](https://github.com/eviltester) created the basic framework for the Chrome Extension and contributed JavaScript snippets to this extension.
70 | - [eviltester.com](https://eviltester.com)
71 | - [@eviltester](https://twitter.com/eviltester)
72 | - [linkedin.com/in/eviltester](https://www.linkedin.com/in/eviltester)
73 | - [Viv Richards](https://github.com/vivrichards600) contributed JavaScript snippets to this extension.
74 | - [vivrichards.co.uk](http://vivrichards.co.uk/)
75 | - [@11vlr](https://twitter.com/11vlr)
76 | - [linkedin.com/in/vivrichards](https://www.linkedin.com/in/vivrichards)
--------------------------------------------------------------------------------
/extension/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eviltester/usefuljssnippetextension/acc84ade54a0722b0c83ec4d5b43b142bb20f750/extension/icon128.png
--------------------------------------------------------------------------------
/extension/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eviltester/usefuljssnippetextension/acc84ade54a0722b0c83ec4d5b43b142bb20f750/extension/icon16.png
--------------------------------------------------------------------------------
/extension/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eviltester/usefuljssnippetextension/acc84ade54a0722b0c83ec4d5b43b142bb20f750/extension/icon48.png
--------------------------------------------------------------------------------
/extension/js/background.js:
--------------------------------------------------------------------------------
1 | //
2 | // Setup the context menu
3 | //
4 | var contextMenus = {};
5 |
6 | // the menuActions are defined in menu.js
7 |
8 | function findMenuRefItem(theMenuArray, theMenuRef){
9 | for (var menuindex = 0; menuindex < theMenuArray.length; menuindex++) {
10 | if(theMenuArray[menuindex].menuref === theMenuRef){
11 | return theMenuArray[menuindex].id;
12 | }
13 | }
14 | }
15 |
16 | for (var actionindex = 0; actionindex < menuActions.length; actionindex++) {
17 | if(menuActions[actionindex].menu===""){
18 | // it is a root level menu, add it to the contextMenus
19 | menuActions[actionindex].id = chrome.contextMenus.create({ "title": menuActions[actionindex].title, "type": "normal", contexts: ["all"] });
20 | }else{
21 | // it is a child menu, find the parent and add it
22 | var parentId = findMenuRefItem(menuActions, menuActions[actionindex].menu);
23 | menuActions[actionindex].id = chrome.contextMenus.create({ "title": menuActions[actionindex].title, "type": "normal", contexts: ["all"], "parentId": parentId });
24 | }
25 | }
26 |
27 | chrome.contextMenus.onClicked.addListener(contextMenuClickHandler);
28 |
29 |
30 | //
31 | // Handle a menu click
32 | //
33 | function contextMenuClickHandler(info, tab) {
34 |
35 | var actionToDo;
36 |
37 | // find the menuAction item for the menu clicked
38 | for (var actionindex = 0; actionindex < menuActions.length; actionindex++) {
39 | if (menuActions[actionindex].id === info.menuItemId) {
40 | actionToDo = menuActions[actionindex];
41 | break;
42 | }
43 | }
44 |
45 | if(!actionToDo){
46 | // could not find a menu action
47 | return;
48 | }
49 |
50 | if(actionToDo.file===""){
51 | // no file associated with action
52 | return;
53 | }
54 |
55 | var errorHandler = function () {
56 | if (chrome.runtime.lastError) {
57 | console.error(chrome.runtime.lastError.message);
58 | }
59 | };
60 |
61 | // file reading is async https://stackoverflow.com/questions/4100927/chrome-filereader
62 | function sendFileContentsAsMessage(filecontents) {
63 | chrome.tabs.sendMessage(tab.id, { type: "display", messageContents: "Script to Run:\n" });
64 | chrome.tabs.sendMessage(tab.id, { type: "display", messageContents: filecontents });
65 | }
66 |
67 | function sendFileContentsAsBookmarklet(filecontents) {
68 | var bookmarklet = "javascript:(function(){" + encodeURI(filecontents) + "})()";
69 | chrome.tabs.sendMessage(tab.id, { type: "display", messageContents: "As Bookmarklet:\n" });
70 | chrome.tabs.sendMessage(tab.id, { type: "display", messageContents: bookmarklet });
71 | }
72 |
73 |
74 | // Execute the Action
75 | // cannot just execute script if the bot wants to access local variables
76 | // https://stackoverflow.com/questions/16784553/chrome-extension-throws-not-defined-on-defined-variable
77 | if (actionToDo.instant) {
78 | chrome.tabs.executeScript(null, { file: actionToDo.file }, errorHandler);
79 | } else {
80 | // inject execution script
81 | chrome.tabs.executeScript(tab.id, { file: 'js/contentscript.js' }, function () {
82 | // execute the snippet code by sending a message
83 | chrome.tabs.sendMessage(tab.id, { type: "execfile", filename: actionToDo.file });
84 | });
85 | }
86 |
87 | // Display the code for the action in the console
88 | getFileContents(actionToDo.file, errorHandler, sendFileContentsAsMessage);
89 | getFileContents(actionToDo.file, errorHandler, sendFileContentsAsBookmarklet);
90 |
91 |
92 | // read a file https://stackoverflow.com/questions/28858027/how-to-read-file-from-chrome-extension
93 | function getFileContents(filename, errorHandler, callback) {
94 | chrome.runtime.getPackageDirectoryEntry(function (root) {
95 | root.getFile(filename, {}, function (fileEntry) {
96 | fileEntry.file(function (file) {
97 | var reader = new FileReader();
98 | reader.onloadend = function (e) {
99 | // contents are in .result
100 | callback(this.result);
101 | };
102 | reader.readAsText(file);
103 | }, errorHandler);
104 | }, errorHandler);
105 | });
106 | }
107 | }
--------------------------------------------------------------------------------
/extension/js/contentscript.js:
--------------------------------------------------------------------------------
1 | // inject bot script
2 | if(window.haveInstalledBotListener!==true){
3 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
4 | if(message.type==="execfile"){
5 | var script = document.createElement('script');
6 | script.type = 'text/javascript';
7 | script.src = chrome.extension.getURL(message.filename);
8 | document.getElementsByTagName('head')[0].appendChild(script);
9 | }
10 | if(message.type==="display"){
11 | console.log(message.messageContents)
12 | }
13 | });
14 | window.haveInstalledBotListener=true;
15 | }
--------------------------------------------------------------------------------
/extension/js/menu.js:
--------------------------------------------------------------------------------
1 | // configure menus here to avoid writing menu creation code,
2 | // background.js will parse this to create the actual menus
3 | var menuActions = [
4 | // parent menu items need to have a unique menuref, which is used by other items as the 'menu:' property
5 | // currently parents need to be defined first in the array
6 | { menu: "", "title": "Useful Snipppets", menuref: "W", file: ""},
7 | { menu: "W", "title": "Accessibility", menuref: "W>A", file: ""},
8 | { menu: "W>A", "title": "Remove Images Without Alt Tags", file: "js/web/accessibility/removeImagesWithoutAltTags.js", instant: false },
9 | { menu: "W>A", "title": "Show Images Without Alt Tags", file: "js/web/accessibility/highlightImagesWithoutAltTags.js", instant: false },
10 | { menu: "W>A", "title": "Remove Inputs Without Labels", file: "js/web/accessibility/removeInputsWithoutLabel.js", instant: false },
11 | { menu: "W>A", "title": "Show Inputs Without Labels", file: "js/web/accessibility/highlightInputsWithoutLabel.js", instant: false },
12 | { menu: "W>A", "title": "Remove Elements With Duplicate Ids", file: "js/web/accessibility/removeElementsWithTheSameId.js", instant: false },
13 | { menu: "W>A", "title": "Show Elements With Duplicate Ids", file: "js/web/accessibility/highlightElementsWithTheSameId.js", instant: false },
14 | { menu: "W>A", "title": "Remove Style Sheets", file: "js/web/accessibility/removeStyleSheets.js", instant: false },
15 | { menu: "W>A", "title": "Visualise Tab Flow", file: "js/web/accessibility/visualiseTabFlow.js", instant: false },
16 | { menu: "W", "title": "Exploits", menuref: "W>E", file: ""},
17 | { menu: "W>E", "title": "Insert JS Script Injection in all inputs", file: "js/web/exploits/xss.js", instant: false },
18 | { menu: "W>E", "title": "Insert SQL Injection in all inputs", file: "js/web/exploits/sql.js", instant: false },
19 | { menu: "W", "title": "Styling", menuref: "W>S", file: ""},
20 | { menu: "W>S", "title": "Check label text overflow", file: "js/web/styling/increaseLabelsText.js", instant: false },
21 | { menu: "W>S", "title": "Check button text overflow", file: "js/web/styling/increaseButtonsText.js", instant: false },
22 | { menu: "W>S", "title": "Check link text overflow", file: "js/web/styling/increaseLinksText.js", instant: false },
23 | { menu: "W>S", "title": "Check page text overflow", file: "js/web/styling/increasePagesText.js", instant: false },
24 | { menu: "W>S", "title": "Check all elements text overflow", file: "js/web/styling/increaseAllElementsText.js", instant: false },
25 | { menu: "W", "title": "Utilities", menuref: "W>U", file: ""},
26 | { menu: "W>U", "title": "Document Edit Mode On", file: "js/web/utilities/documentDesignModeOn.js", instant: false },
27 | { menu: "W>U", "title": "Document Edit Mode Off", file: "js/web/utilities/documentDesignModeOff.js", instant: false },
28 | { menu: "W>U", "title": "Pretty Print JSON String", file: "js/web/utilities/prettyPrintJsonToConsole.js", instant: false },
29 | { menu: "W>U", "title": "Decode Base64 to console", file: "js/web/utilities/decodeBase64ToConsole.js", instant: false },
30 | { menu: "W>U", "title": "Encode String as Base64 to console", file: "js/web/utilities/encodeBase64ToConsole.js", instant: false },
31 | { menu: "W>U", "title": "For Every _element_ Do _this_", file: "js/web/utilities/forEveryDoThis.js", instant: false },
32 | { menu: "W>U", "title": "Link Checker", file: "js/web/utilities/linkchecker.js", instant: false },
33 | { menu: "W", "title": "Validation", menuref: "W>V", file: ""},
34 | { menu: "W>V", "title": "Remove Max Length Attributes", file: "js/web/validation/removeMaxLength.js", instant: false },
35 | { menu: "W>V", "title": "Remove Required Field Attributes", file: "js/web/validation/removeRequired.js", instant: false },
36 | { menu: "W>V", "title": "Remove Paste Restrictions", file: "js/web/validation/removePasteRestrictions.js", instant: false },
37 | { menu: "W>V", "title": "Change all input types to text", file: "js/web/validation/changeInputTypesToText.js", instant: false },
38 | ];
--------------------------------------------------------------------------------
/extension/js/web/accessibility/highlightElementsWithTheSameId.js:
--------------------------------------------------------------------------------
1 |
2 | var ids = {};
3 | var all = document.all || document.getElementsByTagName("*");
4 | for (var i = 0, l = all.length; i < l; i++) {
5 | var id = all[i].id;
6 | if (id) {
7 | if (ids[id]) {
8 | all[i].style = all[i].style+"; border:10px dashed red;"
9 | document.getElementById(id).style = document.getElementById(id).style+"; border:10px dashed red;"
10 | } else {
11 | ids[id] = 1;
12 | }
13 | }
14 | };
--------------------------------------------------------------------------------
/extension/js/web/accessibility/highlightImagesWithoutAltTags.js:
--------------------------------------------------------------------------------
1 | Array.prototype.slice.call (document.querySelectorAll('img')).map(function(el){if(!el.alt){el.style = el.style+"; border:10px dashed red;"}});
--------------------------------------------------------------------------------
/extension/js/web/accessibility/highlightInputsWithoutLabel.js:
--------------------------------------------------------------------------------
1 | var inputs = document.querySelectorAll('input');
2 | var labels = document.querySelectorAll('label');
3 |
4 | for (var currentInput = 0; currentInput < inputs.length; currentInput++) {
5 | var inputHasLabel = false;
6 | for (var currentLabel = 0; currentLabel < labels.length; currentLabel++) {
7 | if (labels[currentLabel].htmlFor == inputs[currentInput].id) {
8 | inputHasLabel = true;
9 | }
10 | }
11 | if (inputHasLabel == false) {
12 | inputs[currentInput].style = inputs[currentInput].style+"; border:10px dashed red;";
13 | }
14 | }
--------------------------------------------------------------------------------
/extension/js/web/accessibility/removeElementsWithTheSameId.js:
--------------------------------------------------------------------------------
1 |
2 | var ids = {};
3 | var all = document.all || document.getElementsByTagName("*");
4 | for (var i = 0, l = all.length; i < l; i++) {
5 | var id = all[i].id;
6 | if (id) {
7 | if (ids[id]) {
8 | all[i].style.display = 'none';
9 | document.getElementById(id).style.display = 'none';
10 | } else {
11 | ids[id] = 1;
12 | }
13 | }
14 | };
--------------------------------------------------------------------------------
/extension/js/web/accessibility/removeImagesWithoutAltTags.js:
--------------------------------------------------------------------------------
1 | Array.prototype.slice.call (document.querySelectorAll('img')).map(function(el){if(!el.alt){el.src="Removed"}});
--------------------------------------------------------------------------------
/extension/js/web/accessibility/removeInputsWithoutLabel.js:
--------------------------------------------------------------------------------
1 | var inputs = document.querySelectorAll('input');
2 | var labels = document.querySelectorAll('label');
3 |
4 | for (var currentInput = 0; currentInput < inputs.length; currentInput++) {
5 | var inputHasLabel = false;
6 | for (var currentLabel = 0; currentLabel < labels.length; currentLabel++) {
7 | if (labels[currentLabel].htmlFor == inputs[currentInput].id) {
8 | inputHasLabel = true;
9 | }
10 | }
11 | if (inputHasLabel == false) {
12 | inputs[currentInput].style.display = 'none';
13 | }
14 | }
--------------------------------------------------------------------------------
/extension/js/web/accessibility/removeStyleSheets.js:
--------------------------------------------------------------------------------
1 | Array.prototype.slice.call (document.styleSheets).map(function(el){el.disabled = true;});
2 |
--------------------------------------------------------------------------------
/extension/js/web/accessibility/visualiseTabFlow.js:
--------------------------------------------------------------------------------
1 | // Get all inputs, buttons, links
2 | var inputs = Array.apply(null, document.querySelectorAll("input, select, button, a")).filter(elem => elem.getBoundingClientRect().left != 0)
3 |
4 | // Go through each input and get top/left
5 | for (I = 0; I < inputs.length; I++) {
6 | var currentInput = inputs[I].getBoundingClientRect();
7 | var nextInput = null;
8 |
9 | if (I < inputs.length - 1) {
10 | nextInput = inputs[I + 1].getBoundingClientRect();
11 | } else {
12 | lastInput = inputs[I];
13 | nextInput = currentInput
14 | }
15 |
16 | // make line draw from middle of control instead of left handside of it
17 | var currentInputLeft = currentInput.left + (currentInput.width / 2) ;
18 | var currentInputTop = currentInput.top + (currentInput.height / 2);
19 | var nextInputLeft = nextInput.left + (nextInput.width / 2) ;
20 | var nextInputTop = nextInput.top + (nextInput.height / 2);
21 |
22 | // Draw a path from current input to next one using top/eft for elements
23 | // for first element we draw from top left to element
24 | if(I == 0) {
25 | document.body.insertAdjacentHTML('afterbegin', '');
26 | }
27 | document.body.insertAdjacentHTML('afterbegin', '');
28 |
29 | }
--------------------------------------------------------------------------------
/extension/js/web/exploits/sql.js:
--------------------------------------------------------------------------------
1 | var textInputs = document.querySelectorAll('input[type=text]');
2 | for(let i=0; ialert('Executing Javascript in input " + i + "')";
5 | }
--------------------------------------------------------------------------------
/extension/js/web/styling/increaseAllElementsText.js:
--------------------------------------------------------------------------------
1 | let elements = document.querySelectorAll('label, button, a, h1, h2, h3, h4, h5, p, input, select');
2 | for(let i=0; i=linkReport.length){console.table(linkReport);clearInterval(finishReport)}}, 3000);
23 |
--------------------------------------------------------------------------------
/extension/js/web/utilities/prettyPrintJsonToConsole.js:
--------------------------------------------------------------------------------
1 | console.log(JSON.stringify(JSON.parse(prompt("Enter JSON TO Pretty Print To Console","")), null, 2));
--------------------------------------------------------------------------------
/extension/js/web/validation/changeInputTypesToText.js:
--------------------------------------------------------------------------------
1 | var inputs = document.querySelectorAll('input');
2 | for(let i=0; i