How to check if a user can access YouTube with Javascript - javascript

I need to programmatically check if a user can access YouTube, as YouTube is blocked in some parts of the world. I need to be able to do this in JavaScript.
What I have tried:
1) Creating an image dynamically and setting the source to be a known image on the YouTube domain - I ran into CORS issues here
2) Creating a simple GET request using XMLHttpRequest (same problem)
3) Looking at the YouTube API.. it does not appear to expose a method which can tell me whether a GET request was successful.. and of course, all calls are routed through https://www.googleapis.com/youtube/v3 which is not, strictly speaking, exactly the same as a request to http://www.youtube.com
Is there something obvious I'm missing here? Would appreciate any and all insight..
Thanks!

CORS is a server-side header. If you're getting a CORS header, you're hitting Youtube's servers which are responding with response headers, which likely means that youtube is not "blocked".
So something like this should work just fine:
async function canAccessYoutube() {
try {
const request = await fetch(
"https://www.youtube.com/",
{
mode: "no-cors"
}
);
return true;
} catch {
return false;
}
}
Assuming the blocking is DNS based, you can test the functionality by blocking Youtube on your own computer. If you have a mac or linux computer, add the following to your /etc/hosts file:
0.0.0.0 youtube.com
0.0.0.0 www.youtube.com
::0 www.youtube.com
::0 youtube.com
You may need to restart your computer for it to take effect.

Related

How do you send a cookie to a cross origin request using react and maybe electron?

I need to make a request to this other website and I need to send a cookie alongside it. I have no control over this other website so I cannot modify its cors policy or allow credentials in any meaningful way.
So, I decided to convert my website to a react app that will run contained inside an electron web browser. I thought that as the electron has full control over the computer, I would be able to send a normal request without having to deal with cors, but it seems, that cors and all sorts of other protections are still enabled.
To clarify my current setup, I have:
A react website localhost:3000
A electron app showing the react website.
There is no other communication happening between the two.
All requests are made solely by the react website.
The react website needs to communicate with foreignwebsite.com and send a cookie to it.
Normally this in any server-side type of application, including electron itself, would be of no problem, but react cannot make direct requests.
One way I could do this was to potentially create a middle server that communicates with the foreigner API and friendly gives me the data I need for my front-end app. But, I don't want to host a server, and if I create a server on the client machine I think the app would be too heavy.
I could use the electron process as a server and make node.js requests with it, but to communicate between react and electron seems weirdly complicated, it feels like it would be a mess of events.
I found an answer online that tries to kind of deactivate the cors of the electron browser, it partially did work, or at least it seems that it worked, it shows no error but the cookie simply isn't transferred, maybe it just tricks the browser but it doesn't work behind the scenes, idk...
const filter = {
urls: ['http://foreignwebsite.com/*']
}
mainWindow.webContents.session.webRequest.onBeforeSendHeaders(
filter,
(details, callback) => {
details.requestHeaders.Origin = `http://foreignwebsite.com/`
details.requestHeaders.Referer = `http://foreignwebsite.com/`
callback({ requestHeaders: details.requestHeaders })
}
)
mainWindow.webContents.session.webRequest.onHeadersReceived(
filter,
(details, callback) => {
details.responseHeaders['access-control-allow-origin'] = ['http://localhost:3000']
details.responseHeaders['access-control-allow-credentials'] = 'true'
callback({ responseHeaders: details.responseHeaders })
}
)
So above it sets the AccessControlAllowOrigin and the AllowCredentials of the response accordingly and it changes the origin and referer of the requests.
And when I go make requests on the react website I do it like this:
document.cookie = 'OmegaCookie=' + cookieVal + '; path=/; SameSite=None; Secure';
let response = await fetch('http://foreignwebsite.com', {credentials: 'include'});
But the cookie is not sent. Do you know what could be going wrong or how to handle it better in this situation?

How to handle CORS in a service account call to Google oAuth?

I access a Google calendar using a service account. This means that the owner of the calendar will not be prompted for his authorization.
This works fine in Python, where I make a requests call to https://accounts.google.com/o/oauth2/token with a specific body. This gets me back a token I can use later.
I now need to have an application running in a standalone browser (Chrome - without user interaction) and tried to directly port this call as
fetch('https://accounts.google.com/o/oauth2/token',
{
method: 'POST',
body: JSON.stringify(body),
})
.then(function(res) { return res.json(); })
.then(function(data) { alert(JSON.stringify(data)) })
but I get a reply from Google
Failed to load https://accounts.google.com/o/oauth2/token: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://devd.io' is therefore not allowed access. The
response had HTTP status code 400. If an opaque response serves your
needs, set the request's mode to 'no-cors' to fetch the resource with
CORS disabled.
My limited understanding of CORS (a previous answer was a very good read) is that
No 'Access-Control-Allow-Origin' header is present on the requested
resource
means that it is not present in the response headers, which means that Google does not want me to access its resources via JS when ran from the browser (which points to something else that https://accounts.google.com).
This may be a good idea but I control all elements, from the code to the browser and would like to get that token the same way I get it in a non-browser environment, specifically my working Python code.
How can I tell https://accounts.google.com to send me back a Access-Control-Allow-Origin header which tell my browser that it is OK to accept the call?
You can't.
Client side and server side code need to interact with OAuth in different ways.
Google provide documentation explaining the client side process.
Importantly, part of it involves redirecting to Google's servers instead of accessing them with fetch or XMLHttpRequest.
#Quentin's answer "You can't" is the right one for my question ("how can I force the server to send back the right header").
This is a decision at Google not to provide this header, effectively cutting off any non-interactive applications.
As a solution, I will look at
how to force the browser not to take into account the security mechanisms provided by CORS (there seems to be some ways through extensions or command-line arguments, I will update this answer once I find it)
or write an intermediate layer which will query the data for me and pass them verbatim to the application (this is equivalent, in my case, of just making the query from JS - but it adds an extra layer of code and server)

CORS headers for accessing a file on another domain

I am attempting to create an audio visualization program on Codepen. I have created my own Ubuntu web server with apache which allows me direct access to modify headers and configuration of the server.
While browsers can access files on a different domain, it requires special CORS headers to read the frequencies within the audio. To read audio frequencies, I must use createMediaElementSource to access audio information including the frequencies. When the browser sees this JavaScript method, it knows that there must be certain headers set on the server to allow access. Which brings us to the motives of this question: What headers need to be set?
All of the browsers I have tested return a variation of a CORS error.
This is what the error looks like in Firefox although I've tested it in Chrome, Opera, and Safari with similar results:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://williamgreen.hopto.org/audioVisualization/song.mp3. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘(null)’).
The file returns 206 partial content.
Here are the returned server headers (currently):
Here are the sent headers (currently):
function log(text) {
document.getElementById("log").textContent += text + "\n";
}
var audio, source, context;
var url = "http://williamgreen.hopto.org/audioVisualization/song.mp3";
document.addEventListener("DOMContentLoaded", function() {
log("URL: " + url);
log("Creating Audio instance from audio file");
audio = new Audio(url);
audio.crossOrigin="anonymous";
audio.addEventListener("canplay", function() {
log("Playing audio file through HTML5 Audio for 3 seconds");
audio.play();
setTimeout(function() {
log("Creating Web Audio context");
context = new (typeof AudioContext != "undefined" ? AudioContext : webkitAudioContext)();
log("Calling createMediaElementSource on audio (switching to Web Audio)");
source = context.createMediaElementSource(audio);
setTimeout(function() {
log("Connecting source to context destination");
source.connect(context.destination);
log("\nIf no sound can be heard right now, the problem was reproduced.");
}, 1000);
}, 3000);
});
});
<div id="log"></div>
What do I need to change to get this working?
My first thought is that the problem is your
Access-Control-Allow-Origin: *, *
I don't think it is understanding the *, * thing. Try just *.
Edit: you can check what the header really looks like with a command like this:
curl -v -o /dev/null http://williamgreen.hopto.org/audioVisualization/song.mp3
And, lo, it even works for me, yielding (among a lot of other headers):
< Access-Control-Allow-Origin: *
So that is hunky-dory.
Second, are you running this from a file: origin? That doesn't work on Chrome (I thought it would work on Firefox, but maybe that's changed). You have to run it from an http: or https: origin.
By "running from an file: origin" I mean, is the HTML file that is running that Javascript being loaded from an URL that beings with "file:". If so, that is not likely to work.

Issue with reading Response headers

I am trying to build a chrome extension for which i need to ping to different machines.The code which i tried with is able to read the response headers for a https site but not for http.I am new to Javascripting. Any help would be great.I understand it is a CORS issue and tried setting the headers in the client code.many forums mention it setting al the server side but where can I do in this case? Please find the code below and the plugin UI and response returned from https site in the snapshot.
Code--
url="https://www.icicibank.com/";
//url = "www.rediff.com/";
ping = new XMLHttpRequest();
ping.open("get", url,true);
//ping.setRequestHeader("Access-Control-Allow-Origin","*");
// ping.setRequestHeader("Access-Control-Allow-Credentials", "true");
ping.send(null)
ping.onreadystatechange=function() {
if (ping.readyState==4) {
alert(ping.getAllResponseHeaders());
//alertify.alert(ping.getAllResponseHeaders());
}
}
Thanks
CORS is indeed part of the server response, not the request. So you cannot "set" it on your side.
However, extensions are allowed to bypass CORS restrictions and make cross-origin requests. But for that you need to list domains you're going to connect to in manifest permissions. The user will be warned, at install time, that you'll interact with those domains.
For example, to allow requests to http://example.com and https://example.com domains regardless of CORS, you need to include in the manifest:
"permissions" : [
"*://example.com/"
],
If you can't say which sites you'll need to connect to in advance, you'll either need permissions for all urls (special permission, literally, "<all_urls>") or use Optional Permissions to request that at runtime.

JSONP callback doesn't execute when running at localhost

This is bizarre, I was wondering if anyone could shed some light on why this happened.
Basically, I've been pulling my hair out trying to test JSONP out so I can implement a JSON web service that other sites can use. I'm doing development on localhost--specifically, Visual Studio 2008 and Visual Studio 2008's built-in web server.
So as a JSONP test run w/ jQuery, I implemented the following:
$().ready(function() {
debugger;
try {
$.getJSON("<%= new Uri(Request.Url, "/").ToString() %>XssTest?callback=?", function(data) {
alert(data.abc);
});
} catch (err) {
alert(err);
}
});
And on the server ..
<%= Request["callback"] %>({abc : 'def'})
So what ends up happening is I set a breakpoint on the server and I get the breakpoint both on the first "debugger;" statment in the client-side script as well as on the server. The JSONP URL is indeed being invoked after the page loads. That's working great.
The problem I was having was that the callback would never execute. I tested this in both IE8 as well as Firefox 3.5. Neither one would invoke the callback. The catch(err) was never reached, either. Nothing happened at all!
I'd been stuck on this for a week, and even tested with a manually keyed HTTP request in Telnet on the specified port to be sure that the server is returning the format...
callbackfn({abc : 'def'})
.. and it is.
Then it dawned on me, what if I change the hostname from localhost to localhost with a globalizer ('.'), i.e http://localhost.:41559/ instead of http://localhost:41559/ (yes, adding a dot to any hostname is legal, it is to DNS what global:: is to C# namespaces). And then it worked! Internet Explorer and Firefox 3.5 finally showed me an alert message when I just added a dot.
So this makes me wonder, what is going on here? Why would late script tag generation work with an Internet hostname and not with plain localhost? Or is that the right question?
Clearly this is implemented for security reasons, but what are they trying to secure?? And, by getting it to work with a dot, did I just expose a security hole in this security feature?
By the way, my hosts file, while altered for other hosts, has nothing special going on with localhost; the default 127.0.0.1 / ::1 are still in place with no overrides below.
FOLLOW-UP: I got past this for local development purposes by adding:
127.0.0.1 local.mysite.com
.. to my hosts file, then adding the following code to my global.asax:
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.Headers["Host"].Split(':')[0] == "localhost")
{
Response.Redirect(
Request.Url.Scheme
+ "://"
+ "local.mysite.com"
+ ":" + Request.Url.Port.ToString()
+ Request.Url.PathAndQuery
, true);
}
}
I'm going to throw an answer out there; after some thought I've reached my own conclusions.
It could be that this is a security feature that's implemented to try to thwart an Internet web site from invoking JSONP services running on the client machine.
A web site could just go through a list of ports and keep invoking localhost on different ports and paths. 'Localhost' is one of few DNS hostnames that are dynamic in meaning depending on when and where it's queried, making the potential targets vulnerable. And yes, the fact that appending a dot (.) to 'localhost' ('localhost.') produces a working workaround does expose a security vulnerability, but does offer a [tentative] workaround for development puposes.
A better approach is to map the loopback IP to a new hostname entry in the hosts file so that it works locally, isn't prone to be "fixed" by a browser update, and doesn't work anywhere else but on the development workstation.
I'm experiencing a similar problem. Most of the solutions I've tried work with IE (7), but I'm having difficulty getting Firefox (3.5.2) to play ball.
I've installed HttpFox in order to see how my server's responses are being interpreted on the client, and I'm getting NS_ERROR_DOM_BAD_URI. My situation is a little different to yours though, as I'm trying to invoke a JSONP call back to the same site the hosting page came from, and then this call is responding with a 302 redirect to another site. (I'm using the redirect as a convenient way to get cookies from both domains returned to the browser.)
I'm using jQuery, and I originally tried doing a standard AJAX call via $.ajax(). I figured that as the initial request was to the same site as the hosting page, Firefox would just follow the 302 response to another domain. But no, it appeared to fall foul of XSS defenses. (Note that contrary to what Returning redirect as response to XHR request implies, jQuery does follow the 302 redirect for a standard dataType="json" call: a redirect to the same domain works fine; a redirect to another domain generates NS_ERROR_DOM_BAD_URI in the browser.) As an aside, I don't see why same-domain 302 redirects to other domains can't just be followed - after all, it's the hosting page's domain that is issuing the redirect, so why can't it be trusted? If you're worried about scripting injection attacks, then the JSONP route is open for abuse anyway...
jQuery's $.getJSON() with a ?callback=? suffix also fails in Firefox with the same error. As does using $.getScript() to roll my own JSONP <script> tag.
What does appear to work, is having a pre-existing <script id="jsonp" type="text/javascript"></script> in the HTML and then using $("jsonp").attr("src", url + "?callback=myCallback") to invoke the JSONP call. If I do that, then the cross-domain 302 redirect is followed and I get my JSON response passed to myCallback (which I've defined at the same time as the <script/> tag).
And, yes, I'm developing all this using Cassini with localhost:port URLs. Cassini won't respond to non-localhost URLs, so I can't easily try local.mysite.com to see if that has any affect on the solutions I've tried above. However, sticking a dot at the end of localhost appears to have fixed all my problems!
Now I can go back to a standard $.ajax({ ... dataType:"jsonp" ... }) call with localhost__.__:port instead of localhost:port and all is well. I find it interesting that modifying the src attribute of a script tag that pre-exists in the page's HTML does allow ordinary localhost URLs to be invoked - I guess following your thought process, this could be another security vulnerability.

Categories