passportJS: using a user id field named other than id - mysql

I found this great node mysql boilerplate:
https://github.com/ocastillo/nodejs-mysql-boilerplate
it works terrific! However, now I need to hook it in to my existing user table, and my key field is named userID, not simply id, and changing the key fieldname in mysql breaks the example. So my question is, where in the project do I need to specify a different id field name? I see user.id in /util/auth.js passport.serializeUser and id in passport.deserializeUser functions, but it seems it must be specified elsewhere too. I'm hoping this is a simple question for users of passportjs!

Yes, you should only need to change the code in the serializeUser and deserializeUser functions. Those two functions you control, and state within them what you'd like to serialize into the session cookie (when the user logs in), and deserialize from the session cookie (when the user revisits the site after logging in). Think of them as ways to remember who this person is, once they return. The passport.use function is only used to define the authentication strategy, and within that, the manner in which you'll "log the user in".
So this should work (assuming I've followed what you've said above):
passport.serializeUser(function(user, done) {
done(null, user.userID);
});
passport.deserializeUser(function(user_id, done) {
new data.ApiUser({userID: user_id}).fetch().then(function(user) {
return done(null, user);
}, function(error) {
return done(error);
});
});
You might benefit from more examples, here's a gist I put together on passport configuration within Node (however this one uses Mongo): https://gist.github.com/dylants/8030433

Related

Node js - how can i do error handling when using mysql2?

i want to handle the probable errors of mysql db. in my case, i have users table that has 7 columns. column email and username values should be unique and i set that for them. but in my sign up form, when users enter and submit their account infos, their entered username and email can be in the database. so in this case, mysql throws an error. for example in my database there is a row with test#test.com email and saman138 username. if a user enters test#test.com for email and saman138 for username, mysql throws an error like this:
Duplicate entry 'saman138' for key 'users.username_UNIQUE'
But the main problem is that i cant display the right error to user. I actually dont know how to do that in the best with the highest performance. For example how can i recognize that the users entered password is duplicated in the database and display the right error to user? I can send two extra queries to get the row that has the entered email or password and then send an error with this message:
your entered username and email already exists in database. Please
enter an other email and username.
this is my codes to insert users infos in to the users table:
import bcrypt from "bcrypt";
import { SignUpInfos } from "../interfaces/Interfaces";
import { mysql } from "../utils/DB";
const signUpUser = async (datas: SignUpInfos) => {
const hashedPassword = await bcrypt.hash(datas["user-password"], 10);
const results = await new Promise((resolve, reject) => {
mysql.query(
"INSERT INTO users ( fullname, email, username, password ) VALUES ( ?, ?, ?, ? )",
[
datas["user-fullname"],
datas["user-email"],
datas["user-username"],
hashedPassword,
],
(err, result) => {
if (err) reject(err);
else resolve(result);
}
);
});
return results;
};
export { signUpUser };
so what is the best way to return the right error message if there was an error? is there any best way to do that or i should send to extra queries? thanks for help :)
As according to the MVC pattern, input validation is typically done before the request gets to the database (in your javascript code), not relying on database errors to inform you that something is wrong.
For example:
First you might check that a username is a valid username through business rules in the javascript; checking that the username doesnt have spaces or something.
Then you might search the database to see if there are any users with a given name, return the number and then use that to tell the user that a name is already taken. Only once this search returns that there are no other similar usernames in the database should you actually let them submit the new account.
But, that is not to say you should abandon the database rules altogether because they are important to ensuring someone doesnt do something dodgy like mess with your database (as an extreme) by bypassing the javascript code somehow and adding duplicate accounts -- that would be tragic.
Where does input validation belong in an MVC application?
"with the highest performance" -- "premature optimization". The login process, even when accounting for error cases, takes only milliseconds. There is no need to optimize this.
Also, since the usual case is "no errors" it is best to assume there will be no errors, then let some lower-level process (such as the databse INSERT) catch the error. If, instead, you checked for errors first, you would usually be wasting your time.
Anyway, the test and the insert must be done atomically, or else someone else can sneak in between your test and your insert and, say, grab the user_name. That is, the two must be combined into an "atomic" action. And the db, with UNIQUE constraints, does that nicely for you.

Typeorm - Cannot update entity because entity id is not set in the entity

I'm trying to save (insert) a new record in my DB but all i get is the error: Cannot update entity because entity id is not set in the entity.
What I'm currently doing:
return this.connection.transaction(entityManager => {
return entityManager.save(MyEntity, {/* payload without id */});
});
This is the only place in my codebase where this issue happen (transaction or not)
TypeORM tracks entities with meta-data and most likely the id is still in the meta-data or has gotten in the meta-data. To fix this pass it through the create function.
return this.connection.transaction(entityManager => {
// make sue payload is at this point already without id field else your problem will remain
const entity = entityManager.create(payload)
return entityManager.save(MyEntity, entity);
});
Most likely you are using a fetched entity as template, deleted the id, plus maybe some other settings and tried saving again.
Even though this might not be the exact way you got this error. This I see most commonly happen when this error occurs.

How can I check if a user already exists before calling smooch.appUsers.get?

I'm developing a service using Smooch using the smooch-core NPM package.
Before I create a user, I want to check if that specific user id already exists in my app, and if not, I wish to create the new user.
Here is my code:
try {
await this.smooch.appUsers.get(appId, userId);
} catch (err) {
await this.smooch.appUsers.create(appId, userId);
await this.smooch.appUsers.get(appId, userId);
}
I always get a 404 error when I try to get user info with non-existant id (smooch.appUsers.get), which I don't find to be a nice way.
Is there another way to check if user already exists?
404 user_not_found is the officially supported way to know when a user does not exist. Alternatively you could make your call to appUsers.create without doing the appUsers.get first, and you will receive 409 conflict in the case where the user already exists.
Note also that the call to .create returns the created user, so you shouldn't need to do a second .get after that (referring to the snippet you posted)

Minimizing server trips in setting default value in 1:n relationship in lightswitch html5 client

I have lightswitch entities created in the HTML5 client. There is a field that the user should not be setting that needs to be set based on their login. In this case, the client the user is associated with.
The standard examples (in Michael Washington's book Creating HTML 5 Websites ... Using Lightswitch and all over the web) involve assigning the user name as the relevant field, setting up a little handler on the server to return the relevant field using an AJAX call.
This is was all well and good while prototyping, but now that we are doing this for real, there is a relationship to another entity involved, the Client Entity, so you can't just assign the Client Id. So instead of simply assigning a Client ID, now we have associate a whole Client Object to the entity.
Here the suggestion is to do what ends up looking like this:
myapp.activeDataWorkspace.ApplicationData.Clients_SingleOrDefault(1).execute().then(function (ClientQuery) {
entity.setClient(ClientQuery.results[0]);
});
My problem is with this part:
Clients_SingleOrDefault(1)
I need to get that number dynamically, not just a hard coded 1, as that OP suggested. So I can do it in two server calls, one to get the ID, and then the next one to substitute that result into the next call, but that seems ... inefficient.
msls.promiseOperation(CallGetClientId).then(function PromiseSuccess(PromiseResult) {
myapp.activeDataWorkspace.ApplicationData.Clients_SingleOrDefault(Number(PromiseResult)).execute().then(function (ClientQuery) {
entity.setClient(ClientQuery.results[0]);
});
});
function CallGetClientId(operation) {
$.ajax({
type: 'post',
data: {},
url: '../UserCode/GetClientId.ashx',
success: operation.code(function AjaxSuccess(AjaxResult) {
operation.complete(AjaxResult);
})
});
}
It would seem that there should be a better way to do it. Is there?
The simplest method of achieving this with one server call is to implement a scalar query.
For example, if you create a scalar query called ClientForCurrentUser against your Clients table you'd be able to make a single client side call as follows:
myapp.activeDataWorkspace.ApplicationData.ClientForCurrentUser().execute().then(function (query) {
if (query && query.results && query.results.length !== 0) {
entity.setClient(query.results[0]);
}
});
As regards configuring the scalar query, the following post covers an example (note the setting of the 'Number of Results Returned' property):
Applying where clause to child collection in LightSwitch query
Then, assuming you have a field against your Client record that relates it to the current username (e.g. Client.RelatedUser) you'd implement the following type of PreprocessQuery method against the scalar query:
partial void ClientForCurrentUserPersonForCurrentUser_PreprocessQuery(ref IQueryable<Client> query)
{
var username = this.Application.User.Name;
query = query.Where(c => c.RelatedUser.Equals(username, StringComparison.OrdinalIgnoreCase)).Take(1);
}

Laravel Eloquent how to limit access to logged in user only

I have a small app where users create things that are assigned to them.
There are multiple users but all the things are in the same table.
I show the things belonging to a user by retrieving all the things with that user's id but nothing would prevent a user to see another user's things by manually typing the thing's ID in the URL.
Also when a user wants to create a new thing, I have a validation rule set to unique but obviously if someone else has a thing with the same name, that's not going to work.
Is there a way in my Eloquent Model to specify that all interactions should only be allowed for things belonging to the logged in user?
This would mean that when a user tries to go to /thing/edit and that he doesn't own that thing he would get an error message.
The best way to do this would be to check that a "thing" belongs to a user in the controller for the "thing".
For example, in the controller, you could do this:
// Assumes that the controller receives $thing_id from the route.
$thing = Things::find($thing_id); // Or how ever you retrieve the requested thing.
// Assumes that you have a 'user_id' column in your "things" table.
if( $thing->user_id == Auth::user()->id ) {
//Thing belongs to the user, display thing.
} else {
// Thing does not belong to the current user, display error.
}
The same could also be accomplished using relational tables.
// Get the thing based on current user, and a thing id
// from somewhere, possibly passed through route.
// This assumes that the controller receives $thing_id from the route.
$thing = Users::find(Auth::user()->id)->things()->where('id', '=', $thing_id)->first();
if( $thing ) {
// Display Thing
} else {
// Display access denied error.
}
The 3rd Option:
// Same as the second option, but with firstOrFail().
$thing = Users::find(Auth::user()->id)->things()->where('id', '=', $thing_id)->firstOrFail();
// No if statement is needed, as the app will throw a 404 error
// (or exception if errors are on)
Correct me if I am wrong, I am still a novice with laravel myself. But I believe this is what you are looking to do. I can't help all that much more without seeing the code for your "thing", the "thing" route, or the "thing" controller or how your "thing" model is setup using eloquent (if you use eloquent).
I think the functionality you're looking for can be achieved using Authority (this package is based off of the rails CanCan gem by Ryan Bates): https://github.com/machuga/authority-l4.
First, you'll need to define your authority rules (see the examples in the docs) and then you can add filters to specific routes that have an id in them (edit, show, destroy) and inside the filter you can check your authority permissions to determine if the current user should be able to access the resource in question.