validation: api is internal only

This commit is contained in:
Quaternions 2024-12-17 18:33:02 -08:00
parent f3af65aa13
commit f7101e2b84
10 changed files with 149 additions and 171 deletions

2
validation/Cargo.lock generated
View File

@ -1804,7 +1804,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]] [[package]]
name = "submissions-api" name = "submissions-api"
version = "0.2.3-scriptname2" version = "0.2.3"
dependencies = [ dependencies = [
"reqwest", "reqwest",
"serde", "serde",

View File

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
submissions-api = { path = "api", features = ["internal","external"], registry = "strafesnet" } submissions-api = { path = "api", features = ["internal"], registry = "strafesnet" }
async-nats = "0.38.0" async-nats = "0.38.0"
futures = "0.3.31" futures = "0.3.31"
rbx_asset = { version = "0.2.5", registry = "strafesnet" } rbx_asset = { version = "0.2.5", registry = "strafesnet" }

View File

@ -952,7 +952,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]] [[package]]
name = "submissions-api" name = "submissions-api"
version = "0.2.3-scriptname2" version = "0.2.3"
dependencies = [ dependencies = [
"reqwest", "reqwest",
"serde", "serde",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "submissions-api" name = "submissions-api"
version = "0.2.3-scriptname2" version = "0.2.3"
edition = "2021" edition = "2021"
publish = ["strafesnet"] publish = ["strafesnet"]
repository = "https://git.itzana.me/StrafesNET/maps-service" repository = "https://git.itzana.me/StrafesNET/maps-service"
@ -17,6 +17,5 @@ serde_json = "1"
url = "2" url = "2"
[features] [features]
default = ["external"] default = ["internal"]
internal = [] internal = []
external = []

View File

@ -1,133 +0,0 @@
use crate::Error;
#[derive(Clone,Copy,serde::Serialize,serde::Deserialize)]
pub struct ScriptID(i64);
#[derive(Clone,Copy,serde::Serialize,serde::Deserialize)]
pub struct ScriptPolicyID(i64);
#[allow(nonstandard_style)]
pub struct GetScriptRequest{
pub ScriptID:ScriptID,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptResponse{
pub ID:i64,
pub Name:String,
pub Hash:String,
pub Source:String,
pub SubmissionID:i64,
}
#[allow(nonstandard_style)]
#[derive(serde::Serialize)]
pub struct CreateScriptRequest<'a>{
pub Name:&'a str,
pub Source:&'a str,
pub SubmissionID:Option<i64>,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptIDResponse{
pub ID:ScriptID,
}
#[derive(serde::Serialize,serde::Deserialize)]
#[repr(i32)]
pub enum Policy{
None=0, // not yet reviewed
Allowed=1,
Blocked=2,
Delete=3,
Replace=4,
}
pub struct ScriptPolicyHashRequest<'a>{
pub hash:&'a str,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptPolicyResponse{
pub ID:i64,
pub FromScriptHash:String,
pub ToScriptID:ScriptID,
pub Policy:Policy
}
#[allow(nonstandard_style)]
#[derive(serde::Serialize)]
pub struct CreateScriptPolicyRequest{
pub FromScriptID:ScriptID,
pub ToScriptID:ScriptID,
pub Policy:Policy,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptPolicyIDResponse{
pub ID:ScriptPolicyID,
}
#[allow(nonstandard_style)]
pub struct UpdateSubmissionModelRequest{
pub SubmissionID:i64,
pub ModelID:u64,
pub ModelVersion:u64,
}
#[derive(Clone)]
pub struct Context(crate::context::Context);
impl Context{
pub fn new(base_url:String)->reqwest::Result<Self>{
Ok(Self(crate::context::Context::new(base_url)?))
}
pub async fn get_script(&self,config:GetScriptRequest)->Result<ScriptResponse,Error>{
let url_raw=format!("{}/scripts/{}",self.0.base_url,config.ScriptID.0);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
self.0.get(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn create_script<'a>(&self,config:CreateScriptRequest<'a>)->Result<ScriptIDResponse,Error>{
let url_raw=format!("{}/scripts",self.0.base_url);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
let body=serde_json::to_string(&config).map_err(Error::JSON)?;
self.0.post(url,body).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn get_script_policy_from_hash<'a>(&self,config:ScriptPolicyHashRequest<'a>)->Result<ScriptPolicyResponse,Error>{
let url_raw=format!("{}/script-policy/hash/{}",self.0.base_url,config.hash);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
self.0.get(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn create_script_policy(&self,config:CreateScriptPolicyRequest)->Result<ScriptPolicyIDResponse,Error>{
let url_raw=format!("{}/script-policy",self.0.base_url);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
let body=serde_json::to_string(&config).map_err(Error::JSON)?;
self.0.post(url,body).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn update_submission_model(&self,config:UpdateSubmissionModelRequest)->Result<(),Error>{
let url_raw=format!("{}/submissions/{}/model",self.0.base_url,config.SubmissionID);
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
{
url.query_pairs_mut()
.append_pair("ModelID",config.ModelID.to_string().as_str())
.append_pair("ModelVersion",config.ModelVersion.to_string().as_str());
}
self.0.post_empty_body(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?;
Ok(())
}
}

View File

@ -1,5 +1,77 @@
use crate::Error; use crate::Error;
#[derive(Clone,Copy,serde::Serialize,serde::Deserialize)]
pub struct ScriptID(i64);
#[derive(Clone,Copy,serde::Serialize,serde::Deserialize)]
pub struct ScriptPolicyID(i64);
#[allow(nonstandard_style)]
pub struct GetScriptRequest{
pub ScriptID:ScriptID,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptResponse{
pub ID:i64,
pub Name:String,
pub Hash:String,
pub Source:String,
pub SubmissionID:i64,
}
#[allow(nonstandard_style)]
#[derive(serde::Serialize)]
pub struct CreateScriptRequest<'a>{
pub Name:&'a str,
pub Source:&'a str,
pub SubmissionID:Option<i64>,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptIDResponse{
pub ID:ScriptID,
}
#[derive(serde::Serialize,serde::Deserialize)]
#[repr(i32)]
pub enum Policy{
None=0, // not yet reviewed
Allowed=1,
Blocked=2,
Delete=3,
Replace=4,
}
pub struct ScriptPolicyHashRequest<'a>{
pub hash:&'a str,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptPolicyResponse{
pub ID:i64,
pub FromScriptHash:String,
pub ToScriptID:ScriptID,
pub Policy:Policy
}
#[allow(nonstandard_style)]
#[derive(serde::Serialize)]
pub struct CreateScriptPolicyRequest{
pub FromScriptID:ScriptID,
pub ToScriptID:ScriptID,
pub Policy:Policy,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptPolicyIDResponse{
pub ID:ScriptPolicyID,
}
#[allow(nonstandard_style)]
pub struct UpdateSubmissionModelRequest{
pub SubmissionID:i64,
pub ModelID:u64,
pub ModelVersion:u64,
}
#[allow(nonstandard_style)] #[allow(nonstandard_style)]
pub struct ActionSubmissionUploadedRequest{ pub struct ActionSubmissionUploadedRequest{
pub SubmissionID:i64, pub SubmissionID:i64,
@ -29,6 +101,57 @@ impl Context{
pub fn new(base_url:String)->reqwest::Result<Self>{ pub fn new(base_url:String)->reqwest::Result<Self>{
Ok(Self(crate::context::Context::new(base_url)?)) Ok(Self(crate::context::Context::new(base_url)?))
} }
pub async fn get_script(&self,config:GetScriptRequest)->Result<ScriptResponse,Error>{
let url_raw=format!("{}/scripts/{}",self.0.base_url,config.ScriptID.0);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
self.0.get(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn create_script<'a>(&self,config:CreateScriptRequest<'a>)->Result<ScriptIDResponse,Error>{
let url_raw=format!("{}/scripts",self.0.base_url);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
let body=serde_json::to_string(&config).map_err(Error::JSON)?;
self.0.post(url,body).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn get_script_policy_from_hash<'a>(&self,config:ScriptPolicyHashRequest<'a>)->Result<ScriptPolicyResponse,Error>{
let url_raw=format!("{}/script-policy/hash/{}",self.0.base_url,config.hash);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
self.0.get(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn create_script_policy(&self,config:CreateScriptPolicyRequest)->Result<ScriptPolicyIDResponse,Error>{
let url_raw=format!("{}/script-policy",self.0.base_url);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
let body=serde_json::to_string(&config).map_err(Error::JSON)?;
self.0.post(url,body).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn update_submission_model(&self,config:UpdateSubmissionModelRequest)->Result<(),Error>{
let url_raw=format!("{}/submissions/{}/model",self.0.base_url,config.SubmissionID);
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
{
url.query_pairs_mut()
.append_pair("ModelID",config.ModelID.to_string().as_str())
.append_pair("ModelVersion",config.ModelVersion.to_string().as_str());
}
self.0.post_empty_body(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?;
Ok(())
}
pub async fn action_submission_uploaded(&self,config:ActionSubmissionUploadedRequest)->Result<(),Error>{ pub async fn action_submission_uploaded(&self,config:ActionSubmissionUploadedRequest)->Result<(),Error>{
let url_raw=format!("{}/submissions/{}/status/validator-uploaded",self.0.base_url,config.SubmissionID); let url_raw=format!("{}/submissions/{}/status/validator-uploaded",self.0.base_url,config.SubmissionID);
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?; let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;

View File

@ -3,9 +3,6 @@ mod context;
#[cfg(feature="internal")] #[cfg(feature="internal")]
pub mod internal; pub mod internal;
#[cfg(feature="external")]
pub mod external;
//lazy reexport //lazy reexport
pub type ReqwestError=reqwest::Error; pub type ReqwestError=reqwest::Error;

View File

@ -10,7 +10,6 @@ mod message_handler;
#[derive(Debug)] #[derive(Debug)]
pub enum StartupError{ pub enum StartupError{
API(submissions_api::ReqwestError), API(submissions_api::ReqwestError),
APIInternal(submissions_api::ReqwestError),
NatsConnect(async_nats::ConnectError), NatsConnect(async_nats::ConnectError),
NatsGetStream(async_nats::jetstream::context::GetStreamError), NatsGetStream(async_nats::jetstream::context::GetStreamError),
NatsConsumer(async_nats::jetstream::stream::ConsumerError), NatsConsumer(async_nats::jetstream::stream::ConsumerError),
@ -40,11 +39,8 @@ async fn main()->Result<(),StartupError>{
let cookie_context=rbx_asset::cookie::CookieContext::new(rbx_asset::cookie::Cookie::new(cookie)); let cookie_context=rbx_asset::cookie::CookieContext::new(rbx_asset::cookie::Cookie::new(cookie));
// maps-service api // maps-service api
let api_host=std::env::var("API_HOST").expect("API_HOST env required");
let api=submissions_api::external::Context::new(api_host).map_err(StartupError::API)?;
let api_host_internal=std::env::var("API_HOST_INTERNAL").expect("API_HOST_INTERNAL env required"); let api_host_internal=std::env::var("API_HOST_INTERNAL").expect("API_HOST_INTERNAL env required");
let api_internal=submissions_api::internal::Context::new(api_host_internal).map_err(StartupError::APIInternal)?; let api=submissions_api::internal::Context::new(api_host_internal).map_err(StartupError::API)?;
// nats // nats
let nats_host=std::env::var("NATS_HOST").expect("NATS_HOST env required"); let nats_host=std::env::var("NATS_HOST").expect("NATS_HOST env required");
@ -62,7 +58,7 @@ async fn main()->Result<(),StartupError>{
.messages().await.map_err(StartupError::NatsStream) .messages().await.map_err(StartupError::NatsStream)
}; };
let message_handler=message_handler::MessageHandler::new(cookie_context,group_id,api,api_internal); let message_handler=message_handler::MessageHandler::new(cookie_context,group_id,api);
// Create a signal listener for SIGTERM // Create a signal listener for SIGTERM
let mut sig_term=tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()).expect("Failed to create SIGTERM signal listener"); let mut sig_term=tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()).expect("Failed to create SIGTERM signal listener");

View File

@ -27,13 +27,12 @@ impl MessageHandler{
pub fn new( pub fn new(
cookie_context:rbx_asset::cookie::CookieContext, cookie_context:rbx_asset::cookie::CookieContext,
group_id:Option<u64>, group_id:Option<u64>,
api:submissions_api::external::Context, api:submissions_api::internal::Context,
api_internal:submissions_api::internal::Context,
)->Self{ )->Self{
Self{ Self{
publish_new:crate::publish_new::Publisher::new(cookie_context.clone(),group_id,api_internal.clone()), publish_new:crate::publish_new::Publisher::new(cookie_context.clone(),group_id,api.clone()),
publish_fix:crate::publish_fix::Publisher::new(cookie_context.clone(),group_id,api_internal.clone()), publish_fix:crate::publish_fix::Publisher::new(cookie_context.clone(),group_id,api.clone()),
validator:crate::validator::Validator::new(cookie_context,api,api_internal), validator:crate::validator::Validator::new(cookie_context,api),
} }
} }
pub async fn handle_message_result(&self,message_result:MessageResult)->Result<(),HandleMessageError>{ pub async fn handle_message_result(&self,message_result:MessageResult)->Result<(),HandleMessageError>{

View File

@ -2,7 +2,7 @@ use futures::TryStreamExt;
use crate::nats_types::ValidateRequest; use crate::nats_types::ValidateRequest;
use submissions_api::external::ScriptPolicyResponse; use submissions_api::internal::ScriptPolicyResponse;
const SCRIPT_CONCURRENCY:usize=16; const SCRIPT_CONCURRENCY:usize=16;
@ -64,20 +64,17 @@ impl std::error::Error for ValidateError{}
pub struct Validator{ pub struct Validator{
roblox_cookie:rbx_asset::cookie::CookieContext, roblox_cookie:rbx_asset::cookie::CookieContext,
api:submissions_api::external::Context, api:submissions_api::internal::Context,
api_internal:submissions_api::internal::Context,
} }
impl Validator{ impl Validator{
pub const fn new( pub const fn new(
roblox_cookie:rbx_asset::cookie::CookieContext, roblox_cookie:rbx_asset::cookie::CookieContext,
api:submissions_api::external::Context, api:submissions_api::internal::Context,
api_internal:submissions_api::internal::Context,
)->Self{ )->Self{
Self{ Self{
roblox_cookie, roblox_cookie,
api, api,
api_internal,
} }
} }
pub async fn validate(&self,message:async_nats::jetstream::Message)->Result<(),ValidateError>{ pub async fn validate(&self,message:async_nats::jetstream::Message)->Result<(),ValidateError>{
@ -120,7 +117,7 @@ impl Validator{
// fetch the script policy // fetch the script policy
let script_policy=interpret_get_script_policy_response( let script_policy=interpret_get_script_policy_response(
self.api.get_script_policy_from_hash(submissions_api::external::ScriptPolicyHashRequest{ self.api.get_script_policy_from_hash(submissions_api::internal::ScriptPolicyHashRequest{
hash:format!("{:016x}",hash).as_str(), hash:format!("{:016x}",hash).as_str(),
}).await }).await
).map_err(ValidateError::ApiGetScriptPolicy)?; ).map_err(ValidateError::ApiGetScriptPolicy)?;
@ -128,12 +125,12 @@ impl Validator{
// write the policy to the script_map, fetching the replacement code if necessary // write the policy to the script_map, fetching the replacement code if necessary
if let Some(script_policy)=script_policy{ if let Some(script_policy)=script_policy{
*policy=match script_policy.Policy{ *policy=match script_policy.Policy{
submissions_api::external::Policy::None=>Policy::None, submissions_api::internal::Policy::None=>Policy::None,
submissions_api::external::Policy::Allowed=>Policy::Allowed, submissions_api::internal::Policy::Allowed=>Policy::Allowed,
submissions_api::external::Policy::Blocked=>Policy::Blocked, submissions_api::internal::Policy::Blocked=>Policy::Blocked,
submissions_api::external::Policy::Delete=>Policy::Delete, submissions_api::internal::Policy::Delete=>Policy::Delete,
submissions_api::external::Policy::Replace=>{ submissions_api::internal::Policy::Replace=>{
let script=self.api.get_script(submissions_api::external::GetScriptRequest{ let script=self.api.get_script(submissions_api::internal::GetScriptRequest{
ScriptID:script_policy.ToScriptID, ScriptID:script_policy.ToScriptID,
}).await.map_err(ValidateError::ApiGetScript)?; }).await.map_err(ValidateError::ApiGetScript)?;
Policy::Replace(script.Source) Policy::Replace(script.Source)
@ -141,17 +138,17 @@ impl Validator{
}; };
}else{ }else{
// upload the script // upload the script
let script=self.api.create_script(submissions_api::external::CreateScriptRequest{ let script=self.api.create_script(submissions_api::internal::CreateScriptRequest{
Name:name.as_str(), Name:name.as_str(),
Source:source.as_str(), Source:source.as_str(),
SubmissionID:Some(validate_info.SubmissionID), SubmissionID:Some(validate_info.SubmissionID),
}).await.map_err(ValidateError::ApiCreateScript)?; }).await.map_err(ValidateError::ApiCreateScript)?;
// create a None policy (pending review by yours truly) // create a None policy (pending review by yours truly)
self.api.create_script_policy(submissions_api::external::CreateScriptPolicyRequest{ self.api.create_script_policy(submissions_api::internal::CreateScriptPolicyRequest{
ToScriptID:script.ID, ToScriptID:script.ID,
FromScriptID:script.ID, FromScriptID:script.ID,
Policy:submissions_api::external::Policy::None, Policy:submissions_api::internal::Policy::None,
}).await.map_err(ValidateError::ApiCreateScriptPolicy)?; }).await.map_err(ValidateError::ApiCreateScriptPolicy)?;
} }
@ -217,7 +214,7 @@ impl Validator{
}; };
// update the submission to use the validated model // update the submission to use the validated model
self.api.update_submission_model(submissions_api::external::UpdateSubmissionModelRequest{ self.api.update_submission_model(submissions_api::internal::UpdateSubmissionModelRequest{
SubmissionID:validate_info.SubmissionID, SubmissionID:validate_info.SubmissionID,
ModelID:model_id, ModelID:model_id,
ModelVersion:1, //TODO ModelVersion:1, //TODO
@ -225,7 +222,7 @@ impl Validator{
}; };
// update the submission model status to validated // update the submission model status to validated
self.api_internal.action_submission_validated( self.api.action_submission_validated(
submissions_api::internal::SubmissionID(validate_info.SubmissionID) submissions_api::internal::SubmissionID(validate_info.SubmissionID)
).await.map_err(ValidateError::ApiActionSubmissionValidate)?; ).await.map_err(ValidateError::ApiActionSubmissionValidate)?;