Skip to content

Commit b5597f7

Browse files
committed
fix: make AppData readonly
1 parent fbc9892 commit b5597f7

File tree

10 files changed

+289
-135
lines changed

10 files changed

+289
-135
lines changed

src/cli/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::{jobs, AppData};
1+
use crate::jobs;
22
use clap::{Parser, Subcommand};
3+
use crate::config::AppData;
34

45
#[derive(Debug, Parser)]
56
#[command(version, about, long_about = None)]
@@ -30,13 +31,13 @@ pub async fn maybe_cli(data: &AppData) -> anyhow::Result<bool> {
3031
return match c {
3132
Commands::Job(job) => match job {
3233
JobCommand::Migrate => {
33-
let mut conn = data.db.acquire().await?;
34+
let mut conn = data.db().acquire().await?;
3435
jobs::migrate::migrate(&mut conn).await?;
3536

3637
Ok(true)
3738
},
3839
JobCommand::CleanupDownloads => {
39-
let mut conn = data.db.acquire().await?;
40+
let mut conn = data.db().acquire().await?;
4041
jobs::cleanup_downloads::cleanup_downloads(&mut *conn).await?;
4142

4243
Ok(true)

src/config.rs

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#[derive(Clone)]
2+
pub struct AppData {
3+
db: sqlx::postgres::PgPool,
4+
app_url: String,
5+
github: GitHubClientData,
6+
webhook_url: String,
7+
disable_downloads: bool,
8+
max_download_mb: u32,
9+
port: u16,
10+
debug: bool,
11+
}
12+
13+
#[derive(Clone)]
14+
pub struct GitHubClientData {
15+
client_id: String,
16+
client_secret: String,
17+
}
18+
19+
pub async fn build_config() -> anyhow::Result<AppData> {
20+
let env_url = dotenvy::var("DATABASE_URL")?;
21+
22+
let pool = sqlx::postgres::PgPoolOptions::default()
23+
.max_connections(10)
24+
.connect(&env_url)
25+
.await?;
26+
let port = dotenvy::var("PORT").map_or(8080, |x: String| x.parse::<u16>().unwrap());
27+
let debug = dotenvy::var("APP_DEBUG").unwrap_or("0".to_string()) == "1";
28+
let app_url = dotenvy::var("APP_URL").unwrap_or("http://localhost".to_string());
29+
let github_client = dotenvy::var("GITHUB_CLIENT_ID").unwrap_or("".to_string());
30+
let github_secret = dotenvy::var("GITHUB_CLIENT_SECRET").unwrap_or("".to_string());
31+
let webhook_url = dotenvy::var("DISCORD_WEBHOOK_URL").unwrap_or("".to_string());
32+
let disable_downloads =
33+
dotenvy::var("DISABLE_DOWNLOAD_COUNTS").unwrap_or("0".to_string()) == "1";
34+
let max_download_mb = dotenvy::var("MAX_MOD_FILESIZE_MB")
35+
.unwrap_or("250".to_string())
36+
.parse::<u32>()
37+
.unwrap_or(250);
38+
39+
Ok(AppData {
40+
db: pool,
41+
app_url,
42+
github: GitHubClientData {
43+
client_id: github_client,
44+
client_secret: github_secret,
45+
},
46+
webhook_url,
47+
disable_downloads,
48+
max_download_mb,
49+
port,
50+
debug,
51+
})
52+
}
53+
54+
impl GitHubClientData {
55+
pub fn client_id(&self) -> &str {
56+
&self.client_id
57+
}
58+
59+
pub fn client_secret(&self) -> &str {
60+
&self.client_secret
61+
}
62+
}
63+
64+
impl AppData {
65+
pub fn db(&self) -> &sqlx::postgres::PgPool {
66+
&self.db
67+
}
68+
69+
pub fn app_url(&self) -> &str {
70+
&self.app_url
71+
}
72+
73+
pub fn github(&self) -> &GitHubClientData {
74+
&self.github
75+
}
76+
77+
pub fn webhook_url(&self) -> &str {
78+
&self.webhook_url
79+
}
80+
81+
pub fn disable_downloads(&self) -> bool {
82+
self.disable_downloads
83+
}
84+
85+
pub fn max_download_mb(&self) -> u32 {
86+
self.max_download_mb
87+
}
88+
89+
pub fn port(&self) -> u16 {
90+
self.port
91+
}
92+
93+
pub fn debug(&self) -> bool {
94+
self.debug
95+
}
96+
}

src/endpoints/auth/github.rs

+21-17
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use serde::Deserialize;
33
use sqlx::{types::ipnetwork::IpNetwork, Acquire};
44
use uuid::Uuid;
55

6+
use crate::config::AppData;
67
use crate::database::repository::{auth_tokens, developers};
78
use crate::{
89
auth::github,
910
types::{
1011
api::{ApiError, ApiResponse},
1112
models::github_login_attempt::GithubLoginAttempt,
1213
},
13-
AppData,
1414
};
1515

1616
#[derive(Deserialize)]
@@ -28,10 +28,14 @@ pub async fn start_github_login(
2828
data: web::Data<AppData>,
2929
info: ConnectionInfo,
3030
) -> Result<impl Responder, ApiError> {
31-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
31+
let mut pool = data
32+
.db()
33+
.acquire()
34+
.await
35+
.or(Err(ApiError::DbAcquireError))?;
3236
let client = github::GithubClient::new(
33-
data.github_client_id.to_string(),
34-
data.github_client_secret.to_string(),
37+
data.github().client_id().to_string(),
38+
data.github().client_secret().to_string(),
3539
);
3640
let ip = match info.realip_remote_addr() {
3741
None => return Err(ApiError::InternalError),
@@ -52,14 +56,14 @@ pub async fn poll_github_login(
5256
data: web::Data<AppData>,
5357
connection_info: ConnectionInfo,
5458
) -> Result<impl Responder, ApiError> {
55-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
56-
let uuid = match Uuid::parse_str(&json.uuid) {
57-
Err(e) => {
58-
log::error!("{}", e);
59-
return Err(ApiError::BadRequest(format!("Invalid uuid {}", json.uuid)));
60-
}
61-
Ok(u) => u,
62-
};
59+
let mut pool = data
60+
.db()
61+
.acquire()
62+
.await
63+
.or(Err(ApiError::DbAcquireError))?;
64+
65+
let uuid = Uuid::parse_str(&json.uuid).or(Err(ApiError::BadRequest("Invalid uuid".into())))?;
66+
6367
let attempt =
6468
GithubLoginAttempt::get_one(uuid, &mut pool)
6569
.await?
@@ -95,8 +99,8 @@ pub async fn poll_github_login(
9599
let mut tx = pool.begin().await.or(Err(ApiError::TransactionError))?;
96100

97101
let client = github::GithubClient::new(
98-
data.github_client_id.to_string(),
99-
data.github_client_secret.to_string(),
102+
data.github().client_id().to_string(),
103+
data.github().client_secret().to_string(),
100104
);
101105
GithubLoginAttempt::poll(uuid, &mut tx).await;
102106
let token = client.poll_github(&attempt.device_code).await?;
@@ -131,16 +135,16 @@ pub async fn github_token_login(
131135
data: web::Data<AppData>,
132136
) -> Result<impl Responder, ApiError> {
133137
let client = github::GithubClient::new(
134-
data.github_client_id.to_string(),
135-
data.github_client_secret.to_string(),
138+
data.github().client_id().to_string(),
139+
data.github().client_secret().to_string(),
136140
);
137141

138142
let user = client
139143
.get_user(&json.token)
140144
.await
141145
.map_err(|_| ApiError::BadRequest(format!("Invalid access token: {}", json.token)))?;
142146

143-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
147+
let mut pool = data.db().acquire().await.or(Err(ApiError::DbAcquireError))?;
144148
let mut tx = pool.begin().await.or(Err(ApiError::TransactionError))?;
145149

146150
let developer = developers::fetch_or_insert_github(user.id, &user.username, &mut tx).await?;

src/endpoints/developers.rs

+47-11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use actix_web::{delete, get, post, put, web, HttpResponse, Responder};
22
use serde::{Deserialize, Serialize};
33
use sqlx::Acquire;
44

5+
use crate::config::AppData;
6+
use crate::database::repository::auth_tokens;
57
use crate::{
68
extractors::auth::Auth,
79
types::{
@@ -12,9 +14,7 @@ use crate::{
1214
mod_version_status::ModVersionStatusEnum,
1315
},
1416
},
15-
AppData,
1617
};
17-
use crate::database::repository::auth_tokens;
1818

1919
#[derive(Deserialize, Serialize, Debug, Clone)]
2020
pub struct SimpleDevMod {
@@ -74,7 +74,11 @@ pub async fn developer_index(
7474
data: web::Data<AppData>,
7575
query: web::Query<DeveloperIndexQuery>,
7676
) -> Result<impl Responder, ApiError> {
77-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
77+
let mut pool = data
78+
.db()
79+
.acquire()
80+
.await
81+
.or(Err(ApiError::DbAcquireError))?;
7882

7983
let mut page = query.page.unwrap_or(1);
8084
if page < 1 {
@@ -104,7 +108,11 @@ pub async fn add_developer_to_mod(
104108
auth: Auth,
105109
) -> Result<impl Responder, ApiError> {
106110
let dev = auth.developer()?;
107-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
111+
let mut pool = data
112+
.db()
113+
.acquire()
114+
.await
115+
.or(Err(ApiError::DbAcquireError))?;
108116
let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?;
109117
if !(Developer::owns_mod(dev.id, &path.id, &mut transaction).await?) {
110118
return Err(ApiError::Forbidden);
@@ -144,7 +152,11 @@ pub async fn remove_dev_from_mod(
144152
auth: Auth,
145153
) -> Result<impl Responder, ApiError> {
146154
let dev = auth.developer()?;
147-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
155+
let mut pool = data
156+
.db()
157+
.acquire()
158+
.await
159+
.or(Err(ApiError::DbAcquireError))?;
148160
let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?;
149161
if !(Developer::owns_mod(dev.id, &path.id, &mut transaction).await?) {
150162
return Err(ApiError::Forbidden);
@@ -182,7 +194,11 @@ pub async fn delete_token(
182194
auth: Auth,
183195
) -> Result<impl Responder, ApiError> {
184196
let token = auth.token()?;
185-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
197+
let mut pool = data
198+
.db()
199+
.acquire()
200+
.await
201+
.or(Err(ApiError::DbAcquireError))?;
186202

187203
auth_tokens::remove_token(token, &mut pool).await?;
188204

@@ -195,7 +211,11 @@ pub async fn delete_tokens(
195211
auth: Auth,
196212
) -> Result<impl Responder, ApiError> {
197213
let dev = auth.developer()?;
198-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
214+
let mut pool = data
215+
.db()
216+
.acquire()
217+
.await
218+
.or(Err(ApiError::DbAcquireError))?;
199219

200220
auth_tokens::remove_developer_tokens(dev.id, &mut pool).await?;
201221

@@ -214,7 +234,11 @@ pub async fn update_profile(
214234
auth: Auth,
215235
) -> Result<impl Responder, ApiError> {
216236
let dev = auth.developer()?;
217-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
237+
let mut pool = data
238+
.db()
239+
.acquire()
240+
.await
241+
.or(Err(ApiError::DbAcquireError))?;
218242
let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?;
219243
if let Err(e) = Developer::update_profile(dev.id, &json.display_name, &mut transaction).await {
220244
transaction
@@ -247,7 +271,11 @@ pub async fn get_own_mods(
247271
auth: Auth,
248272
) -> Result<impl Responder, ApiError> {
249273
let dev = auth.developer()?;
250-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
274+
let mut pool = data
275+
.db()
276+
.acquire()
277+
.await
278+
.or(Err(ApiError::DbAcquireError))?;
251279
let mods: Vec<SimpleDevMod> = Mod::get_all_for_dev(dev.id, query.status, &mut pool).await?;
252280
Ok(HttpResponse::Ok().json(ApiResponse {
253281
error: "".to_string(),
@@ -280,7 +308,11 @@ pub async fn get_developer(
280308
data: web::Data<AppData>,
281309
path: web::Path<GetDeveloperPath>,
282310
) -> Result<impl Responder, ApiError> {
283-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
311+
let mut pool = data
312+
.db()
313+
.acquire()
314+
.await
315+
.or(Err(ApiError::DbAcquireError))?;
284316
let result = Developer::get_one(path.id, &mut pool).await?;
285317

286318
if result.is_none() {
@@ -316,7 +348,11 @@ pub async fn update_developer(
316348
return Ok(HttpResponse::Ok());
317349
}
318350

319-
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
351+
let mut pool = data
352+
.db()
353+
.acquire()
354+
.await
355+
.or(Err(ApiError::DbAcquireError))?;
320356
let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?;
321357

322358
if payload.admin.is_some() && dev.id == path.id {

0 commit comments

Comments
 (0)