jfromaniello/express-unless

Allow parent path but do-not allow subpath to have access

narengs7 opened this issue · 1 comments

Hello,
I was trying to avoid token validation for particular urls as shown below
/ - allow without token
/api - allow without token
/api/auth - allow without token
/api/usrs - allow with token
/api/usrs/:id - allow with token

So i tried to set below

const expressJwt = require("express-jwt");
expressJwt({"Tango"}).unless({
		path:[
			'/',
			'/api',
			'/api/usrs/auth'
		]
	});

Any one facing same issue?

Hi @narengs7,
I'm looking for something like you want,
but I can't find anythings ... Anyway.

For you, the problem may come from your path parameter :

path: [
			'/',
			'/api',
			'/api/usrs/auth'
		]

It should be like this :

path: [
			'/',
			'/api',
			'/api/auth'
		]

In the other case,
I've made my custom function that return true or false
for the parameter custom of express-unless.

Looks like this :

var express_jwt = require('express-jwt');

app.use(express_jwt({
  secret: env.api_secret,
}).unless({
  custom: function(req){
    /* ========== YOUR PARAM HERE ========== */
    const pathsExcluded = [
      '/tests/*',
      '/login',
    ];
    const pathsIncludeNested = [
      '/tests/not-me',
    ];
    /* ===================================== */

    const currentUrl = req.url.split("?")[0];

    var pathsExcludedNotWorking = [];
    // splice: exclude FIRST '/'
    let arrayCurrentUrlDetails = currentUrl.split('/').splice(1,2);

    var allowed = false;
    // for each detail of current URL
    for (var pos = 0; pos < arrayCurrentUrlDetails.length; pos++){
      if (allowed) break;
      // for each pathsExcluded
      for (const pathExcluded of pathsExcluded){
        if (allowed) break;
        // if pathExcluded already treated and do not correspond at our filter
        if (pathsExcludedNotWorking.includes(pathExcluded)) continue;
        // look at the splice param, 'pos + 1', for ignoring 'pathExcludedDetail' already treated
        const arrayPathExcluded = pathExcluded.split('/').splice(pos + 1,2);
        let pathExcludePos = 0;
        // for each detail of pathExcluded
        for (const pathExcludedDetail of arrayPathExcluded){
          // if our filter allow all nested levels
          if (pathExcludedDetail === "*"){
            allowed = true;
          } else if (pathExcludedDetail !== arrayCurrentUrlDetails[pathExcludePos]) {
            // current url doesn't fit with the filter, mark it as already treated
            pathsExcludedNotWorking.push(pathExcluded);
            break;
          }
          // if whe are on the last detail, the current url match perfectly our filter
          if (pos === arrayCurrentUrlDetails.length) allowed = true;
          // if filter is more nested than our currently loop position of arrayCurrentUrlDetails
          if (pathExcludePos === pos) break;
          pathExcludePos++;
        }
      }
    }

    if (allowed){
      // looking for pathsIncludeNested
      // if our url match the pathsIncludeNested values
      if (pathsIncludeNested.includes(currentUrl)) {
        allowed = false;
      }
    }

    return allowed;
  }
}));

It will not include routes with params like users/:name, but you can avoid that by adding users/* in pathsExcluded