totaljs / framework

Node.js framework
http://www.totaljs.com
Other
4.36k stars 450 forks source link

Route any request if a flag is present #674

Closed fgnm closed 6 years ago

fgnm commented 6 years ago

Hello, I'm looking for a smart method to route every page to a single one if, during onAuthorize, is set a special flag. Currently I handle the route in this way:

    ROUTE('/profile', view_personal, ['authorize']);
    ROUTE('/profile/address', view_address, ['authorize']);
    ROUTE('/profile/contacts', view_contacts, ['authorize']);
    .....

The idea is to have a single line that route: /profile, /profile/address, /profile/contacts to another function if there is a flag. So I've tried this route:

    ROUTE('/*', view_index, ['authorize', '@customflag']);

But it does not override existing routes and remove any 404 (not a good choice). Maybe the regex route could be the solution but the example in docs does not works.

petersirka commented 6 years ago

Hi, @customflag can be used for roles only. RegExp routing can be a part of dynamic argument only.

ROUTE(function(url, req, flags) {
    return (/YOUR_REG_EXP/).test(url);
}, your_action);

Or you can use routing group: https://docs.totaljs.com/latest/en.html#api~HttpRouteOptionsFlags~%26group_name

fgnm commented 6 years ago

Thank you for clarification, indeed @customflag is exactly for roles purpose. Users with that role shouldn't be able to explore the whole ['authorize'] pages but only one. So I ask if there is a better solution instead of doing something like this:

exports.install = function () {
    ROUTE('/profile', view_personal, ['authorize']);
    ROUTE('/profile/address', view_address, ['authorize']);
    ROUTE('/profile/contacts', view_contacts, ['authorize']);

    ROUTE('/profile', view_index, ['authorize', '@customflag']);
    ROUTE('/profile/address', view_index, ['authorize', '@customflag']);
    ROUTE('/profile/contacts', view_index, ['authorize', '@customflag']);
}

I've many ROUTE and I don't want to duplicate each one to check @customflag.

Basically I'm looking for a smarter solution for write a routing rule that redirect everything to a single page, if the authenticated user ha @customflag role. Are groups the solution? I didn't understand well the doc, could you make me an example for what I'm trying to do?

Thank you :)

petersirka commented 6 years ago

I understand. Then roles must work. Show me your implementation of F.onAuthorize ... There you need to add your role to flags argument:

F.onAuthorize = function(req, res, flags, callback) {
    flags.push('customflag');
    callback(true, USER_OBJ);
};
fgnm commented 6 years ago

onAuthorize works wall, I've already done an admin role and it works without problem..

F.onAuthorize = function(req, res, flags, callback) {

    var cookie = req.cookie(F.config.cookie);
    if (!cookie || cookie.length < 10) {
        callback(false);
        return;
    }

    var obj = F.decrypt(cookie, 'user');

    if (!obj) {
        callback(false);
        return;
    }

    var user = F.cache.get('user_' + obj.id);
    if (user) {
        req.user = user;
        if(obj.id == 0) {
            flags.push('@administrator');
        }
        if(!user.sponsor_valid) {
            flags.push('@customflag');
        }
        callback(true);
        return;
    }

    MODEL("users").getUserById(obj.id, function(err, data){
        if(err) {
            callback(false);
        } else {
            if(!MODULE("utils").isEmptyObject(data)) {
                F.cache.add('user_' + data.Item.id, data.Item, '5 minutes');
                if(data.Item.id == 0) {
                    flags.push('@administrator');
                }
                if(!data.Item.sponsor_valid) {
                    flags.push('@customflag');
                }
                callback(true, data.Item);
            } else {
                callback(false);
            }
        }
    });

};

It's very simple and almost equals to the example

petersirka commented 6 years ago

😁so does it work?

fgnm commented 6 years ago

Yes, but maybe I did not explain well, I'm looking for a method that allow to redirect EVERY page with a single line without writing this line variant for every single route

ROUTE('/profile/address', view_index, ['authorize', '@customflag']);
petersirka commented 6 years ago

Only wildcard routing with your custom logic.

fgnm commented 6 years ago

Okay but this one:

ROUTE('/*', view_index, ['authorize', '@customflag']);

Does not override already existing route. I mean that /profile page will always use view_personal instead of view_index. It seems that there is a sort of priority during routing that I've don't understand. /* seems to have less priority then /profile.

petersirka commented 6 years ago

Yes, it's correct.

I meant that you create your own mechanism in some action in a route with wildcard.

fgnm commented 6 years ago

So maybe I can try the inverse. Is it possible to do something like: Route the page if is not present this flag, otherwise show 401?

petersirka commented 6 years ago

Inversion is not possible. You can perform your own route in #404 action or you need to use wildcard routing with your own routing logic.

fgnm commented 6 years ago

Okay, thank you for clarifications