The Open Source kanban (built with Meteor). Keep variable/table/field names camelCase. For translations, only add Pull Request changes to wekan/i18n/en.i18n.json , other translations are done at https://transifex.com/wekan/wekan only.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
wekan/server/apiMiddleware.js

101 lines
3.6 KiB

// API middleware: body parsing, auth token handling, API gate, and JSON response helper.
// Replaces communitypackages:json-routes middleware chain.
// Must be imported before model files that register API routes.
const { Meteor } = require('meteor/meteor');
const { Accounts } = require('meteor/accounts-base');
const { WebApp } = require('meteor/webapp');
const bodyParser = require('body-parser');
// ---------------------------------------------------------------------------
// 1. Body parsing (previously registered by json-routes)
// ---------------------------------------------------------------------------
WebApp.handlers.use(bodyParser.urlencoded({ limit: '50mb', extended: false }));
WebApp.handlers.use(bodyParser.json({ limit: '50mb' }));
// ---------------------------------------------------------------------------
// 2. API gate — check WITH_API env var (previously in models/users.js)
// ---------------------------------------------------------------------------
WebApp.handlers.use(function apiGate(req, res, next) {
const api = req.url.startsWith('/api');
if ((api && process.env.WITH_API === 'true') || !api) {
return next();
}
res.writeHead(301, { Location: '/' });
return res.end();
});
// ---------------------------------------------------------------------------
// 3. Bearer token parser (replaces communitypackages:rest-bearer-token-parser)
// ---------------------------------------------------------------------------
WebApp.handlers.use(function parseBearerToken(req, res, next) {
// Check Authorization header first
const authHeader = req.headers.authorization;
if (authHeader) {
const match = authHeader.match(/^Bearer\s+(.+)$/i);
if (match) {
req.authToken = match[1];
}
}
// Fallback to access_token query param
if (!req.authToken && req.query && req.query.access_token) {
req.authToken = req.query.access_token;
}
next();
});
// ---------------------------------------------------------------------------
// 4. User authentication (replaces communitypackages:authenticate-user-by-token)
// ---------------------------------------------------------------------------
WebApp.handlers.use(async function authenticateByToken(req, res, next) {
if (req.authToken) {
try {
const hashedToken = Accounts._hashLoginToken(req.authToken);
const user = await Meteor.users.findOneAsync(
{ 'services.resume.loginTokens.hashedToken': hashedToken },
{ fields: { _id: 1 } },
);
if (user) {
req.userId = user._id;
}
} catch (e) {
// Ignore auth errors — routes handle missing userId themselves
}
}
next();
});
// ---------------------------------------------------------------------------
// 5. sendJsonResult — drop-in replacement for JsonRoutes.sendResult
// ---------------------------------------------------------------------------
function sendJsonResult(res, options) {
options = options || {};
// Default response headers (matching json-routes behavior)
res.setHeader('Cache-Control', 'no-store');
res.setHeader('Pragma', 'no-cache');
// Custom headers
if (options.headers) {
Object.entries(options.headers).forEach(function ([key, value]) {
res.setHeader(key, value);
});
}
// Status code
res.statusCode = options.code || 200;
// JSON body
if (options.data !== undefined) {
const shouldPrettyPrint = process.env.NODE_ENV === 'development';
const spacer = shouldPrettyPrint ? 2 : null;
res.setHeader('Content-Type', 'application/json');
res.write(JSON.stringify(options.data, null, spacer));
}
res.end();
}
module.exports = { sendJsonResult };