Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2024-11-29 06:20:29 +01:00
Merge branch 'master' into rocket-0.4
# Conflicts: # Cargo.lock # Cargo.toml # src/api/core/mod.rs
Dieser Commit ist enthalten in:
Commit
5edbd0e952
8 geänderte Dateien mit 594 neuen und 166 gelöschten Zeilen
8
.env
8
.env
|
@ -40,6 +40,14 @@
|
||||||
## For U2F to work, the server must use HTTPS, you can use Let's Encrypt for free certs
|
## For U2F to work, the server must use HTTPS, you can use Let's Encrypt for free certs
|
||||||
# DOMAIN=https://bw.domain.tld:8443
|
# DOMAIN=https://bw.domain.tld:8443
|
||||||
|
|
||||||
|
## Yubico (Yubikey) Settings
|
||||||
|
## Set your Client ID and Secret Key for Yubikey OTP
|
||||||
|
## You can generate it here: https://upgrade.yubico.com/getapikey/
|
||||||
|
## You can optionally specify a custom OTP server
|
||||||
|
# YUBICO_CLIENT_ID=11111
|
||||||
|
# YUBICO_SECRET_KEY=AAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
# YUBICO_SERVER=http://yourdomain.com/wsapi/2.0/verify
|
||||||
|
|
||||||
## Rocket specific settings, check Rocket documentation to learn more
|
## Rocket specific settings, check Rocket documentation to learn more
|
||||||
# ROCKET_ENV=staging
|
# ROCKET_ENV=staging
|
||||||
# ROCKET_ADDRESS=0.0.0.0 # Enable this to test mobile app
|
# ROCKET_ADDRESS=0.0.0.0 # Enable this to test mobile app
|
||||||
|
|
454
Cargo.lock
generiert
454
Cargo.lock
generiert
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
14
Cargo.toml
14
Cargo.toml
|
@ -9,7 +9,7 @@ rocket = { version = "0.4.0-rc.1", features = ["tls"] }
|
||||||
rocket_contrib = "0.4.0-rc.1"
|
rocket_contrib = "0.4.0-rc.1"
|
||||||
|
|
||||||
# HTTP client
|
# HTTP client
|
||||||
reqwest = "0.9.4"
|
reqwest = "0.9.5"
|
||||||
|
|
||||||
# multipart/form-data support
|
# multipart/form-data support
|
||||||
multipart = "0.15.3"
|
multipart = "0.15.3"
|
||||||
|
@ -26,7 +26,7 @@ chashmap = "2.2.0"
|
||||||
# A generic serialization/deserialization framework
|
# A generic serialization/deserialization framework
|
||||||
serde = "1.0.80"
|
serde = "1.0.80"
|
||||||
serde_derive = "1.0.80"
|
serde_derive = "1.0.80"
|
||||||
serde_json = "1.0.32"
|
serde_json = "1.0.33"
|
||||||
|
|
||||||
# A safe, extensible ORM and Query builder
|
# A safe, extensible ORM and Query builder
|
||||||
diesel = { version = "1.3.3", features = ["sqlite", "chrono", "r2d2"] }
|
diesel = { version = "1.3.3", features = ["sqlite", "chrono", "r2d2"] }
|
||||||
|
@ -36,7 +36,7 @@ diesel_migrations = { version = "1.3.0", features = ["sqlite"] }
|
||||||
libsqlite3-sys = { version = "0.9.3", features = ["bundled"] }
|
libsqlite3-sys = { version = "0.9.3", features = ["bundled"] }
|
||||||
|
|
||||||
# Crypto library
|
# Crypto library
|
||||||
ring = { version = "0.13.2", features = ["rsa_signing"] }
|
ring = { version = "0.13.5", features = ["rsa_signing"] }
|
||||||
|
|
||||||
# UUID generation
|
# UUID generation
|
||||||
uuid = { version = "0.7.1", features = ["v4"] }
|
uuid = { version = "0.7.1", features = ["v4"] }
|
||||||
|
@ -56,11 +56,14 @@ jsonwebtoken = "5.0.1"
|
||||||
# U2F library
|
# U2F library
|
||||||
u2f = "0.1.2"
|
u2f = "0.1.2"
|
||||||
|
|
||||||
|
# Yubico Library
|
||||||
|
yubico= { version = "=0.4.0", default-features = false }
|
||||||
|
|
||||||
# A `dotenv` implementation for Rust
|
# A `dotenv` implementation for Rust
|
||||||
dotenv = { version = "0.13.0", default-features = false }
|
dotenv = { version = "0.13.0", default-features = false }
|
||||||
|
|
||||||
# Lazy static macro
|
# Lazy static macro
|
||||||
lazy_static = "1.1.0"
|
lazy_static = "1.2.0"
|
||||||
|
|
||||||
# Numerical libraries
|
# Numerical libraries
|
||||||
num-traits = "0.2.6"
|
num-traits = "0.2.6"
|
||||||
|
@ -84,3 +87,6 @@ lettre_email = { git = 'https://github.com/lettre/lettre', rev = 'c988b1760ad81'
|
||||||
|
|
||||||
# Version 0.1.2 from crates.io lacks a commit that fixes a certificate error
|
# Version 0.1.2 from crates.io lacks a commit that fixes a certificate error
|
||||||
u2f = { git = 'https://github.com/wisespace-io/u2f-rs', rev = '75b9fa5afb4c5' }
|
u2f = { git = 'https://github.com/wisespace-io/u2f-rs', rev = '75b9fa5afb4c5' }
|
||||||
|
|
||||||
|
# Allows optional libusb support
|
||||||
|
yubico = { git = 'https://github.com/dani-garcia/yubico-rs' }
|
||||||
|
|
29
README.md
29
README.md
|
@ -28,6 +28,7 @@ _*Note, that this project is not associated with the [Bitwarden](https://bitward
|
||||||
- [Enabling HTTPS](#enabling-https)
|
- [Enabling HTTPS](#enabling-https)
|
||||||
- [Enabling WebSocket notifications](#enabling-websocket-notifications)
|
- [Enabling WebSocket notifications](#enabling-websocket-notifications)
|
||||||
- [Enabling U2F authentication](#enabling-u2f-authentication)
|
- [Enabling U2F authentication](#enabling-u2f-authentication)
|
||||||
|
- [Enabling YubiKey OTP authentication](#enabling-yubikey-otp-authentication)
|
||||||
- [Changing persistent data location](#changing-persistent-data-location)
|
- [Changing persistent data location](#changing-persistent-data-location)
|
||||||
- [/data prefix:](#data-prefix)
|
- [/data prefix:](#data-prefix)
|
||||||
- [database name and location](#database-name-and-location)
|
- [database name and location](#database-name-and-location)
|
||||||
|
@ -68,11 +69,11 @@ Basically full implementation of Bitwarden API is provided including:
|
||||||
* Serving the static files for Vault interface
|
* Serving the static files for Vault interface
|
||||||
* Website icons API
|
* Website icons API
|
||||||
* Authenticator and U2F support
|
* Authenticator and U2F support
|
||||||
|
* YubiKey OTP
|
||||||
|
|
||||||
## Missing features
|
## Missing features
|
||||||
* Email confirmation
|
* Email confirmation
|
||||||
* Other two-factor systems:
|
* Other two-factor systems:
|
||||||
* YubiKey OTP (if your key supports U2F, you can use that)
|
|
||||||
* Duo
|
* Duo
|
||||||
* Email codes
|
* Email codes
|
||||||
|
|
||||||
|
@ -252,6 +253,22 @@ docker run -d --name bitwarden \
|
||||||
|
|
||||||
Note that the value has to include the `https://` and it may include a port at the end (in the format of `https://bw.domain.tld:port`) when not using `443`.
|
Note that the value has to include the `https://` and it may include a port at the end (in the format of `https://bw.domain.tld:port`) when not using `443`.
|
||||||
|
|
||||||
|
### Enabling YubiKey OTP authentication
|
||||||
|
To enable YubiKey authentication, you must set the `YUBICO_CLIENT_ID` and `YUBICO_SECRET_KEY` env variables.
|
||||||
|
|
||||||
|
If `YUBICO_SERVER` is not specified, it will use the default YubiCloud servers. You can generate `YUBICO_CLIENT_ID` and `YUBICO_SECRET_KEY` for the default YubiCloud [here](https://upgrade.yubico.com/getapikey/).
|
||||||
|
|
||||||
|
Note: In order to generate API keys or use a YubiKey with an OTP server, it must be registered. After configuring your key in the [YubiKey Personalization Tool](https://www.yubico.com/products/services-software/personalization-tools/use/), you can register it with the default servers [here](https://upload.yubico.com/).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker run -d --name bitwarden \
|
||||||
|
-e YUBICO_CLIENT_ID=12345 \
|
||||||
|
-e YUBICO_SECRET_KEY=ABCDEABCDEABCDEABCDE= \
|
||||||
|
-v /bw-data/:/data/ \
|
||||||
|
-p 80:80 \
|
||||||
|
mprasil/bitwarden:latest
|
||||||
|
```
|
||||||
|
|
||||||
### Changing persistent data location
|
### Changing persistent data location
|
||||||
|
|
||||||
#### /data prefix:
|
#### /data prefix:
|
||||||
|
@ -430,10 +447,18 @@ It will setup a fully functional and secure `bitwarden_rs` application in Kubern
|
||||||
The sqlite3 database should be backed up using the proper sqlite3 backup command. This will ensure the database does not become corrupted if the backup happens during a database write.
|
The sqlite3 database should be backed up using the proper sqlite3 backup command. This will ensure the database does not become corrupted if the backup happens during a database write.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
mkdir $DATA_FOLDER/db-backup
|
||||||
sqlite3 /$DATA_FOLDER/db.sqlite3 ".backup '/$DATA_FOLDER/db-backup/backup.sqlite3'"
|
sqlite3 /$DATA_FOLDER/db.sqlite3 ".backup '/$DATA_FOLDER/db-backup/backup.sqlite3'"
|
||||||
```
|
```
|
||||||
|
|
||||||
This command can be run via a CRON job everyday, however note that it will overwrite the same `backup.sqlite3` file each time. This backup file should therefore be saved via incremental backup either using a CRON job command that appends a timestamp or from another backup app such as Duplicati. To restore simply overwrite `db.sqlite3` with `backup.sqlite3` (while bitwarden_rs is stopped).
|
This command can be run via a CRON job everyday, however note that it will overwrite the same `backup.sqlite3` file each time. This backup file should therefore be saved via incremental backup either using a CRON job command that appends a timestamp or from another backup app such as Duplicati. To restore simply overwrite `db.sqlite3` with `backup.sqlite3` (while bitwarden_rs is stopped).
|
||||||
|
|
||||||
|
Running the above command requires sqlite3 to be installed on the docker host system. You can achieve the same result with a sqlite3 docker container using the following command.
|
||||||
|
```
|
||||||
|
docker run --rm --volumes-from=bitwarden bruceforce/bw_backup /backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also run a container with integrated cron daemon to automatically backup your database. See https://gitlab.com/1O/bitwarden_rs-backup for examples.
|
||||||
|
|
||||||
### 2. the attachments folder
|
### 2. the attachments folder
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@ pub fn routes() -> Vec<Route> {
|
||||||
generate_u2f_challenge,
|
generate_u2f_challenge,
|
||||||
activate_u2f,
|
activate_u2f,
|
||||||
activate_u2f_put,
|
activate_u2f_put,
|
||||||
|
generate_yubikey,
|
||||||
|
activate_yubikey,
|
||||||
|
activate_yubikey_put,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,3 +515,218 @@ pub fn validate_u2f_login(user_uuid: &str, response: &str, conn: &DbConn) -> Api
|
||||||
}
|
}
|
||||||
err!("error verifying response")
|
err!("error verifying response")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct EnableYubikeyData {
|
||||||
|
MasterPasswordHash: String,
|
||||||
|
Key1: Option<String>,
|
||||||
|
Key2: Option<String>,
|
||||||
|
Key3: Option<String>,
|
||||||
|
Key4: Option<String>,
|
||||||
|
Key5: Option<String>,
|
||||||
|
Nfc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct YubikeyMetadata {
|
||||||
|
Keys: Vec<String>,
|
||||||
|
pub Nfc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
use yubico::Yubico;
|
||||||
|
use yubico::config::Config;
|
||||||
|
|
||||||
|
fn parse_yubikeys(data: &EnableYubikeyData) -> Vec<String> {
|
||||||
|
let mut yubikeys: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
if data.Key1.is_some() {
|
||||||
|
yubikeys.push(data.Key1.as_ref().unwrap().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Key2.is_some() {
|
||||||
|
yubikeys.push(data.Key2.as_ref().unwrap().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Key3.is_some() {
|
||||||
|
yubikeys.push(data.Key3.as_ref().unwrap().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Key4.is_some() {
|
||||||
|
yubikeys.push(data.Key4.as_ref().unwrap().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Key5.is_some() {
|
||||||
|
yubikeys.push(data.Key5.as_ref().unwrap().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
yubikeys
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jsonify_yubikeys(yubikeys: Vec<String>) -> serde_json::Value {
|
||||||
|
let mut result = json!({});
|
||||||
|
|
||||||
|
for i in 0..yubikeys.len() {
|
||||||
|
let ref key = &yubikeys[i];
|
||||||
|
result[format!("Key{}", i+1)] = Value::String(key.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_yubikey_otp(otp: String) -> JsonResult {
|
||||||
|
if !CONFIG.yubico_cred_set {
|
||||||
|
err!("`YUBICO_CLIENT_ID` or `YUBICO_SECRET_KEY` environment variable is not set. \
|
||||||
|
Yubikey OTP Disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
let yubico = Yubico::new();
|
||||||
|
let config = Config::default().set_client_id(CONFIG.yubico_client_id.to_owned()).set_key(CONFIG.yubico_secret_key.to_owned());
|
||||||
|
|
||||||
|
let result = match CONFIG.yubico_server {
|
||||||
|
Some(ref server) => yubico.verify(otp, config.set_api_hosts(vec![server.to_owned()])),
|
||||||
|
None => yubico.verify(otp, config)
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_answer) => Ok(Json(json!({}))),
|
||||||
|
Err(_e) => err!("Failed to verify OTP"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/two-factor/get-yubikey", data = "<data>")]
|
||||||
|
fn generate_yubikey(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.yubico_cred_set {
|
||||||
|
err!("`YUBICO_CLIENT_ID` or `YUBICO_SECRET_KEY` environment variable is not set. \
|
||||||
|
Yubikey OTP Disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: PasswordData = data.into_inner().data;
|
||||||
|
|
||||||
|
if !headers.user.check_valid_password(&data.MasterPasswordHash) {
|
||||||
|
err!("Invalid password");
|
||||||
|
}
|
||||||
|
|
||||||
|
let user_uuid = &headers.user.uuid;
|
||||||
|
let yubikey_type = TwoFactorType::YubiKey as i32;
|
||||||
|
|
||||||
|
let r = TwoFactor::find_by_user_and_type(user_uuid, yubikey_type, &conn);
|
||||||
|
|
||||||
|
if let Some(r) = r {
|
||||||
|
let yubikey_metadata: YubikeyMetadata =
|
||||||
|
serde_json::from_str(&r.data).expect("Can't parse YubikeyMetadata data");
|
||||||
|
|
||||||
|
let mut result = jsonify_yubikeys(yubikey_metadata.Keys);
|
||||||
|
|
||||||
|
result["Enabled"] = Value::Bool(true);
|
||||||
|
result["Nfc"] = Value::Bool(yubikey_metadata.Nfc);
|
||||||
|
result["Object"] = Value::String("twoFactorU2f".to_owned());
|
||||||
|
|
||||||
|
Ok(Json(result))
|
||||||
|
} else {
|
||||||
|
Ok(Json(json!({
|
||||||
|
"Enabled": false,
|
||||||
|
"Object": "twoFactorU2f",
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/two-factor/yubikey", data = "<data>")]
|
||||||
|
fn activate_yubikey(data: JsonUpcase<EnableYubikeyData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
let data: EnableYubikeyData = data.into_inner().data;
|
||||||
|
|
||||||
|
if !headers.user.check_valid_password(&data.MasterPasswordHash) {
|
||||||
|
err!("Invalid password");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we already have some data
|
||||||
|
let yubikey_data = TwoFactor::find_by_user_and_type(
|
||||||
|
&headers.user.uuid,
|
||||||
|
TwoFactorType::YubiKey as i32,
|
||||||
|
&conn,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(yubikey_data) = yubikey_data {
|
||||||
|
yubikey_data.delete(&conn).expect("Error deleting current Yubikeys");
|
||||||
|
}
|
||||||
|
|
||||||
|
let yubikeys = parse_yubikeys(&data);
|
||||||
|
|
||||||
|
if yubikeys.len() == 0 {
|
||||||
|
return Ok(Json(json!({
|
||||||
|
"Enabled": false,
|
||||||
|
"Object": "twoFactorU2f",
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure they are valid OTPs
|
||||||
|
for yubikey in &yubikeys {
|
||||||
|
if yubikey.len() == 12 {
|
||||||
|
// YubiKey ID
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = verify_yubikey_otp(yubikey.to_owned());
|
||||||
|
|
||||||
|
if let Err(_e) = result {
|
||||||
|
err!("Invalid Yubikey OTP provided");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let yubikey_ids: Vec<String> = yubikeys.into_iter().map(|x| (&x[..12]).to_owned()).collect();
|
||||||
|
|
||||||
|
let yubikey_metadata = YubikeyMetadata {
|
||||||
|
Keys: yubikey_ids,
|
||||||
|
Nfc: data.Nfc,
|
||||||
|
};
|
||||||
|
|
||||||
|
let yubikey_registration = TwoFactor::new(
|
||||||
|
headers.user.uuid.clone(),
|
||||||
|
TwoFactorType::YubiKey,
|
||||||
|
serde_json::to_string(&yubikey_metadata).unwrap(),
|
||||||
|
);
|
||||||
|
yubikey_registration
|
||||||
|
.save(&conn).expect("Failed to save Yubikey info");
|
||||||
|
|
||||||
|
let mut result = jsonify_yubikeys(yubikey_metadata.Keys);
|
||||||
|
|
||||||
|
result["Enabled"] = Value::Bool(true);
|
||||||
|
result["Nfc"] = Value::Bool(yubikey_metadata.Nfc);
|
||||||
|
result["Object"] = Value::String("twoFactorU2f".to_owned());
|
||||||
|
|
||||||
|
Ok(Json(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[put("/two-factor/yubikey", data = "<data>")]
|
||||||
|
fn activate_yubikey_put(data: JsonUpcase<EnableYubikeyData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
activate_yubikey(data, headers, conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_yubikey_login(user_uuid: &str, response: &str, conn: &DbConn) -> ApiResult<()> {
|
||||||
|
if response.len() != 44 {
|
||||||
|
err!("Invalid Yubikey OTP length");
|
||||||
|
}
|
||||||
|
|
||||||
|
let yubikey_type = TwoFactorType::YubiKey as i32;
|
||||||
|
|
||||||
|
let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, yubikey_type, &conn) {
|
||||||
|
Some(tf) => tf,
|
||||||
|
None => err!("No YubiKey devices registered"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let yubikey_metadata: YubikeyMetadata = serde_json::from_str(&twofactor.data).expect("Can't parse Yubikey Metadata");
|
||||||
|
let response_id = &response[..12];
|
||||||
|
|
||||||
|
if !yubikey_metadata.Keys.contains(&response_id.to_owned()) {
|
||||||
|
err!("Given Yubikey is not registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = verify_yubikey_otp(response.to_owned());
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_answer) => Ok(()),
|
||||||
|
Err(_e) => err!("Failed to verify Yubikey against OTP server"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -199,6 +199,12 @@ fn twofactor_auth(
|
||||||
two_factor::validate_u2f_login(user_uuid, &twofactor_code, conn)?;
|
two_factor::validate_u2f_login(user_uuid, &twofactor_code, conn)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(TwoFactorType::YubiKey) => {
|
||||||
|
use api::core::two_factor;
|
||||||
|
|
||||||
|
two_factor::validate_yubikey_login(user_uuid, twofactor_code, conn)?;
|
||||||
|
}
|
||||||
|
|
||||||
_ => err!("Invalid two factor provider"),
|
_ => err!("Invalid two factor provider"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +259,19 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api
|
||||||
result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map);
|
result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(TwoFactorType::YubiKey) => {
|
||||||
|
let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::YubiKey as i32, &conn) {
|
||||||
|
Some(tf) => tf,
|
||||||
|
None => err!("No YubiKey devices registered"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let yubikey_metadata: two_factor::YubikeyMetadata = serde_json::from_str(&twofactor.data).expect("Can't parse Yubikey Metadata");
|
||||||
|
|
||||||
|
let mut map = JsonMap::new();
|
||||||
|
map.insert("Nfc".into(), Value::Bool(yubikey_metadata.Nfc));
|
||||||
|
result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map);
|
||||||
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,7 +318,9 @@ impl Cipher {
|
||||||
.filter(ciphers::user_uuid.eq(user_uuid).or( // Cipher owner
|
.filter(ciphers::user_uuid.eq(user_uuid).or( // Cipher owner
|
||||||
users_organizations::access_all.eq(true).or( // access_all in Organization
|
users_organizations::access_all.eq(true).or( // access_all in Organization
|
||||||
users_organizations::type_.le(UserOrgType::Admin as i32).or( // Org admin or owner
|
users_organizations::type_.le(UserOrgType::Admin as i32).or( // Org admin or owner
|
||||||
users_collections::user_uuid.eq(user_uuid) // Access to Collection
|
users_collections::user_uuid.eq(user_uuid).and( // Access to Collection
|
||||||
|
users_organizations::status.eq(UserOrgStatus::Confirmed as i32)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -26,6 +26,7 @@ extern crate oath;
|
||||||
extern crate data_encoding;
|
extern crate data_encoding;
|
||||||
extern crate jsonwebtoken as jwt;
|
extern crate jsonwebtoken as jwt;
|
||||||
extern crate u2f;
|
extern crate u2f;
|
||||||
|
extern crate yubico;
|
||||||
extern crate dotenv;
|
extern crate dotenv;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
@ -246,6 +247,11 @@ pub struct Config {
|
||||||
domain: String,
|
domain: String,
|
||||||
domain_set: bool,
|
domain_set: bool,
|
||||||
|
|
||||||
|
yubico_cred_set: bool,
|
||||||
|
yubico_client_id: String,
|
||||||
|
yubico_secret_key: String,
|
||||||
|
yubico_server: Option<String>,
|
||||||
|
|
||||||
mail: Option<MailConfig>,
|
mail: Option<MailConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +265,9 @@ impl Config {
|
||||||
|
|
||||||
let domain = get_env("DOMAIN");
|
let domain = get_env("DOMAIN");
|
||||||
|
|
||||||
|
let yubico_client_id = get_env("YUBICO_CLIENT_ID");
|
||||||
|
let yubico_secret_key = get_env("YUBICO_SECRET_KEY");
|
||||||
|
|
||||||
Config {
|
Config {
|
||||||
database_url: get_env_or("DATABASE_URL", format!("{}/{}", &df, "db.sqlite3")),
|
database_url: get_env_or("DATABASE_URL", format!("{}/{}", &df, "db.sqlite3")),
|
||||||
icon_cache_folder: get_env_or("ICON_CACHE_FOLDER", format!("{}/{}", &df, "icon_cache")),
|
icon_cache_folder: get_env_or("ICON_CACHE_FOLDER", format!("{}/{}", &df, "icon_cache")),
|
||||||
|
@ -284,6 +293,11 @@ impl Config {
|
||||||
domain_set: domain.is_some(),
|
domain_set: domain.is_some(),
|
||||||
domain: domain.unwrap_or("http://localhost".into()),
|
domain: domain.unwrap_or("http://localhost".into()),
|
||||||
|
|
||||||
|
yubico_cred_set: yubico_client_id.is_some() && yubico_secret_key.is_some(),
|
||||||
|
yubico_client_id: yubico_client_id.unwrap_or("00000".into()),
|
||||||
|
yubico_secret_key: yubico_secret_key.unwrap_or("AAAAAAA".into()),
|
||||||
|
yubico_server: get_env("YUBICO_SERVER"),
|
||||||
|
|
||||||
mail: MailConfig::load(),
|
mail: MailConfig::load(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Laden …
In neuem Issue referenzieren