KEYCLOAK-6065 Prevent password managers from saving credentials in admin console

This commit is contained in:
stianst 2017-12-19 19:37:14 +01:00 committed by Stian Thorgersen
parent 626004e782
commit 7d2d7e41d9
45 changed files with 7310 additions and 100 deletions

View file

@ -40,7 +40,7 @@ public class SAMLClientCredentialsForm extends Form {
@FindBy(id = "uploadKeyAlias")
private WebElement uploadKeyAlias;
@FindBy(id = "uploadStorePassword")
@FindBy(id = "uploadStorePas")
private WebElement uploadStorePassword;
public void importPemCertificateKey() {

View file

@ -48,7 +48,7 @@ public class LdapUserProviderForm extends Form {
@FindBy(id = "ldapBindDn")
private WebElement ldapBindDnInput;
@FindBy(id = "ldapBindCredential")
@FindBy(id = "ldapBindCred")
private WebElement ldapBindCredentialInput;
@FindBy(id = "customUserSearchFilter")

View file

@ -18,10 +18,10 @@ public class UserCredentials extends User {
return super.getUriFragment() + "/user-credentials";
}
@FindBy(id = "password")
@FindBy(id = "newPas")
private WebElement newPasswordInput;
@FindBy(id = "confirmPassword")
@FindBy(id = "confirmPas")
private WebElement confirmPasswordInput;
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='temporaryPassword']]")

View file

@ -409,3 +409,8 @@ table.kc-authz-table-expanded {
padding-right:0!important;
padding-left:0!important;
}
.password-conceal {
font-family: 'text-security-disc';
font-size: 14px;
}

View file

@ -1,3 +1,3 @@
parent=keycloak
import=common/rh-sso
styles=lib/rcue/css/rcue.min.css lib/rcue/css/rcue-additions.min.css node_modules/select2/select2.css css/styles.css lib/angular/treeview/css/angular.treeview.css
styles=lib/rcue/css/rcue.min.css lib/rcue/css/rcue-additions.min.css node_modules/select2/select2.css css/styles.css lib/angular/treeview/css/angular.treeview.css node_modules/text-security/dist/text-security.css

View file

@ -2956,3 +2956,14 @@ module.filter('startFrom', function () {
return [];
};
});
module.directive('kcPassword', function ($compile, Notifications) {
return {
restrict: 'A',
link: function ($scope, elem, attr, ctrl) {
elem.addClass("password-conceal");
elem.attr("type","text");
}
}
});

View file

@ -16,9 +16,6 @@
</h1>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group clearfix" data-ng-show="!create">
<label class="col-md-2 control-label" for="configId">{{:: 'id' | translate}} </label>

View file

@ -10,9 +10,6 @@
<h1>{{:: 'generate-private-key' | translate}}</h1>
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset class="form-group col-sm-10">
<div class="form-group">
<label class="col-md-2 control-label" for="downloadKeyFormat">{{:: 'archive-format' | translate}}</label>
@ -34,16 +31,16 @@
<kc-tooltip>{{:: 'key-alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="keyPassword">{{:: 'key-password' | translate}}</label>
<label class="col-md-2 control-label" for="keyPas">{{:: 'key-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="keyPassword" name="keyPassword" data-ng-model="jks.keyPassword" autofocus required>
<input class="form-control" kc-password id="keyPas" name="keyPas" data-ng-model="jks.keyPassword" autofocus required>
</div>
<kc-tooltip>{{:: 'key-password.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="storePassword">{{:: 'store-password' | translate}}</label>
<label class="col-md-2 control-label" for="storePas">{{:: 'store-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="storePassword" name="storePassword" data-ng-model="jks.storePassword" autofocus required>
<input class="form-control" kc-password id="storePas" name="storePassword" data-ng-model="jks.storePassword" autofocus required>
</div>
<kc-tooltip>{{:: 'store-password.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -10,9 +10,6 @@
<h1>{{:: 'import-client-certificate' | translate}}</h1>
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group">
<label class="col-md-2 control-label" for="uploadKeyFormat">{{:: 'archive-format' | translate}}</label>
@ -34,9 +31,9 @@
<kc-tooltip>{{:: 'jwt-import.key-alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group" data-ng-hide="hideKeystoreSettings()">
<label class="col-md-2 control-label" for="uploadStorePassword">{{:: 'store-password' | translate}}</label>
<label class="col-md-2 control-label" for="uploadStorePas">{{:: 'store-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="uploadStorePassword" name="uploadStorePassword" data-ng-model="uploadStorePassword" autofocus required>
<input class="form-control" kc-password id="uploadStorePas" name="uploadStorePas" data-ng-model="uploadStorePassword" autofocus required>
</div>
<kc-tooltip>{{:: 'store-password.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -8,9 +8,6 @@
<kc-tabs-client></kc-tabs-client>
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<legend collapsed><span class="text">{{:: 'import-keys-and-cert' | translate}}</span> <kc-tooltip>{{:: 'import-keys-and-cert.tooltip' | translate}}</kc-tooltip></legend>
<div class="form-group">
@ -33,16 +30,16 @@
<kc-tooltip>{{:: 'key-alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="keyPassword">{{:: 'key-password' | translate}}</label>
<label class="col-md-2 control-label" for="uploadKeyPas">{{:: 'key-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="uploadKeyPassword" name="uploadKeyPassword" data-ng-model="uploadKeyPassword" autofocus required>
<input class="form-control" kc-password id="uploadKeyPas" name="uploadKeyPassword" data-ng-model="uploadKeyPassword" autofocus required>
</div>
<kc-tooltip>{{:: 'key-password.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="uploadStorePassword">{{:: 'store-password' | translate}}</label>
<label class="col-md-2 control-label" for="uploadStorePas">{{:: 'store-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="uploadStorePassword" name="uploadStorePassword" data-ng-model="uploadStorePassword" autofocus required>
<input class="form-control" kc-password id="uploadStorePas" name="uploadStorePas" data-ng-model="uploadStorePassword" autofocus required>
</div>
<kc-tooltip>{{:: 'store-password.tooltip' | translate}}</kc-tooltip>
</div>
@ -85,9 +82,9 @@
<kc-tooltip>Archive alias for your private key and certificate.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="keyPassword">Key Password</label>
<label class="col-md-2 control-label" for="keyPas">Key Password</label>
<div class="col-md-6">
<input class="form-control" type="password" id="keyPassword" name="keyPassword" data-ng-model="jks.keyPassword" autofocus required>
<input class="form-control" kc-password id="keyPas" name="keyPas" data-ng-model="jks.keyPassword" autofocus required>
</div>
<kc-tooltip>Password to access the private key in the archive</kc-tooltip>
</div>
@ -99,9 +96,9 @@
<kc-tooltip>Realm certificate is stored in archive too. This is the alias to it.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="storePassword">Store Password</label>
<label class="col-md-2 control-label" for="storePas">Store Password</label>
<div class="col-md-6">
<input class="form-control" type="password" id="storePassword" name="storePassword" data-ng-model="jks.storePassword" autofocus required>
<input class="form-control" kc-password id="storePas" name="storePas" data-ng-model="jks.storePassword" autofocus required>
</div>
<kc-tooltip>Password to access the archive itself</kc-tooltip>
</div>

View file

@ -10,9 +10,6 @@
<h1>{{:: 'export-saml-key' | translate}} {{client.clientId|capitalize}}</h1>
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset class="form-group col-sm-10">
<div class="form-group">
<label class="col-md-2 control-label" for="downloadKeyFormat">{{:: 'archive-format' | translate}}</label>
@ -34,9 +31,9 @@
<kc-tooltip>{{:: 'key-alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group" data-ng-hide="!keyInfo.privateKey">
<label class="col-md-2 control-label" for="keyPassword">{{:: 'key-password' | translate}}</label>
<label class="col-md-2 control-label" for="keyPas">{{:: 'key-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="keyPassword" name="keyPassword" data-ng-model="jks.keyPassword" autofocus required>
<input class="form-control" kc-password id="keyPas" name="keyPas" data-ng-model="jks.keyPassword" autofocus required>
</div>
<kc-tooltip>{{:: 'key-password.tooltip' | translate}}</kc-tooltip>
</div>
@ -48,9 +45,9 @@
<kc-tooltip>{{:: 'realm-certificate-alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="storePassword">{{:: 'store-password' | translate}}</label>
<label class="col-md-2 control-label" for="storePas">{{:: 'store-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="storePassword" name="storePassword" data-ng-model="jks.storePassword" autofocus required>
<input class="form-control" kc-password id="storePas" name="storePas" data-ng-model="jks.storePassword" autofocus required>
</div>
<kc-tooltip>{{:: 'store-password.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -10,9 +10,6 @@
<h1>{{:: 'import-saml-key' | translate}} {{client.clientId|capitalize}}</h1>
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group">
<label class="col-md-2 control-label" for="uploadKeyFormat">{{:: 'archive-format' | translate}}</label>
@ -34,9 +31,9 @@
<kc-tooltip>{{:: 'key-alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group" data-ng-hide="hideKeystoreSettings()">
<label class="col-md-2 control-label" for="uploadStorePassword">{{:: 'store-password' | translate}}</label>
<label class="col-md-2 control-label" for="uploadStorePas">{{:: 'store-password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" type="password" id="uploadStorePassword" name="uploadStorePassword" data-ng-model="uploadStorePassword" autofocus required>
<input class="form-control" kc-password id="uploadStorePas" name="uploadStorePas" data-ng-model="uploadStorePassword" autofocus required>
</div>
<kc-tooltip>{{:: 'store-password.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -8,9 +8,6 @@
<kc-tabs-identity-provider></kc-tabs-identity-provider>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageIdentityProviders">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="redirectUri">{{:: 'redirect-uri' | translate}}</label>
@ -31,7 +28,7 @@
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="clientSecret"><span class="required">*</span> {{:: 'bitbucket-consumer-secret' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="clientSecret" type="password" ng-model="identityProvider.config.clientSecret" required>
<input class="form-control" id="clientSecret" kc-password ng-model="identityProvider.config.clientSecret" required>
</div>
<kc-tooltip>{{:: 'bitbucket.secret.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -8,9 +8,6 @@
<kc-tabs-identity-provider></kc-tabs-identity-provider>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageIdentityProviders">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="redirectUri">{{:: 'redirect-uri' | translate}}</label>
@ -31,7 +28,7 @@
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="clientSecret"><span class="required">*</span> {{:: 'gitlab-application-secret' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="clientSecret" type="password" ng-model="identityProvider.config.clientSecret" required>
<input class="form-control" id="clientSecret" kc-password ng-model="identityProvider.config.clientSecret" required>
</div>
<kc-tooltip>{{:: 'gitlab.application-secret.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -9,9 +9,6 @@
<kc-tabs-identity-provider></kc-tabs-identity-provider>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageIdentityProviders">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="redirectUri">{{:: 'redirect-uri' | translate}}</label>
@ -172,7 +169,7 @@
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="clientSecret"><span class="required">*</span> {{:: 'client-secret' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="clientSecret" type="password" ng-model="identityProvider.config.clientSecret" required>
<input class="form-control" id="clientSecret" kc-password ng-model="identityProvider.config.clientSecret" required>
</div>
<kc-tooltip>{{:: 'client-secret.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -8,11 +8,6 @@
<kc-tabs-identity-provider></kc-tabs-identity-provider>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageIdentityProviders">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="redirectUri">{{:: 'redirect-uri' | translate}}</label>
@ -47,7 +42,7 @@
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="clientSecret"><span class="required">*</span> {{:: 'client-secret' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="clientSecret" type="password" ng-model="identityProvider.config.clientSecret" required>
<input class="form-control" id="clientSecret" kc-password ng-model="identityProvider.config.clientSecret" required>
</div>
<kc-tooltip>{{:: 'social.client-secret.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -8,9 +8,6 @@
<kc-tabs-identity-provider></kc-tabs-identity-provider>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageIdentityProviders">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="redirectUri">{{:: 'redirect-uri' | translate}}</label>
@ -31,7 +28,7 @@
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="clientSecret"><span class="required">*</span> {{:: 'client-secret' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="clientSecret" type="password" ng-model="identityProvider.config.clientSecret" required>
<input class="form-control" id="clientSecret" kc-password ng-model="identityProvider.config.clientSecret" required>
</div>
<kc-tooltip>{{:: 'social.client-secret.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -2,9 +2,6 @@
<kc-tabs-realm></kc-tabs-realm>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="smtpHost"><span class="required">*</span> {{:: 'host' | translate}}</label>
<div class="col-md-6">
@ -79,9 +76,9 @@
</div>
</div>
<div class="form-group clearfix" data-ng-show="realm.smtpServer.auth">
<label class="col-md-2 control-label" for="smtpPassword"><span class="required">*</span> {{:: 'password' | translate}}</label>
<label class="col-md-2 control-label" for="smtpPas"><span class="required">*</span> {{:: 'password' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="smtpPassword" type="password" ng-model="realm.smtpServer.password" placeholder="{{:: 'login-password' | translate}}" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
<input class="form-control" id="smtpPas" kc-password ng-model="realm.smtpServer.password" placeholder="{{:: 'login-password' | translate}}" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
</div>
</div>

View file

@ -7,22 +7,19 @@
<kc-tabs-user></kc-tabs-user>
<form class="form-horizontal" name="userForm" novalidate>
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset class="border-top">
<legend><span class="text">{{:: 'manage-user-password' | translate}}</span></legend>
<div class="form-group">
<label class="col-md-2 control-label" for="password">{{:: 'new-password' | translate}} <span class="required" data-ng-show="create">*</span></label>
<label class="col-md-2 control-label" for="newPas">{{:: 'new-password' | translate}} <span class="required" data-ng-show="create">*</span></label>
<div class="col-md-6">
<input class="form-control" type="password" id="password" name="password" data-ng-model="password" required>
<input class="form-control" kc-password type="text" id="newPas" name="newPas" data-ng-model="password" required>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="confirmPassword">{{:: 'password-confirmation' | translate}} <span class="required" data-ng-show="create">*</span></label>
<label class="col-md-2 control-label" for="confirmPas">{{:: 'password-confirmation' | translate}} <span class="required" data-ng-show="create">*</span></label>
<div class="col-md-6">
<input class="form-control" type="password" id="confirmPassword" name="confirmPassword" data-ng-model="confirmPassword" required>
<input class="form-control" kc-password id="confirmPas" name="confirmPas" data-ng-model="confirmPassword" required>
</div>
</div>

View file

@ -8,9 +8,6 @@
<kc-tabs-ldap></kc-tabs-ldap>
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<input type="text" readonly value="this is not a login form" style="display: none;">
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset>
<legend><span class="text">{{:: 'required-settings' | translate}}</span></legend>
<div class="form-group clearfix" data-ng-show="!create">
@ -151,9 +148,9 @@
<kc-tooltip>{{:: 'ldap.bind-dn.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix" data-ng-hide="instance.config['authType'][0] == 'none'">
<label class="col-md-2 control-label" for="ldapBindCredential"><span class="required">*</span> {{:: 'bind-credential' | translate}}</label>
<label class="col-md-2 control-label" for="ldapBindCred"><span class="required">*</span> {{:: 'bind-credential' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="ldapBindCredential" type="password" ng-model="instance.config['bindCredential'][0]" placeholder="{{:: 'ldap-bind-credentials' | translate}}" data-ng-required="instance.config['authType'][0] != 'none'">
<input class="form-control" id="ldapBindCred" kc-password ng-model="instance.config['bindCredential'][0]" placeholder="{{:: 'ldap-bind-credentials' | translate}}" data-ng-required="instance.config['authType'][0] != 'none'">
</div>
<kc-tooltip>{{:: 'ldap.bind-credential.tooltip' | translate}}</kc-tooltip>
<div class="col-sm-4" data-ng-show="access.manageRealm">

View file

@ -400,3 +400,8 @@ table.kc-authz-table-expanded {
padding-right:0!important;
padding-left:0!important;
}
.password-conceal {
font-family: 'text-security-disc';
font-size: 14px;
}

View file

@ -1,3 +1,3 @@
parent=base
import=common/keycloak
styles=lib/patternfly/css/patternfly.css node_modules/select2/select2.css css/styles.css lib/angular/treeview/css/angular.treeview.css
styles=lib/patternfly/css/patternfly.css node_modules/select2/select2.css css/styles.css lib/angular/treeview/css/angular.treeview.css node_modules/text-security/dist/text-security.css

View file

@ -0,0 +1,4 @@
demo.html
.eslintrc*
.vscode/
.idea/

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Oskari Noppa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,52 @@
# text-security
Cross-browser alternative to `-webkit-text-security`
This is a simple set of fonts that only consists of 3 different characters.
Disc <img
src="https://cdn.rawgit.com/noppa/text-security/master/assets/disc.svg"
width="5px"> circle <img
src="https://cdn.rawgit.com/noppa/text-security/master/assets/circle.svg"
width="10px"> and square <img
src="https://cdn.rawgit.com/noppa/text-security/master/assets/square.svg"
width="10px">. For example, setting `font-family: "text-security-circle"` for
an element should then display all the element's characters in a concealed
way, like it was a password field.
This is useful if you want to get the benefits of `input[type="password"]`
but also combine that with other element types, like `input[type="tel"]`. In
fact, the project was created for this exact purpose [as an answer to a
StackOverflow
question](https://stackoverflow.com/questions/36935576/how-to-make-input-type-tel-work-as-type-password/36950075#36950075).
## Installation
```
npm install text-security
```
You can use the fonts by adding this repo as a dependency and including
`dist/text-security.css` in your project, like so
`<link rel="stylesheet" type="text/css"
href="node_modules/text-security/dist/text-security.css">`
## Building with custom modifications
If you want to make your own tweaks, the `npm run build` command has two
optional arguments for you. By default, 768 different unicode characters are
included in the fonts, making it reliable for different use-cases but also
adding quite a big font files as a dependency. You can use the
`--max={number}` option to reduce the amount of included unicode characters.
If you are feeling wild, you can also add your custom shapes by dropping them
to *assets* folder and running the build with `--shapes={string}` option. The
value should be comma-separated list of svg file names (don't include the
file extension in the name). The default value is `circle,square,disc`.
The generated css will have class names with `text-security-*` prefix
followed by the name of the shape, like `text-security-disc`.
## Demo
*demo.html* contains a proof-of-concept demo file, which you can just open in
any browser. The same thing can also be found [as a
fiddle](https://jsfiddle.net/449Lamue/6/). In development, you can also try
out the library by just including the css using RawGit `<link
rel="stylesheet" type="text/css"
href="https://rawgit.com/noppa/text-security/master/dist/text-security.css">`

View file

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<svg viewBox="0 0 200 400" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<path d="
M 100, 200
m -50, 0
a 50,50 0 1,0 100,0
a 50,50 0 1,0 -100,0
M 100, 200
m 40, 0
a 40,40 0 1,1 -80,0
a 40,40 0 1,1 80,0
"
fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 346 B

View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg viewBox="0 0 140 500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<circle cx="70" cy="250" r="55"/>
</svg>

After

Width:  |  Height:  |  Size: 148 B

View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg viewBox="0 0 300 500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="250" width="220" height="220"/>
</svg>

After

Width:  |  Height:  |  Size: 161 B

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 151 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 224 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 84 KiB

View file

@ -0,0 +1,24 @@
@font-face {
font-family: 'text-security-circle';
src: url('text-security-circle.eot');
src: url('text-security-circle.eot?#iefix') format('embedded-opentype'),
url('text-security-circle.woff') format('woff'),
url('text-security-circle.ttf') format('truetype'),
url('text-security-circle.svg#text-security') format('svg');
}
@font-face {
font-family: 'text-security-square';
src: url('text-security-square.eot');
src: url('text-security-square.eot?#iefix') format('embedded-opentype'),
url('text-security-square.woff') format('woff'),
url('text-security-square.ttf') format('truetype'),
url('text-security-square.svg#text-security') format('svg');
}
@font-face {
font-family: 'text-security-disc';
src: url('text-security-disc.eot');
src: url('text-security-disc.eot?#iefix') format('embedded-opentype'),
url('text-security-disc.woff') format('woff'),
url('text-security-disc.ttf') format('truetype'),
url('text-security-disc.svg#text-security') format('svg');
}

View file

@ -0,0 +1,89 @@
var
icons2font = require('svgicons2svgfont'),
fs = require('fs'),
path = require('path'),
svg2ttf = require('svg2ttf'),
ttf2eot = require('ttf2eot'),
ttf2woff = require('ttf2woff'),
args = require('yargs').argv;
/**
* We need to loop through the unicode character list and pass them all for svgicons2svgfont.
* If you want to reduce the file-sizes with the cost of worse character support, you can
* specify --max={number} when building. This number will be the highest supported character
* code. For example, building with `npm run build -- --max=126` would only support the Basic Latin unicode block.
*
* @todo Perhaps this could be better achieved by just defining the notdef glyph?
* That would probably reduce the file sizes quite a bit, but I'm not quite sure how that would work with the
* tff and woff versions.
* @param {number=} [max=767]
*/
var MAX_VALUE = args.max || 767;
/**
* Comma-separated list of the supported shapes.
* @param {string} [shapes='circle,square,disc']
*/
var SHAPES = args.shapes || 'circle,square,disc';
var styleTemplate = fs.readFileSync('style-template.css', 'utf-8'), stylesheet = '',
characters = [];
for (var i = 0; i <= MAX_VALUE; i++){
characters.push(String.fromCharCode(i));
}
function bufferFrom(source) {
return typeof Buffer.from === 'function' ? Buffer.from(source) : new Buffer(source);
}
function logError(err) {
if (err) {
console.error(err);
}
}
var DIST_DIR = path.join(__dirname, 'dist');
if (!fs.existsSync(DIST_DIR)) {
fs.mkdirSync(DIST_DIR);
}
SHAPES.split(',').forEach(function (shape) {
var
fontName = 'text-security-' + shape,
fontPath = path.join(DIST_DIR, fontName),
fontStream = icons2font({
fontName: fontName
});
fontStream
.pipe(fs.createWriteStream(fontPath + '.svg'))//Create the .svg font
.on('finish', function () {
//Create the other formats using the newly created font and Fontello's conversion libs
var ttf = svg2ttf(fs.readFileSync(fontPath + '.svg', 'utf-8'), {});
fs.writeFileSync(fontPath + '.ttf', bufferFrom(ttf.buffer), 'utf-8');
// ttf2eot and ttf2woff expect a buffer, while svg2ttf seems to expect a string
// this would be better read from the buffer, but will do for now
var ttfFile = fs.readFileSync(fontPath + '.ttf');
var eot = ttf2eot(ttfFile, {});
fs.writeFile(fontPath + '.eot', bufferFrom(eot.buffer), 'utf-8', logError);
var woff = ttf2woff(ttfFile, {});
fs.writeFile(fontPath + '.woff', bufferFrom(woff.buffer), 'utf-8', logError);
})
.on('error', logError);
var glyph = fs.createReadStream(path.join(__dirname, 'assets', shape + '.svg'));
glyph.metadata = {
unicode: characters,
name: shape
};
fontStream.write(glyph);
fontStream.end();
//Append the new shape to the generated stylesheet
stylesheet += styleTemplate.replace(/\{\{shape}}/g, shape) + '\n';
});
fs.writeFile(path.join(__dirname, 'dist', 'text-security.css'), stylesheet, logError);

View file

@ -0,0 +1,60 @@
{
"_from": "text-security@^1.0.1",
"_id": "text-security@1.0.1",
"_inBundle": false,
"_integrity": "sha512-Y5fStAKoEvLr6h2oz/nkSm+P3b5f3t+JAnNkycFJr15mz32XvrfBONjO+fNAnKaP5+YuD69tVNmlmKmfZu9ZGw==",
"_location": "/text-security",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "text-security@^1.0.1",
"name": "text-security",
"escapedName": "text-security",
"rawSpec": "^1.0.1",
"saveSpec": null,
"fetchSpec": "^1.0.1"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/text-security/-/text-security-1.0.1.tgz",
"_shasum": "9a04f42c322123b1f1fffa49d1d62c638fe72ba3",
"_spec": "text-security@^1.0.1",
"_where": "/home/st/dev/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
"author": {
"name": "Oskari Noppa"
},
"bugs": {
"url": "https://github.com/noppa/text-security/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Cross-browser alternative to -webkit-text-security",
"devDependencies": {
"svg2ttf": "4.0.0",
"svgicons2svgfont": "5.0.0",
"ttf2eot": "2.0.0",
"ttf2woff": "2.0.1",
"yargs": "4.6.0"
},
"homepage": "https://github.com/noppa/text-security#readme",
"keywords": [
"-webkit-text-security",
"conceal",
"password"
],
"license": "MIT",
"main": "index.js",
"name": "text-security",
"repository": {
"type": "git",
"url": "git+https://github.com/noppa/text-security.git"
},
"scripts": {
"build": "node index.js",
"prebuild": "npm install",
"test": ""
},
"version": "1.0.1"
}

View file

@ -0,0 +1,8 @@
@font-face {
font-family: 'text-security-{{shape}}';
src: url('text-security-{{shape}}.eot');
src: url('text-security-{{shape}}.eot?#iefix') format('embedded-opentype'),
url('text-security-{{shape}}.woff') format('woff'),
url('text-security-{{shape}}.ttf') format('truetype'),
url('text-security-{{shape}}.svg#text-security') format('svg');
}

View file

@ -4,22 +4,23 @@
"description": "Keycloak Admin Console",
"license": "Apache-2.0",
"dependencies": {
"angular": "^1.6.6",
"angular-cookies": "^1.6.6",
"angular-loader": "^1.6.6",
"angular-resource": "^1.6.6",
"angular-route": "^1.6.6",
"angular-sanitize": "^1.6.6",
"angular-translate": "^2.15.1",
"angular-translate-loader-url": "^2.15.1",
"angular-treeview": "^0.1.5",
"angular-ui-select2": "^0.0.5",
"autofill-event": "^0.0.1",
"bootstrap": "^3.3.7",
"filesaver": "^0.0.13",
"font-awesome": "^4.7.0",
"jquery": "^3.2.1",
"ng-file-upload": "^12.2.13",
"select2": "3.5.1"
"angular": "1.6.6",
"angular-cookies": "1.6.6",
"angular-loader": "1.6.6",
"angular-resource": "1.6.6",
"angular-route": "1.6.6",
"angular-sanitize": "1.6.6",
"angular-translate": "2.15.1",
"angular-translate-loader-url": "2.15.1",
"angular-treeview": "0.1.5",
"angular-ui-select2": "0.0.5",
"autofill-event": "0.0.1",
"bootstrap": "3.3.7",
"filesaver": "0.0.13",
"font-awesome": "4.7.0",
"jquery": "3.2.1",
"ng-file-upload": "12.2.13",
"select2": "3.5.1",
"text-security": "1.0.1"
}
}