setDiscoverTargets is not allowed for chrome extension - google-chrome

I am trying to develop a chrome extension and in this extension, I need the target related events (targetCreated/targetInfoChanged/targetDestroyed).
To achieve that goal I am using setDiscoverTargets method from the devtools protocol by means of chrome.debugger API. Here is the pseudocode that I am using:
// attach the debugger
chrome.debugger.attach(debuggeeId, version, onAttach);
// when attach is successful send setAuthAttach to make setDiscoverTargets command work
const onAttach = (debuggeeId) => {
if (chrome.runtime.lastError) {
alert(chrome.runtime.lastError.message);
return;
}
console.log(`onAttach: ${JSON.stringify(debuggeeId)}`);
chrome.debugger.sendCommand({ tabId: myTabId }, "Target.setAutoAttach", { autoAttach: false, waitForDebuggerOnStart: false, flatten: true }, setAutoAttachHandler);
}
// when auto attach handler is successful send setDiscoverTargets method
// to enable targetCreated/targetInfoChanged/targetDestroyed events
const setAutoAttachHandler = (result) => {
if (chrome.runtime.lastError) {
console.log("error in setAutoAttachHandler:" + chrome.runtime.lastError.message);
return;
}
console.log(`setAutoAttachHandler result: ${JSON.stringify(result)}`);
chrome.debugger.sendCommand({ tabId: myTabId }, 'Target.setDiscoverTargets', { discover: true }, setDiscoverTargetsHandler);
}
// see the result of command
const setDiscoverTargetsHandler = (result) => {
if (chrome.runtime.lastError) {
console.log("error in setDiscoverTargetsHandler:" + chrome.runtime.lastError.message);
return;
}
console.log(`setDiscoverTargets result: ${JSON.stringify(result)}`);
}
As per execute the code above I am always getting not allowed error
error in setDiscoverTargetsHandler:{"code":-32000,"message":"Not
allowed"}
And the events related to the target are not fired. Is there anything else I should do to get those events?
thank you.

Methods under Target and Browser domain(except for Browser.getVersion) are not allowed when sending command from chrome.debugger api. But if you want to observe for tabs to which debugger is attached or tabs in which developer tools is opened then you can poll chrome.debugger.getTargets at regular intervals. You will get response, something like this :-
[{
"attached": true,
"faviconUrl": "https://www.wikipedia.org/static/favicon/wikipedia.ico",
"id": "DEA9ED6A4A3DFB9A6FC315AF7110465B",
"tabId": 88,
"title": "Wikipedia",
"type": "page",
"url": "https://www.wikipedia.org/,
}, {
"attached": false,
"faviconUrl": "https://github.githubassets.com/favicons/favicon.svg",
"id": "3314432045C3EC141D4C7D7023606122",
"tabId": 87,
"title": "GitHub",
"type": "page",
"url": "https://github.com/"
}]

Related

Google Fit APi for step count is giving permission denied for first time user

i have developed an app which sync user step count from google fit. I have observed that users who are syncing as soon as the installation of google fit app in there mobile and user who haven't installed the app are getting the following error
{
"error": {
"code": 403,
"message": "datasource not found or not readable: derived:com.google.step_count.delta:com.google.android.gms:estimated_steps",
"errors": [
{
"message": "datasource not found or not readable: derived:com.google.step_count.delta:com.google.android.gms:estimated_steps",
"domain": "global",
"reason": "forbidden"
}
],
"status": "PERMISSION_DENIED"
}
}
When they reinstall the app it works fine
If they sync next day it will work
here is the code:
const timeGap = {
endTimeMillis: new Date().getTime() + 1 * 60 * 60 * 1000,
startTimeMillis: new Date('2021-01-01 00:00').getTime(),
};
return gapi.client.fitness.users.dataset
.aggregate({
userId: 'me',
resource: {
aggregateBy: [
{
dataTypeName: 'com.google.step_count.delta',
dataSourceId:
'derived:com.google.step_count.delta:com.google.android.gms:estimated_steps',
},
],
endTimeMillis: timeGap.endTimeMillis,
startTimeMillis: timeGap.startTimeMillis,
bucketByTime: {
durationMillis: 86400000,
},
},
})
.then(
(response) => {
console.log('[[[[[', response);
const stepVals = [];
console.log(response);
observer.next(response.result);
observer.complete();
},
(err: any) => {
observer.error(err);
observer.next(err);
// console.error("ERRRR", err);
observer.complete();
}
);
datasource not found ...
The DataSource you're trying to read won't exist until the user has synced data up to the server.
This error is reasonable to interpret as NOT_FOUND.

Modifying response headers in Chrome extensions

I'm trying to modify the referer-policy header with my Chrome extension, but it doesn't affect the response headers.
Manifest.json:
{
"name": "My Example Extension",
"version": "1.0",
"description": "",
"permissions": [
"webRequest",
"webRequestBlocking",
"*://*/*"
],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"manifest_version": 2
}
background.js:
chrome.webRequest.onHeadersReceived.addListener(details => {
let header = details.responseHeaders.find(e => e.name.toLowerCase() === 'referrer-policy');
// Check if the header has been defined already
if (typeof header !== 'undefined') {
console.log ('Modifying header');
header.value = 'strict-origin';
}
else {
details.responseHeaders.push({ name: 'referrer-policy', value: 'strict-origin' });
}
return {responseHeaders: details.responseHeaders};
}, {urls: ["*://*/*"]}, ['blocking', 'responseHeaders']);
I added debug outputs which show that the code modifies or adds the header accordingly but there is no effect in the browser itself.
I was writing exactly the same code when trying to modify response headers in extension.
// manifest.json
"permissions": [
"webRequest", "webRequestBlocking", "https://developer.chrome.com/*"
]
// background.js
chrome.webRequest.onHeadersReceived.addListener(
function(details) {
const newHeader = {name:"foo", value:"bar"};
const responseHeaders = details.responseHeaders.concat(newHeader);
return { responseHeaders };
},
// filters
{
urls: ["https://developer.chrome.com/*"],
},
// extraInfoSpec
["blocking","responseHeaders"]
);
It just doesn't work at all.
Until I've changed the last argument to:
// extraInfoSpec
["blocking","responseHeaders", "extraHeaders"]
It finally works.
By revisiting the document, in the last paragraphs of Life cycle of requests section:
Starting from Chrome 79, ... On the other hand, response header modifications do not work to deceive CORS checks. If you need to deceive the CORS protocol, you also need to specify 'extraHeaders' for the response modifications.
You were not returning the modified headers. Try with:
chrome.webRequest.onHeadersReceived.addListener(details => {
let myResponseHeaders = details.responseHeaders;
let header = myResponseHeaders.find(e => e.name == 'Referrer-Policy');
// Check if the header has been defined already
if (header) {
console.log ('Modifying header');
let headerIndex = myResponseHeaders.indexOf(header);
myResponseHeaders.splice(headerIndex,1);
}
myResponseHeaders.push({ name: 'Referrer-Policy', value: 'strict-origin' });
return {responseHeaders: myResponseHeaders};
}, {urls: ["*://*/*"]}, ['blocking', 'responseHeaders']);
Or with a slightly modified code copied from the documentation:
chrome.webRequest.onHeadersReceived.addListener(
function(details) {
for (var i = 0; i < details.responseHeaders.length; ++i) {
if (details.responseHeaders[i].name === 'Referrer-Policy') {
details.responseHeaders[i].value = 'strict-origin';
break;
}
}
return {responseHeaders: details.responseHeaders};
},
{urls: ["<all_urls>"]},
["blocking", "responseHeaders"]);

How to create a custom intent and calling helper intent using Actionsdk?

Please find my action.json file content
{
"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "testapp"
},
"intent": {
"name": "actions.intent.MAIN",
"trigger": {
"queryPatterns": [
"talk to Developer"
]
}
}
},
{
"name": "BUY",
"intent": {
"name": "com.example.sekai.BUY",
"parameters": [{
"name": "color",
"type": "SchemaOrg_Color"
}],
"trigger": {
"queryPatterns": [
"find some $SchemaOrg_Color:color sneakers",
"buy some blue suede shoes",
"get running shoes"
]
}
},
"fulfillment": {
"conversationName": "testapp"
}
}
],
"conversations": {
"testapp": {
"name": "testapp",
"url": "https://us-central1-samplejs2-id.cloudfunctions.net/testApp",
"fulfillmentApiVersion": 2,
"inDialogIntents": [
{
"name": "actions.intent.CANCEL"
}
]
}
},
"locale": "en"
}
Please find my index.js file content
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {actionssdk} = require('actions-on-google');
const app = actionssdk({debug: true});
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
app.intent('com.example.sekai.BUY', (conv, input) => {
console.log("Inside custom intent");
conv.ask('<speak>Hi! <break time="1"/> ' +
' The color you typed is' +
`<say-as >${input}</say-as>.</speak>`);
});
app.intent('actions.intent.MAIN', (conv, input) => {
conv.ask('<speak>Hi! <break time="1"/> ' +
'You are entering into samplejs application by typing ' +
`<say-as >${input}</say-as>.</speak>`);
});
app.intent('actions.intent.CANCEL', (conv) => {
conv.close(`Okay, let's try this again later.`);
});
app.intent('actions.intent.TEXT', (conv, input) => {
if (input === 'bye') {
return conv.close('Goodbye!');
}
conv.ask('<speak>You said, ' +
`<say-as >${input}</say-as>.</speak>`);
});
//exports.app = app;
console.log("global----------->",global);
exports.testApp = functions.https.onRequest(app);
Whenever I call the custom intent "BUY" using any color, instead of calling my custom intent it is calling "intent.Text". How to fix this issue?
While creating cloud function I have select JavaScript option.
For creating a custom intent, is these much updates is need in action.json?
Is there any option for creating custom intent?
How to call this helper content in the js file?
app.intent('ask_for_place', (conv) => {
conv.ask(new Place(options));
});
Custom intents are only triggered as welcome intents for "deep linking". Once the conversation has started, all conversational intents will be reported as TEXT.
So for the intent com.example.sekai.BUY you defined in your actions.json file, and if your Action was named something like "super store", then the following invocation would trigger that intent:
Hey Google, ask super store to find some blue sneakers
but once the conversation had started, asking "find some blue sneakers" would trigger a TEXT intent.
The Actions SDK with actions.json is primarily intended for use by systems that provide the natural language processing and just want to get the text after it has been converted from speech.
If you want more sophisticated natural language processing, where each phrase in the conversation will trigger a user-defined Intent, take a look at Dialogflow.

API Gateway + Lambda download CSV file

I want to do a csv download link with API Gateway + Lambda.
But there is a problem that lambda always return JSON.stringify. Is there a way to resolve this?
s-function.json
"responses": {
"default": {
"statusCode": "200",
"responseParameters": {
"method.response.header.Content-disposition": "'attachment; filename=testing.csv'"
},
"responseTemplates": {
"text/csv": ""
}
}
}
handler.js
var json2csv = require('json2csv');
module.exports.handler = function(event, context, cb) {
var fields = ['car', 'price', 'color'];
var myCars = [
{
"car": "Audi",
"price": 40000,
"color": "blue"
}, {
"car": "BMW",
"price": 35000,
"color": "black"
}, {
"car": "Porsche",
"price": 60000,
"color": "green"
}
];
var csv = json2csv({ data: myCars, fields: fields });
return cb(null, csv);
};
In the downloaded csv file.
"\"car\",\"price\",\"color\"\n\"Audi\",40000,\"blue\"\n\"BMW\",35000,\"black\"\n\"Porsche\",60000,\"green\""
Updated:
I still trying but thank you at least I have direction.
By the way, I can't find API Gateway doc about $input.body.replaceAll. replaceAll is Java function?
Finally, I resolve this by below code in Api Gateway template.
$input.body.replaceAll("\\""","").replaceAll("""","").replaceAll("\\n","
")
s-function escaped double quotes.
"responseTemplates": {
"text/csv": "$input.body.replaceAll(\"\\\\\"\"\",\"\").replaceAll(\"\"\"\",\"\").replaceAll(\"\\\\n\",\"\n\")"
}
return data:
car,price,color
Audi,40000,blue
BMW,35000,black
Porsche,60000,green
The template final replaceAll is weird. CSV don't recognize \n or \r\n, but I try copy new line in IDE and pass to code. It work and it's magical.
Serverless has changed a bit since you asked this question but if you're using the lambda_proxy method of integration, you can use a handler like:
module.exports.handler = (event, context, callback) => {
const csvRows = [
'1,"blah",123',
'2,"qwe",456'
]
const result = csvRows.reduce((prev, curr) => {
return prev + '\n' + curr
})
callback(null, {
headers: {
'Content-Type': 'text/csv',
'Content-disposition': 'attachment; filename=testing.csv'
},
body: result,
statusCode: 200
})
}
Note: I've used ES6 features so you'll want to use Node 6 or higher to directly copy-paste this example.
If you can't fix it on the Lambda function, you could probably do a replaceAll() in the API Gateway mapping template. I think this could work just to replace the escaped double quotes:
$input.body.replaceAll("\\""","")
Edit: So the swagger would be (if I got the escaping right):
"responses": {
"default": {
"statusCode": "200",
"responseParameters": {
"method.response.header.Content-disposition": "'attachment; filename=testing.csv'"
},
"responseTemplates": {
"text/csv": "$input.body.replaceAll(\"\\\"\"\",\"\")"
}
}
}

how do I get all my recent commit messages from github?

I would like to display all of my recent commit messages from github on a website. Is this possible?
To get the public events of a user, you should use the /users/:user/events endpoint (Events performed by a user):
curl https://api.github.com/users/IonicaBizau/events
This will give you back a JSON response like this:
[
{
"type": "IssueCommentEvent",
...
}
{
"id": "3349705833",
"type": "PushEvent",
"actor": {...},
"repo": {...},
"payload": {
"push_id": 868451162,
"size": 13,
"distinct_size": 1,
"ref": "refs/heads/master",
"head": "0ea1...12162",
"before": "548...d4bd",
"commits": [
{
"sha": "539...0892e",
"author": {...},
"message": "Some message",
"distinct": false,
"url": "https://api.github.com/repos/owner/repo/commits/53.....92e"
},
...
]
},
"public": true,
"created_at": "2015-11-17T11:05:04Z",
"org": {...}
},
...
]
Now, you only need to filter the response to include only the PushEvent items.
Since you want to display these events on a website, probably you want to code it in javascript. Here is an example how to do it using gh.js–an isomorphic GitHub API wrapper for JavaScript/Node.js written by me:
// Include gh.js
const GitHub = require("gh.js");
// Create the GitHub instance
var gh = new GitHub();
// Get my public events
gh.get("users/IonicaBizau/events", (err, res) => {
if (err) { return console.error(err); }
// Filter by PushEvent type
var pushEvents = res.filter(c => {
return c.type === "PushEvent";
});
// Show the date and the repo name
console.log(pushEvents.map(c => {
return "Pushed at " + c.created_at + " in " + c.repo.name;
}).join("\n"));
// => Pushed at 2015-11-17T11:05:04Z in jillix/jQuery-json-editor
// => Pushed at 2015-11-16T18:56:05Z in IonicaBizau/html-css-examples
// => Pushed at 2015-11-16T16:36:37Z in jillix/node-cb-buffer
// => Pushed at 2015-11-16T16:35:57Z in jillix/node-cb-buffer
// => Pushed at 2015-11-16T16:34:58Z in jillix/node-cb-buffer
// => Pushed at 2015-11-16T13:39:33Z in IonicaBizau/ghosty
});