Logged user: what info to send to the browser? - javascript

Background: Using MEAN stack to build a web app, I am still learning.
The Issue: I find the following confusing. Say I have a user logged in (I am using Passport.js). From Angular I can retrieve it querying my Node.js server.
What I am doing now is something similar to:
app.get('/userLogged',function(req,res){
res.json({req.user});
});
This does not sound safe to me. I might be a novice, but I have seen this in many tutorials. With a console.log in the browser I can print all the info about the user, including the hashed password. My guess is that I should send a minimal set of information to the browser, filtering out the rest.
My Question: is this safe at all, or I am just leaving the door open to hackers?

Take a look at the concept of ViewModel. It represents the data you want to share publicly with an external user of the system.
What can be achieved in your case, is implementing the right view model out of the data model you store internally. A simplistic example illustrating this concept would be to create a view model for your user object that will pick the data you would like to send back :
// This function will return a different version
// of the `user` object having only a `name`
// and an `email` attribute.
var makeViewModel = function (user) {
return _.pick(user, ['name', 'email']);
}
You will then be able to construct the right view model on demand :
app.get('/user',function (req,res){
res.json(makeViewModel(req.user));
});

Related

How can I construct a user from a user json?

I am using the CDN import method for SDK v9. I would like to know, given that I have a JSON-serializable representation of a user object, how can I construct a user object, so that I can use it with methods like updateCurrentUser.
If there was a way that I could access the UserImpl class like you can with npm
import { UserImpl } from '#firebase/auth/internal';
I'd be able to do this. However, I am stuck with the CDN import method, which doesn't allow access to the UserImpl class.
I understand that this may be a strange question, but understand that the way this is set up, once the user logs in, its json representation is saved elsewhere and the user object itself is lost.
I guess a better question would be, how can I deserialize a user?
An important piece of information here is that I want to be able able to deserialize users that once logged in. At some point of the app's lifetime, a user logs in(multiple users might log in and out), the user object is lost, and its json representation is saved elsewhere. I need to be able to retrieve the user object from its json representation later.
A potential workaround that seems to work at first glance, is to save a few informations from the first user that ever logs in:
const userInfo = {}
Object.setPrototypeOf(userInfo.stsTokenManager, auth.currentUser.stsTokenManager.constructor.prototype)
userInfo._clone = auth.currentUser._clone;
userInfo.auth = auth.currentUser.auth;
//and then I apply this to any user json I need to later on
user._clone = userInfo._clone;
user.auth = userInfo.auth;
user.stsTokenManager = userInfo.stsTokenManager;
//if I add the _clone,auth and stsTokenManager,I don't get errors andthe
//user json seems to become a user object for all intents and purposes,
//however I don't know if this is very safe and works in all situations.
//would applying the same clone,auth and tokenManager to all json users
//work?
Unfortunately, using the firebase admin sdk is also not an option because this is a client side app.
Is there any better solution? Thank you for your time.

How to process tracked information in Application Insights

I am using Application Insights to track events in my web pages:
appInsights.trackEvent("my-event", { test: true });
However I can see that each entry in the log, collects some info regarding several other things like:
User Id
Session Id
Operation name
The last one is sensitive as I can get the name of the computer or some other stuff. In order to comply to the GDPR, I wanna strip out those info from my log.
How do I tell Application Insights, to process the data before logging them? In my case, I would like to get access to the object which will be sent out by trackEvent and modify it before it is transmitted.
You can use TelemetryInitializers for that. They allow you to modify items before they are send to Application Insights
In your case it could be as simple as
appInsights.queue.push(function () {
appInsights.context.addTelemetryInitializer(function (envelope) {
envelope.tags['ai.operation.name'] = 'xxx';
});

Firebase >> User Favorites List

I need a little assistance with my app. I'm not asking for a handout, just some guidance as to where to begin. The basic idea is for logged in users to be able to favorite videos, and to have them persist when logged in.
My app uses the YouTube API (Playlist Items) to display videos from my public playlists within my app. I'm using firebase auth to register and login users, but I have yet to implement the RTD. This is where I need some assistance in structuring my data & organizing my app.
I don't want favorite lists created for every user by default, nor do I want to store false values and have to loop through them. I'd only like to set a favorites list if the user requests to do so, and the values are true. I'm open to suggestions regarding structuring my data, but I was thinking something simple like this:
"favorites": {
"John Doe": {
"video1ID": true,
"video2ID": true,
}
}
Videos are contained within cards using a .each function from within the API response. Included in these cards are "favorite" toggle switches that I'd like a user to be able to toggle and add a favorite video to their list.
YouTube provides Video ID's from within their JSON response. I was thinking that assigning a boolean to that video ID would get the job done, but I have no idea where to begin.
Something like:
function writeFavoritesList (name, videoID, toggleValue) {
firebase.database().ref('favorites/' + userId).set({
name: displayName,
videoID: videoID,
toggleValue: true
});
}
I'm very much a newb to anything outside of WordPress, so I hope I'm on the right track. Any help appreciated. Thanks! :)
Looks great. If this were another database, you could consider storing the video IDs in an array, but this being the firebase RealTime Database, you're much better off with objects, which you've already got.
You could modify your structure slightly to take advantage of RTDs push() key generation if you ever intend on sorting your favourite videos. To do so, instead of making the key the videoID and the value the boolean status, you could generate a key using firebase's push() key generation and make the value the videoID. "The unique key generated by push() are ordered by the current time, so the resulting list of items will be chronologically sorted. The keys are also designed to be unguessable (they contain 72 random bits of entropy)."
"favorites": {
"uid1": {
"uniqueKey1": videoID1,
"uniqueKey2": videoID2,
}
}
To generate a push() key, use: const key = firebase.database().ref().push().key.
More info: https://firebase.google.com/docs/reference/js/firebase.database.Reference#push
Saw your Guru post. I think the best way for you to learn is to delve deep into the documentation and figure this out for yourself. If you're truly committed to learning this stuff you'd be doing yourself a disservice to have someone else write the code for you.
I'd start with the GCP(Google Cloud Platform) cloud firestore docs and read through the Concepts section in its entirety:
https://cloud.google.com/firestore/docs/concepts
The firebase site mirrors parts of the GCP documenation, but also covers client implementations:
https://firebase.google.com/docs/firestore/
To get the most out of these docs use the nav sidebar on the left to drill down into all the various Cloud Firestore topics. They go into how to structure your database and provide sample code for you to analyse and play with.
You'll see the terms Documents and Collections thrown around a lot. A Document is somewhat equivalent to a JSON Object. A Collection is a list of documents; similar to an array of JSON objects. But here's where things get interesting; Documents can reference Collections (aka Subcollections):
So I would structure your database as follows:
Create a Users collection
Whenever a new user signs into your app, create a user document and add it to the Users collection.
The first time a user selects a favorite video create a Favorites collection and add it to the user document; then add favorite documents to the Favorites collection for this user
There is a Javascript/Web client (you've seem to already have it loaded from what I've seen in the repo link you provided on Guru). Here's the reference documentation for it:
https://firebase.google.com/docs/reference/js/firebase.firestore
The classes, methods and properties defined in those reference docs are what you'll be calling from within your jquery code blocks.
Good luck and stick with it.

Torii provider name from adapter?

I have a Torii adapter that is posting my e.g. Facebook and Twitter authorization tokens back to my API to establish sessions. In the open() method of my adapter, I'd like to know the name of the provider to write some logic around how to handle the different types of providers. For example:
// app/torii-adapters/application.js
export default Ember.Object.extend({
open(authorization) {
if (this.provider.name === 'facebook-connect') {
var provider = 'facebook';
// Facebook specific logic
var data = { ... };
}
else if (this.provider.name === 'twitter-oauth2') {
var provider = 'twitter';
// Twitter specific logic
var data = { ... };
}
else {
throw new Error(`Unable to handle unknown provider: ${this.provider.name}`);
}
return POST(`/api/auth/${provider}`, data);
}
}
But, of course, this.provider.name is not correct. Is there a way to get the name of the provider used from inside an adapter method? Thanks in advance.
UPDATE: I think there are a couple ways to do it. The first way would be to set the provider name in localStorage (or sessionStorage) before calling open(), and then use that value in the above logic. For example:
localStorage.setItem('providerName', 'facebook-connect');
this.get('session').open('facebook-connect');
// later ...
const providerName = localStorage.getItem('providerName');
if (providerName === 'facebook-connect') {
// ...
}
Another way is to create separate adapters for the different providers. There is code in Torii to look for e.g. app-name/torii-adapters/facebook-connect.js before falling back on app-name/torii-adapters/application.js. I'll put my provider-specific logic in separate files and that will do the trick. However, I have common logic for storing, fetching, and closing the session, so I'm not sure where to put that now.
UPDATE 2: Torii has trouble finding the different adapters under torii-adapters (e.g. facebook-connect.js, twitter-oauth2.js). I was attempting to create a parent class for all my adapters that would contain the common functionality. Back to the drawing board...
UPDATE 3: As #Brou points out, and as I learned talking to the Torii team, fetching and closing the session can be done—regardless of the provider—in a common application adapter (app-name/torii-adapters/application.js) file. If you need provider-specific session-opening logic, you can have multiple additional adapters (e.g. app-name/torii-adapters/facebook-oauth2.js) that may subclass the application adapter (or not).
Regarding the session lifecycle in Torii: https://github.com/Vestorly/torii/issues/219
Regarding the multiple adapters pattern: https://github.com/Vestorly/torii/issues/221
Regarding the new authenticatedRoute() DSL and auto-sesssion-fetching in Torii 0.6.0: https://github.com/Vestorly/torii/issues/222
UPDATE 4: I've written up my findings and solution on my personal web site. It encapsulates some of the ideas from my original post, from #brou, and other sources. Please let me know in the comments if you have any questions. Thank you.
I'm not an expert, but I've studied simple-auth and torii twice in the last weeks. First, I realized that I needed to level up on too many things at the same time, and ended up delaying my login feature. Today, I'm back on this work for a week.
My question is: What is your specific logic about?
I am also implementing provider-agnostic processing AND later common processing.
This is the process I start implementing:
User authentication.
Basically, calling torii default providers to get that OAuth2 token.
User info retrieval.
Getting canonical information from FB/GG/LI APIs, in order to create as few sessions as possible for a single user across different providers. This is thus API-agnotic.
➜ I'd then do: custom sub-providers calling this._super(), then doing this retrieval.
User session fetching or session updates via my API.
Using the previous canonical user info. This should then be the same for any provider.
➜ I'd then do: a single (application.js) torii adapter.
User session persistence against page refresh.
Theoretically, using simple-auth's session implementation is enough.
Maybe the only difference between our works is that I don't need any authorizer for the moment as my back-end is not yet secured (I still run local).
We can keep in touch about our respective progress: this is my week task, so don't hesitate!
I'm working with ember 1.13.
Hope it helped,
Enjoy coding! 8-)

Adding a user to PFRelation using Parse Cloud Code

I am using Parse.com with my iPhone app.
I ran into a problem earlier where I was trying to add the currently logged in user to another user's PFRelation key/column called "friendsRelation" which is basically the friends list.
The only problem, is that you are not allowed to save changes to any other users besides the one that is currently logged in.
I then learned, that there is a workaround you can use, using the "master key" with Parse Cloud Code.
I ended up adding the code here to my Parse Cloud Code: https://stackoverflow.com/a/18651564/3344977
This works great and I can successfully test this and add an NSString to a string column/key in the Parse database.
However, I do not know how to modify the Parse Cloud Code to let me add a user to another user's PFRelation column/key.
I have been trying everything for the past 2 hours with the above Parse Cloud Code I linked to and could not get anything to work, and then I realized that my problem is with the actual cloud code, not with how I'm trying to use it in xcode, because like I said I can get it to successfully add an NSString object for testing purposes.
My problem is that I do not know javascript and don't understand the syntax, so I don't know how to change the Cloud Code which is written in javascript.
I need to edit the Parse Cloud Code that I linked to above, which I will also paste below at the end of this question, so that I can add the currently logged in PFUser object to another user's PFRelation key/column.
The code that I would use to do this in objective-c would be:
[friendsRelation addObject:user];
So I am pretty sure it is the same as just adding an object to an array, but like I said I don't know how to modify the Parse Cloud Code because it's in javascript.
Here is the Parse Cloud Code:
Parse.Cloud.define('editUser', function(request, response) {
var userId = request.params.userId,
newColText = request.params.newColText;
var User = Parse.Object.extend('_User'),
user = new User({ objectId: userId });
user.set('new_col', newColText);
Parse.Cloud.useMasterKey();
user.save().then(function(user) {
response.success(user);
}, function(error) {
response.error(error)
});
});
And then here is how I would use it in xcode using objective-c:
[PFCloud callFunction:#"editUser" withParameters:#{
#"userId": #"someuseridhere",
#"newColText": #"new text!"
}];
Now it just needs to be modified for adding the current PFUser to another user's PFRelation column/key, which I am pretty sure is technically just adding an object to an array.
This should be fairly simple for someone familiar with javascript, so I really appreciate the help.
Thank you.
I would recommend that you rethink your data model, and extract the followings out of the user table. When you plan a data model, especially for a NoSQL database, you should think about your queries first and plan your structure around that. This is especially true for mobile applications, as server connections are costly and often introduces latency issues if your app performs lots of connections.
Storing followings in the user class makes it easy to find who a person is following. But how would you solve the task of finding all users who follow YOU? You would have to check all users if you are in their followings relation. That would not be an efficient query, and it does not scale well.
When planning a social application, you should build for scalabilty. I don't know what kind of social app you are building, but imagine if the app went ballistic and became a rapidly growing success. If you didn't build for scalability, it would quickly fall apart, and you stood the chance of losing everything because the app suddenly became sluggish and therefore unusable (people have almost zero tolerance for waiting on mobile apps).
Forget all previous prioities about consistency and normalization, and design for scalability.
For storing followings and followers, use a separate "table" (Parse class) for each of those two. For each user, store an array of all usernames (or their objectId) they follow. Do the same for followers. This means that when YOU choose to follow someone, TWO tables need to be updated: you add the other user's username to the array of who you follow (in the followings table), and you also add YOUR username to the array of the other user's followers table.
Using this method, getting a list of followers and followings is extremely fast.
Have a look at this example implementation of Twitter for the Cassandra NoSQL database:
https://github.com/twissandra/twissandra

Categories

Resources