Password strength
How guessable a password is (zxcvbn): a score from 0 to 4, a warning and suggestions, and how long it would take to crack.
Version 1.0.0 · 2 functions · 1 crate
Functions
What use password_strength.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use password_check, password_score from password_strength (Quillo 0.6).
password_check(password: str, user_inputs: list) → anyThe full judgement of password: score 0 (guessed at once) to 4 (very hard), warning and suggestions in English, guesses, and crack_time (an offline attack on a slow hash such as bcrypt) and crack_seconds. user_inputs are words a guesser would try first: the user's name, email, the site's name. An empty password is score 0.
password_score(password: str, user_inputs: list) → intOnly the score, 0 to 4: a form can ask for 3 or more.
Get it
$ quillo install password_strength # password_strength.qwer into this folder$ quillo install password_strength --example # and its example, password_strength.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/password_strength.qwer$ curl -O https://quillolang.org/plugins/files/password_strength.qweThen, in your program, all of it or only what you call:
use password_strength.qweruse password_check, password_score from password_strength // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
zxcvbn = "3"Example
// A sign-up form that refuses weak passwords and says why.//// quillo run password_strength.qwe then open http://localhost:8080/check?password=ada1815use "password_strength.qwer"route GET /check ? { password: str, email: str = "ada@example.com" } { let verdict = password_check(password, [email, "quillo shop"]) { ...verdict, accepted: verdict.score >= 3 }}route GET /compare = { weak: password_score("password1", []), own_name: password_score("ada.lovelace", ["Ada Lovelace", "ada@example.com"]), strong: password_score("correct horse battery staple violin", []),}$ quillo run password_strength.qwe$ curl 'localhost:8080/check?password=password1'$ curl 'localhost:8080/compare'$ curl 'localhost:8080/check?password=ada1815'Source
//! How guessable a password is (zxcvbn): a score from 0 to 4, why, what to do about it, and how long it would take to crack, for sign-up forms.//! version: 1.0.0//!//! [dependencies]//! zxcvbn = "3"use serde_json::{json, Value};/// Passwords longer than this are judged on their first 100 characters: zxcvbn's work grows with the length.const MAX_LEN: usize = 100;fn cut(password: &str) -> String { password.chars().take(MAX_LEN).collect()}fn inputs(user_inputs: &[String]) -> Vec<&str> { user_inputs.iter().take(20).map(|s| s.as_str()).collect()}/// The full judgement of `password`: `score` 0 (guessed at once) to 4 (very hard), `warning` and `suggestions` in English, `guesses`,/// and `crack_time` (an offline attack on a slow hash such as bcrypt) and `crack_seconds`. `user_inputs` are words a guesser/// would try first: the user's name, email, the site's name. An empty password is score 0.pub fn password_check(password: &str, user_inputs: Vec<String>) -> Value { let p = cut(password); if p.is_empty() { return json!({ "score": 0, "warning": "Enter a password.", "suggestions": [], "guesses": 0, "crack_time": "instant", "crack_seconds": 0.0 }); } let e = zxcvbn::zxcvbn(&p, &inputs(&user_inputs)); let t = e.crack_times().offline_slow_hashing_1e4_per_second(); let (warning, suggestions) = match e.feedback() { Some(f) => (f.warning().map(|w| w.to_string()), f.suggestions().iter().map(|s| s.to_string()).collect::<Vec<_>>()), None => (None, vec![]), }; json!({ "score": u8::from(e.score()), "warning": warning, "suggestions": suggestions, "guesses": e.guesses().min(i64::MAX as u64) as i64, "crack_time": t.to_string(), "crack_seconds": match t { zxcvbn::time_estimates::CrackTimeSeconds::Integer(i) => i as f64, zxcvbn::time_estimates::CrackTimeSeconds::Float(f) => f }, })}/// Only the score, 0 to 4: a form can ask for 3 or more.pub fn password_score(password: &str, user_inputs: Vec<String>) -> i64 { let p = cut(password); if p.is_empty() { return 0; } u8::from(zxcvbn::zxcvbn(&p, &inputs(&user_inputs)).score()) as i64}Related
pwned.qwer · 1.0.0Have I Been Pwned's Pwned Passwords by k-anonymity: only 5 characters of the SHA-1 leave the server, the answer is checked here.8 views · 9 downloadsArgon2 passwords argon2.qwer · 1.0.0Argon2id password hashes with the memory and passes you choose, any Argon2 hash verified, its parameters read, old ones marked for a rehash, and the cost timed on this server.7 views · 6 downloadsBcrypt bcrypt.qwer · 1.0.0Sign in users whose bcrypt hashes came from PHP, Rails, Django or Laravel, then move them to Quillo's Argon2.8 views · 9 downloadsCaptcha captcha.qwer · 1.0.0Picture captchas made on your own server: distorted letters as a PNG data URL and the answer to keep in the session.7 views · 6 downloadsLegacy passwords legacy_passwords.qwer · 1.0.0Check passwords against Django, Flask/Werkzeug and WordPress hashes, to sign in users moved from those apps and rehash them with Argon2.7 views · 7 downloadsPassphrases passphrase.qwer · 1.0.0Diceware passphrases from the EFF word lists, easy to type and remember and hard to guess, with their strength in bits.7 views · 7 downloadsThread 0 posts
On Password strength: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.