mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 19:15:58 +01:00 
			
		
		
		
	fix(refactor): merging write-api auth middlewares with core middlewares
This commit is contained in:
		| @@ -123,12 +123,7 @@ helpers.notAllowed = async function (req, res, error) { | ||||
|  | ||||
| 	if (req.loggedIn || req.uid === -1) { | ||||
| 		if (res.locals.isAPI) { | ||||
| 			res.status(403).json({ | ||||
| 				path: req.path.replace(/^\/api/, ''), | ||||
| 				loggedIn: req.loggedIn, | ||||
| 				error: data.error, | ||||
| 				title: '[[global:403.title]]', | ||||
| 			}); | ||||
| 			helpers.formatApiResponse(403, res, error); | ||||
| 		} else { | ||||
| 			await middleware.buildHeaderAsync(req, res); | ||||
| 			res.status(403).render('403', { | ||||
| @@ -140,7 +135,7 @@ helpers.notAllowed = async function (req, res, error) { | ||||
| 		} | ||||
| 	} else if (res.locals.isAPI) { | ||||
| 		req.session.returnTo = req.url.replace(/^\/api/, ''); | ||||
| 		res.status(401).json('not-authorized'); | ||||
| 		helpers.formatApiResponse(401, res, error); | ||||
| 	} else { | ||||
| 		req.session.returnTo = req.url; | ||||
| 		res.redirect(nconf.get('relative_path') + '/login'); | ||||
| @@ -353,9 +348,6 @@ helpers.formatApiResponse = async (statusCode, res, payload) => { | ||||
| 			}, | ||||
| 			response: payload || {}, | ||||
| 		}); | ||||
| 	} else if (!payload) { | ||||
| 		// Non-2xx statusCode, generate predefined error | ||||
| 		res.status(statusCode).json(helpers.generateError(statusCode)); | ||||
| 	} else if (payload instanceof Error) { | ||||
| 		if (isLanguageKey.test(payload.message)) { | ||||
| 			const translated = await translator.translate(payload.message, 'en-GB'); | ||||
| @@ -363,6 +355,9 @@ helpers.formatApiResponse = async (statusCode, res, payload) => { | ||||
| 		} else { | ||||
| 			res.status(statusCode).json(helpers.generateError(statusCode, payload.message)); | ||||
| 		} | ||||
| 	} else if (!payload) { | ||||
| 		// Non-2xx statusCode, generate predefined error | ||||
| 		res.status(statusCode).json(helpers.generateError(statusCode)); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -377,34 +372,34 @@ helpers.generateError = (statusCode, message) => { | ||||
|  | ||||
| 	// Need to turn all these into translation strings | ||||
| 	switch (statusCode) { | ||||
| 	case 400: | ||||
| 		payload.status.code = 'bad-request'; | ||||
| 		payload.status.message = message || 'Something was wrong with the request payload you passed in.'; | ||||
| 		break; | ||||
| 		case 400: | ||||
| 			payload.status.code = 'bad-request'; | ||||
| 			payload.status.message = message || 'Something was wrong with the request payload you passed in.'; | ||||
| 			break; | ||||
|  | ||||
| 	case 401: | ||||
| 		payload.status.code = 'not-authorised'; | ||||
| 		payload.status.message = 'A valid login session was not found. Please log in and try again.'; | ||||
| 		break; | ||||
| 		case 401: | ||||
| 			payload.status.code = 'not-authorised'; | ||||
| 			payload.status.message = message || 'A valid login session was not found. Please log in and try again.'; | ||||
| 			break; | ||||
|  | ||||
| 	case 403: | ||||
| 		payload.status.code = 'forbidden'; | ||||
| 		payload.status.message = 'You are not authorised to make this call'; | ||||
| 		break; | ||||
| 		case 403: | ||||
| 			payload.status.code = 'forbidden'; | ||||
| 			payload.status.message = message || 'You are not authorised to make this call'; | ||||
| 			break; | ||||
|  | ||||
| 	case 404: | ||||
| 		payload.status.code = 'not-found'; | ||||
| 		payload.status.message = 'Invalid API call'; | ||||
| 		break; | ||||
| 		case 404: | ||||
| 			payload.status.code = 'not-found'; | ||||
| 			payload.status.message = message || 'Invalid API call'; | ||||
| 			break; | ||||
|  | ||||
| 	case 426: | ||||
| 		payload.status.code = 'upgrade-required'; | ||||
| 		payload.status.message = 'HTTPS is required for requests to the write api, please re-send your request via HTTPS'; | ||||
| 		break; | ||||
| 		case 426: | ||||
| 			payload.status.code = 'upgrade-required'; | ||||
| 			payload.status.message = message || 'HTTPS is required for requests to the write api, please re-send your request via HTTPS'; | ||||
| 			break; | ||||
|  | ||||
| 	case 500: | ||||
| 		payload.status.code = 'internal-server-error'; | ||||
| 		payload.status.message = message || payload.status.message; | ||||
| 		case 500: | ||||
| 			payload.status.code = 'internal-server-error'; | ||||
| 			payload.status.message = message || payload.status.message; | ||||
| 	} | ||||
|  | ||||
| 	return payload; | ||||
|   | ||||
| @@ -1,48 +0,0 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const passport = require('passport'); | ||||
| const winston = require('winston'); | ||||
|  | ||||
| const helpers = require('../controllers/helpers'); | ||||
| const middleware = module.exports; | ||||
|  | ||||
| middleware.authenticate = function (req, res, next) { | ||||
| 	if (req.headers.hasOwnProperty('authorization')) { | ||||
| 		passport.authenticate('bearer', { session: false }, function (err, user) { | ||||
| 			if (err) { return next(err); } | ||||
| 			if (!user) { return helpers.formatApiResponse(401, res); } | ||||
|  | ||||
| 			// If the token received was a master token, a _uid must also be present for all calls | ||||
| 			if (user.hasOwnProperty('uid')) { | ||||
| 				req.login(user, function (err) { | ||||
| 					if (err) { return helpers.formatApiResponse(500, res, err); } | ||||
|  | ||||
| 					req.uid = user.uid; | ||||
| 					req.loggedIn = req.uid > 0; | ||||
| 					next(); | ||||
| 				}); | ||||
| 			} else if (user.hasOwnProperty('master') && user.master === true) { | ||||
| 				if (req.body.hasOwnProperty('_uid') || req.query.hasOwnProperty('_uid')) { | ||||
| 					user.uid = req.body._uid || req.query._uid; | ||||
| 					delete user.master; | ||||
|  | ||||
| 					req.login(user, function (err) { | ||||
| 						if (err) { return helpers.formatApiResponse(500, res, err); } | ||||
|  | ||||
| 						req.uid = user.uid; | ||||
| 						req.loggedIn = req.uid > 0; | ||||
| 						next(); | ||||
| 					}); | ||||
| 				} else { | ||||
| 					return helpers.formatApiResponse(400, res, new Error('A master token was received without a corresponding `_uid` in the request body')); | ||||
| 				} | ||||
| 			} else { | ||||
| 				winston.warn('[api/authenticate] Unable to find user after verifying token'); | ||||
| 				helpers.formatApiResponse(500, res); | ||||
| 			} | ||||
| 		})(req, res, next); | ||||
| 	} else { | ||||
| 		// No bearer token, reject request | ||||
| 		helpers.formatApiResponse(401, res); | ||||
| 	} | ||||
| }; | ||||
| @@ -1,6 +1,8 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const nconf = require('nconf'); | ||||
| const winston = require('winston'); | ||||
| const passport = require('passport'); | ||||
|  | ||||
| const meta = require('../meta'); | ||||
| const user = require('../user'); | ||||
| @@ -11,12 +13,49 @@ const auth = require('../routes/authentication'); | ||||
|  | ||||
| const controllers = { | ||||
| 	helpers: require('../controllers/helpers'), | ||||
| 	authentication: require('../controllers/authentication'), | ||||
| }; | ||||
|  | ||||
| module.exports = function (middleware) { | ||||
| 	async function authenticate(req, res) { | ||||
| 		if (req.loggedIn) { | ||||
| 			return true; | ||||
| 		} else if (req.headers.hasOwnProperty('authorization')) { | ||||
| 			passport.authenticate('bearer', { session: false }, function (err, user) { | ||||
| 				if (err) { throw new Error(err); } | ||||
| 				if (!user) { return false; } | ||||
|  | ||||
| 				// If the token received was a master token, a _uid must also be present for all calls | ||||
| 				if (user.hasOwnProperty('uid')) { | ||||
| 					req.login(user, async function (err) { | ||||
| 						if (err) { throw new Error(err); } | ||||
|  | ||||
| 						await controllers.authentication.onSuccessfulLogin(req, user.uid); | ||||
| 						req.uid = user.uid; | ||||
| 						req.loggedIn = req.uid > 0; | ||||
| 						return true; | ||||
| 					}); | ||||
| 				} else if (user.hasOwnProperty('master') && user.master === true) { | ||||
| 					if (req.body.hasOwnProperty('_uid') || req.query.hasOwnProperty('_uid')) { | ||||
| 						user.uid = req.body._uid || req.query._uid; | ||||
| 						delete user.master; | ||||
|  | ||||
| 						req.login(user, async function (err) { | ||||
| 							if (err) { throw new Error(err); } | ||||
|  | ||||
| 							await controllers.authentication.onSuccessfulLogin(req, user.uid); | ||||
| 							req.uid = user.uid; | ||||
| 							req.loggedIn = req.uid > 0; | ||||
| 							return true; | ||||
| 						}); | ||||
| 					} else { | ||||
| 						throw new Error('A master token was received without a corresponding `_uid` in the request body'); | ||||
| 					} | ||||
| 				} else { | ||||
| 					winston.warn('[api/authenticate] Unable to find user after verifying token'); | ||||
| 					return false; | ||||
| 				} | ||||
| 			})(req, res); | ||||
| 		} | ||||
|  | ||||
| 		await plugins.fireHook('response:middleware.authenticate', { | ||||
| @@ -180,7 +219,7 @@ module.exports = function (middleware) { | ||||
| 		req.session.returnTo = returnTo; | ||||
| 		req.session.forceLogin = 1; | ||||
| 		if (res.locals.isAPI) { | ||||
| 			res.status(401).json({}); | ||||
| 			controllers.helpers.formatApiResponse(401, res); | ||||
| 		} else { | ||||
| 			res.redirect(nconf.get('relative_path') + '/login?local=1'); | ||||
| 		} | ||||
|   | ||||
| @@ -112,7 +112,7 @@ module.exports = async function (app, middleware) { | ||||
|  | ||||
| 	await plugins.reloadRoutes({ router: router }); | ||||
| 	await authRoutes.reloadRoutes({ router: router }); | ||||
| 	await writeRoutes.reload({ router: router }); | ||||
| 	writeRoutes.reload({ router: router }); | ||||
| 	addCoreRoutes(app, router, middleware); | ||||
|  | ||||
| 	winston.info('Routes added'); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const middleware = require('../../middleware/api'); | ||||
| const middleware = require('../../middleware'); | ||||
| const helpers = require('../../controllers/helpers'); | ||||
|  | ||||
| const Write = module.exports; | ||||
| @@ -8,29 +8,32 @@ const Write = module.exports; | ||||
| Write.reload = (params) => { | ||||
| 	const router = params.router; | ||||
|  | ||||
| 	// router.use('/api', function (req, res, next) { | ||||
| 	// 	if (req.protocol !== 'https') { | ||||
| 	// 		res.set('Upgrade', 'TLS/1.0, HTTP/1.1'); | ||||
| 	// 		return helpers.formatApiResponse(426, res); | ||||
| 	// 	} else { | ||||
| 	// 		next(); | ||||
| 	// 	} | ||||
| 	// }); | ||||
| 	router.use('/api/v1', function (req, res, next) { | ||||
| 		// if (req.protocol !== 'https') { | ||||
| 		// 	res.set('Upgrade', 'TLS/1.0, HTTP/1.1'); | ||||
| 		// 	return helpers.formatApiResponse(426, res); | ||||
| 		// } else { | ||||
| 		// 	next(); | ||||
| 		// } | ||||
|  | ||||
| 	// router.use('/users', require('./users')(coreMiddleware)); | ||||
| 		res.locals.isAPI = true; | ||||
| 		next(); | ||||
| 	}); | ||||
|  | ||||
| 	router.use('/api/v1/users', require('./users')()); | ||||
| 	// router.use('/groups', require('./groups')(coreMiddleware)); | ||||
| 	// router.use('/posts', require('./posts')(coreMiddleware)); | ||||
| 	// router.use('/topics', require('./topics')(coreMiddleware)); | ||||
| 	// router.use('/categories', require('./categories')(coreMiddleware)); | ||||
| 	// router.use('/util', require('./util')(coreMiddleware)); | ||||
|  | ||||
| 	router.get('/api/ping', function (req, res) { | ||||
| 	router.get('/api/v1/ping', function (req, res) { | ||||
| 		helpers.formatApiResponse(200, res, { | ||||
| 			pong: true, | ||||
| 		}); | ||||
| 	}); | ||||
|  | ||||
| 	router.post('/api/ping', middleware.authenticate, function (req, res) { | ||||
| 	router.post('/api/v1/ping', middleware.authenticate, function (req, res) { | ||||
| 		helpers.formatApiResponse(200, res, { | ||||
| 			uid: req.user.uid, | ||||
| 		}); | ||||
|   | ||||
							
								
								
									
										177
									
								
								src/routes/write/users.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								src/routes/write/users.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const users = require('../../user'); | ||||
|  | ||||
| const middleware = require('../../middleware'); | ||||
| const helpers = require('../../controllers/helpers'); | ||||
| // 	Messaging = require.main.require('./src/messaging'), | ||||
| // 	apiMiddleware = require('./middleware'), | ||||
| // 	errorHandler = require('../../lib/errorHandler'), | ||||
| // 	auth = require('../../lib/auth'), | ||||
| // 	utils = require('./utils'), | ||||
| // 	async = require.main.require('async'); | ||||
|  | ||||
|  | ||||
| module.exports = function () { | ||||
| 	var app = require('express').Router(); | ||||
|  | ||||
| 	app.post('/', middleware.authenticate, middleware.isAdmin, async (req, res) => { | ||||
| 		helpers.checkRequired(['username'], req, res); | ||||
| 		// if (!utils.checkRequired(['username'], req, res)) { | ||||
| 		// 	return false; | ||||
| 		// } | ||||
|  | ||||
| 		const uid = await users.create(req.body); | ||||
| 		helpers.formatApiResponse(200, res, { | ||||
| 			uid: uid, | ||||
| 		}); | ||||
| 	}); | ||||
|  | ||||
| 	// 	app.route('/:uid') | ||||
| 	// 		.put(apiMiddleware.requireUser, apiMiddleware.exposeAdmin, function(req, res) { | ||||
| 	// 			if (parseInt(req.params.uid, 10) !== parseInt(req.user.uid, 10) && !res.locals.isAdmin) { | ||||
| 	// 				return errorHandler.respond(401, res); | ||||
| 	// 			} | ||||
|  | ||||
| 	// 			// `uid` in `updateProfile` refers to calling user, not target user | ||||
| 	// 			req.body.uid = req.params.uid; | ||||
|  | ||||
| 	// 			Users.updateProfile(req.user.uid, req.body, function(err) { | ||||
| 	// 				return errorHandler.handle(err, res); | ||||
| 	// 			}); | ||||
| 	// 		}) | ||||
| 	// 		.delete(apiMiddleware.requireUser, apiMiddleware.exposeAdmin, function(req, res) { | ||||
| 	// 			if (parseInt(req.params.uid, 10) !== parseInt(req.user.uid, 10) && !res.locals.isAdmin) { | ||||
| 	// 				return errorHandler.respond(401, res); | ||||
| 	// 			} | ||||
|  | ||||
| 	// 			// Clear out any user tokens belonging to the to-be-deleted user | ||||
| 	// 			async.waterfall([ | ||||
| 	// 				async.apply(auth.getTokens, req.params.uid), | ||||
| 	// 				function(tokens, next) { | ||||
| 	// 					async.each(tokens, function(token, next) { | ||||
| 	// 						auth.revokeToken(token, 'user', next); | ||||
| 	// 					}, next); | ||||
| 	// 				}, | ||||
| 	// 				async.apply(Users.delete, req.user.uid, req.params.uid) | ||||
| 	// 			], function(err) { | ||||
| 	// 				return errorHandler.handle(err, res); | ||||
| 	// 			}); | ||||
| 	// 		}); | ||||
|  | ||||
| 	// 	app.put('/:uid/password', apiMiddleware.requireUser, apiMiddleware.exposeAdmin, function(req, res) { | ||||
| 	// 		if (parseInt(req.params.uid, 10) !== parseInt(req.user.uid, 10) && !res.locals.isAdmin) { | ||||
| 	// 			return errorHandler.respond(401, res); | ||||
| 	// 		} | ||||
|  | ||||
| 	// 		Users.changePassword(req.user.uid, { | ||||
| 	// 			uid: req.params.uid, | ||||
| 	// 			currentPassword: req.body.current || '', | ||||
| 	// 			newPassword: req.body['new'] || '' | ||||
| 	// 		}, function(err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}); | ||||
|  | ||||
| 	// 	app.put('/:uid/follow', apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 		Users.follow(req.user.uid, req.params.uid, function(err) { | ||||
| 	// 			return errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}); | ||||
|  | ||||
| 	// 	app.delete('/:uid/follow', apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 		Users.unfollow(req.user.uid, req.params.uid, function(err) { | ||||
| 	// 			return errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}); | ||||
|  | ||||
| 	// 	app.route('/:uid/chats') | ||||
| 	// 		.post(apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 			if (!utils.checkRequired(['message'], req, res)) { | ||||
| 	// 				return false; | ||||
| 	// 			} | ||||
|  | ||||
| 	// 			var timestamp = parseInt(req.body.timestamp, 10) || Date.now(); | ||||
|  | ||||
| 	// 			function addMessage(roomId) { | ||||
| 	// 				Messaging.addMessage({ | ||||
| 	// 					uid: req.user.uid, | ||||
| 	// 					roomId: roomId, | ||||
| 	// 					content: req.body.message, | ||||
| 	// 					timestamp: timestamp, | ||||
| 	// 				}, function(err, message) { | ||||
| 	// 					if (parseInt(req.body.quiet, 10) !== 1) { | ||||
| 	// 						Messaging.notifyUsersInRoom(req.user.uid, roomId, message); | ||||
| 	// 					} | ||||
|  | ||||
| 	// 					return errorHandler.handle(err, res, message); | ||||
| 	// 				}); | ||||
| 	// 			} | ||||
|  | ||||
| 	// 			Messaging.canMessageUser(req.user.uid, req.params.uid, function(err) { | ||||
| 	// 				if (err) { | ||||
| 	// 					return errorHandler.handle(err, res); | ||||
| 	// 				} | ||||
|  | ||||
| 	// 				if (req.body.roomId) { | ||||
| 	// 					addMessage(req.body.roomId); | ||||
| 	// 				} else { | ||||
| 	// 					Messaging.newRoom(req.user.uid, [req.params.uid], function(err, roomId) { | ||||
| 	// 						if (err) { | ||||
| 	// 							return errorHandler.handle(err, res); | ||||
| 	// 						} | ||||
|  | ||||
| 	// 						addMessage(roomId); | ||||
| 	// 					}); | ||||
| 	// 				} | ||||
| 	// 			}); | ||||
| 	// 		}); | ||||
|  | ||||
| 	// 	app.route('/:uid/ban') | ||||
| 	// 		.put(apiMiddleware.requireUser, apiMiddleware.requireAdmin, function(req, res) { | ||||
| 	// 			Users.bans.ban(req.params.uid, req.body.until || 0, req.body.reason || '', function(err) { | ||||
| 	// 				errorHandler.handle(err, res); | ||||
| 	// 			}); | ||||
| 	// 		}) | ||||
| 	// 		.delete(apiMiddleware.requireUser, apiMiddleware.requireAdmin, function(req, res) { | ||||
| 	// 			Users.bans.unban(req.params.uid, function(err) { | ||||
| 	// 				errorHandler.handle(err, res); | ||||
| 	// 			}); | ||||
| 	// 		}); | ||||
|  | ||||
| 	// 	app.route('/:uid/tokens') | ||||
| 	// 		.get(apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 			if (parseInt(req.params.uid, 10) !== parseInt(req.user.uid, 10)) { | ||||
| 	// 				return errorHandler.respond(401, res); | ||||
| 	// 			} | ||||
|  | ||||
| 	// 			auth.getTokens(req.params.uid, function(err, tokens) { | ||||
| 	// 				return errorHandler.handle(err, res, { | ||||
| 	// 					tokens: tokens | ||||
| 	// 				}); | ||||
| 	// 			}); | ||||
| 	// 		}) | ||||
| 	// 		.post(apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 			if (parseInt(req.params.uid, 10) !== parseInt(req.user.uid)) { | ||||
| 	// 				return errorHandler.respond(401, res); | ||||
| 	// 			} | ||||
|  | ||||
| 	// 			auth.generateToken(req.params.uid, function(err, token) { | ||||
| 	// 				return errorHandler.handle(err, res, { | ||||
| 	// 					token: token | ||||
| 	// 				}); | ||||
| 	// 			}); | ||||
| 	// 		}); | ||||
|  | ||||
| 	// 	app.delete('/:uid/tokens/:token', apiMiddleware.requireUser, function(req, res) { | ||||
| 	// 		if (parseInt(req.params.uid, 10) !== req.user.uid) { | ||||
| 	// 			return errorHandler.respond(401, res); | ||||
| 	// 		} | ||||
|  | ||||
| 	// 		auth.revokeToken(req.params.token, 'user', function(err) { | ||||
| 	// 			errorHandler.handle(err, res); | ||||
| 	// 		}); | ||||
| 	// 	}); | ||||
|  | ||||
| 	return app; | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user