kopia lustrzana https://github.com/c9/core
198 wiersze
6.7 KiB
JavaScript
198 wiersze
6.7 KiB
JavaScript
|
define(function(require, exports, module) {
|
||
|
"use strict";
|
||
|
|
||
|
main.consumes = ["Plugin", "http", "auth.bootstrap"];
|
||
|
main.provides = ["auth"];
|
||
|
return main;
|
||
|
|
||
|
function main(options, imports, register) {
|
||
|
var Plugin = imports.Plugin;
|
||
|
var http = imports.http;
|
||
|
var _login = imports["auth.bootstrap"].login;
|
||
|
|
||
|
/***** Initialization *****/
|
||
|
|
||
|
var ANONYMOUS = -1;
|
||
|
|
||
|
var plugin = new Plugin("Ajax.org", main.consumes);
|
||
|
var emit = plugin.getEmitter();
|
||
|
var accessToken = options.accessToken || "";
|
||
|
var apiUrl = options.apiUrl || "";
|
||
|
var ideBaseUrl = options.ideBaseUrl;
|
||
|
var uid = options.userId;
|
||
|
var loggedIn = true;
|
||
|
var checkLoop = createLoopDetector(3, 20 * 1000);
|
||
|
|
||
|
/***** Methods *****/
|
||
|
|
||
|
function request(url, options, callback) {
|
||
|
if (!callback)
|
||
|
return request(url, {}, options);
|
||
|
|
||
|
if (loggingIn) {
|
||
|
var onLogin = function() {
|
||
|
plugin.off("login", onLogin);
|
||
|
request(url, options, callback);
|
||
|
};
|
||
|
plugin.on("login", onLogin);
|
||
|
return { abort: function() { plugin.off("login", onLogin); }};
|
||
|
}
|
||
|
|
||
|
options.query = options.query || {};
|
||
|
|
||
|
// TODO try also using the Authorization header
|
||
|
if (accessToken)
|
||
|
options.query.access_token = accessToken;
|
||
|
|
||
|
return http.request(url, options, function(err, data, res) {
|
||
|
// If we get a 'forbidden' status code login again and retry
|
||
|
if (res && res.status == 401 && !options.noLogin) {
|
||
|
if (!checkLoop(url)) {
|
||
|
console.trace("Login loop detected for URL " + url);
|
||
|
return callback(new Error("Login loop detected!"));
|
||
|
}
|
||
|
|
||
|
plugin.once("login", function() {
|
||
|
request(url, options, callback);
|
||
|
});
|
||
|
login();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
callback(err, data, res);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var loggingIn = false;
|
||
|
function login(checkLogin) {
|
||
|
if (loggingIn) {
|
||
|
if (!checkLogin)
|
||
|
return;
|
||
|
else
|
||
|
loggingIn();
|
||
|
}
|
||
|
|
||
|
emit("loggingin");
|
||
|
|
||
|
loggingIn = _login(function(err, token) {
|
||
|
loggingIn = false;
|
||
|
accessToken = token;
|
||
|
|
||
|
request(apiUrl + "/user", function(err, user) {
|
||
|
if (err || !user) {
|
||
|
if (options.cli)
|
||
|
console.warn("Invalid username or password. Please try again.");
|
||
|
else
|
||
|
console.warn("LOGIN: API /user err", err);
|
||
|
return setTimeout(login, 1000);
|
||
|
}
|
||
|
|
||
|
if (user.id !== ANONYMOUS) {
|
||
|
loggedIn = true;
|
||
|
if (uid != user.id) {
|
||
|
uid = user.id;
|
||
|
emit("relogin", {uid: user.id});
|
||
|
}
|
||
|
// "login" or "logout" event is always dispatched after "loggingin" event
|
||
|
emit("login", {uid: user.id, oldUid: uid});
|
||
|
} else {
|
||
|
loggedIn = false;
|
||
|
emit("logout", {uid: user.id, newUid: ANONYMOUS});
|
||
|
}
|
||
|
});
|
||
|
}, function() {
|
||
|
if (uid != ANONYMOUS) {
|
||
|
emit("logout", {uid: uid, newUid: ANONYMOUS});
|
||
|
}
|
||
|
}) || true;
|
||
|
}
|
||
|
|
||
|
function logout(redirect) {
|
||
|
emit("logout-analytics");
|
||
|
|
||
|
redirect = redirect || window.location.href;
|
||
|
window.location.href = ideBaseUrl + "/api/nc/logout?redirect=" + encodeURIComponent(redirect);
|
||
|
}
|
||
|
|
||
|
function createLoopDetector(count, duration) {
|
||
|
var log = {};
|
||
|
|
||
|
return function check(url) {
|
||
|
var now = Date.now();
|
||
|
|
||
|
var calls = log[url];
|
||
|
if (!calls) {
|
||
|
log[url] = [now];
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
while (calls.length && calls[0] < now - duration) {
|
||
|
calls.shift();
|
||
|
}
|
||
|
|
||
|
calls.push(now);
|
||
|
return calls.length < count;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/***** Register and define API *****/
|
||
|
|
||
|
/**
|
||
|
* Provides login information
|
||
|
* @singleton
|
||
|
**/
|
||
|
plugin.freezePublicAPI({
|
||
|
|
||
|
_events: [
|
||
|
"loggingin",
|
||
|
"login",
|
||
|
"logout"
|
||
|
],
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
get loggedIn() { return loggedIn; },
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
get loggingIn() { return loggingIn; },
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
get accessToken() { return accessToken; },
|
||
|
set accessToken(v) { accessToken = v; loggedIn = true;},
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
login: login,
|
||
|
|
||
|
/**
|
||
|
* @param {Function} [callback]
|
||
|
*/
|
||
|
logout: logout,
|
||
|
|
||
|
/**
|
||
|
* Wrapper for http.request which adds authorization information to
|
||
|
* the request
|
||
|
*
|
||
|
* @param {String} url target URL for the HTTP request
|
||
|
* @param {Object} options optional request options. Same format
|
||
|
* as {@link http#request http.request}.
|
||
|
* @param {Function} callback Called when the request returns.
|
||
|
* @param {Error} callback.err Error object if an error occured.
|
||
|
* @param {String} callback.data The data received.
|
||
|
* @param {Object} callback.res
|
||
|
* @param {String} callback.res.body The body of the response message.
|
||
|
* @param {Number} callback.res.status The status of the response message.
|
||
|
* @param {Object} callback.res.headers The headers of the response message.
|
||
|
*/
|
||
|
request: request
|
||
|
});
|
||
|
|
||
|
register(null, {
|
||
|
auth: plugin
|
||
|
});
|
||
|
}
|
||
|
});
|