0

Despite this running correctly on my local machine while I was writing and testing it, it seems to fail when deployed out to our UAT environment using Docker. I can't seem to track down why it's giving me the following:

next() is not a function

I also seem to be having a routing issue (again only when it's deployed) where even if it when the route is /media/public it seems to still hit the /media route.

dependencies

"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1"

server.js

require('dotenv').config();
const express = require('express');
const { join } = require('path');
const { fileExists, isAuthenticated } = require('./helpers/utils');
const { PORT, ROOT_SHARE } = process.env;
const app = express();

global.__basedir = __dirname

app.use('/robots.txt', function (_req, res) {
    res.type('text/plain');
    res.send('User-agent: *\nDisallow:/');
});

app.use('/media/public', [fileExists, express.static(join(__dirname, ROOT_SHARE, '/public'))]);
app.use('/media', [isAuthenticated, express.static(join(__dirname, ROOT_SHARE))]);

app.listen(PORT, () => console.info(`[File Server] : running on ${PORT}`));

utils.js

const { existsSync } = require('fs');
const { verify } = require('jsonwebtoken');
const { join } = require('path');
const { ACCESS_SECRET, NODE_ENV  } = process.env;

const fileExists = async (req, res, next) => {
    let mediaFile = (NODE_ENV === 'local') ? join(__basedir, req.baseUrl, req.path).replace('\\src','') : req.originalUrl;
    console.log(mediaFile);
    if (!existsSync(mediaFile)) {
        console.log('NOT FOUND')
        return res.status(404).send('NOT FOUND');
    }

    return next();
}

const isAuthenticated = async (req, res, next) => {
    const accessToken = valueOrNull((req.cookies && req.cookies['x-access-token']) || (req.headers && req.headers['x-access-token']));
    
    if (!accessToken) {
        console.log('accessToken not found')
        return res.status(401).send('UNAUTHORIZED');
    }

    try {
        fileExists(req);
        const { user } = verify(accessToken, ACCESS_SECRET);

        if (user) {
            console.log('VALID USER');
        }
    } catch (err) {
        console.log(err)
        return res.status(401).send('UNAUTHORIZED');
    }

    return next();
};

const valueOrNull = (value) => {
    return (typeof value == 'undefined' || value === null || value === '') ? undefined : value;
}

module.exports = {
    fileExists,
    isAuthenticated
}

.env

ROOT_SHARE=../media

Dockerfile

FROM node:latest

RUN mkdir -p /media

WORKDIR /app

COPY package.json .
COPY package-lock.json .

RUN npm install && npm cache clean --force --loglevel=error

RUN npm install -g pm2

COPY src /app/src

EXPOSE 3000

ENTRYPOINT ["node", "src/server.js"]

exact error next() is not a function

Any help would be greatly appreciated

2 Answers 2

2

Your fileExists is being used both as a middleware and as a function called in isAuthenticated — in isAuthenticated it's not being passed res or next. If you do pass it there, you may end up having other issues, since both functions call res.status(status).send(). You also have some async keywords on those functions when they're not awaiting anything — that's not breaking anything, it's just a waste of a few characters :).

Sign up to request clarification or add additional context in comments.

Comments

1

You call:

fileExists(req);

but your implementation of fileExists() expects you to pass it (res, res, next) and you are not passing that. Thus, you get the error next() is not a function when fileExists() tries to call next().

It's not clear to me exactly what you're trying to do, but perhaps you can change to this where you pass (req, res, callback) to fileExists() and then you continue your processing in that callback. That's how you manually call middleware yourself which it appears you are trying to do:

const isAuthenticated = (req, res, next) => {
    const accessToken = valueOrNull((req.cookies && req.cookies['x-access-token']) || (req.headers && req.headers['x-access-token']));
    
    if (!accessToken) {
        console.log('accessToken not found')
        return res.status(401).send('UNAUTHORIZED');
    }

    try {
        fileExists(req, res, () => {
            const { user } = verify(accessToken, ACCESS_SECRET);

            if (user) {
                console.log('VALID USER');
            }
            return next();

        });
    } catch (err) {
        console.log(err)
        return res.status(401).send('UNAUTHORIZED');
    }

};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.