From da859203f7b5b1afde09ebc0f8804f41c87f0fc0 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Tue, 8 Apr 2014 19:14:24 -0400 Subject: [PATCH] - Add a config whitelist - Send the config values to the frontend - Add a service class for exposing the config values - Change the directives to inject both Features and Config - Change directive users to make use of the new scope --- .gitignore | 1 + config.py | 21 +++++++++++ endpoints/common.py | 4 +++ static/js/app.js | 62 +++++++++++++++++++++------------ static/js/controllers.js | 6 ++-- static/partials/landing.html | 2 +- static/partials/org-admin.html | 4 +-- static/partials/user-admin.html | 4 +-- templates/base.html | 18 ++-------- 9 files changed, 76 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 7b2ee0e25..390030af1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ venv static/snapshots/ screenshots/screenshots/ +stack diff --git a/config.py b/config.py index 9765d97d5..d953fc716 100644 --- a/config.py +++ b/config.py @@ -28,6 +28,24 @@ def logs_init_builder(level=logging.DEBUG, return init_logs +# The set of configuration key names that will be accessible in the client. Since these +# values are set to the frontend, DO NOT PLACE ANY SECRETS OR KEYS in this list. +CLIENT_WHITELIST = ['SERVER_NAME', 'PREFERRED_URL_SCHEME', 'GITHUB_CLIENT_ID', + 'GITHUB_LOGIN_CLIENT_ID', 'MIXPANEL_KEY', 'STRIPE_PUBLISHABLE_KEY', + 'ENTERPRISE_LOGO_URL'] + + +def getFrontendVisibleConfig(config_dict): + visible_dict = {} + for name in CLIENT_WHITELIST: + if name.lower().find('secret') >= 0: + raise Exception('Cannot whitelist secrets: %s' % name) + + if name in config_dict: + visible_dict[name] = config_dict.get(name, None) + + return visible_dict + class DefaultConfig(object): # Flask config @@ -94,6 +112,9 @@ class DefaultConfig(object): GITHUB_CLIENT_ID = '' GITHUB_CLIENT_SECRET = '' + GITHUB_LOGIN_CLIENT_ID = '' + GITHUB_LOGIN_CLIENT_SECRET = '' + # Requests based HTTP client with a large request pool HTTPCLIENT = build_requests_session() diff --git a/endpoints/common.py b/endpoints/common.py index 07965a838..2dbc28e19 100644 --- a/endpoints/common.py +++ b/endpoints/common.py @@ -16,6 +16,7 @@ from auth import scopes from endpoints.api.discovery import swagger_route_data from werkzeug.routing import BaseConverter from functools import wraps +from config import getFrontendVisibleConfig import features @@ -119,6 +120,9 @@ def random_string(): def render_page_template(name, **kwargs): resp = make_response(render_template(name, route_data=json.dumps(get_route_data()), feature_set=json.dumps(features.get_features()), + config_set=json.dumps(getFrontendVisibleConfig(app.config)), + mixpanel_key=app.config.get('MIXPANEL_KEY', ''), + is_debug=str(app.config.get('DEBUGGING', False)).lower(), cache_buster=random_string(), **kwargs)) diff --git a/static/js/app.js b/static/js/app.js index 2950a608d..693d89365 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -465,6 +465,23 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'angu return features; }]); + $provide.factory('Config', [function() { + if (!window.__config) { + return {}; + } + + var config = window.__config; + config.getValue = function(name, opt_defaultValue) { + var value = config[name]; + if (value == null) { + return opt_defaultValue; + } + return value; + }; + + return config; + }]); + $provide.factory('ApiService', ['Restangular', function(Restangular) { var apiService = {}; @@ -761,8 +778,8 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'angu return userService; }]); - $provide.factory('NotificationService', ['$rootScope', '$interval', 'UserService', 'ApiService', 'StringBuilderService', 'PlanService', 'UserService', - function($rootScope, $interval, UserService, ApiService, StringBuilderService, PlanService, UserService) { + $provide.factory('NotificationService', ['$rootScope', '$interval', 'UserService', 'ApiService', 'StringBuilderService', 'PlanService', 'UserService', 'Config', + function($rootScope, $interval, UserService, ApiService, StringBuilderService, PlanService, UserService, Config) { var notificationService = { 'user': null, 'notifications': [], @@ -856,23 +873,13 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'angu return notificationService; }]); - $provide.factory('KeyService', ['$location', function($location) { + $provide.factory('KeyService', ['$location', 'Config', function($location, Config) { var keyService = {} - if ($location.host() === 'quay.io') { - keyService['stripePublishableKey'] = 'pk_live_P5wLU0vGdHnZGyKnXlFG4oiu'; - keyService['githubClientId'] = '5a8c08b06c48d89d4d1e'; - keyService['githubRedirectUri'] = 'https://quay.io/oauth2/github/callback'; - } else if($location.host() === 'staging.quay.io') { - keyService['stripePublishableKey'] = 'pk_live_P5wLU0vGdHnZGyKnXlFG4oiu'; - keyService['githubClientId'] = '4886304accbc444f0471'; - keyService['githubRedirectUri'] = 'https://staging.quay.io/oauth2/github/callback'; - } else { - keyService['stripePublishableKey'] = 'pk_test_uEDHANKm9CHCvVa2DLcipGRh'; - keyService['githubClientId'] = 'cfbc4aca88e5c1b40679'; - keyService['githubRedirectUri'] = 'http://localhost:5000/oauth2/github/callback'; - } - + keyService['stripePublishableKey'] = Config['STRIPE_PUBLISHABLE_KEY']; + keyService['githubClientId'] = Config['GITHUB_CLIENT_ID']; + keyService['githubLoginClientId'] = Config['GITHUB_LOGIN_CLIENT_ID']; + keyService['githubRedirectUri'] = Config['PREFERRED_URL_SCHEME'] + '://' + Config['SERVER_NAME'] + '/oauth2/github/callback'; return keyService; }]); @@ -1335,12 +1342,13 @@ quayApp.directive('quayRequire', function ($animate, Features) { }); -quayApp.directive('quayShow', function($animate, Features) { +quayApp.directive('quayShow', function($animate, Features, Config) { return { priority: 590, restrict: 'A', link: function($scope, $element, $attr, ctrl, $transclude) { $scope.Features = Features; + $scope.Config = Config; $scope.$watch($attr.quayShow, function(result) { $animate[!!result ? 'removeClass' : 'addClass']($element, 'ng-hide'); }); @@ -1349,7 +1357,7 @@ quayApp.directive('quayShow', function($animate, Features) { }); -quayApp.directive('quayClasses', function(Features) { +quayApp.directive('quayClasses', function(Features, Config) { return { priority: 580, restrict: 'A', @@ -1382,11 +1390,16 @@ quayApp.directive('quayClasses', function(Features) { } $scope.$watch($attr.quayClasses, function(result) { + var scopeVals = { + 'Features': Features, + 'Config': Config + }; + for (var expr in result) { if (!result.hasOwnProperty(expr)) { continue; } // Evaluate the expression with the entire features list added. - var value = $scope.$eval(expr, Features); + var value = $scope.$eval(expr, scopeVals); if (value) { addClass(result[expr]); } else { @@ -1399,7 +1412,7 @@ quayApp.directive('quayClasses', function(Features) { }); -quayApp.directive('quayInclude', function($compile, $templateCache, $http, Features) { +quayApp.directive('quayInclude', function($compile, $templateCache, $http, Features, Config) { return { priority: 595, restrict: 'A', @@ -1414,12 +1427,17 @@ quayApp.directive('quayInclude', function($compile, $templateCache, $http, Featu return; } + var scopeVals = { + 'Features': Features, + 'Config': Config + }; + var templatePath = null; for (var expr in result) { if (!result.hasOwnProperty(expr)) { continue; } // Evaluate the expression with the entire features list added. - var value = $scope.$eval(expr, Features); + var value = $scope.$eval(expr, scopeVals); if (value) { templatePath = result[expr]; break; diff --git a/static/js/controllers.js b/static/js/controllers.js index cdd728f3d..0221e0573 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -262,7 +262,7 @@ function RepoListCtrl($scope, $sanitize, Restangular, UserService, ApiService) { loadPublicRepos(); } -function LandingCtrl($scope, UserService, ApiService, Features) { +function LandingCtrl($scope, UserService, ApiService, Features, Config) { $scope.namespace = null; $scope.$watch('namespace', function(namespace) { @@ -308,11 +308,11 @@ function LandingCtrl($scope, UserService, ApiService, Features) { }; $scope.getEnterpriseLogo = function() { - if (!Features.ENTERPRISE_LOGO_URL) { + if (!Config.ENTERPRISE_LOGO_URL) { return '/static/img/quay-logo.png'; } - return Features.ENTERPRISE_LOGO_URL; + return Config.ENTERPRISE_LOGO_URL; }; } diff --git a/static/partials/landing.html b/static/partials/landing.html index 98f8a32d2..719d1a9cb 100644 --- a/static/partials/landing.html +++ b/static/partials/landing.html @@ -1,3 +1,3 @@ -
+
diff --git a/static/partials/org-admin.html b/static/partials/org-admin.html index 2b7b0be80..05678695e 100644 --- a/static/partials/org-admin.html +++ b/static/partials/org-admin.html @@ -9,7 +9,7 @@
  • Plan and Usage
  • -
  • +
  • Organization Settings
  • Usage Logs
  • @@ -35,7 +35,7 @@
    -
    +
    diff --git a/static/partials/user-admin.html b/static/partials/user-admin.html index 15cd5cd20..0ad550232 100644 --- a/static/partials/user-admin.html +++ b/static/partials/user-admin.html @@ -30,7 +30,7 @@ -
  • Account E-mail
  • +
  • Account E-mail
  • Robot Accounts
  • Change Password
  • GitHub Login
  • @@ -105,7 +105,7 @@
    -
    +
    An e-mail has been sent to {{ sentEmail }} to verify the change.
    diff --git a/templates/base.html b/templates/base.html index 5a1638574..b43447317 100644 --- a/templates/base.html +++ b/templates/base.html @@ -74,6 +74,7 @@ @@ -83,25 +84,10 @@ - - +mixpanel.init("{{ mixpanel_key }}", { track_pageview : false, debug: {{ is_debug }} });