zxcvbn-ts / zxcvbn

Low-Budget Password Strength Estimation
https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/wheeler
MIT License
907 stars 72 forks source link

Be able to instantiate `zxcvbn` #158

Closed ghost closed 1 year ago

ghost commented 1 year ago

Hi, thanks a lot for the amazing work ! I'm planning to add zxcvbn to my Node server.

Multilanguage for validation is perfect feature :) Setting option while it is handled implicitly I found not the best I don't know what is the constraints for you :)

because I want to use English, French and maybe other languages, (it is fine for me I guess to load all dictionaries because on server side), so because Node is monoprocess, I guess I need attach options just before running the validation, or safer have many objects of import { zxcvbn, zxcvbnOptions } from '@zxcvbn-ts/core' for different languages. This is not possible in Node something like

import { zxcvbn as zxcvbnEn, zxcvbnFr, zxcvbnOptionsEn, zxcvbnOptionsFr } from '@zxcvbn-ts/core'

The problem is if I do import { zxcvbn, zxcvbnOptions } from '@zxcvbn-ts/core' Then depending on current language for one session, one can step on another toe, it would be better to be able to instantiate like let validatorEn = new zxcvbn()

I'm doing a whole async mutex to achieve this (having one zxcvbn instance)

import { zxcvbn, zxcvbnOptions } from '@zxcvbn-ts/core'
import { Mutex } from 'async-mutex'
const options = {
    translations: zxcvbnEnPackage.translations,
    graphs: zxcvbnCommonPackage.adjacencyGraphs,
    dictionary: {
        ...zxcvbnCommonPackage.dictionary,
        ...zxcvbnEnPackage.dictionary,
    },
}
zxcvbnOptions.setOptions(options)
let locks = new Map()
ops.isFinePassword = async function isFinePassword(password, lang, sessionId) {
    if (!locks.has(sessionId)) locks.set(sessionId, new Mutex())
    // @ts-ignore
    const release = await locks.get(sessionId).acquire()

    switch (lang) {
    case 'fr':
        options.dictionary= {
            ...zxcvbnCommonPackage.dictionary,
            ...zxcvbnFrPackage.dictionary,
        }
        options.translations = zxcvbnFrPackage.translations
        break;
    default:
        break;
    }
    zxcvbnOptions.setOptions(options)
    let result = zxcvbn(password)
    release()
    return result
}

I hope you get my idea. Most important is to have a constructor to create new instances.

MrWook commented 1 year ago

I see where you are coming from. This feature would result in an complete rewrite 🤔

Just for information, you could throw every dictionary into it. This would only improve the scoring in the end. You don't need to separate them .

ghost commented 1 year ago

Hi, thanks for responding :) If easy, performant and relevant (I think), make it possible to pass any different options on the evaluation step directly .. like let result = zxcvbn(password, options)

MrWook commented 1 year ago

Unfortunately this is not possible because setting the graphs takes quite some time

ghost commented 1 year ago

ok I understand, I thought there is something underneath and this is why options are set before. Anyway, for me it does work with Mutex with multiple imports on server. Thanks a lot