parent
972e4be811
commit
08d7b4babe
23 changed files with 1290 additions and 630 deletions
193
static/js/directives/ui/credentials-dialog.js
Normal file
193
static/js/directives/ui/credentials-dialog.js
Normal file
|
@ -0,0 +1,193 @@
|
|||
/**
|
||||
* An element which displays a credentials dialog.
|
||||
*/
|
||||
angular.module('quay').directive('credentialsDialog', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/credentials-dialog.html',
|
||||
replace: false,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'credentials': '=credentials',
|
||||
'secretTitle': '@secretTitle',
|
||||
'entityTitle': '@entityTitle',
|
||||
'entityIcon': '@entityIcon'
|
||||
},
|
||||
|
||||
controller: function($scope, $element, $rootScope, Config) {
|
||||
$scope.Config = Config;
|
||||
|
||||
$scope.k8s = {};
|
||||
$scope.rkt = {};
|
||||
$scope.docker = {};
|
||||
|
||||
// Generate a unique ID for the dialog.
|
||||
if (!$rootScope.credentialsDialogCounter) {
|
||||
$rootScope.credentialsDialogCounter = 0;
|
||||
}
|
||||
|
||||
$rootScope.credentialsDialogCounter++;
|
||||
$scope.dialogID = $rootScope.credentialsDialogCounter;
|
||||
|
||||
$scope.hide = function() {
|
||||
$element.find('.modal').modal('hide');
|
||||
};
|
||||
|
||||
$scope.show = function() {
|
||||
$element.find('.modal').modal({});
|
||||
};
|
||||
|
||||
$scope.$watch('credentials', function(credentials) {
|
||||
if (!credentials) {
|
||||
$scope.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.show();
|
||||
});
|
||||
|
||||
$scope.downloadFile = function(info) {
|
||||
var blob = new Blob([info.contents]);
|
||||
saveAs(blob, info.filename);
|
||||
};
|
||||
|
||||
$scope.viewFile = function(context) {
|
||||
context.viewingFile = true;
|
||||
};
|
||||
|
||||
$scope.isDownloadSupported = function() {
|
||||
var isSafari = /^((?!chrome).)*safari/i.test(navigator.userAgent);
|
||||
if (isSafari) {
|
||||
// Doesn't work properly in Safari, sadly.
|
||||
return false;
|
||||
}
|
||||
|
||||
try { return !!new Blob(); } catch(e) {}
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.getNamespace = function(credentials) {
|
||||
if (!credentials || !credentials.username) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return credentials.username.split('+')[0];
|
||||
};
|
||||
|
||||
$scope.getMesosFilename = function(credentials) {
|
||||
return $scope.getSuffixedFilename(credentials, 'auth.tar.gz');
|
||||
};
|
||||
|
||||
$scope.getMesosFile = function(credentials) {
|
||||
var tarFile = new Tar();
|
||||
tarFile.append('.docker/config.json', $scope.getDockerConfig(credentials), {});
|
||||
contents = (new Zlib.Gzip(tarFile.getData())).compress();
|
||||
return {
|
||||
'filename': $scope.getMesosFilename(credentials),
|
||||
'contents': contents
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getDockerConfig = function(credentials) {
|
||||
var auths = {};
|
||||
auths[Config['SERVER_HOSTNAME']] = {
|
||||
'auth': $.base64.encode(credentials.username + ":" + credentials.token),
|
||||
'email': ''
|
||||
};
|
||||
|
||||
var config = {
|
||||
'auths': auths
|
||||
};
|
||||
|
||||
return JSON.stringify(config, null, ' ');
|
||||
};
|
||||
|
||||
$scope.getDockerFile = function(credentials) {
|
||||
return {
|
||||
'filename': $scope.getRktFilename(credentials),
|
||||
'contents': $scope.getDockerConfig(credentials)
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getDockerLogin = function(credentials) {
|
||||
if (!credentials || !credentials.username) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var escape = function(v) {
|
||||
if (!v) { return v; }
|
||||
return v.replace('$', '\\$');
|
||||
};
|
||||
|
||||
return 'docker login -e="." -u="' + escape(credentials.username) + '" -p="' + credentials.password + '" ' + Config['SERVER_HOSTNAME'];
|
||||
};
|
||||
|
||||
$scope.getDockerFilename = function(credentials) {
|
||||
return $scope.getSuffixedFilename(credentials, 'auth.json')
|
||||
};
|
||||
|
||||
$scope.getRktFile = function(credentials) {
|
||||
var config = {
|
||||
'rktKind': 'auth',
|
||||
'rktVersion': 'v1',
|
||||
'domains': [Config['SERVER_HOSTNAME']],
|
||||
'type': 'basic',
|
||||
'credentials': {
|
||||
'user': credentials['username'],
|
||||
'password': credentials['password']
|
||||
}
|
||||
};
|
||||
|
||||
var contents = JSON.stringify(config, null, ' ');
|
||||
return {
|
||||
'filename': $scope.getRktFilename(credentials),
|
||||
'contents': contents
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getRktFilename = function(credentials) {
|
||||
return $scope.getSuffixedFilename(credentials, 'auth.json')
|
||||
};
|
||||
|
||||
$scope.getKubernetesSecretName = function(credentials) {
|
||||
if (!credentials || !credentials.username) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var username = credentials.username.replace('+', '-');
|
||||
return username + '-pull-secret';
|
||||
};
|
||||
|
||||
$scope.getKubernetesFile = function(credentials) {
|
||||
var dockerConfigJson = $scope.getDockerConfig(credentials);
|
||||
var contents = 'apiVersion: v1\n' +
|
||||
'kind: Secret\n' +
|
||||
'metadata:\n' +
|
||||
' name: ' + $scope.getKubernetesSecretName(credentials) + '\n' +
|
||||
'data:\n' +
|
||||
' .dockerconfigjson: ' + $.base64.encode(dockerConfigJson) + '\n' +
|
||||
'type: kubernetes.io/dockerconfigjson'
|
||||
|
||||
return {
|
||||
'filename': $scope.getKubernetesFilename(credentials),
|
||||
'contents': contents
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getKubernetesFilename = function(credentials) {
|
||||
return $scope.getSuffixedFilename(credentials, 'secret.yml')
|
||||
};
|
||||
|
||||
$scope.getSuffixedFilename = function(credentials, suffix) {
|
||||
if (!credentials || !credentials.username) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var username = credentials.username.replace('+', '-');
|
||||
return username + '-' + suffix;
|
||||
};
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
|
@ -1,86 +0,0 @@
|
|||
/**
|
||||
* An element which displays a dialog with docker auth credentials for an entity.
|
||||
*/
|
||||
angular.module('quay').directive('dockerAuthDialog', function (Config) {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/docker-auth-dialog.html',
|
||||
replace: false,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'username': '=username',
|
||||
'token': '=token',
|
||||
'shown': '=shown',
|
||||
'counter': '=counter',
|
||||
'supportsRegenerate': '@supportsRegenerate',
|
||||
'regenerate': '®enerate'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
var updateCommand = function() {
|
||||
var escape = function(v) {
|
||||
if (!v) { return v; }
|
||||
return v.replace('$', '\\$');
|
||||
};
|
||||
$scope.command = 'docker login -e="." -u="' + escape($scope.username) +
|
||||
'" -p="' + $scope.token + '" ' + Config['SERVER_HOSTNAME'];
|
||||
};
|
||||
|
||||
$scope.$watch('username', updateCommand);
|
||||
$scope.$watch('token', updateCommand);
|
||||
|
||||
$scope.regenerating = true;
|
||||
|
||||
$scope.askRegenerate = function() {
|
||||
bootbox.confirm('Are you sure you want to regenerate the token? All existing login credentials will become invalid', function(resp) {
|
||||
if (resp) {
|
||||
$scope.regenerating = true;
|
||||
$scope.regenerate({'username': $scope.username, 'token': $scope.token});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.isDownloadSupported = function() {
|
||||
var isSafari = /^((?!chrome).)*safari/i.test(navigator.userAgent);
|
||||
if (isSafari) {
|
||||
// Doesn't work properly in Safari, sadly.
|
||||
return false;
|
||||
}
|
||||
|
||||
try { return !!new Blob(); } catch(e) {}
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.downloadCfg = function() {
|
||||
var auth = $.base64.encode($scope.username + ":" + $scope.token);
|
||||
config = {}
|
||||
config[Config['SERVER_HOSTNAME']] = {
|
||||
"auth": auth,
|
||||
"email": ""
|
||||
};
|
||||
|
||||
var file = JSON.stringify(config, null, ' ');
|
||||
var blob = new Blob([file]);
|
||||
saveAs(blob, '.dockercfg');
|
||||
};
|
||||
|
||||
var show = function(r) {
|
||||
$scope.regenerating = false;
|
||||
|
||||
if (!$scope.shown || !$scope.username || !$scope.token) {
|
||||
$('#dockerauthmodal').modal('hide');
|
||||
return;
|
||||
}
|
||||
|
||||
$('#copyClipboard').clipboardCopy();
|
||||
$('#dockerauthmodal').modal({});
|
||||
};
|
||||
|
||||
$scope.$watch('counter', show);
|
||||
$scope.$watch('shown', show);
|
||||
$scope.$watch('username', show);
|
||||
$scope.$watch('token', show);
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
|
@ -16,29 +16,12 @@ angular.module('quay').directive('entityReference', function () {
|
|||
'avatarSize': '@avatarSize'
|
||||
},
|
||||
controller: function($scope, $element, UserService, UtilService, Config) {
|
||||
$scope.robotToShow = null;
|
||||
|
||||
$scope.getIsAdmin = function(namespace) {
|
||||
return UserService.isNamespaceAdmin(namespace);
|
||||
};
|
||||
|
||||
$scope.getRobotUrl = function(name) {
|
||||
var namespace = $scope.getPrefix(name);
|
||||
if (!namespace) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!$scope.getIsAdmin(namespace)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var org = UserService.getOrganization(namespace);
|
||||
if (!org) {
|
||||
// This robot is owned by the user.
|
||||
return '/user/' + namespace + '?tab=robots&showRobot=' + UtilService.textToSafeHtml(name);
|
||||
}
|
||||
|
||||
return '/organization/' + org['name'] + '?tab=robots&showRobot=' + UtilService.textToSafeHtml(name);
|
||||
};
|
||||
|
||||
$scope.getTitle = function(entity) {
|
||||
if (!entity) { return ''; }
|
||||
|
||||
|
@ -65,6 +48,12 @@ angular.module('quay').directive('entityReference', function () {
|
|||
var plus = name.indexOf('+');
|
||||
return name.substr(plus + 1);
|
||||
};
|
||||
|
||||
$scope.showRobotCredentials = function() {
|
||||
$scope.robotToShow = {
|
||||
'name': $scope.entity.name
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
|
|
68
static/js/directives/ui/robot-credentials-dialog.js
Normal file
68
static/js/directives/ui/robot-credentials-dialog.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* An element which displays a robot credentials dialog.
|
||||
*/
|
||||
angular.module('quay').directive('robotCredentialsDialog', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/robot-credentials-dialog.html',
|
||||
replace: false,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'info': '=info',
|
||||
},
|
||||
controller: function($scope, $element, ApiService, UserService) {
|
||||
$scope.credentials = null;
|
||||
|
||||
var lookupRobot = function() {
|
||||
var pieces = $scope.info.name.split('+');
|
||||
var params = {
|
||||
'robot_shortname': pieces[1]
|
||||
};
|
||||
|
||||
$scope.credentials = {
|
||||
'loading': true
|
||||
};
|
||||
|
||||
var organization = UserService.isOrganization(pieces[0]) ? pieces[0] : null;
|
||||
ApiService.getRobot(organization, null, params).then(function(resp) {
|
||||
$scope.credentials = {
|
||||
'username': $scope.info.name,
|
||||
'password': resp['token']
|
||||
};
|
||||
|
||||
$scope.showRegenerateToken = false;
|
||||
$scope.tokenRegenerated = false;
|
||||
}, ApiService.errorDisplay('Could not load robot information', function() {
|
||||
$scope.credentials = null;
|
||||
}));
|
||||
};
|
||||
|
||||
$scope.askRegenerateToken = function() {
|
||||
$scope.showRegenerateToken = true;
|
||||
};
|
||||
|
||||
$scope.regenerateToken = function() {
|
||||
var pieces = $scope.info.name.split('+');
|
||||
var shortName = pieces[1];
|
||||
|
||||
var organization = UserService.isOrganization(pieces[0]) ? pieces[0] : null;
|
||||
ApiService.regenerateRobotToken(organization, null, {'robot_shortname': shortName}).then(function(updated) {
|
||||
$scope.credentials = {
|
||||
'username': $scope.info.name,
|
||||
'password': updated['token']
|
||||
};
|
||||
$scope.showRegenerateToken = false;
|
||||
$scope.tokenRegenerated = true;
|
||||
}, ApiService.errorDisplay('Cannot regenerate robot account token'))
|
||||
};
|
||||
|
||||
$scope.$watch('info', function(info) {
|
||||
if (info && info.name) {
|
||||
lookupRobot();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
|
@ -19,10 +19,9 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
|
||||
$scope.robots = null;
|
||||
$scope.loading = false;
|
||||
$scope.shownRobot = null;
|
||||
$scope.showRobotCounter = 0;
|
||||
$scope.Config = Config;
|
||||
$scope.feedback = null;
|
||||
$scope.robotDisplayInfo = null;
|
||||
|
||||
// Listen for route changes and update the tabs accordingly.
|
||||
var locationListener = $rootScope.$on('$routeUpdate', function(){
|
||||
|
@ -66,23 +65,10 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
}
|
||||
};
|
||||
|
||||
$scope.regenerateToken = function(username) {
|
||||
if (!username) { return; }
|
||||
|
||||
var shortName = $scope.getShortenedName(username);
|
||||
ApiService.regenerateRobotToken($scope.organization, null, {'robot_shortname': shortName}).then(function(updated) {
|
||||
var index = $scope.findRobotIndexByName(username);
|
||||
if (index >= 0) {
|
||||
$scope.robots.splice(index, 1);
|
||||
$scope.robots.push(updated);
|
||||
}
|
||||
$scope.shownRobot = updated;
|
||||
}, ApiService.errorDisplay('Cannot regenerate robot account token'));
|
||||
};
|
||||
|
||||
$scope.showRobot = function(info) {
|
||||
$scope.shownRobot = info;
|
||||
$scope.showRobotCounter++;
|
||||
$scope.robotDisplayInfo = {
|
||||
'name': info.name
|
||||
};
|
||||
};
|
||||
|
||||
$scope.findRobotIndexByName = function(name) {
|
||||
|
|
Reference in a new issue