password strength

Just wrap it a <tosi-password-strength> element around an <input> and it will gauge its content strength as a password. It will also let you securely verify that the password hasn't been breached.

import { tosiLocalized, localize } from 'tosijs-ui'

const toggle = preview.querySelector('.toggle')
const icon = preview.querySelector('tosi-icon')
const input = preview.querySelector('input')
const breach = preview.querySelector('.breach')
const output = preview.querySelector('.output')
const passwordStrength = preview.querySelector('tosi-password-strength')

// Localization Example
passwordStrength.append(tosiLocalized({
  refString: 'Yes',
  localeChanged () {
    this.parentElement.strengthDescriptions = [
      'unacceptable',
      'very weak',
      'weak',
      'moderate',
      'strong',
      'very strong',
    ].map(localize)
    this.parentElement.queueRender()
  }
}))

toggle.addEventListener('click', () => {
  if (icon.icon === 'eye') {
    input.type = 'text'
    icon.icon = 'eyeOff'
  } else {
    input.type = 'password'
    icon.icon = 'eye'
  }
})

breach.addEventListener('click', async () => {
  preview.querySelector('tosi-password-strength').isBreached().then(isBreached => {
    output.textContent =
      isBreached
      ? 'This password has been breached, look at console for details'
      : 'Seems OK'
    output.classList.toggle('breached', isBreached)
  })
})
<tosi-password-strength>
  <input class="password" type="password">
  <button class="toggle">
    <tosi-icon icon="eye"></tosi-icon>
  </button>
</tosi-password-strength>

<br><br>
<button class="breach">
  <tosi-localized>Check if breached</tosi-localized>
</button>
<div class="output"></div>
input.password {
  box-shadow: inset 0 0 0 2px var(--indicator-color);
}

.breached {
  color: white;
  background: red;
}

Algorithm

The password is assessed to have a strength based on:

A password smaller than minLength is an automatic 0.

Attributes

Properties

<tosi-password-strength>.issues = {
  tooShort: boolean,
  short: boolean,
  noUpper: boolean,
  noLower: boolean,
  noNumber: boolean,
  noSpecial: boolean,
}

Customizing / Localizing Strings

The following properties control the feedback generated.

issueDescriptions = {
  tooShort: 'too short',
  short: 'short',
  noUpper: 'no upper case',
  noLower: 'no lower case',
  noNumber: 'no digits',
  noSpecial: 'no unusual characters',
}
strengthDescriptions = [
  'unacceptable',
  'very weak',
  'weak',
  'moderate',
  'strong',
  'very strong',
]

isBreached()

<tosi-password-strength> also provides an isBreached(): Promise<boolean> method which uses weakpass.com's API to tell you if the password has been breached.

Note that isBreached does not send the plain-text password anywhere. It uses SHA-1 to hash the password and then sends that for lookup.

Utility Functions

Two functions used internally for querying Weakpass,com are provided in case they're useful on their own.

isBreached(password: striing): Promise<boolean> will return true if the password is found in Weakpass's database (and spit out extra info to the console).

digest(s: string, method="sha-1"): Promise<string> is just a nice wrapper for crypto.digest.