mirror of https://github.com/rancher/ui.git
Access Control config enhancements
- Check Github API and automatically remove users/orgs that don't exist - Saving/Saved state on the authorization save button to show state - Waiting state on test button to show state - Size GitHub popup window bigger to show content
This commit is contained in:
parent
1c0a29899b
commit
b4940855e8
|
|
@ -8,8 +8,8 @@ export function initialize(container, application) {
|
||||||
|
|
||||||
// Find out if auth is enabled
|
// Find out if auth is enabled
|
||||||
store.rawRequest({
|
store.rawRequest({
|
||||||
url: 'token', // Base url, which will be /v1
|
url: 'token',
|
||||||
headers: { 'authorization': undefined }
|
headers: { 'authorization': undefined } // Explicitly not send the auth token
|
||||||
})
|
})
|
||||||
.then(function(obj) {
|
.then(function(obj) {
|
||||||
var body = JSON.parse(obj.xhr.responseText);
|
var body = JSON.parse(obj.xhr.responseText);
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,24 @@ export default Ember.Component.extend({
|
||||||
login: null,
|
login: null,
|
||||||
|
|
||||||
classNames: ['gh-avatar'],
|
classNames: ['gh-avatar'],
|
||||||
name: 'Loading...',
|
name: 'Checking...',
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
|
|
||||||
nameChanged: function() {
|
nameChanged: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var url = 'https://api.github.com/' + this.get('type') + 's/' + this.get('login') + '?s=40';
|
var login = this.get('login');
|
||||||
|
var type = this.get('type');
|
||||||
|
var url = 'https://api.github.com/' + type + 's/' + login;
|
||||||
|
|
||||||
Ember.$.ajax({url: url, dataType: 'json'}).then(function(body) {
|
Ember.$.ajax({url: url, dataType: 'json'}).then(function(body) {
|
||||||
self.set('name', body.name);
|
self.set('name', body.name);
|
||||||
self.set('avatarUrl', body.avatar_url);
|
|
||||||
}, function() {
|
|
||||||
var type = self.get('type');
|
|
||||||
type = type.substr(0,1).toUpperCase() + type.substr(1);
|
|
||||||
|
|
||||||
self.set('name', 'Warning: ' + type + ' not found');
|
var avatarUrl = body.avatar_url;
|
||||||
|
avatarUrl += (avatarUrl.indexOf('?') >= 0 ? '&' : '?') + 's=40';
|
||||||
|
self.set('avatarUrl', avatarUrl);
|
||||||
|
}, function() {
|
||||||
|
self.set('name', '(Not found)');
|
||||||
|
self.sendAction('notFound', login);
|
||||||
});
|
});
|
||||||
}.observes('login','type').on('init'),
|
}.observes('login','type').on('init'),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,5 @@
|
||||||
<div class="clip">
|
<div class="clip">
|
||||||
<a {{bind-attr href=url}} target="_blank">{{login}}</a>
|
<a {{bind-attr href=url}} target="_blank">{{login}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-muted clip">{{name}}</div>
|
<div class="text-muted clip">{{#if name}}{{name}}{{else}}<i>No name</i>{{/if}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
{{#if app.authenticationEnabled}}
|
{{#if app.authenticationEnabled}}
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<span class="fa-stack fa-lg hand" id="user-dropdown" data-toggle="dropdown" aria-expanded="true">
|
<span class="hand" id="user-dropdown" data-toggle="dropdown" aria-expanded="true">
|
||||||
|
<span class="fa-stack fa-lg">
|
||||||
<i class="fa fa-circle-o fa-stack-2x"></i>
|
<i class="fa fa-circle-o fa-stack-2x"></i>
|
||||||
<i class="fa fa-user fa-stack-1x"></i>
|
<i class="fa fa-user fa-stack-1x"></i>
|
||||||
</span>
|
</span>
|
||||||
|
<i class="fa fa-chevron-down"></i>
|
||||||
|
</span>
|
||||||
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="user-dropdown">
|
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="user-dropdown">
|
||||||
<li role="presentation" class="disabled">
|
<li role="presentation" class="disabled">
|
||||||
<a role="menuitem" tabindex="-1">Settings</a>
|
<a role="menuitem" tabindex="-1">Settings</a>
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export default Ember.Controller.extend({
|
||||||
self.set('timedOut', false);
|
self.set('timedOut', false);
|
||||||
self.set('waiting', true);
|
self.set('waiting', true);
|
||||||
|
|
||||||
self.get('torii').open('github-oauth2').then(function(github){
|
self.get('torii').open('github-oauth2',{width: 1024, height: 500}).then(function(github){
|
||||||
return self.get('store').rawRequest({
|
return self.get('store').rawRequest({
|
||||||
url: 'token',
|
url: 'token',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,17 @@ import Ember from 'ember';
|
||||||
export default Ember.ObjectController.extend({
|
export default Ember.ObjectController.extend({
|
||||||
confirmDisable: false,
|
confirmDisable: false,
|
||||||
error: null,
|
error: null,
|
||||||
|
testing: false,
|
||||||
|
saving: false,
|
||||||
|
saved: true,
|
||||||
|
|
||||||
createIncomplete: function() {
|
createDisabled: function() {
|
||||||
var id = (this.get('clientId')||'').trim();
|
var id = (this.get('clientId')||'').trim();
|
||||||
var secret = (this.get('clientSecret')||'').trim();
|
var secret = (this.get('clientSecret')||'').trim();
|
||||||
return id.length < 20 ||secret.length < 40;
|
return id.length < 20 ||secret.length < 40 || this.get('testing');
|
||||||
}.property('clientId','clientSecret'),
|
}.property('clientId','clientSecret','testing'),
|
||||||
|
|
||||||
|
saveDisabled: Ember.computed.or('saving','saved'),
|
||||||
|
|
||||||
destinationUrl: function() {
|
destinationUrl: function() {
|
||||||
return window.location.origin+'/';
|
return window.location.origin+'/';
|
||||||
|
|
@ -17,8 +22,10 @@ export default Ember.ObjectController.extend({
|
||||||
actions: {
|
actions: {
|
||||||
test: function() {
|
test: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
self.send('clearError');
|
||||||
|
self.set('testing',true);
|
||||||
|
|
||||||
var model = this.get('model');
|
var model = self.get('model');
|
||||||
model.set('clientId', model.get('clientId').trim());
|
model.set('clientId', model.get('clientId').trim());
|
||||||
model.set('clientSecret', model.get('clientSecret').trim());
|
model.set('clientSecret', model.get('clientSecret').trim());
|
||||||
model.set('enabled',false); // It should already be, but just in case..
|
model.set('enabled',false); // It should already be, but just in case..
|
||||||
|
|
@ -34,7 +41,8 @@ export default Ember.ObjectController.extend({
|
||||||
|
|
||||||
authenticate: function() {
|
authenticate: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.get('torii').open('github-oauth2').then(function(github){
|
self.send('clearError');
|
||||||
|
self.get('torii').open('github-oauth2',{width: 1024, height: 500}).then(function(github){
|
||||||
return self.get('store').rawRequest({
|
return self.get('store').rawRequest({
|
||||||
url: 'token',
|
url: 'token',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -52,18 +60,21 @@ export default Ember.ObjectController.extend({
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
// Github auth failed.. try again
|
// Github auth failed.. try again
|
||||||
self.send('gotError', err);
|
self.send('gotError', err);
|
||||||
|
})
|
||||||
|
.finally(function() {
|
||||||
|
self.set('testing',false);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
authenticationSucceeded: function(auth) {
|
authenticationSucceeded: function(auth) {
|
||||||
console.log('Authentication succeeded');
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var session = self.get('session');
|
self.send('clearError');
|
||||||
|
|
||||||
|
var session = self.get('session');
|
||||||
session.set('token', auth.jwt);
|
session.set('token', auth.jwt);
|
||||||
session.set('isLoggedIn',1);
|
session.set('isLoggedIn',1);
|
||||||
|
|
||||||
var model = this.get('model');
|
var model = self.get('model');
|
||||||
model.set('enabled',true);
|
model.set('enabled',true);
|
||||||
model.set('allowOrganizations', auth.orgs||[]);
|
model.set('allowOrganizations', auth.orgs||[]);
|
||||||
model.set('allowUsers', [auth.user]);
|
model.set('allowUsers', [auth.user]);
|
||||||
|
|
@ -75,7 +86,6 @@ export default Ember.ObjectController.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
waitAndRefresh: function(expect,limit) {
|
waitAndRefresh: function(expect,limit) {
|
||||||
console.log('Wait and refresh',expect,limit);
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if ( limit === undefined )
|
if ( limit === undefined )
|
||||||
{
|
{
|
||||||
|
|
@ -114,6 +124,9 @@ export default Ember.ObjectController.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
addUser: function() {
|
addUser: function() {
|
||||||
|
this.send('clearError');
|
||||||
|
this.set('saved',false);
|
||||||
|
|
||||||
var str = (this.get('addUser')||'').trim();
|
var str = (this.get('addUser')||'').trim();
|
||||||
if ( str )
|
if ( str )
|
||||||
{
|
{
|
||||||
|
|
@ -122,11 +135,15 @@ export default Ember.ObjectController.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeUser: function(user) {
|
removeUser: function(login) {
|
||||||
this.get('allowUsers').removeObject(user);
|
this.set('saved',false);
|
||||||
|
this.get('allowUsers').removeObject(login);
|
||||||
},
|
},
|
||||||
|
|
||||||
addOrg: function() {
|
addOrg: function() {
|
||||||
|
this.send('clearError');
|
||||||
|
this.set('saved',false);
|
||||||
|
|
||||||
var str = (this.get('addOrg')||'').trim();
|
var str = (this.get('addOrg')||'').trim();
|
||||||
if ( str )
|
if ( str )
|
||||||
{
|
{
|
||||||
|
|
@ -135,17 +152,34 @@ export default Ember.ObjectController.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeOrg: function(org) {
|
removeOrg: function(login) {
|
||||||
this.get('allowOrganizations').removeObject(org);
|
this.set('saved',false);
|
||||||
|
this.get('allowOrganizations').removeObject(login);
|
||||||
|
},
|
||||||
|
|
||||||
|
userNotFound: function(login) {
|
||||||
|
this.send('showError',"User '"+ login + "' not found");
|
||||||
|
this.send('removeUser',login);
|
||||||
|
},
|
||||||
|
|
||||||
|
orgNotFound: function(login) {
|
||||||
|
this.send('showError',"Organization '"+ login + "' not found");
|
||||||
|
this.send('removeOrg',login);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveAuthorization: function() {
|
saveAuthorization: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
self.send('clearError');
|
||||||
|
self.set('saving',true);
|
||||||
|
self.set('saved',false);
|
||||||
|
|
||||||
var model = self.get('model');
|
var model = self.get('model');
|
||||||
model.save().then(function() {
|
model.save().then(function() {
|
||||||
self.send('waitAndRefresh', true);
|
self.set('saved',true);
|
||||||
}).catch(function(err) {
|
}).catch(function(err) {
|
||||||
self.send('gotError', err);
|
self.send('gotError', err);
|
||||||
|
}).finally(function() {
|
||||||
|
self.set('saving',false);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -154,12 +188,21 @@ export default Ember.ObjectController.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
gotError: function(err) {
|
gotError: function(err) {
|
||||||
this.set('error', err.message);
|
this.send('showError', err.message);
|
||||||
|
},
|
||||||
|
|
||||||
|
showError: function(msg) {
|
||||||
|
this.set('error', msg);
|
||||||
window.scrollY = 0;
|
window.scrollY = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
clearError: function() {
|
||||||
|
this.set('error', '');
|
||||||
|
},
|
||||||
|
|
||||||
disable: function() {
|
disable: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
self.send('clearError');
|
||||||
|
|
||||||
var model = this.get('model');
|
var model = this.get('model');
|
||||||
model.set('allowOrganizations',[]);
|
model.set('allowOrganizations',[]);
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,9 @@ export default Ember.Route.extend(AuthenticatedRouteMixin,{
|
||||||
setupController: function(controller, model) {
|
setupController: function(controller, model) {
|
||||||
this._super(controller,model);
|
this._super(controller,model);
|
||||||
controller.set('confirmDisable',false);
|
controller.set('confirmDisable',false);
|
||||||
|
controller.set('saving',false);
|
||||||
|
controller.set('saved',true);
|
||||||
|
controller.set('testing',false);
|
||||||
|
controller.set('error',null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,29 @@
|
||||||
<div style="padding: 20px 20px 0 20px;">
|
<section>
|
||||||
|
{{#if error}}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i style="float: left;" class="fa fa-lg fa-exclamation-circle"></i>
|
||||||
|
<p style="margin-left: 50px">{{error}}</p>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<h2>Access Control is {{#if app.authenticationEnabled}}<b>enabled</b>{{else}}<b class="text-warning">not configured</b>{{/if}}</h2>
|
<h2>Access Control is {{#if app.authenticationEnabled}}<b>enabled</b>{{else}}<b class="text-warning">not configured</b>{{/if}}</h2>
|
||||||
<p>
|
<div>
|
||||||
{{#if app.authenticationEnabled}}
|
{{#if app.authenticationEnabled}}
|
||||||
Rancher is configured to restrict access to the GitHub users and organization members below.
|
Rancher is configured to restrict access to the GitHub users and organization members below.
|
||||||
{{else}}
|
{{else}}
|
||||||
Rancher can be configured to restrict access to a set of GitHub users and organization members. This is not currently set up, so anybody that reach this page (or the API) has full control over the system.
|
Rancher can be configured to restrict access to a set of GitHub users and organization members. This is not currently set up, so anybody that reach this page (or the API) has full control over the system.
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if error}}
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
<i style="float: left;" class="fa fa-exclamation-circle"></i>
|
|
||||||
<p style="margin-left: 50px">{{error}}</p>
|
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if app.authenticationEnabled}}
|
{{#if app.authenticationEnabled}}
|
||||||
|
<div class="well">
|
||||||
|
<h4>Authentication</h4>
|
||||||
|
<hr/>
|
||||||
|
<p>To change the configured GitHub application, disable access control below and then set it up again.</p>
|
||||||
|
<div><b>Client ID: </b> <span class="text-muted">{{clientId}}</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<h4>Configure Authorization</h4>
|
<h4>Configure Authorization</h4>
|
||||||
|
|
@ -27,7 +33,7 @@
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<label>Users</label>
|
<label>Users</label>
|
||||||
|
|
||||||
<form {{action "addUser"}}>
|
<form {{action "addUser" on="submit"}}>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
{{input type="text" value=addUser placeholder="Add GitHub username" class="form-control"}}
|
{{input type="text" value=addUser placeholder="Add GitHub username" class="form-control"}}
|
||||||
<div class="input-group-btn">
|
<div class="input-group-btn">
|
||||||
|
|
@ -41,7 +47,7 @@
|
||||||
<ul class="list-unstyled gh-avatar-list">
|
<ul class="list-unstyled gh-avatar-list">
|
||||||
{{#each user in allowUsers}}
|
{{#each user in allowUsers}}
|
||||||
<li>
|
<li>
|
||||||
{{#github-avatar type="user" login=user}}
|
{{#github-avatar type="user" login=user notFound="userNotFound"}}
|
||||||
<button class="btn btn-danger btn-sm pull-right gh-action" {{action "removeUser" user}}>Remove</button>
|
<button class="btn btn-danger btn-sm pull-right gh-action" {{action "removeUser" user}}>Remove</button>
|
||||||
{{/github-avatar}}
|
{{/github-avatar}}
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -54,7 +60,7 @@
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<label>Organizations</label>
|
<label>Organizations</label>
|
||||||
|
|
||||||
<form {{action "addOrg"}}>
|
<form {{action "addOrg" on="submit"}}>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
{{input type="text" value=addOrg placeholder="Add GitHub organization name" class="form-control"}}
|
{{input type="text" value=addOrg placeholder="Add GitHub organization name" class="form-control"}}
|
||||||
<div class="input-group-btn">
|
<div class="input-group-btn">
|
||||||
|
|
@ -68,7 +74,7 @@
|
||||||
<ul class="list-unstyled gh-avatar-list">
|
<ul class="list-unstyled gh-avatar-list">
|
||||||
{{#each org in allowOrganizations}}
|
{{#each org in allowOrganizations}}
|
||||||
<li>
|
<li>
|
||||||
{{#github-avatar type="org" login=org}}
|
{{#github-avatar type="org" login=org notFound="orgNotFound"}}
|
||||||
<button class="btn btn-danger btn-sm pull-right gh-action" {{action "removeOrg" org}}>Remove</button>
|
<button class="btn btn-danger btn-sm pull-right gh-action" {{action "removeOrg" org}}>Remove</button>
|
||||||
{{/github-avatar}}
|
{{/github-avatar}}
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -81,8 +87,16 @@
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<button class="btn btn-primary" {{action "saveAuthorization"}}>
|
<button class="btn btn-primary" {{bind-attr disabled=saveDisabled}} {{action "saveAuthorization"}}>
|
||||||
Save Authorization Configuration
|
{{#if saved}}
|
||||||
|
Saved
|
||||||
|
{{else}}
|
||||||
|
{{#if saving}}
|
||||||
|
<i class="fa fa-spinner fa-spin"></i> Saving...</i>
|
||||||
|
{{else}}
|
||||||
|
Save authorization configuration
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -96,11 +110,11 @@
|
||||||
|
|
||||||
{{#if confirmDisable}}
|
{{#if confirmDisable}}
|
||||||
<button class="btn btn-danger" {{action "disable"}}>
|
<button class="btn btn-danger" {{action "disable"}}>
|
||||||
<i class="fa fa-fire"></i> Are you sure? Click again to really disable Access Control
|
<i class="fa fa-fire"></i> Are you sure? Click again to really disable access control
|
||||||
</button>
|
</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<button class="btn btn-danger" {{action "promptDisable"}}>
|
<button class="btn btn-danger" {{action "promptDisable"}}>
|
||||||
<i class="fa fa-fire"></i> Disable Access Control
|
<i class="fa fa-fire"></i> Disable access control
|
||||||
</button>
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|
@ -160,11 +174,15 @@
|
||||||
<p>Check that your application is configured correctly by testing authentication with it:</p>
|
<p>Check that your application is configured correctly by testing authentication with it:</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<button {{bind-attr disabled=createIncomplete}} class="btn btn-primary" {{action "test"}}>
|
<button {{bind-attr disabled=createDisabled}} class="btn btn-primary" {{action "test"}}>
|
||||||
|
{{#if testing}}
|
||||||
|
<i class="fa fa-spinner fa-spin"></i> Waiting to hear back from GitHub
|
||||||
|
{{else}}
|
||||||
<i class="fa fa-github"></i> Authenticate with GitHub
|
<i class="fa fa-github"></i> Authenticate with GitHub
|
||||||
|
{{/if}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
</div>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
|
|
||||||
export default Ember.Route.extend({
|
export default Ember.Route.extend({
|
||||||
|
enter: function() {
|
||||||
|
this.send('setPageName','Settings');
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -116,13 +116,12 @@ HEADER {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
margin-left: $nav_width;
|
margin-left: $nav_width;
|
||||||
background-color: $header_bg;
|
background-color: $header_bg;
|
||||||
padding: 0;
|
padding: 0 20px;
|
||||||
|
|
||||||
H2 {
|
H2 {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: $header_height;
|
line-height: $header_height;
|
||||||
padding-left: 20px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
"license": "Apache 2",
|
"license": "Apache 2",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ember-api-store": "1.0.7",
|
"ember-api-store": "1.0.7",
|
||||||
|
"rancher-torii": "^0.2.2",
|
||||||
|
|
||||||
"body-parser": "^1.2.0",
|
"body-parser": "^1.2.0",
|
||||||
"broccoli-asset-rev": "^1.0.0",
|
"broccoli-asset-rev": "^1.0.0",
|
||||||
|
|
@ -38,7 +39,6 @@
|
||||||
"express": "^4.8.5",
|
"express": "^4.8.5",
|
||||||
"forever-agent": "^0.5.2",
|
"forever-agent": "^0.5.2",
|
||||||
"glob": "^4.0.5",
|
"glob": "^4.0.5",
|
||||||
"http-proxy": "^1.6.2",
|
"http-proxy": "^1.6.2"
|
||||||
"torii": "^0.2.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue