commit 8d06d9c1111d642d0c2d03c1d29b0170e79f0c11
parent 06f8e69c7026d4aacc15bbbe0a87377e131336db
Author: Daniel GarcĂa <dani-garcia@users.noreply.github.com>
Date: Sun, 13 Mar 2022 15:46:49 +0100
Merge pull request #2354 from BlackDex/multi-account-login
Update login API code and update crates to fix CVE
Diffstat:
14 files changed, 126 insertions(+), 132 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -100,25 +100,6 @@ dependencies = [
]
[[package]]
-name = "async-mutex"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
-dependencies = [
- "event-listener",
-]
-
-[[package]]
-name = "async-rwlock"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "261803dcc39ba9e72760ba6e16d0199b1eef9fc44e81bffabbebb9f5aea3906c"
-dependencies = [
- "async-mutex",
- "event-listener",
-]
-
-[[package]]
name = "async-stream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -151,6 +132,12 @@ dependencies = [
]
[[package]]
+name = "async_once"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ce4f10ea3abcd6617873bae9f91d1c5332b4a778bd9ce34d0cd517474c1de82"
+
+[[package]]
name = "atomic"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -205,12 +192,6 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]]
name = "base64"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
-
-[[package]]
-name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
@@ -323,25 +304,27 @@ checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cached"
-version = "0.30.0"
+version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af4dfac631a8e77b2f327f7852bb6172771f5279c4512efe79fad6067b37be3d"
+checksum = "aadf76ddea74bab35ebeb8f1eb115b9bc04eaee42d8acc0d5f477dee6b176c9a"
dependencies = [
- "async-mutex",
- "async-rwlock",
"async-trait",
+ "async_once",
"cached_proc_macro",
"cached_proc_macro_types",
"futures",
- "hashbrown",
+ "hashbrown 0.12.0",
+ "lazy_static",
"once_cell",
+ "thiserror",
+ "tokio",
]
[[package]]
name = "cached_proc_macro"
-version = "0.9.0"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "725f434d6da2814b989bd905c62ca28a9383feff7440210dc279665fbbbc9511"
+checksum = "bce0f37f9b77c6b93cdf3f060c89adca303d2ab052cacb3c3d1ab543e8cecd2f"
dependencies = [
"cached_proc_macro_types",
"darling",
@@ -793,12 +776,6 @@ dependencies = [
]
[[package]]
-name = "event-listener"
-version = "2.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
-
-[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1092,9 +1069,9 @@ dependencies = [
[[package]]
name = "h2"
-version = "0.3.11"
+version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e"
+checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b"
dependencies = [
"bytes 1.1.0",
"fnv",
@@ -1117,9 +1094,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
-version = "4.2.1"
+version = "4.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25546a65e5cf1f471f3438796fc634650b31d7fcde01d444c309aeb28b92e3a8"
+checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b"
dependencies = [
"log",
"pest",
@@ -1137,6 +1114,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
+name = "hashbrown"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
+
+[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1315,7 +1298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
- "hashbrown",
+ "hashbrown 0.11.2",
"serde",
]
@@ -1357,9 +1340,9 @@ dependencies = [
[[package]]
name = "ipnet"
-version = "2.3.1"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
+checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c"
[[package]]
name = "itoa"
@@ -1394,11 +1377,11 @@ dependencies = [
[[package]]
name = "jsonwebtoken"
-version = "7.2.0"
+version = "8.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afabcc15e437a6484fc4f12d0fd63068fe457bf93f1c148d3d9649c60b103f32"
+checksum = "012bb02250fdd38faa5feee63235f7a459974440b9b57593822414c31f92839e"
dependencies = [
- "base64 0.12.3",
+ "base64 0.13.0",
"pem",
"ring",
"serde",
@@ -1794,9 +1777,9 @@ dependencies = [
[[package]]
name = "num-bigint"
-version = "0.2.6"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
+checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
@@ -1863,9 +1846,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "opaque-debug"
@@ -2059,13 +2042,11 @@ dependencies = [
[[package]]
name = "pem"
-version = "0.8.3"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
+checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947"
dependencies = [
"base64 0.13.0",
- "once_cell",
- "regex",
]
[[package]]
@@ -2254,7 +2235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "292972edad6bbecc137ab84c5e36421a4a6c979ea31d3cc73540dd04315b33e1"
dependencies = [
"byteorder",
- "hashbrown",
+ "hashbrown 0.11.2",
"idna 0.2.3",
"psl-types",
]
@@ -2288,6 +2269,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
+name = "quickcheck"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
+dependencies = [
+ "rand 0.8.5",
+]
+
+[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2432,9 +2422,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
dependencies = [
"bitflags",
]
@@ -2461,9 +2451,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.5.4"
+version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
@@ -2585,7 +2575,7 @@ dependencies = [
[[package]]
name = "rocket"
version = "0.5.0-rc.1"
-source = "git+https://github.com/SergioBenitez/Rocket?rev=91e3b4397a1637d0f55f23db712cf7bda0c7f891#91e3b4397a1637d0f55f23db712cf7bda0c7f891"
+source = "git+https://github.com/SergioBenitez/Rocket?rev=ae0ccf43f11be5c00bb9cd49996c8bb06a7e1651#ae0ccf43f11be5c00bb9cd49996c8bb06a7e1651"
dependencies = [
"async-stream",
"async-trait",
@@ -2623,7 +2613,7 @@ dependencies = [
[[package]]
name = "rocket_codegen"
version = "0.5.0-rc.1"
-source = "git+https://github.com/SergioBenitez/Rocket?rev=91e3b4397a1637d0f55f23db712cf7bda0c7f891#91e3b4397a1637d0f55f23db712cf7bda0c7f891"
+source = "git+https://github.com/SergioBenitez/Rocket?rev=ae0ccf43f11be5c00bb9cd49996c8bb06a7e1651#ae0ccf43f11be5c00bb9cd49996c8bb06a7e1651"
dependencies = [
"devise",
"glob",
@@ -2638,7 +2628,7 @@ dependencies = [
[[package]]
name = "rocket_http"
version = "0.5.0-rc.1"
-source = "git+https://github.com/SergioBenitez/Rocket?rev=91e3b4397a1637d0f55f23db712cf7bda0c7f891#91e3b4397a1637d0f55f23db712cf7bda0c7f891"
+source = "git+https://github.com/SergioBenitez/Rocket?rev=ae0ccf43f11be5c00bb9cd49996c8bb06a7e1651#ae0ccf43f11be5c00bb9cd49996c8bb06a7e1651"
dependencies = [
"cookie 0.16.0",
"either",
@@ -2936,20 +2926,21 @@ dependencies = [
[[package]]
name = "simple_asn1"
-version = "0.4.1"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b"
+checksum = "4a762b1c38b9b990c694b9c2f8abe3372ce6a9ceaae6bca39cfc46e054f45745"
dependencies = [
- "chrono",
"num-bigint",
"num-traits",
+ "thiserror",
+ "time 0.3.7",
]
[[package]]
name = "siphasher"
-version = "0.3.9"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
+checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "slab"
@@ -3208,6 +3199,7 @@ dependencies = [
"itoa",
"libc",
"num_threads",
+ "quickcheck",
"time-macros 0.2.3",
]
@@ -3387,9 +3379,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]]
name = "tracing"
-version = "0.1.31"
+version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f"
+checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
dependencies = [
"cfg-if 1.0.0",
"log",
@@ -3400,9 +3392,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.19"
+version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716"
+checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b"
dependencies = [
"proc-macro2",
"quote",
@@ -3411,9 +3403,9 @@ dependencies = [
[[package]]
name = "tracing-core"
-version = "0.1.22"
+version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23"
+checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
dependencies = [
"lazy_static",
"valuable",
diff --git a/Cargo.toml b/Cargo.toml
@@ -34,14 +34,14 @@ syslog = "4.0.1" # Needs to be v4 until fern is updated
# Logging
log = "0.4.14"
fern = { version = "0.6.0", features = ["syslog-4"] }
-tracing = { version = "0.1.31", features = ["log"] } # Needed to have lettre and webauthn-rs trace logging to work
+tracing = { version = "0.1.32", features = ["log"] } # Needed to have lettre and webauthn-rs trace logging to work
backtrace = "0.3.64" # Logging panics to logfile instead stderr only
# A `dotenv` implementation for Rust
dotenv = { version = "0.15.0", default-features = false }
# Lazy initialization
-once_cell = "1.9.0"
+once_cell = "1.10.0"
# Numerical libraries
num-traits = "0.2.14"
@@ -89,7 +89,7 @@ job_scheduler = "1.2.1"
data-encoding = "2.3.2"
# JWT library
-jsonwebtoken = "7.2.0"
+jsonwebtoken = "8.0.1"
# TOTP library
totp-lite = "1.0.3"
@@ -110,17 +110,17 @@ idna = "0.2.3" # Punycode conversion
percent-encoding = "2.1.0" # URL encoding library used for URL's in the emails
# Template library
-handlebars = { version = "4.2.1", features = ["dir_source"] }
+handlebars = { version = "4.2.2", features = ["dir_source"] }
# HTTP client
reqwest = { version = "0.11.9", features = ["stream", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] }
# For favicon extraction from main website
html5gum = "0.4.0"
-regex = { version = "1.5.4", features = ["std", "perf", "unicode-perl"], default-features = false }
+regex = { version = "1.5.5", features = ["std", "perf", "unicode-perl"], default-features = false }
data-url = "0.1.1"
bytes = "1.1.0"
-cached = "0.30.0"
+cached = "0.34.0"
# Used for custom short lived cookie jar during favicon extraction
cookie = "0.15.1"
@@ -140,7 +140,7 @@ governor = "0.4.2"
ctrlc = { version = "3.2.1", features = ["termination"] }
[patch.crates-io]
-rocket = { git = 'https://github.com/SergioBenitez/Rocket', rev = '91e3b4397a1637d0f55f23db712cf7bda0c7f891' }
+rocket = { git = 'https://github.com/SergioBenitez/Rocket', rev = 'ae0ccf43f11be5c00bb9cd49996c8bb06a7e1651' }
# The maintainer of the `job_scheduler` crate doesn't seem to have responded
# to any issues or PRs for almost a year (as of April 2021). This hopefully
diff --git a/migrations/mysql/2022-03-02-210038_update_devices_primary_key/down.sql b/migrations/mysql/2022-03-02-210038_update_devices_primary_key/down.sql
diff --git a/migrations/mysql/2022-03-02-210038_update_devices_primary_key/up.sql b/migrations/mysql/2022-03-02-210038_update_devices_primary_key/up.sql
@@ -0,0 +1,4 @@
+-- First remove the previous primary key
+ALTER TABLE devices DROP PRIMARY KEY;
+-- Add a new combined one
+ALTER TABLE devices ADD PRIMARY KEY (uuid, user_uuid);
diff --git a/migrations/postgresql/2022-03-02-210038_update_devices_primary_key/down.sql b/migrations/postgresql/2022-03-02-210038_update_devices_primary_key/down.sql
diff --git a/migrations/postgresql/2022-03-02-210038_update_devices_primary_key/up.sql b/migrations/postgresql/2022-03-02-210038_update_devices_primary_key/up.sql
@@ -0,0 +1,4 @@
+-- First remove the previous primary key
+ALTER TABLE devices DROP CONSTRAINT devices_pkey;
+-- Add a new combined one
+ALTER TABLE devices ADD PRIMARY KEY (uuid, user_uuid);
diff --git a/migrations/sqlite/2022-03-02-210038_update_devices_primary_key/down.sql b/migrations/sqlite/2022-03-02-210038_update_devices_primary_key/down.sql
diff --git a/migrations/sqlite/2022-03-02-210038_update_devices_primary_key/up.sql b/migrations/sqlite/2022-03-02-210038_update_devices_primary_key/up.sql
@@ -0,0 +1,23 @@
+-- Create new devices table with primary keys on both uuid and user_uuid
+CREATE TABLE devices_new (
+ uuid TEXT NOT NULL,
+ created_at DATETIME NOT NULL,
+ updated_at DATETIME NOT NULL,
+ user_uuid TEXT NOT NULL,
+ name TEXT NOT NULL,
+ atype INTEGER NOT NULL,
+ push_token TEXT,
+ refresh_token TEXT NOT NULL,
+ twofactor_remember TEXT,
+ PRIMARY KEY(uuid, user_uuid),
+ FOREIGN KEY(user_uuid) REFERENCES users(uuid)
+);
+
+-- Transfer current data to new table
+INSERT INTO devices_new SELECT * FROM devices;
+
+-- Drop the old table
+DROP TABLE devices;
+
+-- Rename the new table to the original name
+ALTER TABLE devices_new RENAME TO devices;
diff --git a/src/api/identity.rs b/src/api/identity.rs
@@ -98,7 +98,7 @@ async fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> Json
crate::ratelimit::check_limit_login(&ip.ip)?;
// Get the user
- let username = data.username.as_ref().unwrap();
+ let username = data.username.as_ref().unwrap().trim();
let user = match User::find_by_mail(username, &conn).await {
Some(user) => user,
None => err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username)),
@@ -266,17 +266,8 @@ async fn get_device(data: &ConnectData, conn: &DbConn, user: &User) -> (Device,
let mut new_device = false;
// Find device or create new
- let device = match Device::find_by_uuid(&device_id, conn).await {
- Some(device) => {
- // Check if owned device, and recreate if not
- if device.user_uuid != user.uuid {
- info!("Device exists but is owned by another user. The old device will be discarded");
- new_device = true;
- Device::new(device_id, user.uuid.clone(), device_name, device_type)
- } else {
- device
- }
- }
+ let device = match Device::find_by_uuid_and_user(&device_id, &user.uuid, conn).await {
+ Some(device) => device,
None => {
new_device = true;
Device::new(device_id, user.uuid.clone(), device_name, device_type)
@@ -328,7 +319,7 @@ async fn twofactor_auth(
}
Some(TwoFactorType::YubiKey) => _tf::yubikey::validate_yubikey_login(twofactor_code, &selected_data?)?,
Some(TwoFactorType::Duo) => {
- _tf::duo::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn).await?
+ _tf::duo::validate_duo_login(data.username.as_ref().unwrap().trim(), twofactor_code, conn).await?
}
Some(TwoFactorType::Email) => {
_tf::email::validate_email_code_str(user_uuid, twofactor_code, &selected_data?, conn).await?
diff --git a/src/auth.rs b/src/auth.rs
@@ -38,7 +38,7 @@ static PRIVATE_RSA_KEY: Lazy<EncodingKey> = Lazy::new(|| {
static PUBLIC_RSA_KEY_VEC: Lazy<Vec<u8>> = Lazy::new(|| {
read_file(&CONFIG.public_rsa_key()).unwrap_or_else(|e| panic!("Error loading public RSA Key.\n{}", e))
});
-static PUBLIC_RSA_KEY: Lazy<DecodingKey<'_>> = Lazy::new(|| {
+static PUBLIC_RSA_KEY: Lazy<DecodingKey> = Lazy::new(|| {
DecodingKey::from_rsa_pem(&PUBLIC_RSA_KEY_VEC).unwrap_or_else(|e| panic!("Error decoding public RSA Key.\n{}", e))
});
@@ -55,15 +55,11 @@ pub fn encode_jwt<T: Serialize>(claims: &T) -> String {
}
fn decode_jwt<T: DeserializeOwned>(token: &str, issuer: String) -> Result<T, Error> {
- let validation = jsonwebtoken::Validation {
- leeway: 30, // 30 seconds
- validate_exp: true,
- validate_nbf: true,
- aud: None,
- iss: Some(issuer),
- sub: None,
- algorithms: vec![JWT_ALGORITHM],
- };
+ let mut validation = jsonwebtoken::Validation::new(JWT_ALGORITHM);
+ validation.leeway = 30; // 30 seconds
+ validation.validate_exp = true;
+ validation.validate_nbf = true;
+ validation.set_issuer(&[issuer]);
let token = token.replace(char::is_whitespace, "");
jsonwebtoken::decode(&token, &PUBLIC_RSA_KEY, &validation).map(|d| d.claims).map_res("Error decoding JWT")
@@ -350,7 +346,7 @@ impl<'r> FromRequest<'r> for Headers {
_ => err_handler!("Error getting DB"),
};
- let device = match Device::find_by_uuid(&device_uuid, &conn).await {
+ let device = match Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &conn).await {
Some(device) => device,
None => err_handler!("Invalid device id"),
};
diff --git a/src/db/models/device.rs b/src/db/models/device.rs
@@ -8,7 +8,7 @@ db_object! {
#[table_name = "devices"]
#[changeset_options(treat_none_as_null="true")]
#[belongs_to(User, foreign_key = "user_uuid")]
- #[primary_key(uuid)]
+ #[primary_key(uuid, user_uuid)]
pub struct Device {
pub uuid: String,
pub created_at: NaiveDateTime,
@@ -131,32 +131,26 @@ impl Device {
postgresql {
let value = DeviceDb::to_db(self);
crate::util::retry(
- || diesel::insert_into(devices::table).values(&value).on_conflict(devices::uuid).do_update().set(&value).execute(conn),
+ || diesel::insert_into(devices::table).values(&value).on_conflict((devices::uuid, devices::user_uuid)).do_update().set(&value).execute(conn),
10,
).map_res("Error saving device")
}
}
}
- pub async fn delete(self, conn: &DbConn) -> EmptyResult {
+ pub async fn delete_all_by_user(user_uuid: &str, conn: &DbConn) -> EmptyResult {
db_run! { conn: {
- diesel::delete(devices::table.filter(devices::uuid.eq(self.uuid)))
+ diesel::delete(devices::table.filter(devices::user_uuid.eq(user_uuid)))
.execute(conn)
- .map_res("Error removing device")
+ .map_res("Error removing devices for user")
}}
}
- pub async fn delete_all_by_user(user_uuid: &str, conn: &DbConn) -> EmptyResult {
- for device in Self::find_by_user(user_uuid, conn).await {
- device.delete(conn).await?;
- }
- Ok(())
- }
-
- pub async fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
+ pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &DbConn) -> Option<Self> {
db_run! { conn: {
devices::table
.filter(devices::uuid.eq(uuid))
+ .filter(devices::user_uuid.eq(user_uuid))
.first::<DeviceDb>(conn)
.ok()
.from_db()
@@ -173,16 +167,6 @@ impl Device {
}}
}
- pub async fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Self> {
- db_run! { conn: {
- devices::table
- .filter(devices::user_uuid.eq(user_uuid))
- .load::<DeviceDb>(conn)
- .expect("Error loading devices")
- .from_db()
- }}
- }
-
pub async fn find_latest_active_by_user(user_uuid: &str, conn: &DbConn) -> Option<Self> {
db_run! { conn: {
devices::table
diff --git a/src/db/schemas/mysql/schema.rs b/src/db/schemas/mysql/schema.rs
@@ -42,7 +42,7 @@ table! {
}
table! {
- devices (uuid) {
+ devices (uuid, user_uuid) {
uuid -> Text,
created_at -> Datetime,
updated_at -> Datetime,
diff --git a/src/db/schemas/postgresql/schema.rs b/src/db/schemas/postgresql/schema.rs
@@ -42,7 +42,7 @@ table! {
}
table! {
- devices (uuid) {
+ devices (uuid, user_uuid) {
uuid -> Text,
created_at -> Timestamp,
updated_at -> Timestamp,
diff --git a/src/db/schemas/sqlite/schema.rs b/src/db/schemas/sqlite/schema.rs
@@ -42,7 +42,7 @@ table! {
}
table! {
- devices (uuid) {
+ devices (uuid, user_uuid) {
uuid -> Text,
created_at -> Timestamp,
updated_at -> Timestamp,