Google Search Console API: How do I Solve "User does not have sufficient permission for site"? (When User Has Permissions) - node.js

I'm trying to use Google's Search Console API via their Node package, and my code looks like the following:
const auth = new GoogleAuth({
scopes: 'https://www.googleapis.com/auth/webmasters.readonly',
});
const webmasters = google.webmasters('v3');
const params = {
auth,
siteUrl: 'example.com',
resource: {
startDate: '2015-08-25',
endDate: '2015-08-25',
dimensions: ['query', 'page'],
rowLimit: 10,
},
aggregationType: 'byPage',
};
const res = await webmasters.searchanalytics.query(params);
console.log(res.data);
... except that in my version example.com has been replaced with my actual domain.
I'm invoking it at the command line with:
GOOGLE_APPLICATION_CREDENTIALS="/path/to/service_key.json" node index.js
I have a service account created, and the service key JSON file is from it. That service account has access to my Search Console account. When I look at https://search.google.com/search-console/users I see the service user there, and in the Permission column it has "Full".
Can anyone help me understand why I'm getting the following error when I run my code?
{
message: "User does not have sufficient permission for site 'http://example.com'. See also: https://support.google.com/webmasters/answer/2451999.",
domain: 'global',
reason: 'forbidden'
}
The URL mentioned, https://support.google.com/webmasters/answer/2451999, simply links me to the search console users page ... which (again) says the service user has full permissions.

After rooting in google forums and rest of internet I have figured out why it happen.
Need to copy Service account email, long weird format(example: whiskey-tango-foxtrot#certain-something-0123456.iam.gserviceaccount.com) from Google Cloud: https://console.cloud.google.com/apis/credentials to Search Console https://search.google.com/u/1/search-console/users, as a "Full site" user.
Make sure you have added that site(as from on Search Console) via your API or with this tool: https://developers.google.com/webmaster-tools/v1/sites/add
Then, when you perform "list_sites" request, your site should be listed ere and permission_level is "siteFullUser"(according to step 1)
When you add_site or perform query API requests, make sure to set siteUrl according to steps above, eg: http://www.example.com/ (for a URL-prefix property) or sc-domain:example.com (for a Domain property)
Happy coding

Related

How to transfer ownership of file create with service account using Drive API v3

I'm using the googleapis package in npmjs to create a spreadsheet as follows:
const { google } = require("googleapis")
const sheets = google.sheets("v4")
const drive = google.drive("v3")
async function run() {
// ....
// auth obtained here
// ....
var resp = await sheets.spreadsheets.create({
auth,
resource: {
properties: {
title:"SSTEST2",
}
}
})
var folder = "1XXXXXXXXXXXXXXXXXXXXX" // actual folder id omitted
var ssid = resp.data.spreadsheetId
resp = await drive.files.update({
auth,
addParents:[folder],
removeParents:"root",
fileId:ssid
})
}
I'm using a service account I created, so as a result when the process is complete, the spreadsheet is owned by googlesheetsuser#some-random-words.iam.gserviceaccount.com. This doesn't seem to prevent me from editing the document, however if I delete it, presumably it is still sitting off in limbo somewhere (if I try to access it before moving it to my folder I get a page telling me to request access, which doesn't make any sense because a service account address isn't a real e-mail and so there's no way for this to succeed!) so I'm not sure if it's even going into a trash can for the service account or if it will sit around on Google's servers forever. Not actually owning the document causes issues so I need to get ownership.
On the other hand, I haven't found any documentation that explains exactly what I need to do to transfer ownership to myself. Google's API seem to leave out a lot of information about exactly what to pass; leaving out important info in the sample source with comments like "TODO: Add desired properties to the request body" is beyond unhelpful! I have found a few examples in other languages using other mechanisms I don't recognize which purport to do at least something close to this, but I haven't been able to glean any useful information about how to do it in my particular setup. I have also found a couple of answers which seem to imply that doing this is impossible as you can't change ownership between domains, in which case I just have no words because obviously leaving it owned by my service account creates issues and leaving it owned by the service account indefinitely just isn't an option so some solution is needed.
How can I wind up with my file (Google Spreadsheet) owned by myself at the end of this process?
Update: Per the suggested by #Kessy, I tried to use this code:
const resp = await drive.permissions.update({
auth,
fileId: <fileId>,
permissionId: <id found using list call>,
transferOwnership: true,
requestBody: {
role: "owner",
emailAddress: <my email address>,
type: "user",
}
})
I get this error:
Error: The resource body includes fields which are not directly writable.
I don't know which field it thinks isn't writeable. I tried omitting "type" and get the same error. I tried omitting "role" and it complains that this field is required: Error: The permission role field is required. If I omit "emailAddress" then I don't get the error, but this defeats who whole purpose of the call, which is to transfer ownership to that e-mail address!

Performing search queries in Active Directory with Node.js Application

The web application I'm developing involves accessing the Active Directory in order to perform the necessary authorization and authentication operations. The backend of my application involves nodeJS and it should be using Active Directory NPM package in order to access the Active Directory of my organization. I happen to be totally new to Active Directory and I'm a bit confused with the usage of Active Directory NPM package. I read the usage section of this package and it shows that it (the config object variable) requires the user to input four arguments which are as follows: url, baseDN, username & password. Below is the code in the usage section:
var ActiveDirectory = require('activedirectory');
var config = { url: 'ldap://dc.domain.com',
baseDN: 'dc=domain,dc=com',
username: 'username#domain.com',
password: 'password' }
var ad = new ActiveDirectory(config);
Out of these 4 parameters that are there in the config object, I'm not able to understand the role of the baseDN parameter and how do we have to use it when performing search queries in Active Directory. ( I have highlighted this parameter in the above image. )
It would be really great if someone could explain the usage of this particular parameter and how do we have to use it, when performing search queries in Active Directory.
Also, I was wondering if someone could refer me to a source or a tutorial that offers a clear explanation regarding the performing search queries in Active Directory with Nodejs Application. Any help would be highly appreciated. Thanks!
The concept of the base DN is not specific to just Node.js. It's the same for all LDAP queries, regardless of where you do it from.
DN stands for Distinguished Name, which is an identifier for each object in the directory. The base DN (or sometimes called "search root") defines the scope of your search. In most cases, the baseDN will be the root of your domain, like DC=example,DC=com (if your domain name is example.com). However, you can set it to a specific OU if you only want results from that OU: OU=Users,DC=example,DC=com.
In short: the search will only return results where the DN ends with the baseDN you specified.
For documentation on how performing queries in AD in Node.js, you have to refer to the packages that are created for that purpose, like the activedirectory package you found. However, that package is no longer maintained (hasn't been touched in 4 years). The activedirectory2 was forked from that and is actively maintained. You are better off using that.
We can search user using fineUser method in activeDirectory in the following way after user Authentication
var options = {
url: domaincontroller,
tlsOptions: {
ca: [fs.readFileSync(caCertRoot), fs.readFileSync(caCertIntermediate)],
rejectUnauthorized: true,
},
baseDN: "DC=domain,DC=com",
bindDN: `${req.body.username}#domain.com`,
bindCredentials: `${req.body.password}`,
filter: "(objectClass=*)",
attributes: { user: ["givenName", "c", "co"], group: ["com"] },
};
/* Search Functionality */
const ad = new ActiveDirectory(Object.assign(config, options));
ad.findUser(req.body.username, function (err, user) {
if (err) {
res.writeHeader(401, { "Content-Type": "text/html" });
res.write(
`<h3>Username or Password is not valid, please try again!</h3>`
);
res.send();
return;
} else {
res.send({ msg: "user logged successfully", ...user });
}
});

Can we use firebase crashlytics for our web application?

I have a web application and I want to track its crashing reports.
Can I use Firebase crashlytics or Fabric for this purpose. In their site its mentioned its only for Android or ios.
Regards,
Makrand
There is feature request: https://github.com/firebase/firebase-js-sdk/issues/710
Looks like it's not supported at all, fabric didn't supported crashlytics on web either so it looks like there are maybe some alternatives like https://www.bugsnag.com but I would like to have it too in one place. Don't see difference between web, android or iOS clients at all, don't know why this is not supported.
But for some possible solution for Vue framework is to catch errors and send it to google analytics where you can connect also your firebase mobile apps. I think to try it this way for now. I didnt tested it yet so don't know if I have to catch window errors too.
Vue.config.errorHandler = function (error) {
//Toast.error(error.message)
console.warn(error.message)
//send error as event to google analytcs...
if (error) message = error.stack;
ga('send', 'event', 'Vue.config.errorHandler', message, navigator.userAgent);
}
window.onerror = function(message, source, lineno, colno, error) {
// maybe we need to also catch errors here and send to GA
}
But I found something like this too for typescript https://github.com/enkot/catch-decorator
While there is still no firebase crashlytics for web, google offers Stackdriver with error reporting functionality - it keeps track of all errors with ability to mark them as resolved (it can also send email notifications about new errors):
You can access it using the below url (make sure to put your firebase {project_id} in the link before clicking it):
https://console.cloud.google.com/errors?project={project_id}
There are two ways on how to use it:
Easy way, limited flexibility.
Every console.error(new Error(...)) reported from your firebase function is automatically tracked in the Stackdriver error logging platform.
So you just need to send an error report from your web app to your firebase function and log it using console.error inside that function.
Note, only an instances of Error object will be sent to the Stackdriver platform. For example console.error("{field1: 'text'}") won't be sent to Stackdriver. More info on that in this doc
More comprehensive way that provides an additional control (you can also report userId, your custom platform name, it's version, user agent, etc):
Here is a quick snippet on how it can be used (in our case we first send the error log from web app to our server and then report the error to Stackdriver):
in firebase nodejs:
const {ErrorReporting} = require('#google-cloud/error-reporting');
let serviceAccount = {...} //service account is your firebase credetials that holds your secret keys etc. See below for more details.
let config = {
projectId: serviceAccount.project_id,
reportMode: "always",
credentials: serviceAccount
}
let errors = new ErrorReporting(config);
Report error to Stackdriver from nodejs:
async function reportError(message){
//message is a string that contains the error name with an optional
//stacktrace as a string representing each stack frame separated using "\n".
//For example:
//message = "Error: Oh-hoh\n at MyClass.myMethod (filename.js:12:23)\n etc.etc."
const errorEvent = this.errors.event()
.setMessage(message)
.setUser(userId)
.setServiceContext("web-app", "1.0.0")
await errors.report(errorEvent)
}
More info about the Stackdriver library is available in this doc. And more info about the stacktrace and it's format can be found in the docs here
A few notes on setting it up:
You need to enable two things:
Enable Stackdrive api for your project using the link below (make sure to set your firebase {project_id} in the url below before clicking it)
https://console.developers.google.com/apis/library/clouderrorreporting.googleapis.com?project={project_id}
Make sure to also grant "Error writer" permission to the firebase service account so Stackdriver can receive the error logs (service account is a sort of representation of a "user" for your firebase project who accesses the services)
To grant the premission, follow the below steps:
first locate the "Firebase service account" using your firebase dashboard link (you can find it below) and remember it's value - it looks something like firebase-adminsdk-{random_symbols}#{project_id}.iam.gserviceaccount.com
Then open gcloud console under "Access"->"IAM". Or use the following link:
https://console.cloud.google.com/access/iam?project={project_id} <- put your firebase project id here
Locate your Firebase service account from the step 1.
Press edit for that account and add "Errors writer" permission:
Where to find the serviceAccount.json:
Regarding the serviceAccount - this is a universal credentials that can be used to authenticate many google services including the Stackdriver. You can obtain yours from your firebase dashboard using the url below (just put your firebase project_id in the link before using it):
https://console.firebase.google.com/u/0/project/{project_id}/settings/serviceaccounts/adminsdk
Open it and click "generate new credentials". This will generate a new service account and download the serviceAccount.json that you need to keep safe (you won't be able to get it again unless you generate a new one).
Apparently Sentry now supports several web frameworks out of the box.
I have recently integrated Sentry crashlytics for Django App.
see here:
https://sentry.io/platforms/

Facebook graph API - i recieve the error "Missing authorization code"?

i am new to the facebook api and i came across a weird issue and i cannot really find a solution for it. i am trying to get an access token using the following instructions :
but when i try to do :
curl -X GET "https://graph.facebook.com/oauth/access_token?client_id=[ID]&client_secret=[SECRET]&redirect_uri=http://localhost&grant-type=clients_credentials"
it fails even when i do it in my code , it also fails:
var firstOptions = {
method: 'GET',
url: 'https://graph.facebook.com/oauth/access_token?client_id=[ID]&client_secret=[SECRET]&grant-type=client_credentials&redirect_uri=http://localhost',
json: true,
};
request(firstOptions, function (error, response, body) {
console.log(body);
});
so i was wondering if someone could tell me where and how i get the authorization code ? or if i am doing something wrong. because the facebook image isn't including any authorization code..
EDIT:
after a suggestion i tried the following :
var pageOptions={
method: 'GET',
url: 'https://graph.facebook.com/[PAGE-ID]/posts?access_token=' + 'ID|SECRET',
json:true
};
but then i got the follow error:
{ message: '(#10) To use \'Page Public Content Access\', your use of this endpoint must be reviewed and approved by Facebook. To submit this \'Page Public Content Access\' feature for review please read our documentation on reviewable features: https://developers.facebook.com/docs/apps/review.',
this error does not occure when i use an access_token generated by the Access Token Debugger:
https://developers.facebook.com/tools/debug/accesstoken/
{ message: '(#10) To use \'Page Public Content Access\', your use of this endpoint must be reviewed and approved by Facebook. To submit this \'Page Public Content Access\' feature for review please read our documentation on reviewable features: https://developers.facebook.com/docs/apps/review.',
this error does not occure when i use an access_token generated by the Access Token Debugger
You are simply using the wrong kind of access token here.
To access content of just any arbitrary public page, your app would need to be reviewed by Facebook first.
It works with the token you generated in the debug tool, because that is a user token and you have an admin role on the page in question - which means this is not general access to just “public” data any more, but to content you actually have admin access to. With an app access token, the API has no way of checking for that.
You need to use a page admin user token, or a page token for this kind of request.

drive.changes.watch don't sends notifications

I'm using googleapis npm package ("apis/drive/v3.js") for Google Drive service. On backend I'm using NodeJS and ngrok for local testing. My problem is that I can't get notifications.
The following code:
drive.changes.watch({
pageToken: startPageToken,
resource: {
id: uuid.v1(),
type: 'web_hook',
address: 'https://7def94f6.ngrok.io/notifications'
}
}, function(err, result) {
console.log(result)
});
returns some like:
{
kind: 'api#channel',
id: '8c9d74f0-fe7b-11e5-a764-fd0d7465593e',
resourceId: '9amJTbMCYabCkFvn8ssPrtzWvAM',
resourceUri: 'https://www.googleapis.com/drive/v3/changes?includeRemoved=true&pageSize=100&pageToken=6051&restrictToMyDrive=false&spaces=drive&alt=json',
expiration: '1460227829000'
}
When I try to change any files in Google Drive, the notifications do not comes. Dear colleges, what is wrong?
This should be a comment but i do not have enough (50points) experience to post one. Sorry if this is not a real answer but might help.
I learned this today. I'm doing practically the same thing like you - only not with Drive but Gmail api.
I see you have this error:
"push.webhookUrlUnauthorized", "message": "Unauthorized WebHook etc..."
I think this is because one of the 2 reasons:
you didn't give the Drive-api publisher permissions to your topic.
Second if you want to receive notifications, the authorized webHooks Url must be set both on the server( your project) and in your pub/sub service(Google Cloud).
See below - for me this setup works:
1. Create a topic
2. Give the Drive publish permissions to your topic. This is done by adding the Drive scope in the box and following steps 2 and 3.
3. Configure authorized WebHooks. Form the Create Topic page - click on add subscriptions. Not rely vizible here but once you are there you can manage.

Resources