This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/static/js/services/user-service.js
Joseph Schorr 188ea98441 Add new decorator to prevent reflected text attacks
Instead of disabling repo names with periods in them, we simply disallow calls to the API when they are GET requests, whose path ends in a dot, and that do not have a referrer from the frontend.
2018-02-20 11:33:45 -05:00

255 lines
6.7 KiB
JavaScript

import * as Raven from 'raven-js';
/**
* Service which monitors the current user session and provides methods for returning information
* about the user.
*/
angular.module('quay')
.factory('UserService', ['ApiService', 'CookieService', '$rootScope', 'Config', '$location', '$timeout',
function(ApiService, CookieService, $rootScope, Config, $location, $timeout) {
var userResponse = {
verified: false,
anonymous: true,
username: null,
email: null,
organizations: [],
logins: [],
beforeload: true
};
var userService = {};
var _EXTERNAL_SERVICES = ['ldap', 'jwtauthn', 'keystone', 'dex'];
userService.hasEverLoggedIn = function() {
return CookieService.get('quay.loggedin') == 'true';
};
userService.updateUserIn = function(scope, opt_callback) {
scope.$watch(function () { return userService.currentUser(); }, function (currentUser) {
if (currentUser) {
$timeout(function(){
scope.user = currentUser;
if (opt_callback) {
opt_callback(currentUser);
}
}, 0, false);
};
}, true);
};
userService.load = function(opt_callback) {
var handleUserResponse = function(loadedUser) {
userResponse = loadedUser;
if (!userResponse.anonymous) {
if (Config.MIXPANEL_KEY) {
try {
mixpanel.identify(userResponse.username);
mixpanel.people.set({
'$email': userResponse.email,
'$username': userResponse.username,
'verified': userResponse.verified
});
mixpanel.people.set_once({
'$created': new Date()
})
} catch (e) {
window.console.log(e);
}
}
if (Config.MARKETO_MUNCHKIN_ID && userResponse['marketo_user_hash']) {
var associateLeadBody = {'Email': userResponse.email};
if (window.Munchkin !== undefined) {
try {
Munchkin.munchkinFunction(
'associateLead',
associateLeadBody,
userResponse['marketo_user_hash']
);
} catch (e) {
}
} else {
window.__quay_munchkin_queue.push([
'associateLead',
associateLeadBody,
userResponse['marketo_user_hash']
]);
}
}
if (window.Raven !== undefined) {
try {
Raven.setUser({
email: userResponse.email,
id: userResponse.username
});
} catch (e) {
window.console.log(e);
}
}
CookieService.putPermanent('quay.loggedin', 'true');
} else {
if (window.Raven !== undefined) {
Raven.setUser();
}
}
// If the loaded user has a prompt, redirect them to the update page.
if (loadedUser.prompts && loadedUser.prompts.length) {
$location.path('/updateuser');
return;
}
if (opt_callback) {
opt_callback(loadedUser);
}
};
ApiService.getLoggedInUser().then(function(loadedUser) {
handleUserResponse(loadedUser);
}, function() {
handleUserResponse({'anonymous': true});
});
};
userService.isOrganization = function(name) {
return !!userService.getOrganization(name);
};
userService.getOrganization = function(name) {
if (!userResponse || !userResponse.organizations) { return null; }
for (var i = 0; i < userResponse.organizations.length; ++i) {
var org = userResponse.organizations[i];
if (org.name == name) {
return org;
}
}
return null;
};
userService.isNamespaceAdmin = function(namespace) {
if (namespace == userResponse.username) {
return true;
}
var org = userService.getOrganization(namespace);
if (!org) {
return false;
}
return org.is_org_admin;
};
userService.isKnownNamespace = function(namespace) {
if (namespace == userResponse.username) {
return true;
}
var org = userService.getOrganization(namespace);
return !!org;
};
userService.getNamespace = function(namespace) {
var org = userService.getOrganization(namespace);
if (org) {
return org;
}
if (namespace == userResponse.username) {
return userResponse;
}
return null;
};
userService.getCLIUsername = function() {
if (!userResponse) {
return null;
}
var externalUsername = null;
userResponse.logins.forEach(function(login) {
if (_EXTERNAL_SERVICES.indexOf(login.service) >= 0) {
externalUsername = login.service_identifier;
}
});
return externalUsername || userResponse.username;
};
userService.deleteNamespace = function(info, callback) {
var namespace = info.user ? info.user.username : info.organization.name;
if (!namespace) {
return;
}
var errorDisplay = ApiService.errorDisplay('Could not delete namespace', callback);
var deleteNamespaceItself = function() {
info.progress = 1;
info.progressMessage = 'Deleting namespace...';
var cb = function(resp) {
userService.load(function(currentUser) {
callback(true);
$location.path('/');
});
}
if (info.user) {
ApiService.deleteCurrentUser().then(cb, errorDisplay)
} else {
var delParams = {
'orgname': info.organization.name
};
ApiService.deleteAdminedOrganization(null, delParams).then(cb, errorDisplay);
}
};
var repoIndex = 0;
var repositories = null;
var deleteAllRepos = function() {
if (repoIndex >= repositories.length) {
deleteNamespaceItself();
return;
}
var repoParams = {
'repository': namespace + '/' + repositories[repoIndex]['name']
};
info.progress = repoIndex / repositories.length;
info.progressMessage = 'Deleting repository ' + repoParams['repository'] + '...';
ApiService.deleteRepository(null, repoParams).then(function() {
repoIndex++;
deleteAllRepos();
}, errorDisplay);
};
// First delete each repo for the namespace, updating the info so it can show a progress bar.
// This is not strictly necessary (as the namespace delete call will do it as well), but it is
// a better user experience.
var params = {
'namespace': namespace,
'public': false
};
ApiService.listRepos(null, params).then(function(resp) {
repositories = resp['repositories'];
deleteAllRepos();
}, errorDisplay);
};
userService.currentUser = function() {
return userResponse;
};
// Update the user in the root scope.
userService.updateUserIn($rootScope);
return userService;
}]);