From c4d565b15bfdf34b3278d964a9da53e082fed680 Mon Sep 17 00:00:00 2001 From: BlackDex Date: Thu, 3 Mar 2022 21:00:10 +0100 Subject: [PATCH] Update login API code - Updated jsonwebtoken to latest version - Trim `username` received from the login form ( Fixes #2348 ) - Make uuid and user_uuid a combined primary key for the devices table ( Fixes #2295 ) - Updated crates including regex which contains a CVE ( https://blog.rust-lang.org/2022/03/08/cve-2022-24713.html ) --- Cargo.lock | 142 +++++++++--------- Cargo.toml | 14 +- .../down.sql | 0 .../up.sql | 4 + .../down.sql | 0 .../up.sql | 4 + .../down.sql | 0 .../up.sql | 23 +++ src/api/identity.rs | 17 +-- src/auth.rs | 18 +-- src/db/models/device.rs | 30 +--- src/db/schemas/mysql/schema.rs | 2 +- src/db/schemas/postgresql/schema.rs | 2 +- src/db/schemas/sqlite/schema.rs | 2 +- 14 files changed, 126 insertions(+), 132 deletions(-) create mode 100644 migrations/mysql/2022-03-02-210038_update_devices_primary_key/down.sql create mode 100644 migrations/mysql/2022-03-02-210038_update_devices_primary_key/up.sql create mode 100644 migrations/postgresql/2022-03-02-210038_update_devices_primary_key/down.sql create mode 100644 migrations/postgresql/2022-03-02-210038_update_devices_primary_key/up.sql create mode 100644 migrations/sqlite/2022-03-02-210038_update_devices_primary_key/down.sql create mode 100644 migrations/sqlite/2022-03-02-210038_update_devices_primary_key/up.sql diff --git a/Cargo.lock b/Cargo.lock index 9de3455d..a8b21b91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,25 +99,6 @@ dependencies = [ "tokio", ] -[[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" @@ -150,6 +131,12 @@ dependencies = [ "syn", ] +[[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" @@ -203,12 +190,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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" @@ -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", @@ -792,12 +775,6 @@ dependencies = [ "backtrace", ] -[[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" @@ -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", @@ -1136,6 +1113,12 @@ version = "0.11.2" 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" @@ -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", ] @@ -2287,6 +2268,15 @@ version = "2.0.1" 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" @@ -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 index 1f76c0ed..98563c73 100644 --- 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 new file mode 100644 index 00000000..e69de29b 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 new file mode 100644 index 00000000..5eee7434 --- /dev/null +++ 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 new file mode 100644 index 00000000..e69de29b 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 new file mode 100644 index 00000000..0dc9ea67 --- /dev/null +++ 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 new file mode 100644 index 00000000..e69de29b 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 new file mode 100644 index 00000000..7bc5f0d6 --- /dev/null +++ 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 index da079b7d..2ed889bb 100644 --- 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 index a2d64b30..34eff5fb 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -38,7 +38,7 @@ static PRIVATE_RSA_KEY: Lazy = Lazy::new(|| { static PUBLIC_RSA_KEY_VEC: Lazy> = 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> = Lazy::new(|| { +static PUBLIC_RSA_KEY: Lazy = 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(claims: &T) -> String { } fn decode_jwt(token: &str, issuer: String) -> Result { - 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 index 2f5cd018..e265c31f 100644 --- 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 { + pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &DbConn) -> Option { db_run! { conn: { devices::table .filter(devices::uuid.eq(uuid)) + .filter(devices::user_uuid.eq(user_uuid)) .first::(conn) .ok() .from_db() @@ -173,16 +167,6 @@ impl Device { }} } - pub async fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec { - db_run! { conn: { - devices::table - .filter(devices::user_uuid.eq(user_uuid)) - .load::(conn) - .expect("Error loading devices") - .from_db() - }} - } - pub async fn find_latest_active_by_user(user_uuid: &str, conn: &DbConn) -> Option { db_run! { conn: { devices::table diff --git a/src/db/schemas/mysql/schema.rs b/src/db/schemas/mysql/schema.rs index 61234a16..a49159f2 100644 --- 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 index 855b4fbc..9fd6fd97 100644 --- 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 index 855b4fbc..9fd6fd97 100644 --- 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,