Does Google Maps JS API has some command to prevent unauthorized activity in browser version? - google-maps-api-3

I'm working on some app which should use Google Maps JS API (browser version).
And there exists one problem I've got very concerned about.
API keys have restriction to be used only from your domain, however, any request from your domain (for example, from code inspector) is considered a valid request. So, anyone can make a simple script and kick my quota out easily.
So, here is my question:
Is there any option or command to run to block such activity ? Like the script will load just one instance and then will not accept creation of a new one or something like that.
P.S. I know about free quota for mobile versions of API, but I need the browser to work too. Obviously, I don't load this in any public area, but anyone can pretend to be a client and even order some service for couple bucks, but then run the script to make an impact for thousands ((

Related

Firebase Security Problem? Ninja reaction game with Vue.js + Firebase

The problem
I am following a Vue.js 3 tutorial on youtube and I tried to implement the app shown in this video.
Then I started improving it a bit at a time. You can view my project here.
One of the main features I am trying to add is a Hall of Fame component in which you can view the best ten scores of anyone who plays. You can submit your score just after finishing the game. I decided to use Firestore to hold the data.
However, suppose I build the app for production and host it in a server. Then, I can download the whole project on my laptop, change a little bit the logic, and then play it locally on my computer. That way, I can send any type of data to my firestore database (because my credentials are injected in the javascript by Vue). I can then just send the ideal score of 1 ms to hack the game (this is indeed what a friend of mine managed to do).
The question(s)
The question is: how can I prevent this from happening?
Should I make a few changes in the code about the firebase configuration?
Should I use some other way to store the data, and not firestore?
Should I config properly the firestore security rules?
Also, what are the best security practices in JS frameworks like Vue.js (or React, in general) to prevent the insertion of non-wanted data on the client side? How do I manage the connection to a cloud database from such front-end frameworks?
Disclaimer
I learn everything about programming on my own, by watching youtube videos or googling and so on. I am new not only to Vue and Firebase, but to web development in general. Please consider this when answering.
TL;DR;
If the score is calculated on client-side (in browser) you can't secure it.
Anyone can just see the API call being made from the app to the server and replicate that with rest API tool like postman, so you wouldn't even need to download it locally to make changes.
If your game relies on client-side as a source of data, there is no way for the server to ensure that it is un-tampered.
You can try obfuscating the source code and doing client-side data encription, but it's all in javascript so everything is readable.
If you were to implement it in a more secure way, you would have the server trigger an action (as opposed to the script) but then the times would end up being longer because of the data turn-around time. Since the event fired from server to client and back would be reflected, but even then the automated response can be hacked by handling it with a script.

Googlesheets quota limit issues - possible failure to use API key

We are currently using google sheets for a research project on crowd forecasts for Covid-19 case and death numbers.
Google Sheets is used for convenience, but we are often running into quota limit issues - even though the number of users we have should be well below what Google allows.
I attempted to create a somewhat reproducible example by setting up a new google account and creating a sheet from which to read.
The first thing I tried (without making any changes to the google account) is this:
library(googledrive)
library(googlesheets4)
# Google sheets authentification -----------------------------------------------
options(gargle_oauth_cache = ".secrets")
drive_auth(cache = ".secrets", email = "iamatestotest#gmail.com")
gs4_auth(token = drive_token())
sheet_id <- "1Z2O5Mce_haceWfduLenJQP-hddXF9biY_4Ydob_psyQ"
n_tries <- 50
for (i in 1:n_tries) {
data <- read_sheet(ss = sheet_id)
Sys.sleep(0.5)
print(i)
}
From what I understand I should be able to make around 300 read requests per minute, but I'm usually not be able to get the loop to run beyond 30-34.
As I wasn't sure the 300 requests are readily available I went to https://console.cloud.google.com, created a new test project (not sure why that is needed) and explicitly activated the googlesheets API and created some credentials. I created an API key as well as an OAuth 2.0 Client ID (although I am admittedly somewhat lost what this does and how to use it).
I next tried to login with my api key by running
drive_deauth()
drive_auth_configure(api_key = "thisismyapikey")
gs4_auth(token = drive_api_key())
but that also didn't get me beyond 33ish. I also had a look into the google console, but also couldn't see any traffic - so not sure my API key got actually used?
I assume this is due to my inability to actually use the API in the intended way. Any help in setting this up / increasing the quota would be much appreciated. If that helps I'm happy to give access to the test account - simply write me a message.
With some kind help from very friendly people I think I mostly figured this out and it was indeed my failure to use the API correctly.
Why my approach failed
when you use googlesheets4 and any of its function out of the box, you get asked to authorize the tidyverse API OAuth app (you login with your Google credentials and give the OAuth app access rights). This means that you make all requests through the tidyverse OAuth app, as are all other users in the world who use this functionality. This is very nice as it works out of the box, but runs into limitations if other people are using the package at the same time. Sharing this quota with other people meant that I ran into limitations quite unpredictably.
How to change the setup to make it work
There are a couple of things that help to alleviate / solve the problem.
use the devtools version of googlesheets4 (devtools::install_github("tidyverse/googlesheets4"). This dev version of googlesheets4 in turn relies on the dev version of gargle, the package that manages the google authentification. The dev version of gargle has a retry function, that automatically retries your requests if they fail. This should solve the majority of issues.
Get your own OAuth app / google service account.
this allows you to manage the authentification process all on your own. You therefore don't have to share your quota with other users around the world.
To set up your own OAuth app / google service account, you can do the following (I'm focusing on the google service account here, as that is much easier in practice).
Log into https://console.cloud.google.com/. You will be asked to create a project. You can see your projects on the left next to "Google Cloud Platform".
Type "APIs and Services" into the search bar, press "enable APIs and services" and search for sheets. Enable this API.
Go back to the search bar and type in "Credentials"
Press "Create credentials" and select service account. A service account gives you programmatic access to the APIs. Give it a name and a description. You should be able to skip the optional parts. Create the service account and go back to the credentials overview. You may have to refresh the page or wait a minute.
Click on your service account (it looks like a very cryptic email address) and go to the "KEYS" tab.
Click "ADD KEY" and create a new key. As key type, select JSON.
Download that key and store it somewhere secure. This should be treated as a combination of password and username!
Now to actually use your key with googlesheets4, you can run `gs4_auth(path = "path-to-your-service-account.JSON")
In order to be able to access your google sheets, you need to grant your service account permissions. Go to your google sheet, press share (as you would do to share it with any other user) and type in this cryptic service account email (it should look something like "1234#something.iam.gserviceaccount.com". Everything should work now without you having to log in anywhere. If you have previously tried other things, I would suggest to restart your R session.
profit.
You should now also be able to track the API requests in the google console dashboard.
Note that there is still a limit of 60 requests per user per minute, so you're not getting your full 300 requests, but maybe it is possible to create several service accounts and balance the load between these. But not having other people's request interfere with yours is a big improvement!
Google says that it is a security measure. Try to share through adding their emails

Is there a way to disable these additional Cloud Function resources from loading?

Sorry, I'm just getting started with Cloud Functions so excuse me if this doesn't make sense.
I noticed when watching the 'Node.js apps on Firebase Hosting' video that each load was only returning the document in question. However I set up my cloud function and noticed that it is also loading some other resources like a favicon?
My cloud function is making a call to an external api and then returning it to the user. All I need is the json body from the response. Do I need these other resources?
A browser is always going to request favicon.ico. That's how it determines what icon to show for the site in the title. It's harmless. There might be some way to disable that for whatever browser you're using, but I don't think it's worthwhile to worry about it.

HTTP POST from GOOGLE ASSISTANT to PRIVATE SERVER and convert response in voice

I want use Google Assistant from my phone to send HTTP POST command to my server. I have a simple webnms app running over it, this server support REST API and now I want to use Google Assistant to shoot GET or POST command to that server and return my output.
Is it something possible? I am not full time developer.
Yes, as #Prisoner says it is possible. It is not what you asked - but have you seen these ways that Google provides to get skills published without requiring a lot of developer savvy?
https://developers.google.com/actions/content-actions/
https://developers.google.com/actions/templates/first-app
I don't speak for them, but IMO Google's target audience for Action building apart from the above is those who have at least some familiarity with the JavaScript language and its "run-time" Node.
There is also this - which I haven't tried by the way.
https://www.techadvisor.co.uk/how-to/digital-home/easy-actions-google-assistant-3665372/
In case it is not obvious, Google Actions are essentially websites that interact with Google's assistant running on a Home device or a smart phone, say. Think of the Assistant as a browser initiating requests and your Action as serving them. If you can (build and?) deploy a server that handles POSTS over HTTPS on a publicly addressable URL, and if you can understand the JSON payload that the Assistant sends and respond with appropriate JSON to carry out you application then you are good to go.
Where you don't have a public IP address - e.g. in testing - you can use a tool like ngrok ( https://ngrok.com/ ) to reverse proxy requests emanating from the Assistant to your server.
I have slides for a presentation I did targeting fledgling developers who had never built an Action here
https://docs.google.com/presentation/d/1lGxmoMDZLFSievf5phoQVmlp85ofWZ2LDjNnH6wx7UY/edit?usp=sharing
and the code that goes with it here
https://github.com/unclewill/parrot
On the upside the code is about as simple as it gets. On the downside it does almost nothing. In particular, it doesn't try to understand language. As #Prisoner says you'll likely need a tool like Dialog Flow for that.
Yes, it is possible.
Your server will need to implement the Actions on Google API. This is a REST API which will accept JSON containing what the user is intending to do and specific information about what they have said. Your server will need to send back JSON indicating the reply, along with additional information about how to continue the conversation.
You will likely also want to use a tool such as Dialogflow to handle building the conversational script and converting a user's phrases into something that makes sense to you. You'll also need to use the Actions on Google console to manage your Action and provide additional details about how users contact your Action. All of this is explained in the Actions on Google documentation.
Simple Actions are fairly easy to develop, and can certainly be done by a developer as a hobby. Good Actions, however, take a lot more thought and planning. Google offers you to the tools - it is up to you to best take advantage of them.
I've found the solution.
In the "Action" console https://console.actions.google.com/project/sandbox-csuite/scenes/Start
Go to menu "Webhook", click "Change fulfillment method", and then select "HTTPS endpoint"

In my meteor app, how do I make authenticated google API calls on behalf of my user?

Background: This is my first standalone web development project, and my only experience in Meteor is building the Discover Meteor app over the last summer. I come from about a year of CS experience as a side interest in school, and I am most comfortable with C and C++. I have experience in python and java.
Project so far: I'm creating a calendar management system (for fun). Using accounts-google, I have created user accounts that are authenticated through google. I have requested the necessary permissions that I need for my app, including 'identity' and 'calendar read/write access'. I've spent the last week or so trying to get over this next hurdle, which is actually getting data from google.
Goal: I'd like to be able to make an API call to Calendar.list using a GET request. I've already called meteor add http to add the GET request functionality, my issue comes with the actual implementation.
Problem: I have registered my app on the developer console and set up Accounts using the client ID and secret, but I have not been able to find/generate my 'API key' for use in the request. Here is the google guide for creating the access token by using my (already) downloaded private key. I'm having a hard time wrapping my head around an implementation on the server side using JS because I don't have a lot of experience with what is mentioned in the HTTP/REST portion of the implementation examples. I would appreciate some help on how to implement a handshake and receive an access token for use in my app. If there is a call I can make or some package that will handle the token generation for me, that would be even better than implementation help. I believe an answer to this would also benefit this other question
The SO answer that I've been referring to so far: https://stackoverflow.com/a/14543159/4259653 Some of it is in spanish but it's pretty understandable code. He has an API key for his request, which I asked this question to help me with. The accounts-google documentation isn't really enough to explain this all to me.
Also an unrelated small question: What is the easiest way to deal with 'time' parameters in requests. I'm assuming JS has some sort of built-in functionality that I'm just not aware of yet.
Thanks for your research. I have also asked a very similar question, and right now I am looking into the package you recommend. I have considered this meteor-google-api package, but it looks abandoned.
Regarding your question about time manipulation, I recommend MomentJS. There are many packages out there; I am using meteor add mrt:moment
EDIT: MomentJS now has an official package for Meteor, so use meteor add momentjs:moment instead of the mrt command above
Below is a snippet of what moment can do. More documentation here.
var startTimeUTC = moment.utc(event.startTime, "YYYY-MM-DD HH:mm:ss").format();
//Changes above formatting to "2014-09-08T08:02:17-05:00" (ISO 8601)
//which is acceptable time format for Google API
So I started trying to implement all of this myself on the server side, but was wary of a lot of the hard-coding I was doing and assumptions I was making to fill gaps. My security prof. used to say "never implement encryption yourself", so I decided to take another gander for a helpful package. Revising search criteria to "JWT", I found jagi's meteor-google-oauth-jwt on Atmosphere. The readme is comprehensive and provides everything I need. Following the process used in The Google OAuth Guide, an authorization request can be made and a key generated for making an API call.
Link to Atmosphere: https://atmospherejs.com/jagi/google-oauth-jwt
Link to Repo: https://github.com/jagi/meteor-google-oauth-jwt/
I will update this answer with any additional roadblocks I hit in the Google API process and how I solved them:
Recently, I've been running into problems with the API request result. I get an empty calendarlist back from the API call. I suspect this is becuase I make an API call to my developer account rather than to the subject user. I will investigate the problem and either create a new question or update this solution with the fix I find.
Fix: Wasn't including the 'sub' qualifier to the JWT token. Fixed by modifying JWT package token generation code to include delegationEmail: user.services.google.email after scope. I don't know why he used such a long designation for the option instead of sub: as it is in the google API, but I appreciate his package nontheless.
I'm quickly becoming proficient in this, so if people have meteor-related google auth questions, let me know.
DO NOT USE SERVICE ACCOUNTS AS POSTED ABOVE!
The correct approach is to use standard web access + requesting offline access. The documentation on the api page specifically states this:
Typically, an application uses a service account when the application uses Google APIs to work with its own data rather than a user's data.
The only exception to this is when you are using google apps domain accounts and want to delegate access to your service account for the entire domain:
Authorizing a service account to access data on behalf of users in a domain is sometimes referred to as "delegating domain-wide authority"
This makes logical sense as a user must be allowed to "authorise" your application.
Back to the posters original question the flow is simple:
1) Meteor accounts google package already does most of the work for you to get tokens. You can include the scope for offline access required.
2) if you are building your own flow, you will go through the stock standard process and calls as explained on auth
This will require you to:
1) HTTP call to make the original request or you can piggyback off some of the internal meteor calls : Package.oauth.OAuth.showPopup() -- go look at the source there are more nifty functions around there.
2) Then you need to create an Iron router server side route to accept the oauth response which will contain a code parameter that you will use to exchange for tokens.
3) Next use this code to make a final call to exchange the "code" for the token + refresh_token
4) Store these where ever you want - my requirement was to store them not at the user level but multiple per user
5) Use a package like GoogleAPI this wraps up Google API calls and refreshes when required - it only works when tokens are stored in user accounts so you will need to rip it apart a bit if your tokens are stored somewhere else (like in my case)

Resources