diff --git a/crates/database/migrations/20230318135414_refresh_tokens.up.sql b/crates/database/migrations/20230318135414_refresh_tokens.up.sql index 0a897a2..60db86e 100644 --- a/crates/database/migrations/20230318135414_refresh_tokens.up.sql +++ b/crates/database/migrations/20230318135414_refresh_tokens.up.sql @@ -4,6 +4,7 @@ create table if not exists refresh_tokens token TEXT not null primary key, ip_address TEXT not null, user TEXT not null references users (id), + app TEXT not null references apps (id), -- timings created_at TEXT not null default CURRENT_TIMESTAMP, diff --git a/crates/database/queries/refresh_tokens/get_one.sql b/crates/database/queries/refresh_tokens/get_one.sql index f43ec1a..4ad3f47 100644 --- a/crates/database/queries/refresh_tokens/get_one.sql +++ b/crates/database/queries/refresh_tokens/get_one.sql @@ -3,6 +3,7 @@ select token, ip_address, user, + app, -- timings created_at as "created_at: DateTime", diff --git a/crates/database/queries/refresh_tokens/insert.sql b/crates/database/queries/refresh_tokens/insert.sql index ee496a9..9563dc8 100644 --- a/crates/database/queries/refresh_tokens/insert.sql +++ b/crates/database/queries/refresh_tokens/insert.sql @@ -1,2 +1,2 @@ -insert into refresh_tokens (token, ip_address, user, expires_at) -values (?, ?, ?, datetime(?, 'unixepoch')) +insert into refresh_tokens (token, ip_address, user, app, expires_at) +values (?, ?, ?, ?, datetime(?, 'unixepoch')) diff --git a/crates/database/sqlx-data.json b/crates/database/sqlx-data.json index 84b0490..8a7341c 100644 --- a/crates/database/sqlx-data.json +++ b/crates/database/sqlx-data.json @@ -100,6 +100,66 @@ }, "query": "update apps\n\nset secret = ?\n\nwhere id is ?" }, + "37681902a5f5d87492812a525a6488e75d20c1c436a3ba2c5aa3f54da62fe861": { + "describe": { + "columns": [ + { + "name": "token", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "ip_address", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "user", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "app", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "created_at: DateTime", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "expires_at: DateTime", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "used_at: DateTime", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "revoked_at: DateTime", + "ordinal": 7, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true + ], + "parameters": { + "Right": 1 + } + }, + "query": "select\n -- info\n token,\n ip_address,\n user,\n app,\n\n -- timings\n created_at as \"created_at: DateTime\",\n expires_at as \"expires_at: DateTime\",\n used_at as \"used_at: DateTime\",\n revoked_at as \"revoked_at: DateTime\"\nfrom refresh_tokens\n\nwhere token is (?)" + }, "3c8e31ffa5cbfd4dded8a272777cb320fb51fd2e53ed25054d24e9801df0c358": { "describe": { "columns": [], @@ -468,70 +528,6 @@ }, "query": "insert into authorization_codes (code, app, user, expires_at)\nvalues (?, ?, ?, datetime(?, 'unixepoch'))\n" }, - "a7405a0479b551ce8e3ea7451fd781214e049a0f12551146ace1e9a2f2f0c06d": { - "describe": { - "columns": [ - { - "name": "token", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "ip_address", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "user", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "created_at: DateTime", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "expires_at: DateTime", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "used_at: DateTime", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "revoked_at: DateTime", - "ordinal": 6, - "type_info": "Text" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - true - ], - "parameters": { - "Right": 1 - } - }, - "query": "select\n -- info\n token,\n ip_address,\n user,\n\n -- timings\n created_at as \"created_at: DateTime\",\n expires_at as \"expires_at: DateTime\",\n used_at as \"used_at: DateTime\",\n revoked_at as \"revoked_at: DateTime\"\nfrom refresh_tokens\n\nwhere token is (?)" - }, - "aa88eb27d38ba4cfb539e4b4d7a86770c24221109e8fcc188a7d38f41e674817": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 4 - } - }, - "query": "insert into refresh_tokens (token, ip_address, user, expires_at)\nvalues (?, ?, ?, datetime(?, 'unixepoch'))\n" - }, "aae93a39c5a9f46235b5ef871b45ba76d7efa1677bfe8291a62b8cbf9cd9e0d5": { "describe": { "columns": [], @@ -542,6 +538,16 @@ }, "query": "update settings\n\nset first_admin = ?\n\nwhere id is 0\n" }, + "b3936ae237f02cc048ca084372f7975921c79aef8fcd6d15a4d63c10f2377d24": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 5 + } + }, + "query": "insert into refresh_tokens (token, ip_address, user, app, expires_at)\nvalues (?, ?, ?, ?, datetime(?, 'unixepoch'))\n" + }, "b652e67e8e1cd0e2b55c830c5569eb1c6caf73857215b4298265cce5c5462902": { "describe": { "columns": [ diff --git a/crates/database/src/tables/refresh_tokens.rs b/crates/database/src/tables/refresh_tokens.rs index ed6d46b..25f8ed0 100644 --- a/crates/database/src/tables/refresh_tokens.rs +++ b/crates/database/src/tables/refresh_tokens.rs @@ -9,6 +9,7 @@ pub struct RefreshTokens { pub token: String, pub ip_address: String, pub user: String, + pub app: String, // Timings pub created_at: DateTime, @@ -23,6 +24,7 @@ impl RefreshTokens { token: &str, ip_address: &str, user: &str, + app: &str, expires_at: i64, ) -> Result, Error> { let query: SqliteQueryResult = sqlx::query_file!( @@ -30,6 +32,7 @@ impl RefreshTokens { token, ip_address, user, + app, expires_at ) .execute(conn) diff --git a/crates/ezidam/src/guards/jwt.rs b/crates/ezidam/src/guards/jwt.rs index 03d5cd9..29d1e16 100644 --- a/crates/ezidam/src/guards/jwt.rs +++ b/crates/ezidam/src/guards/jwt.rs @@ -275,6 +275,7 @@ pub async fn use_refresh_token( new_refresh_token.as_ref(), ip_address, user.id(), + refresh_token.app(), REFRESH_TOKEN_DURATION_DAYS, ) .await diff --git a/crates/ezidam/src/routes/admin/settings.rs b/crates/ezidam/src/routes/admin/settings.rs index 099adbd..7321a75 100644 --- a/crates/ezidam/src/routes/admin/settings.rs +++ b/crates/ezidam/src/routes/admin/settings.rs @@ -120,9 +120,15 @@ pub async fn settings_security_form( RefreshToken::revoke_all(&mut transaction).await?; // Generate refresh token - generate_refresh_token(&mut transaction, ip_address, user.id(), cookie_jar) - .await - .map_err(Error::internal_server_error)?; + generate_refresh_token( + &mut transaction, + ip_address, + user.id(), + app.id(), + cookie_jar, + ) + .await + .map_err(Error::internal_server_error)?; // Get base url let settings = Settings::get(&mut transaction).await?; diff --git a/crates/ezidam/src/routes/oauth/redirect.rs b/crates/ezidam/src/routes/oauth/redirect.rs index df8bf5b..9d229c4 100644 --- a/crates/ezidam/src/routes/oauth/redirect.rs +++ b/crates/ezidam/src/routes/oauth/redirect.rs @@ -79,9 +79,15 @@ pub async fn redirect_page( // TODO: refactor for "code" route // Generate refresh token - generate_refresh_token(&mut transaction, ip_address, user.id(), cookie_jar) - .await - .map_err(Error::internal_server_error)?; + generate_refresh_token( + &mut transaction, + ip_address, + user.id(), + app.id(), + cookie_jar, + ) + .await + .map_err(Error::internal_server_error)?; // Get latest key from database let key = Key::get_most_recent(&mut transaction) diff --git a/crates/ezidam/src/tokens.rs b/crates/ezidam/src/tokens.rs index f7107d6..e169163 100644 --- a/crates/ezidam/src/tokens.rs +++ b/crates/ezidam/src/tokens.rs @@ -1,5 +1,5 @@ use hash::SecretString; -use id::UserID; +use id::{AppID, UserID}; use jwt::{JwtClaims, PrivateKey}; use refresh_tokens::RefreshToken; use rocket::http::{Cookie, CookieJar, SameSite}; @@ -16,6 +16,7 @@ pub async fn generate_refresh_token( conn: impl SqliteExecutor<'_>, ip_address: IpAddr, user_id: &UserID, + app_id: &AppID, cookie_jar: &CookieJar<'_>, ) -> Result<(), String> { // Generate refresh token @@ -29,6 +30,7 @@ pub async fn generate_refresh_token( refresh_token.as_ref(), ip_address.to_string(), user_id, + app_id, REFRESH_TOKEN_DURATION_DAYS, ) .await diff --git a/crates/refresh_tokens/src/database.rs b/crates/refresh_tokens/src/database.rs index 82686bd..1818f56 100644 --- a/crates/refresh_tokens/src/database.rs +++ b/crates/refresh_tokens/src/database.rs @@ -3,7 +3,7 @@ use crate::RefreshToken; use chrono::{Duration, Utc}; use database::sqlx::SqliteExecutor; use database::RefreshTokens as DatabaseRefreshTokens; -use id::UserID; +use id::{AppID, UserID}; impl From for RefreshToken { fn from(db: DatabaseRefreshTokens) -> Self { @@ -12,6 +12,7 @@ impl From for RefreshToken { token: db.token, ip_address: db.ip_address, user: UserID(db.user), + app: AppID(db.app), // Timings created_at: db.created_at, @@ -28,6 +29,7 @@ impl RefreshToken { token: &str, ip_address: String, user: &UserID, + app: &AppID, duration_days: i64, ) -> Result, Error> { let expires_at = Utc::now() + Duration::days(duration_days); @@ -37,6 +39,7 @@ impl RefreshToken { token, ip_address.as_str(), user.as_ref(), + app.as_ref(), expires_at.timestamp(), ) .await?) diff --git a/crates/refresh_tokens/src/lib.rs b/crates/refresh_tokens/src/lib.rs index 2f71dc0..c4a0886 100644 --- a/crates/refresh_tokens/src/lib.rs +++ b/crates/refresh_tokens/src/lib.rs @@ -2,7 +2,7 @@ mod database; mod error; use chrono::{DateTime, Utc}; -use id::UserID; +use id::{AppID, UserID}; pub use crate::error::Error; @@ -12,6 +12,7 @@ pub struct RefreshToken { token: String, ip_address: String, user: UserID, + app: AppID, // Timings created_at: DateTime, @@ -36,4 +37,8 @@ impl RefreshToken { pub fn user(&self) -> &UserID { &self.user } + + pub fn app(&self) -> &AppID { + &self.app + } }