mirror of https://github.com/wekan/wekan
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.
101 lines
3.6 KiB
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 };
|
|
|