Redirect to login

Solved Plugin Development
  • I have been having some issues since NodeBB went all in on async/await. I have a private forum so I need to redirect to /login if the visitor isn't logged in.

    What worked before was a library function listening to filter:middleware.render, and then:

    library.checkLoginStatus = async (data) => {
    
    	if (data.req.loggedIn ||
    			allowedUrls(data.req.url)
    	) {
    		return data;
    	}
    	return Helpers.redirect(data.res, '/login');
    };
    

    allowedUrls is a function that just checks the requested url against a list of allowed ones (like /login, /email/unsubscribe and /register).

    Everything worked great but now I'm upgraded to 1.16.x.

    The issue I'm having is that there are other functions that tails this one listening to the same hook. So my question is if I can interrupt that flow somehow on redirect. Or maybe there's an even better solution, but it needs to be forum wide. The tailing functions get undefined passed in so everything breaks. The weird thing is that everything seems to work, and it semi silently drops the error. But I don't want a bunch of error logs cluttering things up.

    I know NodeBB is meant to be open and all, but in this case I need to lock it down until someone has registered. I built this functionality when on 1.12 I think so something else might be a better option.

    I'm turning to you community.

  • Maybe 'response:router.page' is better then, it won't call next if you already do a redirect in it.

    https://github.com/NodeBB/NodeBB/blob/master/src/middleware/index.js#L94-L101

  • I think it's better if you don't use filter:middleware.render. Since that is called all the way at the end of the request. In your plugin you can add a handler before everything else and redirect if user isn't allowed. Something like below.

    plugin.init = async (params) => {
       params.router.use(function (req, res, next) {
          if (req.loggedIn || allowedUrls(req.url)) {
             return next();
          }
          
          return Helpers.redirect(res, '/login'););
    };
    

    Let me know if this works.

  • Though this works, it also redirects every call for assets (images, stylesheets etc). So I get a site without CSS. 😄

    Maybe another hook is more appropriate?

    I also have another function that redirects to the profile page if some information is not properly filled in.

    So the overarching question is not to lock people out, it's more about how to divert a user based on some conditions. For instance, we have to require the users full name, so if it's not filled out, they get redirected to their profile edit page and asked to fill it in.

    EDIT: I forgot to tag you @baris.

  • Seems like reverting to callbacks resolves it. I really wanted this to work with async/await, since callbacks will sooner or later be phased out I guess.

    library.checkLoginStatus = (data, callback) => {
    	if (data.req.loggedIn ||
    		allowedUrls(data.req.url)
    	) {
    		callback(null, data);
    	} else {
    		Helpers.redirect(data.res, '/login');
    	}
    };
    
  • I also tried to use the helper function notAllowed, but I get the same result. Redirects to /login but get errors in the log that data is undefined and there is no catch().

    library.checkLoginStatus = async (data) => {
    	if (data.req.loggedIn ||
    		allowedUrls(data.req.url)
    	) {
    		return data;
    	}
    	return Helpers.notAllowed(data.req, data.res);
    };
    
  • Maybe 'response:router.page' is better then, it won't call next if you already do a redirect in it.

    https://github.com/NodeBB/NodeBB/blob/master/src/middleware/index.js#L94-L101

  • @baris That's it. Worked like a charm. Thanks!

  • Hello @baris and @magnusvhendin

    I would like to update my module nodebb-plugin-private-forum that should do exactly what you are trying to archive.
    But it seems it is not working well with v1.16.2 and I need some help on the Hook declaration.

    I understand that I need to use response:router.page, but how exactly?
    Is this ok for you?

    plugin.json

    {
      "id": "nodebb-plugin-private-forum",
      "url": "https://github.com/LM1LC3N7/nodebb-plugin-private-forum",
      "library": "./library.js",
      "hooks": [{
        "hook": "response:router.page", "method": "init"
      }]
    }
    

    library.json

    'use strict';
    
    const plugin = {};
    var winston = module.parent.require('winston');
    const helpers = require.main.require('./src/controllers/helpers');
    
    plugin.init = async (data) => {
    
            const allowedPages = /\/(assets\/|login|register|reset|plugins\/).*|.*(.css|.js)$/;
    
            winston.verbose("[plugin-nodebb-private-forum] Checking URL ("+ req.url +"), redirection.");
    
            # Allow only few pages or logged in users
            if (data.req.loggedIn || allowedPages.test(req.url)) {
                    return data;
            }
    
            # else redirect to /login.
            winston.verbose("[plugin-nodebb-private-forum] User is NOT logged or URL is NOT allowed.");
            return Helpers.notAllowed(data.req, data.res);
    };
    
    module.exports = plugin;
    

    I can't see any of the debug log messages containing accessed URL

  • Trying logging with winston.info, verbose only shows up in dev mode or when you start with --verbose I believe.

  • @baris After a rebuild, reset module and activate again, still nothing.
    I have manually changed the package.json version number but the old version still appears. An idea why? My updates are maybe never used?

  • Maker sure your plugin is linked into node_modules. If it's not your changes won't show up.

  • @baris infact I have installed the old version and I update the installed module directly (in node_modules folder).

    I rebuild and restart nodebb, but the plugin version is still the old one.

    Does my plugin file code looks ok to you?

  • Javascript comments start with // or /* comment */. During startup if there is an error in a plugin it is not loaded. Check the startup messages.

  • @baris My god, it's not good to work with bash and javascript at the same time (thank you btw) 😇

    My "old" code is still working well without depreciation warning, thanks for your answers 🙂

  • @baris I'm also trying this and it works with SSO also. However now I can't logout and use /login?local=1 to log the admin account as above method force only use /login and it use the sso. Any clue, hint to avoid this?

    I use the code in here
    https://github.com/LM1LC3N7/nodebb-plugin-private-forum/blob/master/library.js

  • Hello @jalathpc_demo

    I tried to create a patch:
    https://github.com/LM1LC3N7/nodebb-plugin-private-forum/releases/tag/v1.3.1

    I no longer have a NodeBB instance, so let me know if it works (I am honestly not sure, as /logout should be allowed as you are logged in.

    It would be interesting to check if req.loggedIn is correctly set when using SSO. This could be why the plugin is not working as you need.

    NPM link: https://www.npmjs.com/package/nodebb-plugin-private-forum/v/1.3.1


Suggested Topics