HEX
Server: nginx/1.24.0
System: Linux nowruzgan 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64
User: babak (1000)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: //var/dev/farhangmoaser/web/routes/api/1.0/auth.js
/**
 * Express endpoints for /auth address
 * Version: 0.1
 * Author: Babak Vandad
 *
 * Restful api for addresses:
 * 		GET			/auth
 * 		GET			/auth/local
 * 		GET			/auth/local/fail
 * 		GET			/auth/app
 * 		GET			/auth/app/fail
 * 		GET			/auth/google
 * 		GET			/auth/google/return
 * 		GET			/auth/landing
 * 		GET			/auth/google/fail
 */

var path = require('path');
var express = require('express');
var passport = require('passport');
var db = require(path.join(BASEDIR, 'connectors/mysql'));
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var LocalStrategy = require('passport-local').Strategy;
var LocalAPIKeyStrategy = require('passport-localapikey').Strategy;

var authHelper = require(path.join(BASEDIR, 'helpers/auth'));

var router = express.Router();
var UserModel = require(path.join(BASEDIR, 'models/user'));
var AppModel = require(path.join(BASEDIR, 'models/app'));
var config = require(path.join(BASEDIR, 'config.js'));
var consts = require(path.join(BASEDIR, 'consts.js'));

var GOOGLE_CLIENT_ID = "184976576455-riqlc7naqqke24trp0jqu79klo0u1onj.apps.googleusercontent.com";
var GOOGLE_CLIENT_SECRET = "PfptydZsKhv_j3361AFMGt3H";
var SCOPE_GOOGLE_PLUS = 'https://www.googleapis.com/auth/plus.login';
var SCOPE_GOOGLE_USERINFO = 'https://www.googleapis.com/auth/userinfo.email';

/**
 * Fail a request by releasing database connection, rollback transaction
 * and sending the proper error code and message with 4xx or 5xx status codes.
 * @param  {object}		express response object
 * @param  {object}		error object from costs.js
 * @param  {integer}	override status code (if you want to send 200 instead of 4xx/5xx)
 * @return {function}	the function to fail the request.
 */
var fail = function(response, error, status){
	return function(){
		response.status(status ? status : error.status).json({error: error.code, message: error.message});
	};
};

/* loading google strategy for passport */
passport.use(new GoogleStrategy({
		clientID: GOOGLE_CLIENT_ID,
		clientSecret: GOOGLE_CLIENT_SECRET,
		callbackURL: config.read('client.hostname')+"/auth/google/return"
	}, function(accessToken, refreshToken, profile, done) {
		process.nextTick(function () {
			return done(null, profile);
		});
	}
));

/* loading local user/pass strategy for passport */
passport.use(new LocalStrategy({usernameField: 'email', passwordField: 'password'},
	function(email, password, done) {
		db.getConnection(function(err, conn){
			if(err) return done(null, false, err);
			UserModel.authenticate(conn, email, password).then(
				user => done(null, user),
				errmsg => done(null, false, {message: errmsg})
			);
		});
	}
));

/* loading local api key strategy for passport */
passport.use(new LocalAPIKeyStrategy({apiKeyField: 'key'},
	function(apikey, done) {
		db.getConnection(function(err, conn){
			if(err) return done(null, false, err);
			var app = new AppModel(conn, {key: apikey});
			app.load().then(
				function () {
					return done(null, app);
				}, function(errmsg) {
					return done(null, false, {message: errmsg});
				}
			);
		});
	}
));

passport.serializeUser(authHelper.serialize);
passport.deserializeUser(authHelper.deserialize);

/* login page */
router.get('/', function(req, res){
	if(req.isAuthenticated()) {
		var target = config.read('client.path');
		if(req.query.hasOwnProperty('target'))
			target = req.query.target;
		res.redirect(target);
	}else {
		if(req.query.hasOwnProperty('login_target'))
			req.session.login_target = req.query.target;
		res.redirect(config.read('client.path')+'/auth/google');
	}
});

/* login with username/password */
router.get('/local',
	passport.authenticate('local', {failureRedirect: config.read('client.path')+'api/1.0/auth/local/fail'}),
	function(req, res) {
		let userData = req.user.data;
		delete userData.id;
		delete userData.password;
		delete userData.searchable;
		delete userData.sortable;
		delete userData.activationKey;

		let subscriptions = req.user.subscriptions.map(subscription => ({
			book: subscription.book,
			book_title: subscription.book_title,
			dateExpire: subscription.dateExpire,
			dateStart: subscription.dateStart,
			state: subscription.state
		}));
		return res.json({token: req.user.token, user: {data: userData, subscriptions: subscriptions, token: req.user.token}});
	}
/* failure message */
).get('/local/fail', function(req, res){
	fail(res, consts.e.ERR_AUTH)();
});

/* login with api key */
router.get('/app',
	passport.authenticate('localapikey', {session: false, failureRedirect: config.read('client.path')+'api/1.0/auth/app/fail'}),
	function(req, res) {
		authHelper.serialize(req.user, function(err, token){
			if(err) return fail(res, consts.e.ERR_SERIALIZATION_ERROR)();
			else{
				var userData = req.user.data;
				delete userData.id;
				delete userData.password;
				delete userData.searchable;
				delete userData.sortable;
				delete userData.activationKey;
				return res.json({token: token, app: {data: userData, token: req.user.token}});
			}
		})
	}
/* failure message */
).get('/local/fail', function(req, res){
	fail(res, consts.e.ERR_AUTH)();
});

/* login with google account */
router.get('/google', passport.authenticate('google', {scope: [SCOPE_GOOGLE_PLUS, SCOPE_GOOGLE_USERINFO]}));
/* callback from google */
router.get('/google/return',
	passport.authenticate('google', {failureFlash: true, failureRedirect: config.read('client.path')+'auth/google/fail' }),
	function(req, res) {
		res.redirect(config.read('client.path')+'/auth/landing');
	});
/* after successfull login */
router.get('/landing',
	function(req, res, next) {
		var target = '/';
		if(req.session.hasOwnProperty('login_target')) {
			target = req.session.login_target;
			delete req.session.login_target;
		}
		if(req.isAuthenticated())
			res.render('auth/landing', {userdata: req.user, target: target});
		else
			res.send('not authenticated.');
	});
/* failure message */
router.get('/google/fail',
	function(req, res, next) {
		var errmessage = '';
		if(req.session.hasOwnProperty('errmessage'))
			errmessage = req.session.errmessage;

		res.render('auth/google_failure', {message: errmessage});
	}
);

module.exports = router;