<commit_before>/**
 * Appcelerator Common Library for Node.js
 * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved.
 * Please see the LICENSE file for information about licensing.
 */

var i18n = require('./i18n')(__dirname),
	__ = i18n.__,
	__n = i18n.__n,
	fs = require('fs'),
	crypto = require('crypto'),
	querystring = require('querystring'),
	https = require('https'),
	uuid = require('node-uuid'),
	wrench = require('wrench'),
	
	mix = require('./util').mix,

	interfaces = require('./net').interfaces,
	afs = require('./fs'),
	analytics = require('./analytics'),

	loginHost = 'api.appcelerator.net',
	loginPath = '/p/v1/sso-login',
	logoutHost = 'api.appcelerator.net',
	logoutPath = '/p/v1/sso-logout',

	titaniumConfigFolder = afs.resolvePath('~', '.titanium'),
	sessionFile = afs.resolvePath(titaniumConfigFolder, 'auth_session.json'),
	
	statusCache,
	mid;

exports.login = function (username, password, callback) {
	var message = querystring.stringify({
			un: username,
			pw: password,
			mid: mid
		}),
		options = {
			host: loginHost,
			path: loginPath,
			port: 443,
			method: 'POST',
			headers: {
				'Content-Type': 'application/x-www-form-urlencoded',
				'Content-Length': message.length
			}
		},
		req;
	
	statusCache = null;
	
	// Otherwise we need to re-auth with the server
	req = https.request(options, function(res) {
		res.on('data', function(e) {
			var responseValid = false,
				result,
				response,
				cookie,
				p;

			try {
				response = JSON.parse(e.toString());
				if (response.success) {
					cookie = res.headers['set-cookie'];
					if (cookie.length === 1 && cookie[0].match('^PHPSESSID')) {
						responseValid = true;

						// Create the result
						result = {
							loggedIn: true,
							cookie: cookie[0],
							data: {}
						};

						// Copy over response, excluding redundant or irrelevant information
						for (p in response) {
							if (p !== 'success' && p !== 'attributes') {
								result.data[p] = response[p];
							}
						}

						// Write the data out to the session file
						if (!afs.exists(titaniumConfigFolder)) {
							wrench.mkdirSyncRecursive(titaniumConfigFolder);
						}
						fs.writeFileSync(sessionFile, JSON.stringify(result));
					}
				} else if (response.code === 4 || response.code === 5) {
					responseValid = true;
					result = {
						error: __('Invalid username or password combination. If you have forgotten your password, please visit %s.', 'https://my.appcelerator.com/'.cyan)
					};
					createLoggedOutSessionFile();
				}
			} catch(e) {}

			if (!responseValid) {
				result = {
					error: 'Invalid server response'
				};
				createLoggedOutSessionFile();
			}
			callback && callback(result);
		});
	});

	req.write(message);
	req.end();

	req.on('error', function(e) {
		createLoggedOutSessionFile();
		callback && callback({
			error: 'Error communicating with the server: ' + e
		});
	});
};

exports.logout = function (callback) {
	var result,
		session,
		req;
	
	statusCache = null;
	
	if (fs.existsSync(sessionFile)) {
		try {
			session = JSON.parse(fs.readFileSync(sessionFile));
			if (session.loggedIn) {
				req = https.request({
					host: logoutHost,
					path: logoutPath,
					port: 443,
					method: 'GET',
					headers: {
						'Cookie': session.cookie
					}
				}, function(res) {
					res.on('data', function(e) {
						try {
							response = JSON.parse(e.toString());
							result = createLoggedOutSessionFile();
							if (response.success) {
								callback && callback(mix(result, { success: true }));
							} else {
								result.error = 'Error logging out from server: ' + response.reason;
								callback && callback(result);
							}
						} catch(e) {
							result = createLoggedOutSessionFile();
							result.error = 'Invalid server response';
							callback && callback(result);
						}
					});
				});

				req.end();

				req.on('error', function(e) {
					result = createLoggedOutSessionFile();
					result.error = 'Error communicating with the server: ' + e;
					callback && callback(result);
				});
			} else {
				callback && callback(mix(session, { success: true }));
			}
		} catch(e) { // Invalid session file. This should never happen
			result = createLoggedOutSessionFile();
			callback && callback(mix(result, { success: true }));
		}
	} else { // Create a default (logged out, expired) session file
		result = createLoggedOutSessionFile();
		callback && callback(mix(result, { success: true }));
	}
};

exports.status = function () {
	if (statusCache) return statusCache;
	
	var result = {},
		session;
	
	if (fs.existsSync(sessionFile)) {
		try {
			// Fetch and parse the session data
			session = JSON.parse(fs.readFileSync(sessionFile));
			result = {
				loggedIn: session.loggedIn,
				uid: session.data && session.data.uid,
				email: session.data && session.data.email,
				cookie: session.cookie
			};
			if (!session.loggedIn) {
				// If we are offline, calculated whether or not we are expired
				if (session.offlineExpires) {
					result.offlineExpires = session.offlineExpires;
					result.expired = result.offlineExpires < Date.now();
				} else {
					result.expired = true;
				}
			}
		} catch(e) { // Invalid session file. This should never happen
			result = mix(createLoggedOutSessionFile(), { expired: true });<commit_msg>[TIMOB-11361] Added support for better logout logging<commit_after>/**
 * Appcelerator Common Library for Node.js
 * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved.
 * Please see the LICENSE file for information about licensing.
 */

var i18n = require('./i18n')(__dirname),
	__ = i18n.__,
	__n = i18n.__n,
	fs = require('fs'),
	crypto = require('crypto'),
	querystring = require('querystring'),
	https = require('https'),
	uuid = require('node-uuid'),
	wrench = require('wrench'),
	
	mix = require('./util').mix,

	interfaces = require('./net').interfaces,
	afs = require('./fs'),
	analytics = require('./analytics'),

	loginHost = 'api.appcelerator.net',
	loginPath = '/p/v1/sso-login',
	logoutHost = 'api.appcelerator.net',
	logoutPath = '/p/v1/sso-logout',

	titaniumConfigFolder = afs.resolvePath('~', '.titanium'),
	sessionFile = afs.resolvePath(titaniumConfigFolder, 'auth_session.json'),
	
	statusCache,
	mid;

exports.login = function (username, password, callback) {
	var message = querystring.stringify({
			un: username,
			pw: password,
			mid: mid
		}),
		options = {
			host: loginHost,
			path: loginPath,
			port: 443,
			method: 'POST',
			headers: {
				'Content-Type': 'application/x-www-form-urlencoded',
				'Content-Length': message.length
			}
		},
		req;
	
	statusCache = null;
	
	// Otherwise we need to re-auth with the server
	req = https.request(options, function(res) {
		res.on('data', function(e) {
			var responseValid = false,
				result,
				response,
				cookie,
				p;

			try {
				response = JSON.parse(e.toString());
				if (response.success) {
					cookie = res.headers['set-cookie'];
					if (cookie.length === 1 && cookie[0].match('^PHPSESSID')) {
						responseValid = true;

						// Create the result
						result = {
							loggedIn: true,
							cookie: cookie[0],
							data: {}
						};

						// Copy over response, excluding redundant or irrelevant information
						for (p in response) {
							if (p !== 'success' && p !== 'attributes') {
								result.data[p] = response[p];
							}
						}

						// Write the data out to the session file
						if (!afs.exists(titaniumConfigFolder)) {
							wrench.mkdirSyncRecursive(titaniumConfigFolder);
						}
						fs.writeFileSync(sessionFile, JSON.stringify(result));
					}
				} else if (response.code === 4 || response.code === 5) {
					responseValid = true;
					result = {
						error: __('Invalid username or password combination. If you have forgotten your password, please visit %s.', 'https://my.appcelerator.com/'.cyan)
					};
					createLoggedOutSessionFile();
				}
			} catch(e) {}

			if (!responseValid) {
				result = {
					error: 'Invalid server response'
				};
				createLoggedOutSessionFile();
			}
			callback && callback(result);
		});
	});

	req.write(message);
	req.end();

	req.on('error', function(e) {
		createLoggedOutSessionFile();
		callback && callback({
			error: 'Error communicating with the server: ' + e
		});
	});
};

exports.logout = function (callback) {
	var result,
		session,
		req;
	
	statusCache = null;
	
	if (fs.existsSync(sessionFile)) {
		try {
			session = JSON.parse(fs.readFileSync(sessionFile));
			if (session.loggedIn) {
				req = https.request({
					host: logoutHost,
					path: logoutPath,
					port: 443,
					method: 'GET',
					headers: {
						'Cookie': session.cookie
					}
				}, function(res) {
					res.on('data', function(e) {
						try {
							response = JSON.parse(e.toString());
							result = createLoggedOutSessionFile();
							if (response.success) {
								callback && callback(mix(result, { success: true, alreadyLoggedOut: false }));
							} else {
								result.error = 'Error logging out from server: ' + response.reason;
								callback && callback(result);
							}
						} catch(e) {
							result = createLoggedOutSessionFile();
							result.error = 'Invalid server response';
							callback && callback(result);
						}
					});
				});

				req.end();

				req.on('error', function(e) {
					result = createLoggedOutSessionFile();
					result.error = 'Error communicating with the server: ' + e;
					callback && callback(result);
				});
			} else {
				callback && callback(mix(session, { success: true, alreadyLoggedOut: true }));
			}
		} catch(e) { // Invalid session file. This should never happen
			result = createLoggedOutSessionFile();
			callback && callback(mix(result, { success: true, alreadyLoggedOut: true }));
		}
	} else { // Create a default (logged out, expired) session file
		result = createLoggedOutSessionFile();
		callback && callback(mix(result, { success: true, alreadyLoggedOut: true }));
	}
};

exports.status = function () {
	if (statusCache) return statusCache;
	
	var result = {},
		session;
	
	if (fs.existsSync(sessionFile)) {
		try {
			// Fetch and parse the session data
			session = JSON.parse(fs.readFileSync(sessionFile));
			result = {
				loggedIn: session.loggedIn,
				uid: session.data && session.data.uid,
				email: session.data && session.data.email,
				cookie: session.cookie
			};
			if (!session.loggedIn) {
				// If we are offline, calculated whether or not we are expired
				if (session.offlineExpires) {
					result.offlineExpires = session.offlineExpires;
					result.expired = result.offlineExpires < Date.now();
				} else {
					result.expired = true;
				}
			}
		} catch(e) { // Invalid session file. This should never happen
			result = mix(createLoggedOutSessionFile(), { expired: true });
{'fraction_non_alphanumeric': 0.14534506716072257, 'fraction_numerical': 0.005094951366373321, 'mean_word_length': 2.9401459854014598, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1715684', 'n_tokens_mistral': 4341, 'n_tokens_neox': 3350, 'n_words': 810}