If I run this Code:
function sendRequest() {
var req = new XMLHttpRequest();
req.open("GET", "http://www.google.com/search?XXXX", true);
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status == 200) {
alert( req.responseText );
}
}
};
req.send();
}
I get this error:
XMLHttpRequest cannot load http://www.google.com/search?XXXX. Origin chrome-extension://loifkhcbcjakjhcmecadcbdgfldfjfce is not allowed by Access-Control-Allow-Origin.
why??
In manifest file I have:
"permissions": [
"<all_urls>"
]
Demi
That will work for a packaged Chrome app, but not a hosted one.
Related
I'm trying to build a home automation system by myself. For this, I use the Blynk server to control my hardware. I can control my hardware by requesting the URL of the blynk server.
For example: When I make a request to https://139.59.206.133/myprivatekey/update/V1?value=1 and update a Virtual Pin to "1" and my light turns on.
I used this to make an Alexa custom skill which is able to turn my light on by making an HTTPS request to the Blynk server. For example when I say "Alexa ask my Room to turn the light on". The custom Skill is working how it should.
But a Custom skill is not really what I was looking for, so I decided to build an Alexa Smart Home Skill. So I set one up and simply tried to make an HTTPS request when "TurnON" or "TurnOFF" is called.
My problem is that every time I try to make an HTTPS request Alexa says that the device is not responding.
I tried a lot of things, but I couldn't solve my problem on my own.
Code:
The Code is from the node.js Alexa Smart Home Example.
exports.handler = function (request, context) {
if (request.directive.header.namespace === 'Alexa.Discovery' && request.directive.header.name === 'Discover') {
log("DEBUG:", "Discover request", JSON.stringify(request));
handleDiscovery(request, context, "");
}
else if (request.directive.header.namespace === 'Alexa.PowerController') {
if (request.directive.header.name === 'TurnOn' || request.directive.header.name === 'TurnOff') {
log("DEBUG:", "TurnOn or TurnOff Request", JSON.stringify(request));
handlePowerControl(request, context);
}
}
function handleDiscovery(request, context) {
var payload = {
"endpoints":
[
{
"endpointId": "demo_id",
"manufacturerName": "Smart Device Company",
"friendlyName": "Zimmerlicht",
"description": "Smart Device Switch",
"displayCategories": ["SWITCH"],
"cookie": {
"key1": "arbitrary key/value pairs for skill to reference this endpoint.",
"key2": "There can be multiple entries",
"key3": "but they should only be used for reference purposes.",
"key4": "This is not a suitable place to maintain current endpoint state."
},
"capabilities":
[
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
},
{
"interface": "Alexa.PowerController",
"version": "3",
"type": "AlexaInterface",
"properties": {
"supported": [{
"name": "powerState"
}],
"retrievable": true
}
}
]
}
]
};
var header = request.directive.header;
header.name = "Discover.Response";
log("DEBUG", "Discovery Response: ", JSON.stringify({ header: header, payload: payload }));
context.succeed({ event: { header: header, payload: payload } });
}
function log(message, message1, message2) {
console.log(message + message1 + message2);
}
function handlePowerControl(request, context) {
// get device ID passed in during discovery
var requestMethod = request.directive.header.name;
var responseHeader = request.directive.header;
responseHeader.namespace = "Alexa";
responseHeader.name = "Response";
responseHeader.messageId = responseHeader.messageId + "-R";
// get user token pass in request
var requestToken = request.directive.endpoint.scope.token;
var powerResult;
if (requestMethod === "TurnOn") {
const Http = new XMLHttpRequest();
const url='https://139.59.206.133/myprivatekey/update/V1?value=1';
Http.open("GET", url);
Http.send();
// Make the call to your device cloud for control
// powerResult = stubControlFunctionToYourCloud(endpointId, token, request);
powerResult = "ON";
}
else if (requestMethod === "TurnOff") {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", 'http://myprivatekey/update/V0?value=0', false ); // false for synchronous request
xmlHttp.send( null );
// Make the call to your device cloud for control and check for success
// powerResult = stubControlFunctionToYourCloud(endpointId, token, request);
powerResult = "OFF";
}
var contextResult = {
"properties": [{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": powerResult,
"timeOfSample": "2017-09-03T16:20:50.52Z", //retrieve from result.
"uncertaintyInMilliseconds": 50
}]
};
var response = {
context: contextResult,
event: {
header: responseHeader,
endpoint: {
scope: {
type: "BearerToken",
token: requestToken
},
endpointId: "demo_id"
},
payload: {}
}
};
log("DEBUG", "Alexa.PowerController ", JSON.stringify(response));
context.succeed(response);
}
};
My Requests:
if (requestMethod === "TurnOn") {
const Http = new XMLHttpRequest();
const url='https://139.59.206.133/myprivatekey/update/V1?value=1';
Http.open("GET", url);
Http.send();
// Make the call to your device cloud for control
// powerResult = stubControlFunctionToYourCloud(endpointId, token, request);
powerResult = "ON";
}
else if (requestMethod === "TurnOff") {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", 'http://myprivatekey/update/V0?value=0', false ); // false for synchronous request
xmlHttp.send( null );
// Make the call to your device cloud for control and check for success
// powerResult = stubControlFunctionToYourCloud(endpointId, token, request);
powerResult = "OFF";
}
Additional Info:
Programming language node.js
account linking, IAM role, and everything to create a smart home skill should be set up right
I am rather new to Alexa Skill building, and I'm also not very good at JavaScript.
If the request went through, I mean your code is being called, and light is being turned on/off, the problem is with the response.
My guess is that you are missing correlation id.
you need to add something like:
responseHeader.correlationToken = request.directive.header.correlationToken;
You should also implement the EndpointHealth: https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-endpointhealth.html
What is the correct way to pass the code from myscript.js to background.js?
I have
myscript.js
function fox2(){
{
var url = 'https://sub.domain.com'
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var parser = new DOMParser();
source_code = parser.parseFromString(xhr.responseText, "text/html");
var a = source_code;
console.log(a)
}
};
xhr.send();
}
}
fox2();
Background.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "nuevo.js"});
});
Error: Cross-Origin Read Blocking (CORB) blocked cross-origin response with MIME type text/html
I know that the solution is to use the code in Background, But How should I do it?.
Thanks.
I'm having an issue when following this tutorial https://devcenter.heroku.com/articles/s3-upload-node
I've setup the code here https://desolate-island-40106.herokuapp.com/account and get the following error:
XMLHttpRequest cannot load
https://s3.amazonaws.com/nns.app.images/Nom%20Nom%20Snap.png?AWSAccessKeyId…=1466571088&Signature=9zyWWJrY5oQQtunDbZ1oRtVrJSo%3D&x-amz-acl=public-read.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://desolate-island-40106.herokuapp.com' is
therefore not allowed access.
The app gets a signed request successfully but the error occurs in the below where xhr.status = 0:
function uploadFile(file, signedRequest, url){
const xhr = new XMLHttpRequest();
xhr.open('PUT', signedRequest);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4){
if(xhr.status === 200){
document.getElementById('preview').src = url;
document.getElementById('avatar-url').value = url;
}
else{
alert('Could not upload file.');
}
}
};
xhr.send(file);
}
Anyone have any ideas?
I can't get a user's id_token (https://developers.google.com/accounts/docs/CrossClientAuth) from the Chrome identity api (https://developer.chrome.com/apps/identity).
I can get an access_token using the chrome identity sample when the oauth section in the manifest is:
"oauth2": {
"client_id": "<chrome-app-client-id>.apps.googleusercontent.com",
"scopes": ["https://www.googleapis.com/auth/plus.login"]
}
But when I try to get the id_token the same way I get it on my android client a get the error:
"OAuth2 request failed: Service responded with error: 'invalid scope: {0}'"}
The manifest section is now:
"oauth2": {
"client_id": "<chrome-app-client-id>.apps.googleusercontent.com",
"scopes": ["audience:server:client_id:<app-engine-client-id>.apps.googleusercontent.com"]
}
On Android I get the id_token by passing the same scope string to android.gms.auth.GoogleAuthUtil.getToken(), but I can't get it to work with the chrome identity api.
Is it possible to get an id_token with Chrome App Indentity Api? If not, how can I get an id_token for my Chrome app?
Thanks for your help!
I've came to the same problem yesterday and since I've found a solution, I might as well share it, as it wasn't that obvious. As far as i know Google does not provide a direct and documented way to do this, but you can use the chrome.identity.launchWebAuthFlow() function.
First you should create an Web application credentials in google console and add the following url as a valid Authorized redirect URI: https://<EXTENSION_OR_APP_ID>.chromiumapp.org. The URI does not have to exist, chrome will just catch the redirect to this URL and call your callback function later.
manifest.json:
{
"manifest_version": 2,
"name": "name",
"description": "description",
"version": "0.0.0.1",
"background": {
"scripts": ["background.js"]
},
"permissions": [
"identity"
],
"oauth2": {
"client_id": "<CLIENT_ID>.apps.googleusercontent.com",
"scopes": [
"openid", "email", "profile"
]
}
}
background.js:
// Using chrome.identity
var manifest = chrome.runtime.getManifest();
var clientId = encodeURIComponent(manifest.oauth2.client_id);
var scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
var redirectUri = encodeURIComponent('https://' + chrome.runtime.id + '.chromiumapp.org');
var url = 'https://accounts.google.com/o/oauth2/auth' +
'?client_id=' + clientId +
'&response_type=id_token' +
'&access_type=offline' +
'&redirect_uri=' + redirectUri +
'&scope=' + scopes;
chrome.identity.launchWebAuthFlow(
{
'url': url,
'interactive':true
},
function(redirectedTo) {
if (chrome.runtime.lastError) {
// Example: Authorization page could not be loaded.
console.log(chrome.runtime.lastError.message);
}
else {
var response = redirectedTo.split('#', 2)[1];
// Example: id_token=<YOUR_BELOVED_ID_TOKEN>&authuser=0&hd=<SOME.DOMAIN.PL>&session_state=<SESSION_SATE>&prompt=<PROMPT>
console.log(response);
}
}
);
Google OAuth2 API (for OpenID Connect) documentation can be found here: https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
PS: If you don't need the oauth2 section in your manifest. You can safely omit it, and provide the identifiers and scopes in code only.
EDIT:
For those interested, you don't need the identity API. You can even access the token using a little trick with tabs API. The code is a little longer, but you have better error messages and control. Keep in mind that in the following example, you need to create Chrome App credentials.
manifest.json:
{
"manifest_version": 2,
"name": "name",
"description": "description",
"version": "0.0.0.1",
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs"
],
"oauth2": {
"client_id": "<CLIENT_ID>.apps.googleusercontent.com",
"scopes": [
"openid", "email", "profile"
]
}
}
background.js:
// Using chrome.tabs
var manifest = chrome.runtime.getManifest();
var clientId = encodeURIComponent(manifest.oauth2.client_id);
var scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
var redirectUri = encodeURIComponent('urn:ietf:wg:oauth:2.0:oob:auto');
var url = 'https://accounts.google.com/o/oauth2/auth' +
'?client_id=' + clientId +
'&response_type=id_token' +
'&access_type=offline' +
'&redirect_uri=' + redirectUri +
'&scope=' + scopes;
var RESULT_PREFIX = ['Success', 'Denied', 'Error'];
chrome.tabs.create({'url': 'about:blank'}, function(authenticationTab) {
chrome.tabs.onUpdated.addListener(function googleAuthorizationHook(tabId, changeInfo, tab) {
if (tabId === authenticationTab.id) {
var titleParts = tab.title.split(' ', 2);
var result = titleParts[0];
if (titleParts.length == 2 && RESULT_PREFIX.indexOf(result) >= 0) {
chrome.tabs.onUpdated.removeListener(googleAuthorizationHook);
chrome.tabs.remove(tabId);
var response = titleParts[1];
switch (result) {
case 'Success':
// Example: id_token=<YOUR_BELOVED_ID_TOKEN>&authuser=0&hd=<SOME.DOMAIN.PL>&session_state=<SESSION_SATE>&prompt=<PROMPT>
console.log(response);
break;
case 'Denied':
// Example: error_subtype=access_denied&error=immediate_failed
console.log(response);
break;
case 'Error':
// Example: 400 (OAuth2 Error)!!1
console.log(response);
break;
}
}
}
});
chrome.tabs.update(authenticationTab.id, {'url': url});
});
First, I assume that in your manifest.json snippet you don't mean that your client_id is literally "<chrome-app-client-id>.apps.googleusercontent.com. It should be something like 9414861317621.apps.googleusercontent.com -- something you got from the Developer Console, or whatever Google site you used to register the app.
Assuming the above is OK, and you have the client_id right, and the scope right, you get what's called an "OAuth2 access token" with a call to chrome.identity.getAuthToken. As you don't show us any JavaScript code, I can't tell if this is what you're doing. The access token you get you need to save for subsequent use when you call an API function. For example:
var access_token;
chrome.identity.getAuthToken(
{
'interactive': true
},
function(token) {
access_token = token;
// do something if you like to indicate
// that the app is authorized
}
);
Then, when you make an API call, you supply that access token, like this:
var url = 'https://www.googleapis.com/' + method;
Ajax.ajaxSend(url, "json",
function (status, response) {
if (response && response.error && response.error.message)
errorCallback(response.error.message);
else if (status == 200)
successCallback(response);
else
errorCallback('Result code: ' + status);
},
function (e) {
if (errorCallback)
errorCallback('Communication error');
},
{
Authorization: 'Bearer ' + access_token
}
);
Ajax.ajaxSend is my own function:
var Ajax = (function () {
var api = {
ajaxSend: function (url, responseType, successCallback, errorCallback, headers) {
var req = new XMLHttpRequest();
req.onload = function (e) {
successCallback(req.status, req.response);
};
req.onerror = errorCallback;
req.responseType = responseType ? responseType : "text";
req.open("get", url);
if (headers)
for (var v in headers)
req.setRequestHeader(v, headers[v]);
req.send();
}
};
return api;
})();
The other undefined functions also are what you'd expect. The third argument to Ajax.ajaxSend is a header to be sent along. (Sorry, I don't have time to develop standalone code just for this answer.)
I hope the above is useful.
I guess it depends on why one would want token id, but in my case
access_token was enough to authorize user - by pulling user info from https://www.googleapis.com/oauth2/v2/userinfo?alt=json ( with Authorization header = access_token).
I try to get the html page from a internal webserver in my js code, and parse it to make bookmarks.
At the moment I have problems with Access-Control-Allow-Origin, but the permissions are set !
{
"manifest_version": 2,
"name": "test",
"description": "test",
"version": "1.0",
"options_page":"config.html",
"browser_action": {
"default_popup": "test.html",
"permissions": [
"*://*/*"
],
"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"
}
}
I try the code from the example here : https://developer.chrome.com/extensions/xhr :
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// JSON.parse does not evaluate the attacker's scripts.
var resp = JSON.parse(xhr.responseText);
}
}
xhr.send();
But I get the error
XMLHttpRequest cannot load http://api.example.com/data.json. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'chrome-extension://nnbpdlokhkemfjmfkmlfnjonmeaccdmo'
is therefore not allowed access.
I'm pretty lost !
Actually I want to do that (that doesn't work either) :
function httpGet(url,user,pass)
{
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET",url, false );
xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(user + ":" +pass))
xmlHttp.send( null );
response= xmlHttp.responseText;
startT=response.indexOf("menuData = [");
//alert(startT);
Text=response.substr(startT+11 );
Text=Text.substr(0,Text.indexOf("\n"));
var obj = eval (Text)
return Text
}
The permissions section of the manifest should be an independent entry, not located inside browser_action. Check the documentation for the manifest file format.