You've already forked AstralRinth
forked from didirus/AstralRinth
Add support for hashes in Maven (#264)
Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
2badcfa546
commit
989f2d3001
@@ -561,25 +561,24 @@ impl Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_full_from_slug_or_project_id<'a, 'b, E>(
|
pub async fn get_full_from_slug_or_project_id<'a, 'b, E>(
|
||||||
slug_or_project_id: String,
|
slug_or_project_id: &str,
|
||||||
executor: E,
|
executor: E,
|
||||||
) -> Result<Option<QueryProject>, sqlx::error::Error>
|
) -> Result<Option<QueryProject>, sqlx::error::Error>
|
||||||
where
|
where
|
||||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||||
{
|
{
|
||||||
let id_option =
|
let id_option = crate::models::ids::base62_impl::parse_base62(slug_or_project_id).ok();
|
||||||
crate::models::ids::base62_impl::parse_base62(&*slug_or_project_id.clone()).ok();
|
|
||||||
|
|
||||||
if let Some(id) = id_option {
|
if let Some(id) = id_option {
|
||||||
let mut project = Project::get_full(ProjectId(id as i64), executor).await?;
|
let mut project = Project::get_full(ProjectId(id as i64), executor).await?;
|
||||||
|
|
||||||
if project.is_none() {
|
if project.is_none() {
|
||||||
project = Project::get_full_from_slug(&slug_or_project_id, executor).await?;
|
project = Project::get_full_from_slug(slug_or_project_id, executor).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(project)
|
Ok(project)
|
||||||
} else {
|
} else {
|
||||||
let project = Project::get_full_from_slug(&slug_or_project_id, executor).await?;
|
let project = Project::get_full_from_slug(slug_or_project_id, executor).await?;
|
||||||
Ok(project)
|
Ok(project)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::database;
|
use crate::database::models::version_item::{QueryFile, QueryVersion};
|
||||||
use crate::models::projects::ProjectId;
|
use crate::models::projects::ProjectId;
|
||||||
use crate::routes::ApiError;
|
use crate::routes::ApiError;
|
||||||
use crate::util::auth::get_user_from_headers;
|
use crate::util::auth::get_user_from_headers;
|
||||||
|
use crate::{database, util::auth::is_authorized};
|
||||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use yaserde_derive::YaSerialize;
|
use yaserde_derive::YaSerialize;
|
||||||
@@ -51,15 +52,11 @@ pub struct MavenPom {
|
|||||||
#[get("maven/modrinth/{id}/maven-metadata.xml")]
|
#[get("maven/modrinth/{id}/maven-metadata.xml")]
|
||||||
pub async fn maven_metadata(
|
pub async fn maven_metadata(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
info: web::Path<(String,)>,
|
web::Path((project_id,)): web::Path<(String,)>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
) -> Result<HttpResponse, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let string = info.into_inner().0;
|
|
||||||
|
|
||||||
let project_data =
|
let project_data =
|
||||||
database::models::Project::get_full_from_slug_or_project_id(string, &**pool).await?;
|
database::models::Project::get_full_from_slug_or_project_id(&project_id, &**pool).await?;
|
||||||
|
|
||||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
|
||||||
|
|
||||||
let data = if let Some(data) = project_data {
|
let data = if let Some(data) = project_data {
|
||||||
data
|
data
|
||||||
@@ -67,32 +64,12 @@ pub async fn maven_metadata(
|
|||||||
return Ok(HttpResponse::NotFound().body(""));
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut authorized = !data.status.is_hidden();
|
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||||
|
|
||||||
if let Some(user) = user_option {
|
if !is_authorized(&data, &user_option, &pool).await? {
|
||||||
if !authorized {
|
|
||||||
if user.role.is_mod() {
|
|
||||||
authorized = true;
|
|
||||||
} else {
|
|
||||||
let user_id: database::models::ids::UserId = user.id.into();
|
|
||||||
|
|
||||||
let project_exists = sqlx::query!(
|
|
||||||
"SELECT EXISTS(SELECT 1 FROM team_members WHERE team_id = $1 AND user_id = $2)",
|
|
||||||
data.inner.team_id as database::models::ids::TeamId,
|
|
||||||
user_id as database::models::ids::UserId,
|
|
||||||
)
|
|
||||||
.fetch_one(&**pool)
|
|
||||||
.await?
|
|
||||||
.exists;
|
|
||||||
|
|
||||||
authorized = project_exists.unwrap_or(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !authorized {
|
|
||||||
return Ok(HttpResponse::NotFound().body(""));
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
let version_names = sqlx::query!(
|
let version_names = sqlx::query!(
|
||||||
"
|
"
|
||||||
SELECT version_number, version_type
|
SELECT version_number, version_type
|
||||||
@@ -137,22 +114,11 @@ pub async fn maven_metadata(
|
|||||||
#[get("maven/modrinth/{id}/{versionnum}/{file}")]
|
#[get("maven/modrinth/{id}/{versionnum}/{file}")]
|
||||||
pub async fn version_file(
|
pub async fn version_file(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
web::Path((string, vnum, file)): web::Path<(String, String, String)>,
|
web::Path((project_id, vnum, file)): web::Path<(String, String, String)>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
) -> Result<HttpResponse, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let id_option: Option<ProjectId> = serde_json::from_str(&*format!("\"{}\"", string)).ok();
|
let project_data =
|
||||||
|
database::models::Project::get_full_from_slug_or_project_id(&project_id, &**pool).await?;
|
||||||
let project_data = if let Some(id) = id_option {
|
|
||||||
match database::models::Project::get_full(id.into(), &**pool).await {
|
|
||||||
Ok(Some(data)) => Ok(Some(data)),
|
|
||||||
Ok(None) => database::models::Project::get_full_from_slug(&string, &**pool).await,
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
database::models::Project::get_full_from_slug(&string, &**pool).await
|
|
||||||
}?;
|
|
||||||
|
|
||||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
|
||||||
|
|
||||||
let data = if let Some(data) = project_data {
|
let data = if let Some(data) = project_data {
|
||||||
data
|
data
|
||||||
@@ -160,30 +126,9 @@ pub async fn version_file(
|
|||||||
return Ok(HttpResponse::NotFound().body(""));
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut authorized = !data.status.is_hidden();
|
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||||
|
|
||||||
if let Some(user) = user_option {
|
if !is_authorized(&data, &user_option, &pool).await? {
|
||||||
if !authorized {
|
|
||||||
if user.role.is_mod() {
|
|
||||||
authorized = true;
|
|
||||||
} else {
|
|
||||||
let user_id: database::models::ids::UserId = user.id.into();
|
|
||||||
|
|
||||||
let project_exists = sqlx::query!(
|
|
||||||
"SELECT EXISTS(SELECT 1 FROM team_members WHERE team_id = $1 AND user_id = $2)",
|
|
||||||
data.inner.team_id as database::models::ids::TeamId,
|
|
||||||
user_id as database::models::ids::UserId,
|
|
||||||
)
|
|
||||||
.fetch_one(&**pool)
|
|
||||||
.await?
|
|
||||||
.exists;
|
|
||||||
|
|
||||||
authorized = project_exists.unwrap_or(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !authorized {
|
|
||||||
return Ok(HttpResponse::NotFound().body(""));
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +154,7 @@ pub async fn version_file(
|
|||||||
return Ok(HttpResponse::NotFound().body(""));
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
};
|
};
|
||||||
|
|
||||||
if file == format!("{}-{}.pom", &string, &version.version_number) {
|
if file == format!("{}-{}.pom", &project_id, &version.version_number) {
|
||||||
let respdata = MavenPom {
|
let respdata = MavenPom {
|
||||||
schema_location:
|
schema_location:
|
||||||
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||||
@@ -217,7 +162,7 @@ pub async fn version_file(
|
|||||||
xsi: "http://www.w3.org/2001/XMLSchema-instance".to_string(),
|
xsi: "http://www.w3.org/2001/XMLSchema-instance".to_string(),
|
||||||
model_version: "4.0.0".to_string(),
|
model_version: "4.0.0".to_string(),
|
||||||
group_id: "maven.modrinth".to_string(),
|
group_id: "maven.modrinth".to_string(),
|
||||||
artifact_id: string,
|
artifact_id: project_id,
|
||||||
version: version.version_number,
|
version: version.version_number,
|
||||||
name: data.inner.title,
|
name: data.inner.title,
|
||||||
description: data.inner.description,
|
description: data.inner.description,
|
||||||
@@ -229,7 +174,7 @@ pub async fn version_file(
|
|||||||
return Ok(HttpResponse::TemporaryRedirect()
|
return Ok(HttpResponse::TemporaryRedirect()
|
||||||
.header("Location", &*selected_file.url)
|
.header("Location", &*selected_file.url)
|
||||||
.body(""));
|
.body(""));
|
||||||
} else if file == format!("{}-{}.jar", &string, &version.version_number) {
|
} else if file == format!("{}-{}.jar", &project_id, &version.version_number) {
|
||||||
if let Some(selected_file) = version.files.iter().find(|x| x.primary) {
|
if let Some(selected_file) = version.files.iter().find(|x| x.primary) {
|
||||||
return Ok(HttpResponse::TemporaryRedirect()
|
return Ok(HttpResponse::TemporaryRedirect()
|
||||||
.header("Location", &*selected_file.url)
|
.header("Location", &*selected_file.url)
|
||||||
@@ -243,3 +188,145 @@ pub async fn version_file(
|
|||||||
|
|
||||||
Ok(HttpResponse::NotFound().body(""))
|
Ok(HttpResponse::NotFound().body(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("maven/modrinth/{id}/{versionnum}/{file}.sha1")]
|
||||||
|
pub async fn version_file_sha1(
|
||||||
|
req: HttpRequest,
|
||||||
|
web::Path((project_id, vnum, file)): web::Path<(String, String, String)>,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
|
let project_data =
|
||||||
|
database::models::Project::get_full_from_slug_or_project_id(&project_id, &**pool).await?;
|
||||||
|
|
||||||
|
let data = if let Some(data) = project_data {
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||||
|
|
||||||
|
if !is_authorized(&data, &user_option, &pool).await? {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
let vid = if let Some(vid) = sqlx::query!(
|
||||||
|
"SELECT id FROM versions WHERE mod_id = $1 AND version_number = $2",
|
||||||
|
data.inner.id as database::models::ids::ProjectId,
|
||||||
|
vnum
|
||||||
|
)
|
||||||
|
.fetch_optional(&**pool)
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
vid
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = if let Some(version) =
|
||||||
|
database::models::Version::get_full(database::models::ids::VersionId(vid.id), &**pool)
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
version
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let selected_file =
|
||||||
|
if let Some(selected_file) = version.files.iter().find(|x| x.filename == file) {
|
||||||
|
selected_file
|
||||||
|
} else if file == format!("{}-{}.jar", &project_id, &version.version_number) {
|
||||||
|
if let Some(selected_file) = version.files.iter().last() {
|
||||||
|
selected_file
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let hash_bytes = if let Some(val) = selected_file.hashes.get("sha1") {
|
||||||
|
val
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let hash_text = if let Some(text) = std::str::from_utf8(hash_bytes).ok() {
|
||||||
|
text.to_string()
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(HttpResponse::Ok().body(hash_text));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("maven/modrinth/{id}/{versionnum}/{file}.sha512")]
|
||||||
|
pub async fn version_file_sha512(
|
||||||
|
req: HttpRequest,
|
||||||
|
web::Path((project_id, vnum, file)): web::Path<(String, String, String)>,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
|
let project_data =
|
||||||
|
database::models::Project::get_full_from_slug_or_project_id(&project_id, &**pool).await?;
|
||||||
|
|
||||||
|
let data = if let Some(data) = project_data {
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||||
|
|
||||||
|
if !is_authorized(&data, &user_option, &pool).await? {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
let vid = if let Some(vid) = sqlx::query!(
|
||||||
|
"SELECT id FROM versions WHERE mod_id = $1 AND version_number = $2",
|
||||||
|
data.inner.id as database::models::ids::ProjectId,
|
||||||
|
vnum
|
||||||
|
)
|
||||||
|
.fetch_optional(&**pool)
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
vid
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = if let Some(version) =
|
||||||
|
database::models::Version::get_full(database::models::ids::VersionId(vid.id), &**pool)
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
version
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let selected_file =
|
||||||
|
if let Some(selected_file) = version.files.iter().find(|x| x.filename == file) {
|
||||||
|
selected_file
|
||||||
|
} else if file == format!("{}-{}.jar", &project_id, &version.version_number) {
|
||||||
|
if let Some(selected_file) = version.files.iter().last() {
|
||||||
|
selected_file
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let hash_bytes = if let Some(val) = selected_file.hashes.get("sha512") {
|
||||||
|
val
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
let hash_text = if let Some(text) = std::str::from_utf8(hash_bytes).ok() {
|
||||||
|
text.to_string()
|
||||||
|
} else {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(HttpResponse::Ok().body(hash_text));
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ pub fn projects_config(cfg: &mut web::ServiceConfig) {
|
|||||||
|
|
||||||
pub fn maven_config(cfg: &mut web::ServiceConfig) {
|
pub fn maven_config(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(maven::maven_metadata);
|
cfg.service(maven::maven_metadata);
|
||||||
|
cfg.service(maven::version_file_sha512);
|
||||||
|
cfg.service(maven::version_file_sha1);
|
||||||
cfg.service(maven::version_file);
|
cfg.service(maven::version_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,8 +71,7 @@ pub async fn project_get(
|
|||||||
let string = info.into_inner().0;
|
let string = info.into_inner().0;
|
||||||
|
|
||||||
let project_data =
|
let project_data =
|
||||||
database::models::Project::get_full_from_slug_or_project_id(string.clone(), &**pool)
|
database::models::Project::get_full_from_slug_or_project_id(&string, &**pool).await?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||||
|
|
||||||
@@ -251,8 +250,7 @@ pub async fn project_edit(
|
|||||||
|
|
||||||
let string = info.into_inner().0;
|
let string = info.into_inner().0;
|
||||||
let result =
|
let result =
|
||||||
database::models::Project::get_full_from_slug_or_project_id(string.clone(), &**pool)
|
database::models::Project::get_full_from_slug_or_project_id(&string, &**pool).await?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let Some(project_item) = result {
|
if let Some(project_item) = result {
|
||||||
let id = project_item.inner.id;
|
let id = project_item.inner.id;
|
||||||
|
|||||||
Reference in New Issue
Block a user