I am building a sidebar with the appscript. People who use this sidebar, are already users of my website abc.com. When he opens sidebar, I need to show him some content from my main website accessible only to his account. Lets say his profile in my website should be filled in the sidebar. For that, I need to authenticate that 'CALL TO SERVER' somehow so that I can send his data. In appscript, getActiveUser().getEmail() (or related) returns email, so we can fetch that persons data, but no authentication is done like this as anyone can send his email. Can you tell me the best way for this ?
You can use ContentService to GAS (as REST web-service), which will respond according to the parameter (for example you can send username to server and get reply)
doGet(e){
var user = e.parameter.username;
var reply = getReplyFor(user); //get some reply for concrete user
return ContentService.createTextOutput(reply).setMimeType(ContentService.MimeType.JSON);
}
I hope this helps
sorry for bad english =)
Related
I'm a bit new to Google App Script and I can't find how to do it. I am creating a Google Chat bot using Google App Script and I want to get the profile picture of the user who messaged the bot, preferably the link instead of the image itself since I will be passing the image to a website.
Edit: I do know that Google has an API to get the user photo like this, if I'm an admin - which I'm not - or like this
but I don't know how to use it in App Script or if it's even possible to do so. From what I understand I need to have the user's ID which I have no idea how to get. I have also looked at this question however the links that could be helpful for me doesn't work anymore. If it helps I also know their email address, I just need to get the account ID from there. I don't mind using other APIs that require OAuth to do this. If it helps I also know their email address, I just need to get the account ID from there.
In case anyone would need the answer in the future what I did was add "https://www.googleapis.com/auth/userinfo.profile" to my scopes and added this to my code
var accessToken = ScriptApp.getOAuthToken();
var url = 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' + accessToken + '';
var response = UrlFetchApp.fetch(url);
response = JSON.parse(response.getContentText());
var image = response['picture'];
The image then returns a link to the public profile picture.
Answer:
This information cannot be retrieved with Chat API.
Reference:
Chat API User resource doesn't include any information about the profile picture:
{
"name": string,
"displayName": string,
"domainId": string,
"type": enum (Type),
"isAnonymous": boolean
}
File a feature request:
If you think this feature can be useful, I'd suggest requesting it in Issue Tracker using this template.
I'm building a Google Script Web App that uses the user's Gmail messages
(I'm using the built-in gmail api), when the user chooses a message, I want to show him the message's content, to asure that's the right message.
I'm afraid the mail might contain xss, but I don't want to loose the styling of the message, it's ugly, so I can't write
var output=HtmlService.createHtmlOutput("");
output.appendUntrusted(message.getPlainBody());
my current Code is:
function getMessageContent(message)
{
var output=HtmlService.createHtmlOutput("");
output.append(message.getBody());
return output;
}
does a mail really might include xss?
If the answer is yes, how can I prevent it?
thanks Noam.
Making a web app that makes changes to certain (Sheets) files on my Google Drive (i.e. user will use the app as me), but I would like to restrict the Web app access
only to certain users. When deploying app, I only have the options of making it private or public.
One solution would be to use the session class to see if a correct user is logged in.
function onAppBegin(){
if (Session.getActiveUser().getEmail() != "correctappuser#gmail.com") return null;
accessGranted();
}
However, I am concerned if this crude method is actually safe and is not hackable?
The method is too safe: nobody will have access. If your web app is deployed with the option "Execute the app as: me", then Session.getActiveUser().getEmail() will probably return the empty string. See documentation:
The circumstances in which the email address is available vary: for example, the user's email address is not available in any context that allows a script to run without that user's authorization, like [...] a web app deployed to "execute as me" (that is, authorized by the developer instead of the user). However, these restrictions generally do not apply if the developer and the user belong to the same G Suite domain.
The issue is that even though the user logged in to access the web app, they did not authorize it to do anything on their behalf, e.g., find their email address.
If the web app is deployed to be executed by "User accessing the web app", then they will be asked to authorize it, and so the web app can learn their identity. But then, it will only be able to modify those files that the user already can modify directly.
The way I get around this difficulty is by giving the authorized users a key to the web app (some long random string). They access the app by going to https://..../exec?key=mykey, and the app checks the key as follows:
function doGet(e) {
if (e.parameter.key == "mykey") {
var ss = SpreadsheetApp.openById("spreadsheet Id");
// modify the spreadsheet
}
}
Now, this is even more crude than your original approach, but it works. If a wrong person gets the key, they will be able to use the app but the damage will be limited to what the app can do. It's not nearly as bad as someone getting access to your Google Account.
Combining the two ideas works great.
Checking to make sure it's the right user, and requiring a key.
If not both are correct it displays a no access page, instead of the real page.
function doGet(e) {
if (Session.getActiveUser().getEmail() != "good#email.here") {
var t = HtmlService.createTemplateFromFile("pageNoKey");
return t.evaluate().setTitle("userDelegation No Access");
} else if (e.parameter.key == "SomeKeyHere") {
var t = HtmlService.createTemplateFromFile("page");
return t.evaluate().setTitle("PageTitle");
}
var t = HtmlService.createTemplateFromFile("pageNoKey");
return t.evaluate().setTitle("PageTitle No Access");
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
My code can probably be improved. I'm still learning. (Maybe validate both values in the first if loop?)
Anyway, this is what I'm using to restrict access to users managing Gmail delegation, using my free tool userDelegation. Since it's powered by a service account with domain wide rights, it needs to be locked down hard.
If you want a really flexible solution, check out this video, where the validation is done based on what type of access users have to a specific Google Doc! That was unnecessarily complex for my situation, as I only needed to restrict access to a single person accessing my web app. I will instead create separate versions of the same web app, and give each admin their own.
If you need an easy way to restrict your web app to several people, then that method might be just right for you.
I'm trying to connect to the Facebook Graph API via a Google Apps Script but I'm getting an error
I've tried:
function myFunction (name) {
FB.init({
appId : '{your-app-id}',
status : true,
xfbml : true,
version : 'v2.0'
});
var jsonData = UrlFetchApp.fetch("graph.facebook.com/"; + name);
}
I've also tried:
function myFuntion(name) {
window.fbAsyncInit = function() {
FB.init({
appId : 'your-app-id',
xfbml : true,
version : 'v2.0'
});
};
var jsonData = UrlFetchApp.fetch("graph.facebook.com/"; + name);
}
but neither have worked, I always get a:
"ReferenceError: "FB" is not defined." and a "ReferenceError: "window" is not
defined"
and
"(#4) Application request limit reached","type":"OAuthException","code":4}}
despite putting in my facebook app ID into the variable. I know that "window" is part of an external javascript library so that's why I'm unable to use it in a Google Apps Script, but even after looking at other posts I'm still confused on why I get a "FB" is not defined error.
Any ideas on how to solve this?
There are error codes at the bottom of this page:
Facebook Graph API - Error codes
The "OAuthException" has to do with the Login Status. If you get that error, then you aren't logged in, and to get what you want, you need to be logged in.
You can get an App Access Token using a Server to Server request. There are four types of
Access Tokens:
User - to read, modify or write a specific person's Facebook data on their behalf.
App - modify and read the app settings, and publish Open Graph actions.
Page - read, write or modify the data belonging to a Facebook Page.
Client - the client token is used rarely. Very limited Access to Facebook.
Forms of Access Tokens
User access tokens come in two forms: short-lived tokens and long-lived tokens
short-lived - lifetime of about an hour or two - generated via web login
long-lived - lifetime of about 60 days
You probably don't have an App Access Token. You have an App ID, but that's different than an App Token.
You only get your App Token once. You need to run some code to get it.
Note, that you also must know your App Secret in order to run this code. If you don't know, or have your App Secret, then you need to get that.
See if you can run this code:
//A Facebook App Token never changes unless you go to the Facebook Developers Console,
//and you
//change the App Secret. So, do NOT keep requesting a new App Token. Just get it once,
//then
//hard code it into a backend secret function.
// The App Token can be used to modify your App, but you can just do that 'Manually'
function getOneTimeFB_AppToken() {
Logger.log("getOneTimeFB_AppToken ran");
//keep this info secret
//Generate an App Access Token
var myApp_ID = 'Your App ID';
var myAppSecret = 'Your App Secret';
var optnAppTkn = {"method" : "get"};
var getAppTknURL = "https://graph.facebook.com/oauth/access_token?client_id=" + myApp_ID + "&client_secret=" + myAppSecret + "&grant_type=client_credentials"
var getAppTkn = UrlFetchApp.fetch(getAppTknURL, optnAppTkn);
Logger.log("Object returned from GET: " + getAppTkn)
var myAppTkn = getAppTkn.getContentText();
Logger.log("myAppTkn: " + myAppTkn);
};
Run that code, then in the script editor, choose the VIEW menu, and the LOGS menu item. Read what is in the LOGS. Don't keep running this code over and over again. Just run it once if it's successful.
If that code works, then you just successfully communicated with Facebook.
You need to understand what the Tokens can do, and what your options are. If you are not going to get a token from a user through client side authorization, then you need to understand the App Token.
App Tokens allow you to interact with Facebook on behalf of an app rather than a user. This can be used to read YOUR app insights and modify the parameters of YOUR app.
You never want to use an App Token in client side (browser) code. That would be a major security problem.
However, if a user has granted your application publishing permissions, then you can use the App Token to publish content to Facebook on behalf of that person. So, app access token can be used in place of a user access token to make API calls IF your app has been granted publishing permissions.
But how do you get publishing permissions? Well, there is no way to get the initial short term access token through the server. That just makes sense if you think about it in terms of security. You can't get the initial, short term access token any other way than through a client login. So, if you want to do something that isn't within the bounds of the App Access Token, you can't do it without having the user login through client side.
You can achieve a client side login, without using the JavaScript SDK. So, in the case of an Apps Script Stand Alone HTML web app, you can still use Facebook login without needing to link to the Facebook JavaScript SDK. If you need to do that, let me know.
In that code, FB is an object. The object needs to be assigned "key/value" pairs. Every "key/value" pair is an element (property) in the object. The error is directly related to how objects work. That FB object gets assigned values from a link (inside HTML) to the Facebook API. If you are trying to use an HTML link to the Facebook API from server side (.gs) code, it won't work. There are lots of things that could be going wrong. In order to know exactly what is going wrong, we need to know whether that code is in a gs file, or an HTML file inside a <script> tag.
There are a couple of ways to connect to Facebook:
From HTML (Client Side)
From the server with HTTP Requests
It looks like the code you are using is from an example of how to use the Facebook JavaScript SDK that is meant to run from inside HTML. The problem with that, is that Apps Script sanitizes HTML sent to the browser. So, if you try to link to the Facebook JavaScript SDK through the HTML, you may not get access. I know that, in the past, I have not been able to use a link to the Facebook API in HTML with the NATIVE sandboxed mode. I haven't tried the new IFRAME sandbox mode.
I need to get the user email when I get document permissions. I have seen this problem here
value attribute for Permissions Resource not populated in responses
but in about service does not appear my email. I need it because I have a service account and my application need know the user email. I want to avoid call to profile service.
Is this possible? from where I can get the user email?
Thanks.
As you rightly say, you will have to make a call to the profile service. In some ways it is better like this, because it separates the concerns of the Drive API and the Profile API, and can use specific scoping to let the user know exactly what they are authorizing your app to do.