Window.addEventListener not working on Chrome - tampermonkey

I have the following userscript which I am trying to run on Chrome and on Firefox. I am getting inconsistent results. The script is matched (the alert fires) but on Chrome the addEventListener does not appear to work. On Firefox, it runs although there is still a problem of some kind with the insertion of the modified .js which I have yet to figure out. FWIW, my ultimate objective is to add port labeling functionality to an Ethernet switch which would be cool if I could get it to work. This script is just meant to see if I can modify the .js file that the switch runs as part of its web GUI.
// ==UserScript==
// #name Test
// #match http://192.168.3.21/System.html
// #description TEST
// #version 1
// #grant GM_xmlhttpRequest
// #run-at document-start
// ==/UserScript==
function addScript(text) {
//text = text.replace(/Normal/g, "Abnormal");
alert(text);
var newScript = document.createElement('script');
newScript.type = "text/javascript";
newScript.textContent = text;
var head = document.getElementsByTagName('head')[0];
head.appendChild(newScript);
}
window.addEventListener('beforescriptexecute', function(e) {
var src = e.target.src;
if (src.search(/system_data\.js/) != -1) {
e.preventDefault();
e.stopPropagation();
GM_xmlhttpRequest({
method: "GET",
url: e.target.src,
onload: function(response) {
addScript(response.responseText);
}
});
}
});

Related

Handling secure login page in protractor

My team is working to use AngularJs and Polymer components for a new web app. I am looking into how to create a UI automation suite for this. After lots of research looks like Protractor may help me out here with some tweaks to handle Polymer. But, the current challenge is as follows -
I navigate to the app
As part of our company policy, the every web visit is validated (unless within same session). Here is how the validation works -
A login page (non-Anugular) page appears after one types the required url. Sign in with the credentials
Another intermediate page appears where it asks to wait for page to load or click a link to go to next page. Click the link
Url changes back to the original used in #1
Note: These validation pages take hell lot of time to load (changes to different internal urls). Also, the validation is skipped sometimes (within same session or through some other logic)
I have been struggling to design a prototype to handle all these. I am also trying to use Page Object while designing the prototype. Here is what I have so far.
login.js
________________________________________________________
var currentUrl;
var lastChangedUrl;
var secureUrl = 'corplogin.ssogen2.corporate.company.com';
var getwayUrl = 'gateway.zscalertwo.net';
var loginSuite = function(driver) {
var defer = protractor.promise.defer();
describe('Handle login', function() {
/*afterEach(function() {
//driver.manage().deleteAllCookies();
})*/
//it('Login to security test', function(){
//********** Wait for page to load/URL to change to secure login page ************
driver.getCurrentUrl().then(function(url) {
currentUrl = url;
}).then(function() {
driver.wait(function() {
return driver.getCurrentUrl().then(function (url) {
lastChangedUrl = url;
return url !== currentUrl;
});
});
}).then(function() {
//********** login to secure page ************
if (lastChangedUrl.indexOf(secureUrl) > -1 || lastChangedUrl.indexOf(getwayUrl) > -1) {
var element = driver.findElement(By.name("username"));
element.sendKeys("Username");
element = driver.findElement(By.name("password"));
element.sendKeys("password"); //Give password
element = driver.findElement(By.name("submitFrm"));
element.click();
}
}).then (function() {
//********** page is slow. wait for page to load/URL to change ************
driver.getCurrentUrl().then(function(url) {
currentUrl = url;
}).then(function() {
driver.wait(function() {
return driver.getCurrentUrl().then(function (url) {
lastChangedUrl = url;
return url !== currentUrl;
});
});
}).then (function() {
//********** Click on the link to to go to test page ***********
if (lastChangedUrl.indexOf(getwayUrl) > -1) {
var element = driver.findElement(By.tagName("a"));
console.log("before click............");
element.click();
}
//********** page is slow. wait for page to load/URL to change ************
driver.getCurrentUrl().then(function(url) {
currentUrl = url;
}).then(function() {
driver.wait(function() {
return driver.getCurrentUrl().then(function (url) {
lastChangedUrl = url;
return url !== currentUrl;
});
});
})
.then (function() {
//return defer.promise;
//browser.pause();
});
}, 60000);
});
//});
}, 60000);
return defer.promise;
};
module.exports = loginSuite;
spec.js
___________________________________________________________________________
describe('Protractor Demo App', function() {
var myUrl = 'http://<my test app url>/';
var driver = browser.driver;
beforeEach(function() {
driver.get(myUrl);
});
it('should login', function() {
loginSuite(driver)
.then(
function(){
console.log("End of tests:");
expect(driver.getCurrentUrl()).toBe(myUrl);
});
});
The issue here -
My expectation here is to have the promise returns to spec.js after the secure login page is handled so that I can continue with other testing using the driver object. For the sake testing I am logging 'End of tests' message and doing a dummy validation. But, looks like those two lines don't get executed.
Login to the secure site works and I see page changes to original test page. I tested that with Browser.pause(). But, the logging 'End of test' never happens, nor the validation.
I need to handle the scenario where the secure login page doesn't appear. Not sure what adjustment I need to do in login.js page
Is my approach for page object and handling the promises wrong here? I am able to go to one step further on the test app page when all the code are placed under one js file instead of splitting them for page object. Please help here.
I wanted to share with you the "polymer way" of solving your problem.
The code below use two elements to monitor the URL, the auth flow, the previous page visited and log the user in/out of the app
The first will bind to the origin route, so you can send the user back there
<app-route
route="{{route}}"
pattern="/origin/:page"
data="{{data}}"
tail="{{subroute}}">
</app-route>
The second will bind to the authPage, allowing you to show/hide the auth page.
<app-route
route="{{subroute}}"
pattern=":authPage"
data="{{data}}
active="{{authPageActive}}">
</app-route>
User auth, monitoring and page redirecting
Use the element: <firebase-auth>
Is the user singned in?: signedIn="{{isSignedIn}}"
<firebase-auth id="auth" user="{{user}}" provider="google" on-
error="handleError" signedIn="{{isSignedIn}}"></firebase-auth>
Add an observer
observers: [
'_userSignedInStatus(isSignedIn)' // observe the user in/out
],
Add a Function
_userSignedInStatus: function (isSignedIn) {
if (isSignedIn === false) {
this.page = 'view404'; // redirect the user to another page
// import an element that cover the view
} else {
//send a log message to your database
}
}

AngularJS $Http not triggered on Edge/IE

I have the following code, which works perfectly fine on Mozilla, Chrome, but not on Microsoft Edge or Internet Explorer. Here is what happens.
When user loads a webpage I trigger the following code:
$http.get("/api/items")
.then(function (response) {
angular.copy(response.data, $scope.items);
}, function (error) {
$scope.errorMessage = error.statusText;
})
.finally(function () {
$scope.isBusy = false;
});
which pulls all the values into the <ul>. This part works normally on all browsers. However when I trigger the following one:
$scope.interval = $interval(function () {
$http.get("/api/items")
.then(function (response) {
//success
//loop through the response
angular.forEach(response.data, function (value, key) { ... more code here}
then suddenly the response is no longer from my web api. What I mean is, that when I was debugging my application and placed breakpoint in my GET api (I mean under Visual Studio in my MVC Controller) I could not see the get call being triggered from Microsoft Edge.
Here is what network inspector looks like from Chrome:
and this one is from Edge:
As far as I understand, Edge has only made one real XHR call towards my GET, and all the remaining ones are just cached from memory?
How can one solve this problem? Why is this even happening?
In the end I found out, that the problem is with Angular with storing Cache. There are two options one can use (taken from other StackOverflow posts):
1) Angular Method (which for unknown reason did not work for me):
myModule.config(['$httpProvider', function($httpProvider) {
//initialize get if not there
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
// Answer edited to include suggestions from comments
// because previous version of code introduced browser-related errors
//disable IE ajax request caching
$httpProvider.defaults.headers.get['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
// extra
$httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
$httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
}]);
2) The ASP.NET way of decorating GET method:
[ResponseCache(NoStore = true, Duration = 0)]

Ionic http get request (with Ionic) returns html data

I am using Ionic and making http request like this:
$http.get('//GLOBAL.IP/?username=' + username + '&content_type=json')
.then(function (result) {
$scope.days = [];
alert(JSON.stringify(result));
for (first in result.data.weeks) break;
var currentWeek = result.data.weeks[first];
var time = currentWeek.overall.as_time;
$scope.week = currentWeek;
for (day in currentWeek.days.sort().reverse()) {
if (day < 2) {
continue;
}
var currentDay = currentWeek.days[day];
$scope.days.push(currentDay);
if (currentDay.present) {
console.log(parseInt(currentDay.work_time_balance) + parseInt(currentWeek.overall.seconds));
}
}
}, function (result) {
alert(JSON.stringify(result));
$ionicPopup.alert({
title: 'Error',
template: 'Connection failed, try again later!'
});
})
.finally(function () {
// Stop the ion-refresher from spinning
$scope.$broadcast('scroll.refreshComplete');
});
While I am opening app in browser with command ionic serve, everything seems working okay, I've already fixed CORS and other stuff.
But when In mobile app, I am getting this (sorry for not providing plaintext)
UPDATE
$http.get('//GLOBAL.IP/?username=' + username + '&content_type=json')
.then(function (result) {
alert('Good');
}, function (result) {
alert('Bad');
})
This code returns me GOOD, but result.data is still with script tags.
When you are testing this app in working mode what is localhost, Its a local server running on same machine, right.
When you install or run app in your mobile device where it is pointing to? Do you know that, If code is okay then replacing localhost with IP of your machine should resolve this issue.
Many script tags with addRow in ionic http request response, was because of // in the beginning of uri, protocol was selecting successfully in browser, but not in compiled app.

form data upload progress using xhr javascript

I have written a service, which allows me to upload a given file along with a json object to a given url. My code is:
(function() {
angular.module('petrofacApp')
.service("fileUpload", fileUpload);
function fileUpload() {
function uploadFileToUrl(file, uploadUrl, jsonRequest, callback){
var fd = new FormData();
fd.append('JsonRequestData', JSON.stringify(jsonRequest));
fd.append('file', file, file.name);
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete);
}
};
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
callback(xhr.response);
}
};
xhr.open('POST', uploadUrl, true);
xhr.send(fd);
}
return {
uploadFileToUrl: uploadFileToUrl
}
}
}());
My problem is- if I mention the onprogress event as
xhr.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete);
}
};
file gets uploaded without any problem, but onprogress event gets triggered only once, when the upload is finished.
I found out that, to avoid this problem I have to use upload.onprogress. So I changed my code to
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete);
}
};
When I execute this, I get error-
XMLHttpRequest cannot load http://192.168.xxx.xxx:6152/api/UploadFile. Response for preflight has invalid HTTP status code 405.
Please help me in solving this issue.
The problem was related to CORS. I got it fixed from the server side by installing "CORS" from Nuget and then adding the following code to WebApi.config file
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
This solved my problem.

How to overcome "Access-Control-Allow-Origin" error when client talks to server

So I'm using a yeoman project from swiip called generator-gulp-angular - just do "npm search gulp-angular" and you'll see it.
Out of the box the client is running from 127.0.0.1:3000 and I wish to make a $http call to a (python) service on 127.0.0.1:8080. Its using browser-sync for live reload and proxy middleware to make the proxy calls from client to server. Proxy middleware is per default disabled, so the trick is to enable it and successfully make requests to and receive responses from server. So far i've not been able to successfully enable it :-(
Update: I recreated the yeoman project following the motto "give yourself a simple example" in order to concentrate on the Access-Control issue and I got it to work more or less out of the box without having to resort to modifying the server logic in order to allow cross origin requests. Pleasingly it's as simple as the instructions describe. Here's the proxy file that extends the gulp middleware to perform the proxy, or rather mapping from client to server:
/*jshint unused:false */
/***************
This file proxy.js allows you to configure a proxy system plugged into BrowserSync
in order to redirect backend requests while still serving and watching
files from the web project
IMPORTANT: The proxy is disabled by default.
If you want to enable it, watch at the configuration options and finally
change the `module.exports` at the end of the file
***************/
'use strict';
var proxyMiddleware = require('http-proxy-middleware');
var options = {
target: 'http://127.0.0.1:8080'
};
var proxy = proxyMiddleware('/quote', options);
module.exports = function(){
return [proxy];
}
From the gulpfile (gulpfile.js) we have:
'use strict';
var gulp = require('gulp');
var browserSync = require('browser-sync');
var browserSyncSpa = require('browser-sync-spa');
var util = require('util');
var middleware = require('./proxy');
module.exports = function(options) {
function browserSyncInit(baseDir, browser) {
browser = browser === undefined ? 'default' : browser;
var routes = null;
if(baseDir === options.src || (util.isArray(baseDir) && baseDir.indexOf(options.src) !== -1)) {
routes = {
'/bower_components': 'bower_components'
};
}
var server = {
baseDir: baseDir,
routes: routes
};
//
// Here's the relevant bit
//
server.middleware = middleware();
browserSync.instance = browserSync.init({
startPath: '/',
server: server,
browser: browser
});
}
browserSync.use(browserSyncSpa({
selector: '[ng-app]'// Only needed for angular apps
}));
gulp.task('serve', ['watch'], function () {
browserSyncInit([options.tmp + '/serve', options.src]);
});
..
gulp.task('serve:e2e-dist', ['build'], function () {
browserSyncInit(options.dist, []);
});
};
As you see we're configuring gulp to be aware of the "/quote" context that when used on the client (http://localhost:3000/quote) will get mapped to the backend (http://localhost:8080/quote) - for further information: https://github.com/chimurai/http-proxy-middleware/blob/v0.0.5/README.md
Here's where we make the call on the client using the $http service:
function quotePriceGenerator($q, $http) {
var lowPrice = 1.45000, highPrice = 1.47000;
var askPrice, sellPrice;
var service = {};
service.getPrice = function() {
var deferred = $q.defer();
$http({
url: '/quote',
method: 'GET'
})
.then(function(quote) {
var date = new Date();
const quoteZoom = 100000;
const quotePipsWindow = -3;
..
qBox['trading-size-string'] = qBox['trading-size'].toString();
service.qBox = qBox;
return deferred.resolve(service);
});
// Returns a random integer between min (included) and max (included)
// Using Math.round() will give you a non-uniform distribution!
function getRandomIntInclusive(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
return deferred.promise;
};
return service;
..
function randomizeAskSell(low, high){
}
}
quotePriceGenerator.$inject = ['$q', '$http'];
export default quotePriceGenerator;
The backend, a python tornado REST API, didn't require any configuration for Access-Control-Allow-Origin. Here it is:
from __future__ import division
import tornado.ioloop
import pyrestful.rest
import random
from pyrestful import mediatypes
from pyrestful.rest import get
class Quote(object):
quote_date_time = float
..
sell_price = float
trading_size = int
class QuoteResource(pyrestful.rest.RestHandler):
#get(_path="/quote", _produces=mediatypes.APPLICATION_JSON)
def getQuoteJson(self):
price_min = random.randint(145000,146000)/100000
price_max = random.randint(146000,147000)/100000
..
quote.sell_price = sell_price
quote.trading_size = trading_size
return quote
if __name__ == "__main__":
try:
print("Start the service")
app = pyrestful.rest.RestService([QuoteResource])
app.listen(8080)
tornado.ioloop.IOLoop.instance().start()
except KeyboardInterrupt:
print("\nStop the service")
Some information on the erroneous request/response would be helpful too.
You could try to set the changeOrigin param to true. This will modify the request's host header to match the server's hostname.
var proxyMiddleware = require('http-proxy-middleware');
var options = {
target: 'http://127.0.0.1:8080',
changeOrigin: true // <-- changeOrigin
};
If that doesn't work; you can add the Access-Control-Allow-Origin header to the response:
var proxyMiddleware = require('http-proxy-middleware');
var options = {
target: 'http://127.0.0.1:8080',
onProxyRes: function (proxyRes, req, res) {
proxyRes.headers['Access-Control-Allow-Origin'] = '*';
}
};
http-proxy-middleware onProxyRes option is added in v0.5.0 , so make sure to update it if you're still using v0.0.5
You have to setup a proxy server to forward your requests, setup a reverse proxy, or setup CORS on the back-end to allow the cross-origin request.

Resources