Run file after chrome.downloads.download - google-chrome-extension

I have a background script in my Chrome Extension which downloads a file called install.bat from the extensions directory. That works perfectly. But when I want to call chrome.downloads.open(id); the following error gets thrown:
Unchecked runtime.lastError while running downloads.open: User gesture required
I have requested both permissions (["downloads", "downloads.open"]) in the manifest.json file which are required for this procedure.
Is there a workaround for this problem or even a plain solution?

So after I read the discussion #abielita mentioned in his comment, I found a solution for my problem. Notifications are now counted as User gesture again.
But being not able to open downloads automatically when the permission downloads.open is requested in the manifest makes this permission just useless.
So here is my solution (with wich I'm not really satisfied with, because the download doesn't open automatically) but it worked for me:
var downloadID = 123;
var nIcon = chrome.extension.getURL("icons/icon_48.png");
var nTitle = "My Extension - Client Installer";
var nMessage = "Please click the button below to run the installer.";
var nButtons = [{ title: "Run the installer..." }];
var nOptions = { type: "basic", iconUrl: nIcon, priority: 2, title: nTitle, message: nMessage, buttons: nButtons };
chrome.notifications.create("hello_world", nOptions, function (nIDa) {
chrome.notifications.onButtonClicked.addListener(function (nIDb, nButtonIndex) {
if (nIDb === nIDa) {
chrome.downloads.open(downloadID);
}
});
});

Related

is there any init entry point in google chrome extension that could set app config

I am developing a google chrome v3 extension, now I read some config from local storage in pulic lib like this(this function may be used in different google chrome extension, different extension with different settings):
pluginLogin: async () => {
let username:string = await LocalStorage.readLocalStorage(WheelGlobal.USER_NAME);
let password:string = await LocalStorage.readLocalStorage(WheelGlobal.PASSWORD);
let deviceId:string = await Device.getDeviceId();
let appId:string = await LocalStorage.readLocalStorage(WheelGlobal.REDDWARF_APP_ID_KEY);
let loginParams = {
phone: username,
password: password,
deviceId: deviceId,
app: Number(appId),
deviceType: 7,
loginType: LoginType.PHONE,
};
AuthHandler.login(loginParams);
}
the function pluginLogin which invoke in the http interceptor when server side return not login response. and the login will trigger in background silently if user input the username and password for once.
what I want to do is store some system config like appId and other settings in the google chrome extension started or triggered for anyway(popup/script....). Is there have a startup point for me to put the setttings in one single places?
Now I can put the system setting in popup trigger or script trigger, but this way I must do the put system settting logic in different places. Is there one places to do this? or any other suggetsion?

Sending the file from bot to user(1:1)

I am new to development in teams and botkit. There is a bot that is up and running on Teams.
I want to share a file generated by the bot to the user(send a file from bot to the user) on teams. I have read the Microsoft-teams document. According to which first step is to send a Message requesting permission to upload which I am able to complete successfully. Below is the code, I have used to show the card to the user to ask for permission.
controller.hears('download', ['message_received', 'direct_message', 'direct_mention'], function (bot, message) {
var reply = { text:"" ,attachments: [] }
var ticketObj = {
"contentType": "application/vnd.microsoft.teams.card.file.consent",
"name": "result.txt",
"content": {
"description": "Text recognized from image",
"sizeInBytes": 4348,
"acceptContext": {
"resultId": "1a1e318d-8496-471b-9612-720ee4b1b592"
},
"declineContext": {
"resultId": "1a1e318d-8496-471b-9612-720ee4b1b592"
}
}
}
reply.attachments.push(ticketObj)
bot.reply(message, reply)
})
According to the Microsoft-teams document, when the user will click on accept button, the bot will receive an Invoke activity with a location URL.
But, when I click on the accept, nothing goes to my bot. It shows the error message: "This card action is not supported".
How to provide support for this card action?
Adding answer from comment section for more visibility:
Issue is resolved now. The issue was of uploading the manifest.json.
To send and receive files in the bot, set the supportsFiles property
in the manifest to true. This property is described in the bots
section of the Manifest reference.
The definition looks like this, "supportsFiles": true. If the bot does
not enable supportsFiles, the features listed in this section do not
work.
https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/bots-filesv4#configure-the-bot-to-support-files
Sample Link:
https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/javascript_nodejs/56.teams-file-upload

How to add Get Started button in the typing bar using bot builder sdk for node.js

I am using bot builder sdk for node.js to create a chatbot. Also connected it to facebook channel. I am using the following code to greet the user:
var bot = new builder.UniversalBot(connector, [
(session, result, next) => {
let text = '';
switch(session.message.address.channelId) {
case 'facebook':
text = 'Hi ' + session.message.user.name + ' !';
break;
default:
text = 'Hi !';
}
session.sendTyping();
session.say(text);
next();
},
(session, say) => {
}
]);
The above code works fine, but I want to add "Get Started" button in the typing bar to invoke the above code. Note that this button appears only once. Please find image of the typing bar below:
Is there a way to achieve this using bot builder sdk for node.js ?
Thanks
Although one can certainly add a button to start any activity with the bot, but that will limit the bots potential to only one customizable channel, i.e. WebChat.
I think there are better 2 alternative ways to get the desired functionality which will work across many channels.
First
I would suggest to add a conversation update event. Code goes in the botbuilder's middleware. Here is a sample code from the docs.
bot.on('conversationUpdate', function (message) {
if (message.membersAdded && message.membersAdded.length > 0) {
// Say hello
var txt = "Send me a Hi";
var reply = new builder.Message()
.address(message.address)
.text(txt);
bot.send(reply);
});
What this will do is make the bot send a message Send me a Hi to the user, if it determines this is a first time visitor. This will give the visitor enough cue to send the bot Hi by typing it. Although he can enter whatever he wants, but this will result in the invocation of the 1st dialog configured which in this case is the will be the dialog which you have posted in question.
Second
You can mark some dialog to be invoked automatically if your bot has never encountered this visitor. Here is the sample code...
var bot = new builder.UniversalBot(connector);
bot.dialog('firstRun', function (session) {
session.userData.firstRun = true;
session.send("Hello...").endDialog();
}).triggerAction({
onFindAction: function (context, callback) {
// Only trigger if we've never seen user before
if (!context.userData.firstRun) {
// Return a score of 1.1 to ensure the first run dialog wins
callback(null, 1.1);
} else {
callback(null, 0.0);
}
}
});
Here we have split the bot creation and dialog registration in 2 steps. And while registering the firstRun dialog, we have provided it the triggerAction that if the visitor is new, then trigger this dialog.
Both of these approaches do not use adding some extra buttons and it is up to the bot either to educate him on sending some message which in turn will start the 1st dialog or directly start some dialog.
For more info on conversationEvent you can refer to this page
I tried the above options, but they didn't seem to be working for facebook messenger. But I found a solution to add the Get Started button into the typing bar of the messenger. For that we need to use the Facebook Graph API and not the bot builder sdk.
https://graph.facebook.com/v2.6/me/messenger_profile?access_token=<PAGE_ACCESS_TOKEN>
{
"get_started":{
"payload":"Get Started"
}
}
The above API call will add the button for you to get the conversation started.
Thanks all for the help!!

How to copy postman history from chrome app to native app?

Since Google is now ending the support for chrome apps. Recently Postman deprecated their chrome app and introduced a native app.
I am in the process of switching from postman chrome app to native app.
How do I copy the history from my chrome app to native app. Sync doesn't work.
There is a option to export data but that doesn't export the history.
Any Ideas?
So while searching for this I came across this post which is very helpful.
Thanks to stephan for sharing this code.
Follow these steps to copy your history from chrome app to native app.
//In Chrome DevTools on the background page of the Postman extension...
//A handy helper method that lets you save data from the console to a file
(function(console){
console.save = function(data, filename){
if(!data) {
console.error('Console.save: No data')
return;
}
if(!filename) filename = 'console.json'
if(typeof data === "object"){
data = JSON.stringify(data, undefined, 4)
}
var blob = new Blob([data], {type: 'text/json'}),
e = document.createEvent('MouseEvents'),
a = document.createElement('a')
a.download = filename
a.href = window.URL.createObjectURL(blob)
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
a.dispatchEvent(e)
}
})(console)
//Common error reporting function
function reportError(){
console.error('Oops, something went wrong :-(');
}
//Open the database
var dbReq = indexedDB.open('postman')
dbReq.onerror = reportError;
dbReq.onsuccess = function(){
var db = dbReq.result;
//Query for all the saved requests
var requestReq = db.transaction(["requests"],"readwrite").objectStore('requests').getAll();
requestReq.onerror = reportError;
requestReq.onsuccess = function(){
var requests = requestReq.result;
//Dump them to a file
console.save(JSON.stringify(requests), 'postman-requests-export.json')
console.info('Your existing requests have been exported to a file and downloaded to your computer. You will need to copy the contents of that file for the next part')
};
};
//Switch to standalone app and open the dev console
//Paste the text from the exported file here (overwriting the empty array)
var data = []
//Enter the guid/id of the workspace to import into. Run the script with this value blank if you need some help
// finding this value. Also, be sure you don't end up with extra quotes if you copy/paste the value
var ws = '';
//Common error reporting function
function reportError(){
console.error('Oops, something went wrong :-(');
}
//Open the database
var dbReq = indexedDB.open('postman-app')
dbReq.onerror = reportError;
dbReq.onsuccess = function(){
var db = dbReq.result;
if(!data.length){
console.error('You did not pass in any exported requests so there is nothing for this script to do. Perhaps you forgot to paste your request data?');
return;
}
if(!ws){
var wsReq = db.transaction(["workspace"],"readwrite").objectStore('workspace').getAll();
wsReq.onerror = reportError;
wsReq.onsuccess = function(){
console.error('You did not specify a workspace. Below is a dump of all your workspaces. Grab the guid (ID field) from the workspace you want these requests to show up under and include it at the top of this script');
console.log(wsReq.result);
}
return;
}
data.forEach(function(a){
a.workspace = ws;
db.transaction(["history"],"readwrite").objectStore('history').add(a);
});
console.log('Requests have been imported. Give it a second to finish up and then restart Postman')
}
//Restart Postman
Note :
1.To Use DevTools on your chrome app you will need to enable following flag in
chrome://flags
2.Then just right click and inspect on your chrome postman app.
3.To User DevTools on your native app ctrl+shift+I (view->showDevTools)

How can I check if I have permission to call chrome.tabs.captureVisibleTab()?

My extensions makes excessive use of chrome.tabs.captureVisibleTab(), however if the user is browsing in pages that I don't have permissions on the call fails with the following error message in the console:
Error during tabs.captureVisibleTab: Cannot access contents of url "chrome://settings/extensions#". Extension manifest must request permission to access this host.
While this doesn't interfere with the normal flow of my extension, I was wondering if these is a way to check for permissions before calling chrome.tabs.captureVisibleTab() to prevent my extension from seeming unprofessional
Did you try handling the error with a try...catch statement? Something like this:
try {
// If any error rises here
chrome.tabs.captureVisibleTab();
} catch(e) {
// Supress the error and go here
}
Just get extension's manifest info and then:
for(var i = 0, permissions = {}; i < chrome.manifest.permissions.length; i++){
// map array to object for later use
permissions[chrome.manifest.permissions[i]] = true;
}
if(permissions.hasOwnProperty('tabs')){
// capture
}
UPDATE:
Recently (dev channel) Chrome devs added new powerfull API - chrome.permissions (docs). So you can check if your extension have particular permission by:
chrome.permissions.contains({
permissions: ['tabs'],
origins: ['http://www.google.com/']
}, function(result) {
if (result) {
// The extension has the permissions.
} else {
// The extension doesn't have the permissions.
}
});

Resources