Commit 84896536 authored by Pedro Eduardo Trujillo's avatar Pedro Eduardo Trujillo
Browse files

Refactoriza código de callbacks en server

parent faec8844
Loading
Loading
Loading
Loading
+271 −0
Original line number Diff line number Diff line
const http = require('http'),
	https = require('https'),
	jwt = require('jsonwebtoken'),

	oauthUrl = process.env.OAUTH_URL,
	oauthClientId = process.env.OAUTH_CLIENT_ID,
	oauthClientSecret = process.env.OAUTH_CLIENT_SECRET,

	oidUrl = process.env.OID_URL,
	oidClientId = process.env.OID_CLIENT_ID,
	oidClientSecret = process.env.OID_CLIENT_SECRET,
	oidPemPublicKey = process.env.OID_PEM_PUBLIC_KEY,
	oidPemPublicKeyWrap = `-----BEGIN PUBLIC KEY-----\n${oidPemPublicKey}\n-----END PUBLIC KEY-----`;

let logger, externalRequest;

function onOauthTokenRequest(req, res) {

	res.set('Content-Type', 'application/json');

	if (!oauthUrl || !oauthUrl.length) {
		logger.error('Missing OAuth URL, set it using OAUTH_URL environment variable');
		res.send('{}');
		return;
	}

	const getTokenUrl = oauthUrl + '/token',
		clientCredentials = oauthClientId + ':' + oauthClientSecret,
		internalReqBodyData = getOauthBodyData(req.body);

	onAuthTokenRequest({res, getTokenUrl, clientCredentials, internalReqBodyData});
}

function getOauthBodyData(reqBody) {

	const grantType = 'password',
		scope = 'write',
		password = encodeURIComponent(reqBody.password),
		username = encodeURIComponent(reqBody.username);

	return `grant_type=${grantType}&username=${username}&password=${password}&scope=${scope}`;
}

function onOauthRevokeRequest(req, res) {

	res.set('Content-Type', 'application/json');

	if (!oauthUrl || !oauthUrl.length) {
		logger.error('Missing OAuth URL, set it using OAUTH_URL environment variable');
		res.send('{}');
		return;
	}

	const revokeTokenUrl = `${oauthUrl}/token/revoke`,
		tokenToRevoke = req.body.token,
		revokeTokenBodyData = `{"token":"${tokenToRevoke}"}`;

	const revokeTokenHeaders = {
		'Content-Type': 'application/json',
		'Authorization': `Bearer ${tokenToRevoke}`
	};

	onAuthTokenRevoke({res, revokeTokenUrl, revokeTokenHeaders, revokeTokenBodyData});
}

function onOidTokenRequest(req, res) {

	res.set('Content-Type', 'application/json');

	if (!oidUrl || !oidUrl.length) {
		logger.error('Missing OpenID URL, set it using OID_URL environment variable');
		res.send('{}');
		return;
	}

	const getTokenUrl = oidUrl + '/token',
		clientCredentials = oidClientId + ':' + oidClientSecret,
		reqBody = req.body;

	let internalReqBodyData;

	if (!!reqBody.refresh_token) {
		internalReqBodyData = getOidRefreshTokenBodyData(reqBody);
	} else {
		internalReqBodyData = getOidPasswordBodyData(reqBody);
	}

	onAuthTokenRequest({res, getTokenUrl, clientCredentials, internalReqBodyData});
}

function getOidPasswordBodyData(reqBody) {

	const grantType = 'password',
		password = encodeURIComponent(reqBody.password),
		username = encodeURIComponent(reqBody.username);

	return `grant_type=${grantType}&username=${username}&password=${password}`;
}

function getOidRefreshTokenBodyData(reqBody) {

	const grantType = 'refresh_token',
		refreshToken = encodeURIComponent(reqBody.refresh_token);

	return `grant_type=${grantType}&refresh_token=${refreshToken}`;
}

function onAuthTokenRequest(params) {

	const base64ClientCredentials = Buffer.from(params.clientCredentials).toString('base64');

	const options = {
		method: 'POST',
		headers: {
			'Content-Type': 'application/x-www-form-urlencoded',
			'Authorization': 'Basic ' + base64ClientCredentials
		}
	};

	const getTokenUrl = params.getTokenUrl,
		res = params.res,
		internalReqBodyData = params.internalReqBodyData;

	const bindParams = {
		originalRes: res,
		onError: onAuthTokenRequestError
	};

	const reqLibrary = getTokenUrl.indexOf('https') === -1 ? http : https;

	const internalReq = reqLibrary.request(getTokenUrl, options,
		externalRequest.onOwnRequestResponse.bind(this, bindParams));

	internalReq.on('error', onAuthTokenRequestError.bind(this, res));

	internalReq.write(internalReqBodyData);
	internalReq.end();
}

function onAuthTokenRequestError(originalRes, err) {

	if (this.statusCode < 500) {
		onAuthTokenClientError.bind(this)(originalRes, err);
		return;
	}

	externalRequest.onOwnRequestError.bind(this)(originalRes, err);
}

function onOidRevokeRequest(req, res) {

	res.set('Content-Type', 'application/json');

	if (!oidUrl || !oidUrl.length) {
		logger.error('Missing OpenID URL, set it using OID_URL environment variable');
		res.send('{}');
		return;
	}

	const revokeTokenUrl = `${oidUrl}/revoke`,
		clientCredentials = `${oidClientId}:${oidClientSecret}`,
		base64ClientCredentials = Buffer.from(clientCredentials).toString('base64'),
		tokenToRevoke = req.body.token,
		revokeTokenBodyData = `token=${tokenToRevoke}`;

	const revokeTokenHeaders = {
		'Content-Type': 'application/x-www-form-urlencoded',
		'Authorization': `Basic ${base64ClientCredentials}`
	};

	onAuthTokenRevoke({res, revokeTokenUrl, revokeTokenHeaders, revokeTokenBodyData});
}

function onAuthTokenRevoke(params) {

	const options = {
		method: 'POST',
		headers: params.revokeTokenHeaders
	};

	const revokeTokenUrl = params.revokeTokenUrl,
		res = params.res;

	const bindParams = {
		originalRes: res,
		onError: onAuthTokenRevokeError
	};

	const reqLibrary = revokeTokenUrl.indexOf('https') === -1 ? http : https;

	const internalReq = reqLibrary.request(revokeTokenUrl, options,
		externalRequest.onOwnRequestResponse.bind(this, bindParams));

	internalReq.on('error', onAuthTokenRevokeError.bind(this, res));

	internalReq.write(params.revokeTokenBodyData);
	internalReq.end();
}

function onAuthTokenRevokeError(originalRes, err) {

	if (this.statusCode < 500) {
		onAuthTokenClientError.bind(this)(originalRes, err);
		return;
	}

	externalRequest.onOwnRequestError.bind(this)(originalRes, err);
}

function onAuthTokenClientError(originalRes, err) {

	const error = JSON.parse(err);

	originalRes.set('Content-Type', 'application/json');

	originalRes.status(this.statusCode).send({
		code: error.error,
		description: error.error_description
	});

	logger.error(err);
}

function onOidTokenPayloadRequest(req, res) {

	const token = req.body.token;

	res.set('Content-Type', 'application/json');

	if (token?.length) {
		jwt.verify(token, oidPemPublicKeyWrap, (err, decoded) => jwtVerifyCallback(err, decoded, res));
		return;
	}

	res.status(400).send({
		code: 'Client error',
		description: 'Something went wrong. Please, check your request and try again.'
	});

	logger.error('Missing "token" parameter at request body');
}

function jwtVerifyCallback(err, verifiedPayload, res) {

	if (!err) {
		res.send(verifiedPayload);
		return;
	}

	res.status(500).send({
		code: 'Server error',
		description: 'Something went wrong at server. Please, try again.'
	});

	const errorMessage = err instanceof Object ? err.toString() : err;
	logger.error(errorMessage);
}

module.exports = function(loggerParameter, externalRequest) {

	logger = loggerParameter;
	externalRequest = externalRequest;

	return {
		onOauthTokenRequest,
		onOauthRevokeRequest,
		onOidTokenRequest,
		onOidRevokeRequest,
		onOidTokenPayloadRequest
	};
};
+106 −0
Original line number Diff line number Diff line
const production = !!parseInt(process.env.PRODUCTION, 10),
	apiUrl = process.env.API_URL;

let logger, params, version, robotsContent;

function onGeneralRequest(req, res) {

	res.render('index', {
		env: getEnv(req)
	});
}

function onActivateAccountRequest(req, res) {

	res.render('activateAccount', {
		env: getEnv(req),
		token: req.params.token
	});
}

function onNoSupportBrowserRequest(req, res) {

	res.render('noSupportBrowser', {
		env: getEnv(req)
	});
}

function on404Request(req, res) {

	res.status(404);
	res.render('404', {
		env: getEnv(req)
	});
}

function getEnv(req) {

	return {
		version: version,
		useBuilt: params.useBuilt,
		debug: params.debug,
		apiUrl: apiUrl,
		production: production,
		lang: getLang(req)
	};
}

function getLang(req) {

	return req && req.headers && req.headers['content-language'] || params.lang;
}

function onNullableJsRequest(_req, res) {

	res.set('Content-Type', 'text/javascript');
	res.send('');
}

function onUnknownRequest(_req, res, _next) {

	res.redirect('/404');
}

function onRobotsRequest(req, res) {

	res.set('Content-Type', 'text/plain');

	if (!robotsContent || !robotsContent.length) {
		const userAgentLine = 'User-agent: *\n';

		robotsContent = userAgentLine;

		if (production) {
			const apiPath = '/api',
				disallowApiLine = 'Disallow: ' + apiPath + '\n',
				allowAllLine = 'Allow: /\n',
				sitemapPath = 'https://' + req.hostname + '/sitemap.xml',
				sitemapLine = 'Sitemap: ' + sitemapPath;

			robotsContent += disallowApiLine + allowAllLine + '\n' + sitemapLine;
		} else {
			const disallowAllLine = 'Disallow: /';

			robotsContent += disallowAllLine;
		}
	}

	res.send(robotsContent);
}

module.exports = function(loggerParameter, paramsParameter, versionParameter) {

	logger = loggerParameter;
	params = paramsParameter;
	version = versionParameter;

	return {
		onGeneralRequest,
		onActivateAccountRequest,
		onNoSupportBrowserRequest,
		on404Request,
		onNullableJsRequest,
		onUnknownRequest,
		onRobotsRequest
	};
};
+101 −0
Original line number Diff line number Diff line
const http = require('http'),
	https = require('https'),

	configUrl = process.env.CONFIG_URL,
	configExpirationMs = 3600000,

	sitemapUrl = process.env.SITEMAP_URL,
	sitemapExpirationMs = 36000000;

let logger, externalRequest, configContent, configLastUpdated, sitemapContent, sitemapLastUpdated;

function onConfigRequest(req, res) {

	res.set('Content-Type', 'application/json');

	if (!configContent || !configContent.length || req.query.forceRefresh ||
		configLastUpdated < Date.now() - configExpirationMs) {

		const afterResponseCallback = (successful, content) => {

			if (!successful) {
				configContent = '';
				return;
			}

			configContent = content;
			configLastUpdated = Date.now();
		};

		if (!configUrl || !configUrl.length) {
			logger.error('Missing config URL, set it using CONFIG_URL environment variable');
			res.send('{}');
			return;
		}

		const reqLibrary = configUrl.indexOf('https') === -1 ? http : https;

		const internalReq = reqLibrary.request(configUrl, externalRequest.onOwnRequestResponse.bind(this, {
			originalRes: res,
			afterResponse: afterResponseCallback
		}));

		internalReq.on('error', externalRequest.onOwnRequestError.bind(this, res));

		internalReq.end();
	} else {
		res.send(configContent);
	}
}

function onSitemapRequest(_req, res) {

	res.set('Content-Type', 'text/xml');

	if (!sitemapContent || !sitemapContent.length || sitemapLastUpdated < Date.now() - sitemapExpirationMs) {
		const afterResponseCallback = (successful, content) => {

			if (!successful) {
				sitemapContent = '';
				return;
			}

			sitemapContent = content;
			sitemapLastUpdated = Date.now();
		};

		if (!sitemapUrl || !sitemapUrl.length) {
			logger.error('Missing sitemap URL, set it using SITEMAP_URL environment variable');

			const emptySitemap = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset ' +
				'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"/>';

			res.send(emptySitemap);
			return;
		}

		const reqLibrary = sitemapUrl.indexOf('https') === -1 ? http : https;

		const internalReq = reqLibrary.request(sitemapUrl, externalRequest.onOwnRequestResponse.bind(this, {
			originalRes: res,
			afterResponse: afterResponseCallback
		}));

		internalReq.on('error', externalRequest.onOwnRequestError.bind(this, res));

		internalReq.end();
	} else {
		res.send(sitemapContent);
	}
}

module.exports = function(loggerParameter, externalRequestParameter) {

	logger = loggerParameter;
	externalRequest = externalRequestParameter;

	return {
		onConfigRequest,
		onSitemapRequest
	};
};
+32 −156
Original line number Diff line number Diff line
const express = require('express'),
	path = require('path'),
	bodyParser = require('body-parser'),
	jwt = require('jsonwebtoken'),
	bodyParser = require('body-parser');

	production = !!parseInt(process.env.PRODUCTION, 10),
	apiUrl = process.env.API_URL,
	oidPemPublicKey = process.env.OID_PEM_PUBLIC_KEY,
	oidPemPublicKeyWrap = `-----BEGIN PUBLIC KEY-----\n${oidPemPublicKey}\n-----END PUBLIC KEY-----`;
let params, commonCallbacks, dataCallbacks, authCallbacks;

let logger, params, version, robotsContent, externalRequest;

function getLang(req) {

	return req && req.headers && req.headers['content-language'] || params.lang;
}

function getEnv(req) {

	return {
		version: version,
		useBuilt: params.useBuilt,
		debug: params.debug,
		apiUrl: apiUrl,
		production: production,
		lang: getLang(req)
	};
}

function onGeneralRequest(req, res) {

	res.render('index', {
		env: getEnv(req)
	});
}

function onActivateAccountRequest(req, res) {

	res.render('activateAccount', {
		env: getEnv(req),
		token: req.params.token
	});
}

function onNoSupportBrowserRequest(req, res) {

	res.render('noSupportBrowser', {
		env: getEnv(req)
	});
}

function on404Request(req, res) {

	res.status(404);
	res.render('404', {
		env: getEnv(req)
	});
}

function onRobotsRequest(req, res) {

	res.set('Content-Type', 'text/plain');

	if (!robotsContent || !robotsContent.length) {
		const userAgentLine = 'User-agent: *\n';

		robotsContent = userAgentLine;

		if (production) {
			const apiPath = '/api',
				disallowApiLine = 'Disallow: ' + apiPath + '\n',
				allowAllLine = 'Allow: /\n',
				sitemapPath = 'https://' + req.hostname + '/sitemap.xml',
				sitemapLine = 'Sitemap: ' + sitemapPath;

			robotsContent += disallowApiLine + allowAllLine + '\n' + sitemapLine;
		} else {
			const disallowAllLine = 'Disallow: /';

			robotsContent += disallowAllLine;
		}
	}

	res.send(robotsContent);
}

function onNullableJsRequest(_req, res) {

	res.set('Content-Type', 'text/javascript');
	res.send('');
}

function onUnknownRequest(_req, res, _next) {

	res.redirect('/404');
}

function onOidTokenPayloadRequest(req, res) {

	const token = req.body.token;

	res.set('Content-Type', 'application/json');

	if (token?.length) {
		jwt.verify(token, oidPemPublicKeyWrap, (err, decoded) => jwtVerifyCallback(err, decoded, res));
		return;
	}

	res.status(400).send({
		code: 'Client error',
		description: 'Something went wrong. Please, check your request and try again.'
	});

	logger.error('Missing "token" parameter at request body');
}
function expose(app) {

function jwtVerifyCallback(err, verifiedPayload, res) {
	app.use(express.urlencoded({ extended: false }));

	if (!err) {
		res.send(verifiedPayload);
		return;
	if (!params.useBuilt) {
		require('./styles')(app);
		exposeContents(app, 'node_modules');
	}

	res.status(500).send({
		code: 'Server error',
		description: 'Something went wrong at server. Please, try again.'
	});

	const errorMessage = err instanceof Object ? err.toString() : err;
	logger.error(errorMessage);
}
	exposeContents(app, 'client-app');

function exposeRoutes(app) {
	app.set('view engine', 'pug')
		.set('views', path.join(__dirname, '..', 'views'));

	app.get('/activateAccount/:token', onActivateAccountRequest)
		.get('/noSupportBrowser', onNoSupportBrowserRequest)
		.get('/404', on404Request)
		.get('/config', externalRequest.onConfigRequest)
		.get('/sitemap.xml', externalRequest.onSitemapRequest)
		.get('/robots.txt', onRobotsRequest)
		.get(/^.+\.js$/, onNullableJsRequest)
		.get(/.*/, onGeneralRequest)
		.post('/oauth/revoke', bodyParser.json(), externalRequest.onOauthRevokeRequest)
		.post('/oauth/token', externalRequest.onOauthTokenRequest)
		.post('/oid/revoke', bodyParser.json(), externalRequest.onOidRevokeRequest)
		.post('/oid/token', externalRequest.onOidTokenRequest)
		.post('/oid/refresh', bodyParser.json(), externalRequest.onOidTokenRequest)
		.post('/oid/payload', bodyParser.json(), onOidTokenPayloadRequest)
		.use(onUnknownRequest);
	exposeRoutes(app);
}

function exposeContents(app, directoryName) {
@@ -164,30 +36,34 @@ function exposeContents(app, directoryName) {
		.use('/' + directoryName, servedPath);
}

function expose(app) {

	app.use(express.urlencoded({ extended: false }));

	if (!params.useBuilt) {
		require('./styles')(app);
		exposeContents(app, 'node_modules');
	}

	exposeContents(app, 'client-app');

	app.set('view engine', 'pug')
		.set('views', path.join(__dirname, '..', 'views'));
function exposeRoutes(app) {

	exposeRoutes(app);
	app.get('/activateAccount/:token', commonCallbacks.onActivateAccountRequest)
		.get('/noSupportBrowser', commonCallbacks.onNoSupportBrowserRequest)
		.get('/404', commonCallbacks.on404Request)
		.get('/robots.txt', commonCallbacks.onRobotsRequest)
		.get('/config', dataCallbacks.onConfigRequest)
		.get('/sitemap.xml', dataCallbacks.onSitemapRequest)
		.get(/^.+\.js$/, commonCallbacks.onNullableJsRequest)
		.get(/.*/, commonCallbacks.onGeneralRequest)
		.post('/oauth/revoke', bodyParser.json(), authCallbacks.onOauthRevokeRequest)
		.post('/oauth/token', authCallbacks.onOauthTokenRequest)
		.post('/oid/revoke', bodyParser.json(), authCallbacks.onOidRevokeRequest)
		.post('/oid/token', authCallbacks.onOidTokenRequest)
		.post('/oid/refresh', bodyParser.json(), authCallbacks.onOidTokenRequest)
		.post('/oid/payload', bodyParser.json(), authCallbacks.onOidTokenPayloadRequest)
		.use(commonCallbacks.onUnknownRequest);
}

module.exports = function(loggerParameter, paramsParameter, versionParameter) {

	logger = loggerParameter;
	const externalRequest = require('./externalRequest')(loggerParameter);

	params = paramsParameter;
	version = versionParameter;

	externalRequest = require('./externalRequest')(logger);
	commonCallbacks = require('./common-callbacks')(loggerParameter, params, versionParameter);
	dataCallbacks = require('./data-callbacks')(loggerParameter, externalRequest);
	authCallbacks = require('./auth-callbacks')(loggerParameter, externalRequest);

	return {
		exposeApp: expose
+3 −308

File changed.

Preview size limit exceeded, changes collapsed.