Creating FollowMe link SoundCloud - javascript

I'm trying to create a simple FollowMe link for our Company and I am having a problem with the case when a user does not allow pop-ups. Here is the code:
$(document).ready(function(){
SC.initialize({
client_id: '***********************',
redirect_uri: 'http://localhost:8002/callback.html'
});
var isCalled = false;
var connect = function (){
isCalled = true;
SC.connect(function(){
SC.put('/me/followings/123456', function(me, error){
console.log('me: ', me)
console.log('error: ', error)
window.location.replace("http://www.soundcloud.com");
});
});
};
$('a').click(function(){
isCalled = true;
connect();
});
if(!isCalled){
console.log(isCalled);
//console.log('connect called')
isCalled = true;
connect();
}
});
Currently if you allow pup-ups in the browser you properly follow the desired user however when the user blocks popups and clicks the link they get the following error in the dialog box.
Unsafe JavaScript attempt to access frame with URL http://localhost:8002/ from frame with URL http://soundcloud.monstercat.com/callback.html?code=79e58c1c4ee8b3fb2a1c935fb676da90&state=SoundCloud_Dialog_1c798#access_token=1-24501-24540735-ab27bed0d285f42&scope=non-expiring. Domains, protocols and ports must match. callback.html:6
Uncaught TypeError: Cannot read property 'connectCallback' of undefined callback.html:6
Unsafe JavaScript attempt to access frame with URL http://soundcloud.monstercat.com/callback.html?code=79e58c1c4ee8b3fb2a1c935fb676da90&state=SoundCloud_Dialog_1c798#access_token=1-24201-27645735-ab27bed0d285f42&scope=non-expiring from frame with URL http://soundcloud.monstercat.com/callback.html?code=79e58c1c4ee8b3fb2a1c935fb676da90&state=SoundCloud_Dialog_1c798#access_token=1-24201-27645735-ab27bed0d285f42&scope=non-expiring. Domains, protocols and ports must match.
Any help would be much appreciated.
Note: callback.html is the standard one from the soundcloud dev site.

You're calling connect (and hence, trying to follow yourself) immediately upon page load. This is why the popup is being blocked. Unless the popup happens immediately while handling a click event, the browser will block it. Remove this part from the end of that script:
if(!isCalled){
console.log(isCalled);
//console.log('connect called')
isCalled = true;
connect();
}

Related

How to test programatically chosen external URL with Cypress for Bootstrap4 page

I am getting to grips with Cypress. Loving it so far, however, I have got stuck with the following.
I want to test that when a button is clicked, the user is directed to the correct external site. This works fine (at the moment) using the following code:
$("#my-button").click(function() {
var external_url = 'https://www.somesite.com/';
if($("#my-checkbox").prop("checked")) {
external_url += 'foo';
} else {
external_url += 'bar';
}
window.location.href = external_url;
return false;
});
Starting small within a Cypress spec:
it('Should direct to external site depending on checkbox state', () => {
cy.get('#my-button').click()
})
Receives Cypress Error:
Cypress detected a cross origin error happened on page load:
Blocked a frame with origin "http://localhost:8888" from accessing a cross-origin frame.
This is fair enough, and I understand why I get the error. I don't want to disable Chrome Web Security to get around it.
Can someone show me how I should test this use case?
I think I should be trapping the location change with cy.stub() and/or cy.on() but so far I have not had success:
it('Should direct to external site depending on checkbox state', () => {
cy.stub(Cypress.$("#my-button"), "click", () => {
console.log('stub')
})
cy.on("window.location.href", win => {
console.log('on')
})
cy.get('#my-button').click()
})
The button click still results in the error being thrown as the script still attempts to set the location to an external site.

Display error when iframe refuse to display [duplicate]

I am using Knockout.js to bind iframe src tag(This will be configurable with respect to User).
Now, if user has configured http://www.google.com (I know it won't load in iframe, thats why I am using it for -ve scenario) and that has to be shown in IFrame.
but it throws error:-
Refused to display 'http://www.google.co.in/' in a frame because it
set 'X-Frame-Options' to 'SAMEORIGIN'.
I have the following code for Iframe:-
<iframe class="iframe" id="iframe" data-bind="attr: {src: externalAppUrl, height: iframeheight}">
<p>Hi, This website does not supports IFrame</p>
</iframe>
What I want is, if the URL fails to load. I want to display Custom Message.
FIDDLE HERE
Now, if I use onload and onerror as:-
<iframe id="browse" style="width:100%;height:100%" onload="alert('Done')" onerror="alert('Failed')"></iframe>
It works fine loading w3schools.com but not with google.com.
Secondly:- if I make it as a function and try like I have done in my fiddle, it doesn't works.
<iframe id="browse" style="width:100%;height:100%" onload="load" onerror="error"></iframe>
I don't know how should I make it run and capture the error.
Edited:- I have seen Want to call a function if iframe doesn't load or load's question in stackoverflow but it shows error for sites that can be loaded in iframe.
Also, I have looked into Stackoverflow iframe on load event
Thanks!!
You wont be able to do this from the client side because of the Same Origin Policy set by the browsers. You wont be able to get much information from the iFrame other than basic properties like its width and height.
Also, google sets in its response header an 'X-Frame-Options' of SAMEORIGIN.
Even if you did an ajax call to google you wont be able to inspect the response because the browser enforcing Same Origin Policy.
So, the only option is to make the request from your server to see if you can display the site in your IFrame.
So, on your server.. your web app would make a request to www.google.com and then inspect the response to see if it has a header argument of X-Frame-Options. If it does exist then you know the IFrame will error.
I think that you can bind the load event of the iframe, the event fires when the iframe content is fully loaded.
At the same time you can start a setTimeout, if the iFrame is loaded clear the timeout alternatively let the timeout fire.
Code:
var iframeError;
function change() {
var url = $("#addr").val();
$("#browse").attr("src", url);
iframeError = setTimeout(error, 5000);
}
function load(e) {
alert(e);
}
function error() {
alert('error');
}
$(document).ready(function () {
$('#browse').on('load', (function () {
load('ok');
clearTimeout(iframeError);
}));
});
Demo: http://jsfiddle.net/IrvinDominin/QXc6P/
Second problem
It is because you miss the parens in the inline function call; try change this:
<iframe id="browse" style="width:100%;height:100%" onload="load" onerror="error"></iframe>
into this:
<iframe id="browse" style="width:100%;height:100%" onload="load('Done func');" onerror="error('failed function');"></iframe>
Demo: http://jsfiddle.net/IrvinDominin/ALBXR/4/
The onload will always be trigger, i slove this problem use try catch block.It will throw an exception when you try to get the contentDocument.
iframe.onload = function(){
var that = $(this)[0];
try{
that.contentDocument;
}
catch(err){
//TODO
}
}
This is a slight modification to Edens answer - which for me in chrome didn't catch the error. Although you'll still get an error in the console:
"Refused to display 'https://www.google.ca/' in a frame because it set 'X-Frame-Options' to 'sameorigin'." At least this will catch the error message and then you can deal with it.
<iframe id="myframe" src="https://google.ca"></iframe>
<script>
myframe.onload = function(){
var that = document.getElementById('myframe');
try{
(that.contentWindow||that.contentDocument).location.href;
}
catch(err){
//err:SecurityError: Blocked a frame with origin "http://*********" from accessing a cross-origin frame.
console.log('err:'+err);
}
}
</script>
I solved it with window.length.
But with this solution you can take current error (X-Frame or 404).
iframe.onload = event => {
const isLoaded = event.target.contentWindow.window.length // 0 or 1
}
MSDN
Update:
contentWindow.name will now always throw an error on cross-origin frames.
Seems like the only way is to do this server side (for now).
I have written a small cloudflare worker to capture headers for remote apis and it can be used here to check for X-Frame-Options.
Sample code to check before rendering in iframe: (jsfiddle: https://jsfiddle.net/2gud39aw/2/)
function checkUrlFrameOptions(apiurl){
return fetch("https://header-inspector.repalash.workers.dev/?" + new URLSearchParams({
'apiurl': apiurl,
'headers': 'x-frame-options'
}), {
method: 'GET'
}).then(r => r.json()).then(json => {
let xFrameOp = (json.headers['x-frame-options'] || '').toLowerCase();
// deny all requests
if(xFrameOp==='deny') return false;
// deny if different origin
if(xFrameOp==='sameorigin' && json.origin !== location.origin) return false;
return true;
})
}
checkUrlFrameOptions("https://google.com").then((res)=>console.log("google.com can be loaded in iframe: ", res))
checkUrlFrameOptions("https://example.com").then((res)=>console.log("example.com can be loaded in iframe: ", res))
The cloudflare worker endpoint ( https://header-inspector.repalash.workers.dev ) is just for testing, don't use this in production. The code is available at: https://gist.github.com/repalash/b1e778dbe3ac2e7149831c530a6535f9
and can be deployed directly as a cloudflare worker
OLD Answer
Here's a simple solution, tested on Chrome and Safari.
const iframe = document.createElement('iframe')
iframe.onload = function() {
try {
iframe.contentWindow.name
} catch (e) {
if (e.message.includes('cross-origin')) console.warn(e.message);
else console.error(e.message);
}
}
iframe.src = "https://google.com";
jsFiddle demo: https://jsfiddle.net/k5e1mg3t/5/
I faced similar problem. I solved it without using onload handler.I was working on AngularJs project so i used $interval and $ timeout. U can also use setTimeout and setInterval.Here's the code:
var stopPolling;
var doIframePolling;
$scope.showIframe = true;
doIframePolling = $interval(function () {
if(document.getElementById('UrlIframe') && document.getElementById('UrlIframe').contentDocument.head && document.getElementById('UrlIframe').contentDocument.head.innerHTML != ''){
$interval.cancel(doIframePolling);
doIframePolling = undefined;
$timeout.cancel(stopPolling);
stopPolling = undefined;
$scope.showIframe = true;
}
},400);
stopPolling = $timeout(function () {
$interval.cancel(doIframePolling);
doIframePolling = undefined;
$timeout.cancel(stopPolling);
stopPolling = undefined;
$scope.showIframe = false;
},5000);
$scope.$on("$destroy",function() {
$timeout.cancel(stopPolling);
$interval.cancel(doIframePolling);
});
Every 0.4 Seconds keep checking the head of iFrame Document. I somthing is present.Loading was not stopped by CORS as CORS error shows blank page.
If nothing is present after 5 seconds there was some error (Cors policy) etc..
Show suitable message.Thanks. I hope it solves your problem.
As explained in the accepted answer, https://stackoverflow.com/a/18665488/4038790, you need to check via a server.
Because there's no reliable way to check this in the browser, I suggest you build yourself a quick server endpoint that you can use to check if any url is loadable via iframe. Once your server is up and running, just send a AJAX request to it to check any url by providing the url in the query string as url (or whatever your server desires). Here's the server code in NodeJs:
const express = require('express')
const app = express()
app.get('/checkCanLoadIframeUrl', (req, res) => {
const request = require('request')
const Q = require('q')
return Q.Promise((resolve) => {
const url = decodeURIComponent(req.query.url)
const deafultTimeout = setTimeout(() => {
// Default to false if no response after 10 seconds
resolve(false)
}, 10000)
request({
url,
jar: true /** Maintain cookies through redirects */
})
.on('response', (remoteRes) => {
const opts = (remoteRes.headers['x-frame-options'] || '').toLowerCase()
resolve(!opts || (opts !== 'deny' && opts !== 'sameorigin'))
clearTimeout(deafultTimeout)
})
.on('error', function() {
resolve(false)
clearTimeout(deafultTimeout)
})
}).then((result) => {
return res.status(200).json(!!result)
})
})
app.listen(process.env.PORT || 3100)

CasperJS isn't doing the same request as normal browser

I have made some script in CasperJs to login to page, open specific page and get content of it.
I'm opening desired page with content to scrap with casper.thenOpen and it shows different content on casperjs and different on my browser. I have setted up useragent from my browser and still no effects. Here are request and response headers from casperjs:
http://screenshot.sh/m7QeJGUbqK5Kg
And here from my browser:
http://screenshot.sh/n8j3Gf9QkuXxm
I don't know why the results are different on browser and casperjs. I don't know why there is no cookie in request header in casperjs but i'm sure that it's logged in because previusly in code i can see code allowed only for logged users.
Thanks in advance for any help
Code:
casper.thenOpen('website.com', function() {
this.echo("start");
this.echo(this.fetchText('html'), "INFO");
casper.then(function () {
var json;
var start;
var end;
function checkReload()
{
json = JSON.parse(this.fetchText('html'));
if(json.msg.indexOf('desiredtext') === 0) {
this.echo("good", 'PARAMETER');
return;
}
else
{
this.echo('bad news: ' + json.msg, 'COMMENT');
}
casper.thenOpen('website.com');
this.echo(this.fetchText('html'));
this.wait(1, checkReload);
}
this.then(checkReload);
});
});
But problem isn't in code(I also tried to put request headers from browser to casper but this didn't work)

Close popup window for Google OAuth2

I have my oauth2 for Gmail open up in a popup using newWindow = window.open(...) and then when the user is done filling it out and hit 'allow' it redirects to my server where the tokens are retrieved and stored. Finally, the server returns 'Error' or 'Success' so the popup will just have that in it. Now on the Angular side I have this running.
checkConnect = setInterval(function() {
try{
if(newWindow.document.body.innerText === 'Success') {
console.log('Success');
newWindow.close();
window.clearInterval(checkConnect);
}else if(newWindow.document.body.innerText === 'Error') {
console.log('We had an error!');
newWindow.close();
window.clearInterval(checkConnect);
}else if(newWindow.closed) {
console.log('WINDOW WAS closed');
window.clearInterval(checkConnect);
}
}catch(e) {
//console.log(e);
}
}, 100);
This works sometimes and other times it fails. I also reuse this code for other Oauth providers, such as Dropbox.Sometimes it works and sometimes it doesn't. Any idea why?
Well I couldn't figure it out by using a popup. However, I was able to over come this problem by just having the oauth page open in the same page and redirect back to the page I wanted the user on afterwards.
Also, there are libraries provided by google that open it for you in a popup and handle the closing.

How to get access token from node-webkit for a desktop app without hosting page?

I'm trying to create a desktop app with node-webkit. A part of this app require the use of facebook to get/post some content to any profile (facebook user) that use my desktop app on my personal computer.
Regarding facebook api documentation (https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0) , I have to manually implement the login flow and use the following URI as the redirect URI: https://www.facebook.com/connect/login_success.html
Currently, in my node-webkit app, via a child window (a popup), a user can login to facebook and authorize my desktop app to interact with it's profile.
Here is a part of the code:
var url = "https://www.facebook.com/dialog/oauth?client_id=myclientID&redirect_uri=https://www.facebook.com/connect/login_success.html&response_type=token&scope=publish_actions";
loginWindow = window.open(url, 'Login facebook', 'location=yes,toolbar=yes,menubar=yes,directories=yes,status=yes,resizable=yes,scrollbars=yes,height=480,width=640', false);
After that, the user is redirected to the following URI and as mentioned in the doc, the access token appear correctly:
https://www.facebook.com/connect/login_success.html#access_token=theBigTokenString&expires_in=3864.
But it appears only for few seconds and after that the url is replaced by https://www.facebook.com/connect/blank.html#_=_ (with a security warning message).
I've read some post that propose to add eventListener like hashchange to the opened window in order to capture the access token. But after some redirect within the child window, I'm no longer available to interact with it via javascript.
So finally, I can't get the access token that the child window has retrieved and make visible for few seconds.
Is anyone can help me to get this user access token with node-webkit?
I really don't want to use a server (for hosting a web page) between my desktop app and facebook.
Thanks in advance for help.
With the help of an other question (here) I found a solution to my problem.
I post the code that I use now and I Hope it will help someone else:
var url = "https://www.facebook.com/dialog/oauth?&client_id=myBigClientID&redirect_uri=https://www.facebook.com/connect/login_success.html&response_type=token&scope=publish_actions";
function Response() {
this.access_token = null;
this.expires_in = null;
};
var response = new Response();
//function called every 500ms to check if token is in url
window.hashUpdate = function() {
if(window.loginWindow.closed){
window.clearInterval(intervalId);
start(); //just a callback that I'm using to start another part of my application (after I caught the token)
}
else {
var url = window.loginWindow.document.URL;
var tabUrl = url.split("#"); //first split to separate the domain part and the parameter part
var paramString = tabUrl[1]; //I concerned only by the second part after the '#'
if(paramString != undefined){
var allParam = paramString.split("&");
for (var i = 0; i < allParam.length; i++) {
var oneParamKeyValue = allParam[i].split("=");
response[oneParamKeyValue[0]] = oneParamKeyValue[1]; //store my token in form of key => value
};
//close the window after 1500ms
setTimeout(function(){
window.loginWindow.close();
}, 1500);
}
}
}
//open the url and start the watching process
window.loginWindow = window.open(this.url, 'Login facebook', false);
this.intervalId = window.setInterval("window.hashUpdate()", 500);

Categories

Resources