Add password strength meter to backup creation UI
https://github.com/vector-im/riot-meta/issues/227
This commit is contained in:
parent
0c6e98548e
commit
075c13a5bd
5 changed files with 205 additions and 39 deletions
|
@ -96,7 +96,8 @@
|
||||||
"text-encoding-utf-8": "^1.0.1",
|
"text-encoding-utf-8": "^1.0.1",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"velocity-vector": "github:vector-im/velocity#059e3b2",
|
"velocity-vector": "github:vector-im/velocity#059e3b2",
|
||||||
"whatwg-fetch": "^1.1.1"
|
"whatwg-fetch": "^1.1.1",
|
||||||
|
"zxcvbn": "^4.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.26.0",
|
"babel-cli": "^6.26.0",
|
||||||
|
|
|
@ -19,8 +19,26 @@ limitations under the License.
|
||||||
padding: 20px
|
padding: 20px
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_CreateKeyBackupDialog_primaryContainer::after {
|
||||||
|
content: "";
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CreateKeyBackupDialog_passPhraseHelp {
|
||||||
|
float: right;
|
||||||
|
width: 230px;
|
||||||
|
height: 85px;
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CreateKeyBackupDialog_passPhraseHelp progress {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_CreateKeyBackupDialog_passPhraseInput {
|
.mx_CreateKeyBackupDialog_passPhraseInput {
|
||||||
width: 300px;
|
width: 250px;
|
||||||
border: 1px solid $accent-color;
|
border: 1px solid $accent-color;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sdk from '../../../../index';
|
import sdk from '../../../../index';
|
||||||
import MatrixClientPeg from '../../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../../MatrixClientPeg';
|
||||||
|
import { scorePassword } from '../../../../utils/PasswordScorer';
|
||||||
|
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
|
|
||||||
|
@ -30,6 +31,8 @@ const PHASE_BACKINGUP = 4;
|
||||||
const PHASE_DONE = 5;
|
const PHASE_DONE = 5;
|
||||||
const PHASE_OPTOUT_CONFIRM = 6;
|
const PHASE_OPTOUT_CONFIRM = 6;
|
||||||
|
|
||||||
|
const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc.
|
||||||
|
|
||||||
// XXX: copied from ShareDialog: factor out into utils
|
// XXX: copied from ShareDialog: factor out into utils
|
||||||
function selectText(target) {
|
function selectText(target) {
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
|
@ -52,6 +55,7 @@ export default React.createClass({
|
||||||
passPhraseConfirm: '',
|
passPhraseConfirm: '',
|
||||||
copied: false,
|
copied: false,
|
||||||
downloaded: false,
|
downloaded: false,
|
||||||
|
zxcvbnResult: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -173,6 +177,10 @@ export default React.createClass({
|
||||||
_onPassPhraseChange: function(e) {
|
_onPassPhraseChange: function(e) {
|
||||||
this.setState({
|
this.setState({
|
||||||
passPhrase: e.target.value,
|
passPhrase: e.target.value,
|
||||||
|
// precompute this and keep it in state: zxcvbn is fast but
|
||||||
|
// we use it in a couple of different places so so point recomputing
|
||||||
|
// it unnecessarily.
|
||||||
|
zxcvbnResult: scorePassword(e.target.value),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -183,17 +191,46 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_passPhraseIsValid: function() {
|
_passPhraseIsValid: function() {
|
||||||
return this.state.passPhrase !== '';
|
return this.state.zxcvbnResult && this.state.zxcvbnResult.score >= PASSWORD_MIN_SCORE;
|
||||||
},
|
},
|
||||||
|
|
||||||
_renderPhasePassPhrase: function() {
|
_renderPhasePassPhrase: function() {
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
|
let strengthMeter;
|
||||||
|
let helpText;
|
||||||
|
if (this.state.zxcvbnResult) {
|
||||||
|
if (this.state.zxcvbnResult.score >= PASSWORD_MIN_SCORE) {
|
||||||
|
helpText = _t("Great! This passphrase looks strong enough.");
|
||||||
|
} else {
|
||||||
|
const suggestions = [];
|
||||||
|
for (let i = 0; i < this.state.zxcvbnResult.feedback.suggestions.length; ++i) {
|
||||||
|
suggestions.push(<div key={i}>{this.state.zxcvbnResult.feedback.suggestions[i]}</div>);
|
||||||
|
}
|
||||||
|
const suggestionBlock = suggestions.length > 0 ? <div>
|
||||||
|
{suggestions}
|
||||||
|
</div> : null;
|
||||||
|
|
||||||
|
helpText = <div>
|
||||||
|
{this.state.zxcvbnResult.feedback.warning}
|
||||||
|
{suggestionBlock}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
strengthMeter = <div>
|
||||||
|
<progress max={PASSWORD_MIN_SCORE} value={this.state.zxcvbnResult.score} />
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<p>{_t("Secure your encrypted message history with a Recovery Passphrase.")}</p>
|
<p>{_t("Secure your encrypted message history with a Recovery Passphrase.")}</p>
|
||||||
<p>{_t("You'll need it if you log out or lose access to this device.")}</p>
|
<p>{_t("You'll need it if you log out or lose access to this device.")}</p>
|
||||||
|
|
||||||
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
<div className="mx_CreateKeyBackupDialog_primaryContainer">
|
||||||
|
<div className="mx_CreateKeyBackupDialog_passPhraseHelp">
|
||||||
|
{strengthMeter}
|
||||||
|
{helpText}
|
||||||
|
</div>
|
||||||
<input type="password"
|
<input type="password"
|
||||||
onChange={this._onPassPhraseChange}
|
onChange={this._onPassPhraseChange}
|
||||||
onKeyPress={this._onPassPhraseKeyPress}
|
onKeyPress={this._onPassPhraseKeyPress}
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
"Failed to invite users to community": "Failed to invite users to community",
|
"Failed to invite users to community": "Failed to invite users to community",
|
||||||
"Failed to invite users to %(groupId)s": "Failed to invite users to %(groupId)s",
|
"Failed to invite users to %(groupId)s": "Failed to invite users to %(groupId)s",
|
||||||
"Failed to add the following rooms to %(groupId)s:": "Failed to add the following rooms to %(groupId)s:",
|
"Failed to add the following rooms to %(groupId)s:": "Failed to add the following rooms to %(groupId)s:",
|
||||||
|
"Error": "Error",
|
||||||
"Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.",
|
"Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.",
|
||||||
"Dismiss": "Dismiss",
|
"Dismiss": "Dismiss",
|
||||||
"Riot does not have permission to send you notifications - please check your browser settings": "Riot does not have permission to send you notifications - please check your browser settings",
|
"Riot does not have permission to send you notifications - please check your browser settings": "Riot does not have permission to send you notifications - please check your browser settings",
|
||||||
|
@ -220,6 +221,31 @@
|
||||||
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
|
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
|
||||||
"Not a valid Riot keyfile": "Not a valid Riot keyfile",
|
"Not a valid Riot keyfile": "Not a valid Riot keyfile",
|
||||||
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
|
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
|
||||||
|
"Use a few words, avoid common phrases": "Use a few words, avoid common phrases",
|
||||||
|
"No need for symbols, digits, or uppercase letters": "No need for symbols, digits, or uppercase letters",
|
||||||
|
"Use a longer keyboard pattern with more turns": "Use a longer keyboard pattern with more turns",
|
||||||
|
"Avoid repeated words and characters": "Avoid repeated words and characters",
|
||||||
|
"Avoid sequences": "Avoid sequences",
|
||||||
|
"Avoid recent years": "Avoid recent years",
|
||||||
|
"Avoid years that are associated with you": "Avoid years that are associated with you",
|
||||||
|
"Avoid dates and years that are associated with you": "Avoid dates and years that are associated with you",
|
||||||
|
"Capitalization doesn't help very much": "Capitalization doesn't help very much",
|
||||||
|
"All-uppercase is almost as easy to guess as all-lowercase": "All-uppercase is almost as easy to guess as all-lowercase",
|
||||||
|
"Reversed words aren't much harder to guess": "Reversed words aren't much harder to guess",
|
||||||
|
"Predictable substitutions like '@' instead of 'a' don't help very much": "Predictable substitutions like '@' instead of 'a' don't help very much",
|
||||||
|
"Add another word or two. Uncommon words are better.": "Add another word or two. Uncommon words are better.",
|
||||||
|
"Repeats like \"aaa\" are easy to guess": "Repeats like \"aaa\" are easy to guess",
|
||||||
|
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"",
|
||||||
|
"Sequences like abc or 6543 are easy to guess": "Sequences like abc or 6543 are easy to guess",
|
||||||
|
"Recent years are easy to guess": "Recent years are easy to guess",
|
||||||
|
"Dates are often easy to guess": "Dates are often easy to guess",
|
||||||
|
"This is a top-10 common password": "This is a top-10 common password",
|
||||||
|
"This is a top-100 common password": "This is a top-100 common password",
|
||||||
|
"This is a very common password": "This is a very common password",
|
||||||
|
"This is similar to a commonly used password": "This is similar to a commonly used password",
|
||||||
|
"A word by itself is easy to guess": "A word by itself is easy to guess",
|
||||||
|
"Names and surnames by themselves are easy to guess": "Names and surnames by themselves are easy to guess",
|
||||||
|
"Common names and surnames are easy to guess": "Common names and surnames are easy to guess",
|
||||||
"Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.",
|
"Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.",
|
||||||
"Please contact your homeserver administrator.": "Please contact your homeserver administrator.",
|
"Please contact your homeserver administrator.": "Please contact your homeserver administrator.",
|
||||||
"Failed to join room": "Failed to join room",
|
"Failed to join room": "Failed to join room",
|
||||||
|
@ -275,7 +301,6 @@
|
||||||
"Incoming call from %(name)s": "Incoming call from %(name)s",
|
"Incoming call from %(name)s": "Incoming call from %(name)s",
|
||||||
"Decline": "Decline",
|
"Decline": "Decline",
|
||||||
"Accept": "Accept",
|
"Accept": "Accept",
|
||||||
"Error": "Error",
|
|
||||||
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains",
|
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains",
|
||||||
"Incorrect verification code": "Incorrect verification code",
|
"Incorrect verification code": "Incorrect verification code",
|
||||||
"Enter Code": "Enter Code",
|
"Enter Code": "Enter Code",
|
||||||
|
@ -973,41 +998,6 @@
|
||||||
"Room contains unknown devices": "Room contains unknown devices",
|
"Room contains unknown devices": "Room contains unknown devices",
|
||||||
"\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.",
|
"\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.",
|
||||||
"Unknown devices": "Unknown devices",
|
"Unknown devices": "Unknown devices",
|
||||||
"Secure your encrypted message history with a Recovery Passphrase.": "Secure your encrypted message history with a Recovery Passphrase.",
|
|
||||||
"You'll need it if you log out or lose access to this device.": "You'll need it if you log out or lose access to this device.",
|
|
||||||
"Enter a passphrase...": "Enter a passphrase...",
|
|
||||||
"Next": "Next",
|
|
||||||
"If you don't want encrypted message history to be availble on other devices, <button>opt out</button>.": "If you don't want encrypted message history to be availble on other devices, <button>opt out</button>.",
|
|
||||||
"Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.": "Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.",
|
|
||||||
"That matches!": "That matches!",
|
|
||||||
"That doesn't match.": "That doesn't match.",
|
|
||||||
"Go back to set it again.": "Go back to set it again.",
|
|
||||||
"Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.",
|
|
||||||
"Repeat your passphrase...": "Repeat your passphrase...",
|
|
||||||
"Make a copy of this Recovery Key and keep it safe.": "Make a copy of this Recovery Key and keep it safe.",
|
|
||||||
"As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.",
|
|
||||||
"Your Recovery Key": "Your Recovery Key",
|
|
||||||
"Copy to clipboard": "Copy to clipboard",
|
|
||||||
"Download": "Download",
|
|
||||||
"I've made a copy": "I've made a copy",
|
|
||||||
"Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:": "Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:",
|
|
||||||
"Your Recovery Key is in your <b>Downloads</b> folder.": "Your Recovery Key is in your <b>Downloads</b> folder.",
|
|
||||||
"<b>Print it</b> and store it somewhere safe": "<b>Print it</b> and store it somewhere safe",
|
|
||||||
"<b>Save it</b> on a USB key or backup drive": "<b>Save it</b> on a USB key or backup drive",
|
|
||||||
"<b>Copy it</b> to your personal cloud storage": "<b>Copy it</b> to your personal cloud storage",
|
|
||||||
"Got it": "Got it",
|
|
||||||
"Backup created": "Backup created",
|
|
||||||
"Your encryption keys are now being backed up to your Homeserver.": "Your encryption keys are now being backed up to your Homeserver.",
|
|
||||||
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.",
|
|
||||||
"Set up Secure Message Recovery": "Set up Secure Message Recovery",
|
|
||||||
"Create a Recovery Passphrase": "Create a Recovery Passphrase",
|
|
||||||
"Confirm Recovery Passphrase": "Confirm Recovery Passphrase",
|
|
||||||
"Recovery Key": "Recovery Key",
|
|
||||||
"Keep it safe": "Keep it safe",
|
|
||||||
"Backing up...": "Backing up...",
|
|
||||||
"Create Key Backup": "Create Key Backup",
|
|
||||||
"Unable to create key backup": "Unable to create key backup",
|
|
||||||
"Retry": "Retry",
|
|
||||||
"Unable to load backup status": "Unable to load backup status",
|
"Unable to load backup status": "Unable to load backup status",
|
||||||
"Unable to restore backup": "Unable to restore backup",
|
"Unable to restore backup": "Unable to restore backup",
|
||||||
"No backup found!": "No backup found!",
|
"No backup found!": "No backup found!",
|
||||||
|
@ -1016,6 +1006,7 @@
|
||||||
"Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys",
|
"Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys",
|
||||||
"Enter Recovery Passphrase": "Enter Recovery Passphrase",
|
"Enter Recovery Passphrase": "Enter Recovery Passphrase",
|
||||||
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Access your secure message history and set up secure messaging by entering your recovery passphrase.",
|
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Access your secure message history and set up secure messaging by entering your recovery passphrase.",
|
||||||
|
"Next": "Next",
|
||||||
"If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>",
|
"If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>",
|
||||||
"Enter Recovery Key": "Enter Recovery Key",
|
"Enter Recovery Key": "Enter Recovery Key",
|
||||||
"This looks like a valid recovery key!": "This looks like a valid recovery key!",
|
"This looks like a valid recovery key!": "This looks like a valid recovery key!",
|
||||||
|
@ -1346,6 +1337,41 @@
|
||||||
"The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
|
"The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
|
||||||
"File to import": "File to import",
|
"File to import": "File to import",
|
||||||
"Import": "Import",
|
"Import": "Import",
|
||||||
|
"Great! This passphrase looks strong enough.": "Great! This passphrase looks strong enough.",
|
||||||
|
"Secure your encrypted message history with a Recovery Passphrase.": "Secure your encrypted message history with a Recovery Passphrase.",
|
||||||
|
"You'll need it if you log out or lose access to this device.": "You'll need it if you log out or lose access to this device.",
|
||||||
|
"Enter a passphrase...": "Enter a passphrase...",
|
||||||
|
"If you don't want encrypted message history to be availble on other devices, <button>opt out</button>.": "If you don't want encrypted message history to be availble on other devices, <button>opt out</button>.",
|
||||||
|
"Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.": "Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.",
|
||||||
|
"That matches!": "That matches!",
|
||||||
|
"That doesn't match.": "That doesn't match.",
|
||||||
|
"Go back to set it again.": "Go back to set it again.",
|
||||||
|
"Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.",
|
||||||
|
"Repeat your passphrase...": "Repeat your passphrase...",
|
||||||
|
"Make a copy of this Recovery Key and keep it safe.": "Make a copy of this Recovery Key and keep it safe.",
|
||||||
|
"As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.",
|
||||||
|
"Your Recovery Key": "Your Recovery Key",
|
||||||
|
"Copy to clipboard": "Copy to clipboard",
|
||||||
|
"Download": "Download",
|
||||||
|
"I've made a copy": "I've made a copy",
|
||||||
|
"Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:": "Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:",
|
||||||
|
"Your Recovery Key is in your <b>Downloads</b> folder.": "Your Recovery Key is in your <b>Downloads</b> folder.",
|
||||||
|
"<b>Print it</b> and store it somewhere safe": "<b>Print it</b> and store it somewhere safe",
|
||||||
|
"<b>Save it</b> on a USB key or backup drive": "<b>Save it</b> on a USB key or backup drive",
|
||||||
|
"<b>Copy it</b> to your personal cloud storage": "<b>Copy it</b> to your personal cloud storage",
|
||||||
|
"Got it": "Got it",
|
||||||
|
"Backup created": "Backup created",
|
||||||
|
"Your encryption keys are now being backed up to your Homeserver.": "Your encryption keys are now being backed up to your Homeserver.",
|
||||||
|
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.",
|
||||||
|
"Set up Secure Message Recovery": "Set up Secure Message Recovery",
|
||||||
|
"Create a Recovery Passphrase": "Create a Recovery Passphrase",
|
||||||
|
"Confirm Recovery Passphrase": "Confirm Recovery Passphrase",
|
||||||
|
"Recovery Key": "Recovery Key",
|
||||||
|
"Keep it safe": "Keep it safe",
|
||||||
|
"Backing up...": "Backing up...",
|
||||||
|
"Create Key Backup": "Create Key Backup",
|
||||||
|
"Unable to create key backup": "Unable to create key backup",
|
||||||
|
"Retry": "Retry",
|
||||||
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
||||||
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
||||||
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
|
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
|
||||||
|
|
84
src/utils/PasswordScorer.js
Normal file
84
src/utils/PasswordScorer.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018 New Vector Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Zxcvbn from 'zxcvbn';
|
||||||
|
|
||||||
|
import MatrixClientPeg from '../MatrixClientPeg';
|
||||||
|
import { _t, _td } from '../languageHandler';
|
||||||
|
|
||||||
|
const ZXCVBN_USER_INPUTS = [
|
||||||
|
'riot',
|
||||||
|
'matrix',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Translations for zxcvbn's suggestion strings
|
||||||
|
_td("Use a few words, avoid common phrases");
|
||||||
|
_td("No need for symbols, digits, or uppercase letters");
|
||||||
|
_td("Use a longer keyboard pattern with more turns");
|
||||||
|
_td("Avoid repeated words and characters");
|
||||||
|
_td("Avoid sequences");
|
||||||
|
_td("Avoid recent years");
|
||||||
|
_td("Avoid years that are associated with you");
|
||||||
|
_td("Avoid dates and years that are associated with you");
|
||||||
|
_td("Capitalization doesn't help very much");
|
||||||
|
_td("All-uppercase is almost as easy to guess as all-lowercase");
|
||||||
|
_td("Reversed words aren't much harder to guess");
|
||||||
|
_td("Predictable substitutions like '@' instead of 'a' don't help very much");
|
||||||
|
_td("Add another word or two. Uncommon words are better.");
|
||||||
|
|
||||||
|
// and warnings
|
||||||
|
_td("Repeats like \"aaa\" are easy to guess");
|
||||||
|
_td("Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"");
|
||||||
|
_td("Sequences like abc or 6543 are easy to guess");
|
||||||
|
_td("Recent years are easy to guess");
|
||||||
|
_td("Dates are often easy to guess");
|
||||||
|
_td("This is a top-10 common password");
|
||||||
|
_td("This is a top-100 common password");
|
||||||
|
_td("This is a very common password");
|
||||||
|
_td("This is similar to a commonly used password");
|
||||||
|
_td("A word by itself is easy to guess");
|
||||||
|
_td("Names and surnames by themselves are easy to guess");
|
||||||
|
_td("Common names and surnames are easy to guess");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around zxcvbn password strength estimation
|
||||||
|
* Include this only from async components: it pulls in zxcvbn
|
||||||
|
* (obviously) which is large.
|
||||||
|
*/
|
||||||
|
export function scorePassword(password) {
|
||||||
|
if (password.length === 0) return null;
|
||||||
|
|
||||||
|
const userInputs = ZXCVBN_USER_INPUTS.slice();
|
||||||
|
userInputs.push(MatrixClientPeg.get().getUserIdLocalpart());
|
||||||
|
|
||||||
|
let zxcvbnResult = Zxcvbn(password, userInputs);
|
||||||
|
// Work around https://github.com/dropbox/zxcvbn/issues/216
|
||||||
|
if (password.includes(' ')) {
|
||||||
|
const resultNoSpaces = Zxcvbn(password.replace(/ /g, ''), userInputs);
|
||||||
|
if (resultNoSpaces.score < zxcvbnResult.score) zxcvbnResult = resultNoSpaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < zxcvbnResult.feedback.suggestions.length; ++i) {
|
||||||
|
// translate suggestions
|
||||||
|
zxcvbnResult.feedback.suggestions[i] = _t(zxcvbnResult.feedback.suggestions[i]);
|
||||||
|
}
|
||||||
|
// and warning, if any
|
||||||
|
if (zxcvbnResult.feedback.warning) {
|
||||||
|
zxcvbnResult.feedback.warning = _t(zxcvbnResult.feedback.warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
return zxcvbnResult;
|
||||||
|
}
|
Loading…
Reference in a new issue