mirror of https://github.com/apibillme/broker
release 11.2.0
This commit is contained in:
parent
597b05b6f7
commit
559cc792e8
|
@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [11.2.0] - 2021-04-06
|
||||
|
||||
### Added
|
||||
- Added zxcvbn password strength checker
|
||||
|
||||
### Fixed
|
||||
- Fixed JWT issued not being in JSON format
|
||||
|
||||
## [11.1.0] - 2021-04-06
|
||||
|
||||
### Added
|
||||
|
|
|
@ -396,6 +396,21 @@ dependencies = [
|
|||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
|
@ -465,7 +480,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "broker"
|
||||
version = "11.1.0"
|
||||
version = "11.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
|
@ -489,6 +504,7 @@ dependencies = [
|
|||
"tide-acme",
|
||||
"tide-rustls",
|
||||
"uuid",
|
||||
"zxcvbn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -555,11 +571,13 @@ version = "0.4.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time 0.1.44",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -592,7 +610,7 @@ dependencies = [
|
|||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"strsim 0.8.0",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
|
@ -734,6 +752,41 @@ version = "0.1.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.9.3",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "4.0.2"
|
||||
|
@ -775,6 +828,31 @@ dependencies = [
|
|||
"rusticata-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"derive_builder_core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
|
@ -802,6 +880,12 @@ dependencies = [
|
|||
"tide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
|
@ -821,6 +905,16 @@ version = "2.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36996e5f56f32ca51a937f325094fa450b32df871af1a89be331b7145b931bfc"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fast_chemail"
|
||||
version = "0.9.6"
|
||||
|
@ -855,6 +949,12 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
|
@ -1134,9 +1234,15 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
dependencies = [
|
||||
"quick-error",
|
||||
"quick-error 1.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.2"
|
||||
|
@ -1163,6 +1269,15 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
|
@ -1543,6 +1658,12 @@ version = "1.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
|
@ -2056,6 +2177,12 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.0"
|
||||
|
@ -2535,3 +2662,18 @@ checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zxcvbn"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5f9db3a05b2ee81dcda4602487314ab654eca316f517be2e2e64175658f0dd0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"derive_builder",
|
||||
"fancy-regex",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"quick-error 2.0.0",
|
||||
"regex",
|
||||
]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "broker"
|
||||
version = "11.1.0"
|
||||
version = "11.2.0"
|
||||
authors = ["Bevan Hunt <bevan@bevanhunt.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
|
@ -33,3 +33,4 @@ futures = "0.3"
|
|||
tide-acme = "0.1.0"
|
||||
base64 = "0.13"
|
||||
mailchecker = "4"
|
||||
zxcvbn = "2"
|
||||
|
|
|
@ -30,6 +30,7 @@ Broker follows an insert-only/publish/subscribe paradigm rather than a REST CRUD
|
|||
* Verify endpoint for external services using Broker user system like [portal](https://crates.io/crates/portal)
|
||||
* User Management API endpoints (revoke, unrevoke, list, get, update)
|
||||
* User Email Address Validation (regex and blacklist check against throwaway emails)
|
||||
* Password Strength Checker using [zxcvbn](https://crates.io/crates/zxcvbn)
|
||||
|
||||
### How it works
|
||||
|
||||
|
@ -283,7 +284,8 @@ will return: `200`
|
|||
- the `db` flag is the path where the embedded database will be saved - default `db`
|
||||
- the `domain` flag is the domain name (e.g. api.broker.com) of the domain you want to register with LetsEncrypt - must be fully resolvable
|
||||
- the `admin_token` flag is the password for the admin to add users - default `letmein`
|
||||
- production example: `./broker --secure="true" --admin_token"23ce4234@123$" --jwt_secret="xTJEX234$##$" --domain="api.broker.com"`
|
||||
- the `password_checker` flag enables zxcvbn password checking - default `false`
|
||||
- production example: `./broker --secure="true" --admin_token"23ce4234@123$" --jwt_secret="xTJEX234$##$" --domain="api.broker.com" --password_checker="true"`
|
||||
|
||||
### Service
|
||||
|
||||
|
|
77
src/main.rs
77
src/main.rs
|
@ -15,6 +15,7 @@ use std::time::Duration;
|
|||
use futures::StreamExt;
|
||||
use tide_acme::{AcmeConfig, TideRustlsExt};
|
||||
use mailchecker::is_valid;
|
||||
use zxcvbn::zxcvbn;
|
||||
|
||||
lazy_static! {
|
||||
static ref DB : Arc<rocksdb::DB> = {
|
||||
|
@ -45,6 +46,7 @@ pub struct EnvVarConfig {
|
|||
pub auto_cert: bool,
|
||||
pub key_path: String,
|
||||
pub cert_path: String,
|
||||
pub password_checker: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
@ -146,7 +148,7 @@ fn activate_user(username: String) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
fn modify_user(update_user_form: UpdateUserForm) -> Result<()> {
|
||||
fn modify_user(update_user_form: UpdateUserForm) -> Result<Option<String>> {
|
||||
match get_user_by_username(update_user_form.clone().username)? {
|
||||
Some(mut user) => {
|
||||
|
||||
|
@ -170,6 +172,33 @@ fn modify_user(update_user_form: UpdateUserForm) -> Result<()> {
|
|||
|
||||
match update_user_form.password {
|
||||
Some(password) => {
|
||||
|
||||
let configure = env_var_config();
|
||||
|
||||
if configure.password_checker {
|
||||
let estimate = zxcvbn(&password, &[&user.username]).unwrap();
|
||||
if estimate.score() < 3 {
|
||||
let err: String;
|
||||
match estimate.feedback() {
|
||||
Some(feedback) => {
|
||||
match feedback.warning() {
|
||||
Some(warning) => {
|
||||
err = format!("password is too weak because {}", warning);
|
||||
},
|
||||
None => {
|
||||
err = format!("password is too weak");
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
err = format!("password is too weak");
|
||||
}
|
||||
}
|
||||
let j = json!({"error": err}).to_string();
|
||||
return Ok(Some(j));
|
||||
}
|
||||
}
|
||||
|
||||
let config = Argon2Config::default();
|
||||
let uuid_string = Uuid::new_v4().to_string();
|
||||
let salt = uuid_string.as_bytes();
|
||||
|
@ -180,9 +209,9 @@ fn modify_user(update_user_form: UpdateUserForm) -> Result<()> {
|
|||
None => {}
|
||||
}
|
||||
puts_user(user)?;
|
||||
Ok(())
|
||||
Ok(None)
|
||||
},
|
||||
None => { Ok(()) }
|
||||
None => { Ok(None) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,6 +294,30 @@ fn user_create(user_form: UserForm) -> Result<Option<String>> {
|
|||
let j = json!({"error": "username already taken"}).to_string();
|
||||
return Ok(Some(j));
|
||||
} else {
|
||||
if configure.password_checker {
|
||||
let estimate = zxcvbn(&user_form.password, &[&user_form.username]).unwrap();
|
||||
if estimate.score() < 3 {
|
||||
let err: String;
|
||||
match estimate.feedback() {
|
||||
Some(feedback) => {
|
||||
match feedback.warning() {
|
||||
Some(warning) => {
|
||||
err = format!("password is too weak because {}", warning);
|
||||
},
|
||||
None => {
|
||||
err = format!("password is too weak");
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
err = format!("password is too weak");
|
||||
}
|
||||
}
|
||||
let j = json!({"error": err}).to_string();
|
||||
return Ok(Some(j));
|
||||
}
|
||||
}
|
||||
|
||||
let uuid = Uuid::new_v4();
|
||||
let config = Argon2Config::default();
|
||||
let uuid_string = Uuid::new_v4().to_string();
|
||||
|
@ -329,6 +382,7 @@ fn env_var_config() -> EnvVarConfig {
|
|||
let mut admin_token = "letmein".to_string();
|
||||
let mut key_path = "certs/private_key.pem".to_string();
|
||||
let mut cert_path = "certs/chain.pem".to_string();
|
||||
let mut password_checker = false;
|
||||
let _ : Vec<String> = go_flag::parse(|flags| {
|
||||
flags.add_flag("port", &mut port);
|
||||
flags.add_flag("origin", &mut origin);
|
||||
|
@ -342,9 +396,10 @@ fn env_var_config() -> EnvVarConfig {
|
|||
flags.add_flag("auto_cert", &mut auto_cert);
|
||||
flags.add_flag("key_path", &mut key_path);
|
||||
flags.add_flag("cert_path", &mut cert_path);
|
||||
flags.add_flag("password_checker", &mut password_checker);
|
||||
});
|
||||
|
||||
EnvVarConfig{port, origin, jwt_expiry, jwt_secret, secure, domain, certs, db, admin_token, auto_cert, key_path, cert_path}
|
||||
EnvVarConfig{port, origin, jwt_expiry, jwt_secret, secure, domain, certs, db, admin_token, auto_cert, key_path, cert_path, password_checker}
|
||||
}
|
||||
|
||||
async fn jwt_verify(token: String) -> Result<Option<TokenData<Claims>>> {
|
||||
|
@ -420,7 +475,6 @@ async fn create_user(mut req: Request<()>) -> tide::Result {
|
|||
let user_form : UserForm = serde_json::from_str(&r)?;
|
||||
match user_create(user_form)? {
|
||||
Some(err) => {
|
||||
let err = format!("error: {}", err);
|
||||
Ok(tide::Response::builder(400).body(err).header("content-type", "application/json").build())
|
||||
},
|
||||
None => {
|
||||
|
@ -434,7 +488,7 @@ async fn login_user(mut req: Request<()>) -> tide::Result {
|
|||
let login_form : LoginForm = serde_json::from_str(&r)?;
|
||||
match create_jwt(login_form).await? {
|
||||
Some(jwt) => {
|
||||
let msg = format!("jwt: {}", jwt);
|
||||
let msg = json!({"jwt": jwt}).to_string();
|
||||
Ok(tide::Response::builder(200).body(msg).header("content-type", "application/json").build())
|
||||
},
|
||||
None => {
|
||||
|
@ -555,8 +609,15 @@ async fn update_user(mut req: Request<()>) -> tide::Result {
|
|||
let update_user_form : UpdateUserForm = serde_json::from_str(&r)?;
|
||||
let configure = env_var_config();
|
||||
if configure.admin_token == update_user_form.admin_token {
|
||||
modify_user(update_user_form)?;
|
||||
Ok(tide::Response::builder(200).header("content-type", "application/json").build())
|
||||
match modify_user(update_user_form)? {
|
||||
Some(err) => {
|
||||
Ok(tide::Response::builder(400).body(err).header("content-type", "application/json").build())
|
||||
},
|
||||
None => {
|
||||
Ok(tide::Response::builder(200).header("content-type", "application/json").build())
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Ok(tide::Response::builder(401).header("content-type", "application/json").build())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue