mirror of https://github.com/apibillme/broker
update to 12.0.0
This commit is contained in:
parent
559cc792e8
commit
e488cc75e0
|
@ -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).
|
||||
|
||||
## [12.0.0] - 2021-04-08
|
||||
|
||||
### Added
|
||||
- Added JWT custom scopes on user
|
||||
|
||||
### Updated
|
||||
- Updated README
|
||||
|
||||
## [11.2.0] - 2021-04-06
|
||||
|
||||
### Added
|
||||
|
|
|
@ -480,7 +480,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "broker"
|
||||
version = "11.2.0"
|
||||
version = "12.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "broker"
|
||||
version = "11.2.0"
|
||||
version = "12.0.0"
|
||||
authors = ["Bevan Hunt <bevan@bevanhunt.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
|
|
18
README.md
18
README.md
|
@ -18,18 +18,19 @@ Broker follows an insert-only/publish/subscribe paradigm rather than a REST CRUD
|
|||
* Under 1000 lines of code
|
||||
* Secure Real-time Event Stream via SSE - requires the use of [broker-client](https://www.npmjs.com/package/broker-client)
|
||||
* Supports CORS
|
||||
* JSON API
|
||||
* Add users with admin token permission
|
||||
* Multi-tenant
|
||||
* Supports SSL - full end-to-end encryption
|
||||
* Provides user authentication with JWTs or HTTP Basic
|
||||
* Secure passwords with Argon2 encoding
|
||||
* Uses Global NTP servers and doesn't rely on your local server time
|
||||
* Insert event via JSON POST request
|
||||
* Issues JWTs for authentication (username) and authorization (scopes) for external services
|
||||
* Verify endpoint for external services using Broker user system like [portal](https://crates.io/crates/portal)
|
||||
* Secure password storage with Argon2 encoding
|
||||
* Uses Global NTP servers and doesn't rely on your local server time for JWT expiry timing
|
||||
* Sync latest events on SSE client connection
|
||||
* Auto-provision and renews SSL cert via LetsEncrypt or use your own SSL cert
|
||||
* 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)
|
||||
* User Management API endpoints (create, revoke, unrevoke, list, get, update)
|
||||
* User Email Address Validation (regex and blacklist check against throwaway emails) using [mailchecker](https://crates.io/crates/mailchecker)
|
||||
* Password Strength Checker using [zxcvbn](https://crates.io/crates/zxcvbn)
|
||||
|
||||
### How it works
|
||||
|
@ -72,6 +73,7 @@ POST /create_user
|
|||
"admin_token": "letmein",
|
||||
"tenant_name": "tenant_1",
|
||||
"email": "bob@hotmail.com",
|
||||
"scopes": ["news:get", "news:post"],
|
||||
"data": {
|
||||
"name": "Robert Wieland",
|
||||
"image": "https://img.com/bucket/123/123.jpg"
|
||||
|
@ -102,6 +104,7 @@ will return
|
|||
"jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTc2NzQ5MTUsImlhdCI6MTYxNzU4ODUxNSwiaXNzIjoiRGlzcGF0Y2hlciIsInN1YiI6ImZvbyJ9.OwiaZJcFUC_B0CA0ffRZVTWKRf5_vQ7vt5USNJEeKRE"
|
||||
}
|
||||
```
|
||||
- note: `iss` is `Broker` while `aud` is the user scopes joined with a comma like in this example `news:get,news:post`
|
||||
|
||||
#### Step 3 - connect to SSE
|
||||
|
||||
|
@ -195,6 +198,7 @@ will return: `200` or `500` or `400` or `401`
|
|||
"tenant_name": "tenant_1",
|
||||
"username": "bob",
|
||||
"email": "bob@hotmail.com",
|
||||
"scopes": ["news:get", "news:post"],
|
||||
"data": {
|
||||
"name": "Robert Wieland",
|
||||
"image": "https://img.com/bucket/123/123.jpg"
|
||||
|
@ -228,6 +232,7 @@ will return: `200` or `500` or `400` or `401`
|
|||
"tenant_name": "tenant_1",
|
||||
"username": "bob",
|
||||
"email": "bob@hotmail.com",
|
||||
"scopes": ["news:get", "news:post"],
|
||||
"data": {
|
||||
"name": "Robert Wieland",
|
||||
"image": "https://img.com/bucket/123/123.jpg"
|
||||
|
@ -249,6 +254,7 @@ POST /update_user
|
|||
"tenant_name": "tenant_2",
|
||||
"password": "new_password",
|
||||
"email": "bober@hotmail.com",
|
||||
"scopes": ["news:get", "news:post"],
|
||||
"data": {
|
||||
"name": "Robert Falcon",
|
||||
"image": "https://img.com/bucket/123/1234.jpg"
|
||||
|
|
26
src/main.rs
26
src/main.rs
|
@ -58,6 +58,7 @@ pub struct User {
|
|||
pub password: String,
|
||||
pub tenant_name: String,
|
||||
pub data: Option<serde_json::Value>,
|
||||
pub scopes: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
@ -68,6 +69,7 @@ pub struct UserForm {
|
|||
pub admin_token: String,
|
||||
pub email: Option<String>,
|
||||
pub data: Option<serde_json::Value>,
|
||||
pub scopes: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
@ -78,6 +80,7 @@ pub struct UpdateUserForm {
|
|||
pub email: Option<String>,
|
||||
pub password: Option<String>,
|
||||
pub data: Option<serde_json::Value>,
|
||||
pub scopes: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
@ -103,6 +106,7 @@ pub struct Claims {
|
|||
pub iat: i64,
|
||||
pub iss: String,
|
||||
pub sub: String,
|
||||
pub aud: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
|
@ -169,6 +173,7 @@ fn modify_user(update_user_form: UpdateUserForm) -> Result<Option<String>> {
|
|||
}
|
||||
|
||||
user.data = update_user_form.data;
|
||||
user.scopes = update_user_form.scopes;
|
||||
|
||||
match update_user_form.password {
|
||||
Some(password) => {
|
||||
|
@ -332,6 +337,7 @@ fn user_create(user_form: UserForm) -> Result<Option<String>> {
|
|||
revoked: false,
|
||||
email: user_form.clone().email,
|
||||
data: user_form.clone().data,
|
||||
scopes: user_form.clone().scopes,
|
||||
};
|
||||
|
||||
puts_user(new_user).unwrap();
|
||||
|
@ -353,8 +359,15 @@ async fn create_jwt(login: LoginForm) -> Result<Option<String>> {
|
|||
let app = env_var_config();
|
||||
let iat = nippy::get_unix_ntp_time().await?;
|
||||
let exp = iat + app.jwt_expiry;
|
||||
let iss = "Dispatcher".to_string();
|
||||
let my_claims = Claims{sub: user.clone().username, exp, iat, iss};
|
||||
let iss = "Broker".to_string();
|
||||
let aud: String;
|
||||
match user.scopes.clone() {
|
||||
Some(scopes) => {
|
||||
aud = scopes.join(",");
|
||||
},
|
||||
None => { aud = "".to_string() }
|
||||
}
|
||||
let my_claims = Claims{sub: user.clone().username, exp, iat, iss, aud};
|
||||
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret(app.jwt_secret.as_ref()))?;
|
||||
Ok(Some(token))
|
||||
} else {
|
||||
|
@ -432,7 +445,14 @@ async fn jwt_verify(token: String) -> Result<Option<TokenData<Claims>>> {
|
|||
let iat = nippy::get_unix_ntp_time().await?;
|
||||
let exp = iat + app.jwt_expiry;
|
||||
let iss = "Broker".to_string();
|
||||
let my_claims = Claims{sub: user.clone().username, exp, iat, iss};
|
||||
let aud: String;
|
||||
match user.scopes.clone() {
|
||||
Some(scopes) => {
|
||||
aud = scopes.join(",");
|
||||
},
|
||||
None => { aud = "".to_string() }
|
||||
}
|
||||
let my_claims = Claims{sub: user.clone().username, exp, iat, iss, aud};
|
||||
let my_token = TokenData{
|
||||
header: Header::default(),
|
||||
claims: my_claims,
|
||||
|
|
Loading…
Reference in New Issue