Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve display of secrets #963

Merged
merged 1 commit into from
Dec 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/scripts/directives/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ angular.module('openshiftConsole')
clipboardText: "=",
isDisabled: "=?",
displayWide: "=?",
inputText: "=?"
inputText: "=?",
multiline: "=?"
},
templateUrl: 'views/directives/_copy-to-clipboard.html',
controller: function($scope) {
Expand Down
15 changes: 13 additions & 2 deletions app/scripts/filters/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,21 @@ angular.module('openshiftConsole')
};
})
.filter('isMultiline', function() {
return function(str) {
return function(str, ignoreTrailing) {
if (!str) {
return false;
}
return str.indexOf('\n') !== -1;

var index = str.search(/\r|\n/);
if (index === -1) {
return false;
}

// Ignore a final, trailing newline?
if (ignoreTrailing) {
return index !== (str.length - 1);
}

return true;
};
});
37 changes: 25 additions & 12 deletions app/scripts/services/secrets.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,35 @@ angular.module("openshiftConsole")
};

var decodeSecretData = function(secretData) {
return _.mapValues(secretData, function(data, paramName) {
var nonPrintable = {};
var decodedSecret = _.mapValues(secretData, function(data, paramName) {
var decoded, isNonPrintable;
switch (paramName) {
case ".dockercfg":
return decodeDockercfg(data);
case ".dockerconfigjson":
return decodeDockerconfigjson(data);
case "username":
case "password":
case ".gitconfig":
case "ssh-privatekey":
case "ca.crt":
return window.atob(data);
default:
case ".dockercfg":
return decodeDockercfg(data);
case ".dockerconfigjson":
return decodeDockerconfigjson(data);
default:
decoded = window.atob(data);
// Allow whitespace like newlines and tabs, but detect other
// non-printable characters in the unencoded data.
// http://stackoverflow.com/questions/1677644/detect-non-printable-characters-in-javascript
isNonPrintable = /[\x00-\x09\x0E-\x1F]/.test(decoded);
if (isNonPrintable) {
nonPrintable[paramName] = true;
return data;
}

return decoded;
}
});

// Add a property to indicate when the decoded data contains
// non-printable characters. Use the `$$` prefix so it's not
// considered part of the data.
decodedSecret.$$nonprintable = nonPrintable;

return decodedSecret;
};

return {
Expand Down
16 changes: 16 additions & 0 deletions app/styles/_forms.less
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
color: @text-color;
}

.copy-to-clipboard-multiline {
position: relative;
width: 100%;
a {
box-shadow: none;
position: absolute;
right: 0;
top: 0;
}
pre {
background-color: #fff;
max-width: 100%;
overflow-x: auto;
}
}

.input-group-addon.wildcard-prefix {
padding-left: 10px;
}
Expand Down
29 changes: 18 additions & 11 deletions app/styles/_secrets.less
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@
}
}

dl.secret-data {
overflow: hidden;
pre {
margin-bottom: 0;
}
dd {
margin-bottom: 10px;
overflow-x: auto;
.copy-to-clipboard {
font-family: @font-family-monospace;
}
}
@media (min-width: @screen-md-min) {
.dl-horizontal();
}
}

.create-secret-modal {
background-color: #F5F5F5;
.modal-footer{
Expand All @@ -77,16 +94,6 @@
}
}

.secret-data {
max-width: 450px;
max-height: 150px;
@media (max-width: @screen-sm-max) {
// The `table-responsive` div adds a 100% border. Make sure the table is at
// least 100% to avoid a white block at some screen sizes.
max-width: 100%;
}
}

.create-secret-editor {
height: 150px;
}
}
14 changes: 8 additions & 6 deletions app/views/_config-file-params.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<div ng-repeat="(serverName, data) in secretData" class="image-source-item">
<h4>{{serverName}}</h4>
<dt>Username:</dt>
<h3>{{serverName}}</h3>
<dt>username</dt>
<dd class="word-break">{{data.username}}</dd>
<dt>Password:</dt>
<dd ng-if="view.showSecret" class="word-break">{{data.password}}</dd>
<dt>password</dt>
<dd ng-if="view.showSecret">
<copy-to-clipboard clipboard-text="data.password" display-wide="true"></copy-to-clipboard>
</dd>
<dd ng-if="!view.showSecret">*****</dd>
<dt>Email:</dt>
<dt>email</dt>
<dd class="word-break">{{data.email}}</dd>
</div>
</div>
101 changes: 17 additions & 84 deletions app/views/browse/secret.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ <h1>
<div class="container-fluid">
<div ng-if="secret" class="row">
<div class="col-sm-12">
<div class="resource-details secret-details">
<dl class="dl-horizontal left">
<dt>Type:</dt>
<dd>{{secret.type}}</dd>

<div class="resource-details">
<h2 class="mar-top-none">
{{secret.type}}
<small class="mar-left-sm"><a href="" ng-click="view.showSecret = !view.showSecret">{{view.showSecret ? "Hide" : "Reveal"}} secret</a></small>
</h2>
<dl class="secret-data left">
<div ng-repeat="(secretDataName, secretData) in decodedSecretData" class="image-source-item">
<div ng-switch="secretDataName">
<div ng-switch-when=".dockercfg">
Expand All @@ -56,92 +57,24 @@ <h1>
<div ng-switch-when=".dockerconfigjson">
<ng-include src=" 'views/_config-file-params.html' "></ng-include>
</div>

<div ng-switch-when="username">
<dt>Username:</dt>
<dd class="word-break">{{decodedSecretData.username}}</dd>
</div>

<div ng-switch-when="password">
<dt>Password:</dt>
<dd ng-if="view.showSecret" class="word-break">{{secretData}}</dd>
<dd ng-if="!view.showSecret">*****</dd>
</div>

<div ng-switch-when="ssh-privatekey">
<dt>SSH Private Key:</dt>
<dd ng-if="view.showSecret" class="gutter-bottom">
<div ui-ace="{
theme: 'dreamweaver',
highlightActiveLine: false,
showGutter: false,
rendererOptions: {
fadeFoldWidgets: true,
highlightActiveLine: false,
showPrintMargin: false
},
advanced: {
highlightActiveLine: false
}
}" readonly ng-model="secretData" class="ace-bordered ace-read-only ace-inline secret-data"></div>
</dd>
<dd ng-if="!view.showSecret">*****</dd>
</div>

<div ng-switch-when="ca.crt">
<dt>CA Certificate:</dt>
<dd ng-if="view.showSecret" class="gutter-bottom">
<div ui-ace="{
theme: 'dreamweaver',
highlightActiveLine: false,
showGutter: false,
rendererOptions: {
fadeFoldWidgets: true,
highlightActiveLine: false,
showPrintMargin: false
},
advanced: {
highlightActiveLine: false
}
}" readonly ng-model="secretData" class="ace-bordered ace-read-only ace-inline secret-data"></div>
</dd>
<dd ng-if="!view.showSecret">*****</dd>
</div>

<div ng-switch-when=".gitconfig">
<dt>Git Configuration File:</dt>
<dd ng-if="view.showSecret" class="gutter-bottom">
<div ui-ace="{
mode: 'ini',
theme: 'dreamweaver',
highlightActiveLine: false,
showGutter: false,
rendererOptions: {
fadeFoldWidgets: true,
highlightActiveLine: false,
showPrintMargin: false
},
advanced: {
highlightActiveLine: false
}
}" readonly ng-model="secretData" class="ace-bordered ace-read-only ace-inline secret-data"></div>
</dd>
<dd ng-if="!view.showSecret">*****</dd>
</div>

<div ng-switch-default>
<dt>{{secretDataName}}:</dt>
<dd ng-if="view.showSecret" class="word-break gutter-bottom" >{{secretData}}</dd>
<dt ng-attr-title="{{secretDataName}}">{{secretDataName}}</dt>
<dd ng-if="view.showSecret">
<copy-to-clipboard
clipboard-text="secretData"
multiline="secretData | isMultiline : true"
display-wide="true">
</copy-to-clipboard>
<div ng-if="decodedSecretData.$$nonprintable[secretDataName]" class="help-block">
This secret value contains non-printable characters and is displayed as a Base64-encoded string.
</div>
</dd>
<dd ng-if="!view.showSecret">*****</dd>
</div>

</div>
</div>
</dl>
</div>
<div class="gutter-bottom">
<a href="" ng-click="view.showSecret = !view.showSecret">{{view.showSecret ? "Hide" : "Reveal"}} secret contents</a>
</div>
<annotations annotations="secret.metadata.annotations"></annotations>
</div><!-- /col-* -->
</div>
Expand Down
46 changes: 30 additions & 16 deletions app/views/directives/_copy-to-clipboard.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
<div class="input-group copy-to-clipboard" ng-class="{'limit-width': !displayWide}">
<input id="{{id}}" type="text" class="form-control" value="{{inputText ? inputText : clipboardText}}" ng-disabled="isDisabled" ng-readonly="!isDisabled" select-on-focus>
<span class="input-group-btn" ng-hide="hidden">
<a ng-show="!inputText" data-clipboard-target="#{{id}}"
ng-disabled="isDisabled"
data-toggle="tooltip"
title="Copy to clipboard"
role="button"
class="btn btn-default"><i class="fa fa-clipboard"/></a>
<a ng-show="inputText" data-clipboard-text="{{clipboardText}}"
ng-disabled="isDisabled"
data-toggle="tooltip"
title="Copy to clipboard"
role="button"
class="btn btn-default"><i class="fa fa-clipboard"/></a>
<div class="input-group copy-to-clipboard"
ng-class="{'limit-width': !displayWide, 'copy-to-clipboard-multiline': multiline}">
<input
ng-if="!multiline"
id="{{id}}"
type="text"
class="form-control"
value="{{inputText || clipboardText}}"
ng-disabled="isDisabled"
ng-readonly="!isDisabled"
select-on-focus>
<pre ng-if="multiline" id="{{id}}">{{inputText || clipboardText}}</pre>
<span ng-class="{ 'input-group-btn': !multiline }" ng-hide="hidden">
<a ng-show="!inputText"
data-clipboard-target="#{{id}}"
href=""
ng-disabled="isDisabled"
data-toggle="tooltip"
title="Copy to clipboard"
role="button"
class="btn btn-default"><i class="fa fa-clipboard"/></a>
<a ng-show="inputText"
data-clipboard-text="{{clipboardText}}"
href=""
ng-disabled="isDisabled"
data-toggle="tooltip"
title="Copy to clipboard"
role="button"
class="btn btn-default"><i class="fa fa-clipboard"/></a>
</span>
</div><!-- /input-group -->
</div><!-- /input-group -->
24 changes: 11 additions & 13 deletions dist/scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -3360,25 +3360,20 @@ email:a.email
};
}), b;
}, d = function(a) {
return _.mapValues(a, function(a, d) {
switch (d) {
var d = {}, e = _.mapValues(a, function(a, e) {
var f, g;
switch (e) {
case ".dockercfg":
return b(a);

case ".dockerconfigjson":
return c(a);

case "username":
case "password":
case ".gitconfig":
case "ssh-privatekey":
case "ca.crt":
return window.atob(a);

default:
return a;
return f = window.atob(a), g = /[\x00-\x09\x0E-\x1F]/.test(f), g ? (d[e] = !0, a) :f;
}
});
return e.$$nonprintable = d, e;
};
return {
groupSecretsByType:a,
Expand Down Expand Up @@ -10255,7 +10250,8 @@ scope:{
clipboardText:"=",
isDisabled:"=?",
displayWide:"=?",
inputText:"=?"
inputText:"=?",
multiline:"=?"
},
templateUrl:"views/directives/_copy-to-clipboard.html",
controller:[ "$scope", function(a) {
Expand Down Expand Up @@ -14196,8 +14192,10 @@ return function(a) {
return _.capitalize(a);
};
}).filter("isMultiline", function() {
return function(a) {
return !!a && a.indexOf("\n") !== -1;
return function(a, b) {
if (!a) return !1;
var c = a.search(/\r|\n/);
return c !== -1 && (!b || c !== a.length - 1);
};
}), angular.module("openshiftConsole").directive("affix", [ "$window", function(a) {
return {
Expand Down
Loading