Ways to using Google storage buckets on frontend by token without user creation - google-cloud-storage

I have a client - server application that stores files on the server, however I would like to integrate google cloud.
I must say right away that the user can log in by email, as well as by phone (in this case, he will not have an email).
My main task is to make the frontend for each specific user be able to upload files directly to Google cloud storage (without the right to delete them)
My main idea is to give a specific user the right to add new files to a specific scope. At first, I thought that I would create a service account with administrator rights on the backend and give access to a specific basket folder to a specific user using my backend. However, as far as I understand, it is better to create a separate bucket for each user and give the user the right to create new files.
The main problem is how do I give the frontend a token that will contain the right to add only to this bucket.
Initially, I hoped that I could create some kind of token without creating a user entity on the Google Cloud side.
But after a little googling, I realized that I need to use IAM.
IAM offers several options for user identification:
Google Account email: user#gmail.com - But as I wrote earlier, I may not have an email, but just a phone number
Google Group: admins#googlegroups.com - Not my option
Service account: server#example.gserviceaccount.com - But as far as I understand, service accounts are not allowed on the frontend.
Google Workspace domain: example.com - Not my option
Perhaps there are some other options. Ideally, I would like a permanent token, for a specific bucket without creating a user on the Google storage side, since I already have a user in my own database.

I found a solution, the only one that is suitable for a similar task. These are Signed URLs.
The logic is next: The client asks server for a link to upload a file, the server creates a signed link that is available for a certain time, and the client makes a put request by upload the desired file on GCS.
Here is an example in all languages how to create such a link
Here is a simple example of how to upload a file to google cloud storage on the frontend using such a link:
<div>
<label htmlFor="inventoryPicture">Choose file to upload</label>
<input type="file" name="someFile" accept=".jpg" id="photo"/>
</div>
<script>
document.getElementById('photo').addEventListener('change', async (event) => {
const file = event.target.files[0];
//your signed url:
const url = 'https://storage.googleapis.com/your-bucket/123.jpeg?X-Goog-Algorithm=...';
try {
const response = await fetch(url, {
method: 'PUT',
body: file,
});
} catch (error) {
console.error('Error:', error);
}
});
</script>

Related

How to setup firebase trigger-mail and cloud functions

I faced a lot of trouble setting up trigger mail extensions along with cloud functions. Here I explain step-by-step how to get things done!
Lets get working.
Set up Firebase
Create a project if you haven't already here.
To use trigger-mail extension and cloud functions, you need to
upgrade the project to BLAZE Plan.
Go on and do that now (check bottom left side of window).
Go on and set-up firestore database and storage. This is
necessary for both extension and functions to work.
Configuring Extensions
Click on Extensions panel under Build.
Find Trigger Mail extension and click on install.
Here's the main part:
Click on next 2 times.
Grant all necessary permissions.
This is where you'll link your mail account from which you'll be sending mail
You'll be greeted with such a screen ->
URI
If the mail I'm linking is xyz123#gmail.com, this will be your SMTPS format:
smtps://xyz123#gmail.com#smtp.gmail.com:465
Use this in the SMTPS connection URI field.
Password
This is a little hectic step.
Enable 2 factor Authorization in your Gmail here.
Now you would need to create an App Password
Click on Generate.
You'll see such a screen ->
You have to enter this password in the SMTP password field and click Create secret.
NOTE: Do not enter spaces.
Wait for sometime for the process to finish.
After it's done, Your screen will look like this ->
You could keep the same Gmail for Default Reply-To address as the original mail, or one of your choice.
Let Email documents collection be the same.
Click on Install Extension.
This will take few minutes.*
Voila, you're done!
Let's send a test mail.
Now in-order to send a mail, you need to add a document to mail collection in your firestore db.
Find official documentation here.
to: ['someone#example.com'],
message: {
subject: 'Hello from Firebase!',
text: 'This is the plaintext section of the email body.',
html: 'This is the <code>HTML</code> section of the email body.',
}
This is the format of document to send mail.
"to" is an array and "message" is a map .
Let's create a collection manually ->
Here's my document window
Let's save this document.
If done correctly, within few seconds, you'll see the document automatically update with more fields like attempts etc.
Check your mail for the email.
Writing a function.
Lets set up Firebase CLI
Download Node.js here.
Run the installer.
Copy the installed path in your drive.
I have mine installed under C:\Program Files\nodejs.
Search environment variables in your system tray.
Paste the directory under System Variables -> Path, create new and add.
Download and install Firebase CLI by following the steps here..
login to firebase cli using the above doc.
Open your project in code editor, and type firebase init in terminal.
Select project and add functions support. It'll create a new folder functions.
I've written a function that sends a onboarding email when a new user is created.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
// sends mail if new user is regestired
exports.userOnboardingMail = functions.auth.user().onCreate((user)=>{
admin.firestore().collection("mail").add({
"to": [user.email],
"message": {
"subject": "Welcome to My app! Explore functionalities here.",
"text": `Hi, ${user.displayName}. \n\nIt's nice to have you on-board.`,
},
})
.then((result) => {
console.log(
"onboarding email result: ", result,
"\ntime-stamp: ", Date.now);
});
});
Hope I was able to make your day a bit easier :)
Upvote if it helped..
Additional Links
Learn firebase cloud functions here. really recommend this channel.
Official Trigger-mail docs.
Firebase CLI docs.
Firebase Cloud Functions docs

Google Cloud Storage getting download link

I'm working in an Asp.Net Core 2 web api for files hosted at Google Cloud Storage. The files hosted there are not public, so I can't use the MediaLink property of the object. I tried to make a download endpoint using MemoryStream but when there are many users downloading large files at once I run into memory issues.
My question is: is there a way to create something link a one-time download link for a file or something similar?
I'm also trying to implement what's described in this link but I'd need to give the bearer token to the user. I can't do that.
Any tips?
Yes. Google Cloud Storage offers a feature called "signed URLs" that is what you described: a URL that is only good for a short while to download a single file. The idea is that you craft a download URL, then use the private key of a service account to "sign" the URL. Anyone holding that final URL can use it to act as that service account for the purpose of downloading that one object.
Take a look: https://cloud.google.com/storage/docs/access-control/#Signed-URLs
Writing code to generate the signed URL is a bit tricky, but the client libraries provide helper methods in several languages to do it for you. You can also generate one with the gsutil command: gsutil signurl -d 10m privatekey.p12 gs://bucket/foo
There is a code sample for generating he signed URLs programatically on their GitHub project: Signed URLs
I managed to Create it using C#. I'm posting here because this will be useful to someone else:
1 - Create your private key
2 - Create and UrlSigner:
private readonly UrlSigner _urlSigner;
2 - In your class constructor:
using (var stream = File.OpenRead(_googleSettings.StorageAuthJson))
{
_urlSigner = UrlSigner.FromServiceAccountData(stream);
}
_googleSettings.StorageAuthJson has the physical path of the json file you downloaded when creating your key.
3 - Method to get the URL:
public string GetSignedUrl(string bucketName, string objectName, TimeSpan duration) {
var url = _urlSigner.Sign(bucketName, objectName, duration, null);
return url;
}

Facebook pixel events call from server

I have absolutelly the same question as dan here - Facebook conversion pixel with "server to server" option . There was written, that there was no way, but it was 2013, so I hope something changed.
So, is there any way to call facebook pixel events (e.g. CompleteRegistration) from server side now?
I can describe situation in more details. Imagine, that user visits our site, where fb pixel tracks 'PageView' of course. When user passes form and sends his phone number, we call 'Lead' event. But then we need to track one more event, when our manager successfully confirmes this user! Of course, it happens on other computer and so on, so there is no idea, how to "connect" to base user.
I've seen a lot of documentation departments like this, but I can't fully understand even if it's possible or not.
Logically, we need to generate specific id for user (or it can be phone number really), when 'Lead' event is called. Then, we should use this id to 'CompleteRegistration' for that user. But I can't understand, how to do it technically.
It would be gratefull, if somebody could explain it.
P.S. As I understand, it is fully available in API for mobile apps. Is it ok idea to use it for our situation, if there is no other solution?
Use Offline Conversions to record events that happen after a user has left your website. Logging these conversions, technically, is very easy. Setting everything up takes a little effort
tldr; check the code below
Follow setup steps in the FB docs (Setup steps 1-5) which are:
Setup facebook Business Manager account
Add a new app to Business Manager account
Create an Ad account, if you don't already have one
Create a System User for the ad account
After the setup, follow Upload Event Data steps on the same page, steps 1-3 to create an offline event set and associate it with your ad. These can be carried out in the Graph API Explorer by following the links in the examples. These can be done programmatically, but is out of the scope of making the event calls from the server for one campaign.
Once you have created the event set, then you can upload your CompleteRegistration events!
You will need to make a multipart form data request to FB, the data key will be an array of your conversion events. As #Cbroe mentioned, you must hash your match keys (the data you have available about your user to match them with a FB user) before sending to FB. The more match keys you are able to provide, the better chance at matching your user. So if you can get their email and phone at the same time, you're much more likely to match your user.
Here's an example of the call to FB using node.js:
var request = require('request')
// The access token you generated for your system user
var access_token = 'your_access_token'
// The ID of the conversion set you created
var conversionId = 'your_conversion_set_id'
var options = {
url: 'https://graph.facebook.com/v2.12/' + conversionId + '/events',
formData: {
access_token: access_token,
upload_tag: 'registrations', //optional
data: [{
match_keys: {
"phone": ["<HASH>", "<HASH>"]
},
currency: "USD",
event_name: "CompleteRegistration",
event_time: 1456870902,
custom_data: { // optional
event_source: "manager approved"
},
}]
}
}
request(options, function(err, result) {
// error handle and check for success
})
Offline Conversion Docs
Facebook has now a Server-Side API: https://developers.facebook.com/docs/marketing-api/server-side-api/get-started
Implementing this is similar to implementing the offline events outlined in the accepted answer.
Keep in mind that it will always be cumbersome to track and connect events from the browser and from your server. You need to share a unique user id between the browser and server, so that Facebook (or any other analytics provider) will know that the event belongs to the same user.
Tools like mixpanel.com and amplitude.com may be more tailored to your needs, but will get very expensive once you move out of the free tier (100+ EUR at mixpanel, 1000+ EUR at Amplitude, monthly). Those tools are tailored towards company success, whereas Facebook is tailored towards selling and measuring Facebook ads.

Parse Signup Problems

So, I wanted to create a new social media app using Swift and Parse. When I go to the Parse site, and click on dashboard, it gives me a login screen. I don't have an account, so I click on the "I don't have a parse account" button. When I click on that, it just takes me back to the home page. I did manage to get the code and frameworks and stuff that I needed from the docs, but that didn't quite work. It gave me this for the initialize code:
let configuration = ParseClientConfiguration {
$0.applicationId = "YOUR_APP_ID"
$0.server = "http://YOUR_PARSE_SERVER:1337/parse"
}
In the tutorial I'm watching, rather than "YOUR_APP_ID" and "http://YOUR_PARSE_SERVER:1337/parse" it just had a bunch of letters and numbers, which I would assume are the app ID and Parse server. My guess is, that I need an account to get those. Would that be correct? And, does anyone know why I can't seem to get an account? Thanks.
Parse.com is shutting down, so that's why you are not allowed to create new accounts on the service. Check the blog post.
They open sourced a nodeJS implementation, which you should definitely check out at link, and here is an example to get you started. You can easily use the deploy buttons to host the server on services like Heroku, AWS, Azure, etc. You can also deploy a server locally, for testing purposes.
Although it's true that Parse is discontinuing early next year, you can still setup a new app if you want to use the service for a shorter term project. Replace your code with the following.
Parse.setApplicationId("YOUR-APP-ID", clientKey: "YOUR-CLIENT-ID")
You can find your App ID and Client ID in your app's settings > security & keys.
EDIT: You definitely need an account for this to work.

How to use new enhanced sessions in Parse with users created on cloud code?

I was trying out the new enhanced revocable sessions in Parse on my Android app. It works well when logging in or signing up via email password or facebook but doesn't work well for custom authentication, e.g. google+.
I'm currently logging in the user using the cloud code which also creates the new user when signing up. This does not create a new Session object, that means the new enhanced sessions are not used and it still uses the legacy sessions.
I pass the session token back to client where using the become method the user logs in but it's the legacy sessions.
This feels like the feature is not complete but I would really like to move to the new enhanced sessions with my app. Has anyone worked with them yet? Are there any workarounds using the REST API or by creating the sessions manually and handling them manually? I looked into the JS API but it says it's only read only.
Here's the Blog post on Enhanced Sessions.
Where should I go next?
Yes, I found a solution but it's a workaround, works for my case because I don't support signing up with user/password.
Basically, the solution (cloud code) in semi pseudo-code is:
Fetch the user with master key
Check if user.getSessionToken() has value
if it has, return the session token and do a user.become() in the client as usual
if it's not, here the workaround, do the following:
yourPreviousPromiseInOrderToChainThem.then(function(user)
password = new Buffer(24);
_.times(24, function(i) {
password.set(i, _.random(0, 255));
});
password = password.toString('base64')
user.setPassword(password);
return user.save();
}).then(function(user) {
return Parse.User.logIn(user.get('username'), password)
}).then(function(user) {
var sessionToken = user.getSessionToken();
// Return the session token to the client as you've been doing with legacy sessions
})
That means, I'm changing the user password each time in order to make a remote login and, of course, I know thist can't be applied to all cases, it's enough for app because I don't support login with user/password (only third party logins) but I understand that maybe it's not for all cases.
I got the idea from this official Parse example.
I don't like this solution because I think is not a workaround, it's a mega hack but I think there is no other way to do it currently (either Parse.com or Parse-Server)
If you find other workaround, please, share it :)