You've already forked AstralRinth
* WIP end-of-day push * Authorize endpoint, accept endpoints, DB stuff for oauth clients, their redirects, and client authorizations * OAuth Client create route * Get user clients * Client delete * Edit oauth client * Include redirects in edit client route * Database stuff for tokens * Reorg oauth stuff out of auth/flows and into its own module * Impl OAuth get access token endpoint * Accept oauth access tokens as auth and update through AuthQueue * User OAuth authorization management routes * Forgot to actually add the routes lol * Bit o cleanup * Happy path test for OAuth and minor fixes for things it found * Add dummy data oauth client (and detect/handle dummy data version changes) * More tests * Another test * More tests and reject endpoint * Test oauth client and authorization management routes * cargo sqlx prepare * dead code warning * Auto clippy fixes * Uri refactoring * minor name improvement * Don't compile-time check the test sqlx queries * Trying to fix db concurrency problem to get tests to pass * Try fix from test PR * Fixes for updated sqlx * Prevent restricted scopes from being requested or issued * Get OAuth client(s) * Remove joined oauth client info from authorization returns * Add default conversion to OAuthError::error so we can use ? * Rework routes * Consolidate scopes into SESSION_ACCESS * Cargo sqlx prepare * Parse to OAuthClientId automatically through serde and actix * Cargo clippy * Remove validation requiring 1 redirect URI on oauth client creation * Use serde(flatten) on OAuthClientCreationResult
127 lines
3.4 KiB
Rust
127 lines
3.4 KiB
Rust
use chrono::{DateTime, Utc};
|
|
use itertools::Itertools;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::models::pats::Scopes;
|
|
|
|
use super::{DatabaseError, OAuthClientAuthorizationId, OAuthClientId, UserId};
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
|
pub struct OAuthClientAuthorization {
|
|
pub id: OAuthClientAuthorizationId,
|
|
pub client_id: OAuthClientId,
|
|
pub user_id: UserId,
|
|
pub scopes: Scopes,
|
|
pub created: DateTime<Utc>,
|
|
}
|
|
|
|
struct AuthorizationQueryResult {
|
|
id: i64,
|
|
client_id: i64,
|
|
user_id: i64,
|
|
scopes: i64,
|
|
created: DateTime<Utc>,
|
|
}
|
|
|
|
impl From<AuthorizationQueryResult> for OAuthClientAuthorization {
|
|
fn from(value: AuthorizationQueryResult) -> Self {
|
|
OAuthClientAuthorization {
|
|
id: OAuthClientAuthorizationId(value.id),
|
|
client_id: OAuthClientId(value.client_id),
|
|
user_id: UserId(value.user_id),
|
|
scopes: Scopes::from_postgres(value.scopes),
|
|
created: value.created,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl OAuthClientAuthorization {
|
|
pub async fn get(
|
|
client_id: OAuthClientId,
|
|
user_id: UserId,
|
|
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
|
) -> Result<Option<OAuthClientAuthorization>, DatabaseError> {
|
|
let value = sqlx::query_as!(
|
|
AuthorizationQueryResult,
|
|
"
|
|
SELECT id, client_id, user_id, scopes, created
|
|
FROM oauth_client_authorizations
|
|
WHERE client_id=$1 AND user_id=$2
|
|
",
|
|
client_id.0,
|
|
user_id.0,
|
|
)
|
|
.fetch_optional(exec)
|
|
.await?;
|
|
|
|
Ok(value.map(|r| r.into()))
|
|
}
|
|
|
|
pub async fn get_all_for_user(
|
|
user_id: UserId,
|
|
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
|
) -> Result<Vec<OAuthClientAuthorization>, DatabaseError> {
|
|
let results = sqlx::query_as!(
|
|
AuthorizationQueryResult,
|
|
"
|
|
SELECT id, client_id, user_id, scopes, created
|
|
FROM oauth_client_authorizations
|
|
WHERE user_id=$1
|
|
",
|
|
user_id.0
|
|
)
|
|
.fetch_all(exec)
|
|
.await?;
|
|
|
|
Ok(results.into_iter().map(|r| r.into()).collect_vec())
|
|
}
|
|
|
|
pub async fn upsert(
|
|
id: OAuthClientAuthorizationId,
|
|
client_id: OAuthClientId,
|
|
user_id: UserId,
|
|
scopes: Scopes,
|
|
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
|
) -> Result<(), DatabaseError> {
|
|
sqlx::query!(
|
|
"
|
|
INSERT INTO oauth_client_authorizations (
|
|
id, client_id, user_id, scopes
|
|
)
|
|
VALUES (
|
|
$1, $2, $3, $4
|
|
)
|
|
ON CONFLICT (id)
|
|
DO UPDATE SET scopes = EXCLUDED.scopes
|
|
",
|
|
id.0,
|
|
client_id.0,
|
|
user_id.0,
|
|
scopes.bits() as i64,
|
|
)
|
|
.execute(&mut **transaction)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn remove(
|
|
client_id: OAuthClientId,
|
|
user_id: UserId,
|
|
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
|
) -> Result<(), DatabaseError> {
|
|
sqlx::query!(
|
|
"
|
|
DELETE FROM oauth_client_authorizations
|
|
WHERE client_id=$1 AND user_id=$2
|
|
",
|
|
client_id.0,
|
|
user_id.0
|
|
)
|
|
.execute(exec)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|