Auth0 hooks post-user-registration edit user_metadata - auth0

I created a post-user-registration hook, in which i would like to save some information to user_metadata. However, I don't see the data being saved
/*
#param {object} user.user_metadata - user metadata
*/
module.exports = function (user, context, cb) {
// Perform any asynchronous actions, e.g. send notification to Slack.
user.user_metadata = {
"someinfo": "abcd"
}
cb();
};

Something like:
module.exports = function (user, context, cb) {
var response = {};
user.user_metadata.foo = 'bar';
response.user = user;
return cb(null, response);
};
worked fine for me.
For rules the docs say that you can't directly update the user_metadata. As described on the link you have to use the updateUserMetadata function after you set the new values. I am not sure if this applies to hooks too (probably not, since the auth0 object is not defined on hooks).
p.s. Keep in mind that hooks only run for Database Connections, as outlined in the docs. Is there a chance you used an account based on social login?

Related

How to unregister middleware in Telegraf?

When I add bot.hears(...), it registers middleware for handling matching text messages. But now it will handle those messages even if they are sent any time, even if not expected.
So if I am creating a stateful service, I would like to listen to particular messages only at appropriate time.
How can I unregister middleware, so that it does not hear any more previously handled messages?
I turned out I was looking for Scenes. How to use them is described on Github.
I'll just post a slightly modified code from the links above:
const { Telegraf, Scenes, session } = require('telegraf')
const contactDataWizard = new Scenes.WizardScene(
'CONTACT_DATA_WIZARD_SCENE_ID', // first argument is Scene_ID, same as for BaseScene
(ctx) => {
ctx.reply('Please enter guest\'s first name', Markup.removeKeyboard());
ctx.wizard.state.contactData = {};
return ctx.wizard.next();
},
(ctx) => {
// validation example
if (ctx.message.text.length < 2) {
ctx.reply('Please enter real name');
return;
}
ctx.wizard.state.contactData.firstName = ctx.message.text;
ctx.reply('And last name...');
return ctx.wizard.next();
},
);
const stage = new Scenes.Stage();
stage.register(contactDataWizard);
bot.use(session());
bot.use(stage.middleware());
But I still don't know how to generally implement it, so I need to find it out in the Scenes code of Telegraf.

Aurelia: how to manage sessions

I'm trying to develop a website where the nav-bar items depend on the role of the user who is logged in.
As Patrick Walter suggested on his blog, I was thinking to create a session.js file where I would store information about the current user: their username and role. I would then inject this file in nav-bar.js and create a filter for the routes, for which the user does not have access to. Everything worked fine until I hit the refresh button... In fact, it creates a new session object and I loose all the information store in the previous one.
I have seen in the docs the singleton method, but I'm not sure how to use it. If I insert it in my code such as below, I get the message: aurelia.use.singleton is not a function.
import config from './auth-config';
export function configure(aurelia) {
console.log('Hello from animation-main config');
aurelia.use
.singleton(Session)
.standardConfiguration()
.developmentLogging()
.plugin('aurelia-animator-css')
.plugin('paulvanbladel/aurelia-auth', (baseConfig) => {
baseConfig.configure(config);
});
aurelia.start().then(a => a.setRoot());
}
export class Session {
username = '';
role = '';
reset() {
console.log('Resetting session');
this.username = '';
this.role = '';
};
}
My last idea would be to encrypt the role/username and use the browser's session to store the information. But I wanted to ask to more experienced developers their opinion about the topic.
Thanks for your help!
EDIT: Here is my code for session.js
export class Session {
username = '';
role = '';
reset() {
console.log('Resetting session');
this.username = '';
this.role = '';
};
}
And this is how I inject it:
import {Session} from './services/session';
#inject(Session)
export class RoleFilterValueConverter {
constructor(session) {
console.log('Hello from RoleFilter constructor', session)
this.session = session;
};
toView(routes, role) {
console.log('Hello from view', role, this.session)
if (this.session.role == 'Superuser')
return routes;
return routes.filter(r => {
var res = !r.config.role || (r.config.role == this.session.role);
return res
});
}
}
In the main entry point (let's assume it's index.html) you should have something like this:
<body aurelia-app="path/to/main">
<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
System.import('aurelia-bootstrapper');
</script>
</body>
This imports the entire aurelia enviorment and so when it reaches the export function configure(aurelia) { ... } it should pass an instance of type Aurelia and bind it to the aurelia parameter and should resolve your aurelia.use.singleton is not a function. error. After that, in your session.js file when using #inject(Session) it should pass the same instance you declared at startup.
I also implemented a singleton session object to store user data and have chosen this method because it's more convenient to rely on dependency injection rather than always calling a method to get user data from a cookie.
Though Laurentiu's answer is not bad, there are better ways to handle this that do not add complexity to your app.
You do not need to need to specify this as a singleton. This particular function is more for an edge case where you would want to expose a particular item to the dependency injection container as a singleton before startup.
In fact, the Aurelia dependency injection framework treats all modules as singletons unless specified otherwise. Thus, the code should work as you have it written there, without the configure function.
I've written up an in-depth blog that you maay find helpful here: http://davismj.me/blog/aurelia-auth-pt2/

pass options to mongoose schema toJSON transform inline (in expressjs)?

I have a mongoose (3.1) 'Thing' schema whose toJSON I can customize in the following manner...
Thing.options.toJSON = {};
Thing.options.toJSON.transform = function (doc, ret, options){
// do something to ret, depending on options
}
As noted in the code comment, I would like to change the JSON representation given the value of options. I would like to pass these options in an expressjs action, maybe...
app.get(..., function (req ,res){
Thing.find({}, function(err, things){
var myOptions = {...} // something application stateful
return response.send(things) // MAYBE ADD OPTIONS HERE?
});
});
How do I modify expressjs to allow me to supply options?
Thanks,
G
IMHO, the accepted answer (#VladStirbu's) is wrong because the options are being set at the schema level. It's changing the schema, so those options will be available in subsequent calls, even if you don't request so explicitly.
The options should be set inline, individually for that call:
Regular call using express:
app.get(..., function (req ,res){
Thing.find({}, function(err, things){
return response.send(things);
});
});
Call using express, but passing inline options to toJSON():
app.get(..., function (req ,res){
Thing.find({}, function(err, things){
let toJSONOptions; // may be undefined, it's fine
if ( /* whatever condition you decide */ ) {
// this keeps the schema's original options:
toJSONOptions = Object.assign({ }, Thing.schema.options.toJSON);
// request to use original transform function, if any:
toJSONOptions.transform = true;
// set your own options to be passed to toJSON():
toJSONOptions._options = {...}; // whatever you need here
}
return response.send( things.map(e => e.toJSON(toJSONOptions)) );
});
});
No problem if toJSONOptions = undefined, it would be like a regular call to toJSON(), which is what express does when stringifying.
If you're using findOne() or findById(), then just return:
return response.send( thing.toJSON(toJSONOptions) );
This is the Mongoose commit that made me think of this:
https://github.com/Automattic/mongoose/commit/1161f79effc074944693b1799b87bb0223103220
You could pass options in the route handler by passing them to the schema options:
app.get(..., function (req ,res){
Thing.find({}, function(err, things){
Thing.schema.options.toJSON.myOptions = {...} // something application stateful
return response.send(things) // MAYBE ADD OPTIONS HERE?
});
});
this way, the options will be available in the transform function as a property of the options object:
Thing.options.toJSON.transform = function (doc, ret, options){
console.log(options.myOptions); // prints the app specific data provided earlier
}

What is the role of exec() and next() call in cascade delete in mongoose middleware?

I'm new to using mongoose middleware and don't know if I'm following it well. Here is the purpose. After saving department, I want to populate university and save departmentId inside university object.
DepartmentSchema.post('save', function(next) {
var departmentId = this._id;
University.findOne({
_id: this.university
}, function(err, university) {
if (!university.departments) {
university.departments = [];
}
university.departments.push(new ObjectId(departmentId));
university.save(function(err) {
if (err) return console.log('err-->' + err);
// saved!
});
});
});
This is working fine but I'm not sure why in Cascade style delete in Mongoose they have used exec() and next() calls. Could you please tell me the purpose of these calls? I don't know what they do and not able to find relevant documentation. I just want to make sure I'm not missing anything.
clientSchema.pre('remove', function(next) {
// 'this' is the client being removed. Provide callbacks here if you want
// to be notified of the calls' result.
Sweepstakes.remove({
client_id: this._id
}).exec();
Submission.remove({
client_id: this._id
}).exec();
next();
});
Post middleware doesn't have reference to the next function and you cant do any flow control. Its actually passing the department that just got saved, so your code can be something like this:
DepartmentSchema.post('save', function(department) {
var departmentId = department._id;
In pre middleware you have access to the next middleware in the order of execution. Which is the order of definition on a particular hook.
// hook two middlewares before the execution of the save method
schema.pre('save', pre1);
schema.pre('save', pre2);
function pre1(next) {
// next is a reference to pre2 here
next()
}
function pre2(next) {
// next will reference the hooked method, in this case its 'save'
next(new Error('something went wrong');
}
// somewhere else in the code
MyModel.save(function(err, doc) {
//It'll get an error passed from pre2
});
Mongoose also gives you the ability to execute pre middlewares in parallel, in this case all middlewares will be executed in parallel but hooked method will not execute till the done is called from each middleware.
As for the exec() function, there are two ways of executing a query in Mongoose, either pass a callback to the query or chain it with an exec(): User.remove(criteria, callback) or User.remove(criteria).exec(callback), if you don't pass a callback to the query, it'll return a query object and it won't execute unless you chain it with exec()

Prevent duplicate routes in express.js

Is there a nice way to prevent duplicate routes from being registered in express? I have a pretty large application with hundreds of routes across different files, and it gets difficult to know if I've already registered a certain route when I go to add a new one. For example, I'd like to throw an error when express gets to routes487.js:
File: routes1.js
var ctrl = require('../controllers/testctrl');
var auth = require('../libs/authentication');
module.exports = function (app) {
app.get('/hi', auth.getToken, ctrl.hi);
app.get('/there', auth.getToken, ctrl.there);
};
File: routes487.js
var ctrl = require('../controllers/testctrl487');
var auth = require('../libs/authentication');
module.exports = function (app) {
app.get('/hi', auth.getToken, ctrl.hi487);
};
You could try a custom solution by wrapping express methods with the validation. Consider the following modification to your express app:
// route-validation.js
module.exports = function (app) {
var existingRoutes = {}
, originalMethods = [];
// Returns true if the route is already registered.
function routeExists(verb, path) {
return existingRoutes[verb] &&
existingRoutes[verb].indexOf(path) > -1;
}
function registerRoute(verb, path) {
if (!existingRoutes[verb]) existingRoutes[verb] = [];
existingRoutes[verb].push(path);
}
// Return a new app method that will check repeated routes.
function validatedMethod(verb) {
return function() {
// If the route exists, app.VERB will throw.
if (routeExists(verb, arguments[0]) {
throw new Error("Can't register duplicate handler for path", arguments[0]);
}
// Otherwise, the route is saved and the original express method is called.
registerRoute(verb, arguments[0]);
originalMethods[verb].apply(app, arguments);
}
}
['get', 'post', 'put', 'delete', 'all'].forEach(function (verb) {
// Save original methods for internal use.
originalMethods[verb] = app[verb];
// Replace by our own route-validator methods.
app[verb] = validatedMethod(verb);
});
};
You just need to pass your app to this function after creation and duplicate route checking will be implemented. Note that you might need other "verbs" (OPTIONS, HEAD).
If you don't want to mess with express' methods (we don't know whether or how express itself or middleware modules will use them), you can use an intermediate layer (i.e., you actually wrap your app object instead of modifying its methods). I actually feel that would be a better solution, but I feel lazy to type it right now :)