Skip to content

Commit a2060a8

Browse files
committed
fix: check github username in middleware and pass it to signer object afterwards
1 parent 2fdee1e commit a2060a8

File tree

6 files changed

+177
-156
lines changed

6 files changed

+177
-156
lines changed

fplus-http-server/src/main.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use env_logger;
22
use log::info;
33
mod middleware;
4-
use middleware::gh_auth;
4+
use middleware::verifier_auth::VerifierAuth;
55
pub(crate) mod router;
66
use std::env;
77

@@ -12,8 +12,6 @@ use actix_web::{
1212
middleware::Logger,
1313
};
1414

15-
use gh_auth::GHAuth;
16-
1715
#[tokio::main]
1816
async fn main() -> std::io::Result<()> {
1917
dotenv::dotenv().ok();
@@ -36,7 +34,7 @@ async fn main() -> std::io::Result<()> {
3634
.service(router::application::create)
3735
.service(
3836
web::scope("/api")
39-
.wrap(GHAuth) // Apply GitHubAuth to all routes under "/api"
37+
.wrap(VerifierAuth) // Apply GitHubAuth to all routes under "/api"
4038
.service(router::application::trigger)
4139
.service(router::application::propose)
4240
.service(router::application::approve)

fplus-http-server/src/middleware/gh_auth.rs

Lines changed: 0 additions & 134 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
pub mod gh_auth;
1+
pub mod verifier_auth;
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
use actix_web::{
2+
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
3+
Error, web,
4+
};
5+
use futures_util::future::{LocalBoxFuture, ready, Ready};
6+
use reqwest::Client;
7+
use serde::Deserialize;
8+
9+
// Import any other modules that you reference in this file
10+
use fplus_database::database::allocators::get_allocator;
11+
#[derive(Deserialize, Debug)]
12+
struct RepoQuery {
13+
owner: String,
14+
repo: String,
15+
github_username: String
16+
}
17+
18+
pub struct VerifierAuth;
19+
20+
impl<S, B> Transform<S, ServiceRequest> for VerifierAuth
21+
where
22+
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
23+
S::Future: 'static,
24+
B: 'static,
25+
{
26+
type Response = ServiceResponse<B>;
27+
type Error = Error;
28+
type InitError = ();
29+
type Transform = VerifierAuthMiddleware<S>;
30+
type Future = Ready<Result<Self::Transform, Self::InitError>>;
31+
32+
fn new_transform(&self, service: S) -> Self::Future {
33+
ready(Ok(VerifierAuthMiddleware { service }))
34+
}
35+
}
36+
37+
pub struct VerifierAuthMiddleware<S> {
38+
service: S,
39+
}
40+
41+
impl<S, B> Service<ServiceRequest> for VerifierAuthMiddleware<S>
42+
where
43+
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
44+
S::Future: 'static,
45+
B: 'static,
46+
{
47+
type Response = ServiceResponse<B>;
48+
type Error = Error;
49+
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
50+
51+
forward_ready!(service);
52+
53+
fn call(&self, req: ServiceRequest) -> Self::Future {
54+
let query_string = req.query_string();
55+
let query: Result<web::Query<RepoQuery>, _> = web::Query::from_query(query_string);
56+
let RepoQuery { owner, repo, github_username } = match query {
57+
Ok(q) => q.into_inner(),
58+
Err(_) => {
59+
return Box::pin(async {
60+
return Err(actix_web::error::ErrorBadRequest("Wrong query string format"));
61+
});
62+
}
63+
};
64+
65+
let auth_header_value = req.headers().get("Authorization")
66+
.and_then(|hv| hv.to_str().ok())
67+
.filter(|hv| hv.starts_with("Bearer "))
68+
.map(|hv| hv["Bearer ".len()..].to_string());
69+
let fut = self.service.call(req);
70+
71+
Box::pin(async move {
72+
let mut user_handle = String::new();
73+
74+
if let Some(token) = auth_header_value {
75+
// Make the asynchronous HTTP request here
76+
let client = Client::new();
77+
let user_info_result = client.get("https://api.github.com/user")
78+
.header("Authorization", format!("Bearer {}", token))
79+
.header("User-Agent", "Actix-web")
80+
.send()
81+
.await;
82+
83+
match user_info_result {
84+
Ok(response) => {
85+
//Raise an actix test error
86+
if response.status().is_success() {
87+
let user_info = response
88+
.json::<serde_json::Value>()
89+
.await
90+
.expect("Failed to parse JSON");
91+
92+
if let Some(login) = user_info.get("login").and_then(|v| v.as_str()) {
93+
user_handle = login.to_string();
94+
} else {
95+
println!("GitHub handle information not found.");
96+
return Err(actix_web::error::ErrorInternalServerError("GitHub handle information not found."))
97+
}
98+
} else {
99+
println!("Failed to get GitHub user info");
100+
return Err(actix_web::error::ErrorUnauthorized("Failed to get GitHub user info."))
101+
}
102+
},
103+
Err(e) => {
104+
println!("Request error: {:?}", e);
105+
return Err(actix_web::error::ErrorBadRequest(e))
106+
}
107+
}
108+
}
109+
110+
if github_username != user_handle {
111+
return Err(actix_web::error::ErrorBadRequest("Sent GitHub handle different than auth token owner."))
112+
}
113+
114+
match get_allocator(&owner, &repo).await {
115+
Ok(allocator) => {
116+
if let Some(allocator) = &allocator {
117+
if let Some(verifiers) = &allocator.verifiers_gh_handles {
118+
let verifier_handles: Vec<String> = verifiers.split(',')
119+
.map(|s| s.trim().to_lowercase())
120+
.collect();
121+
if verifier_handles.contains(&user_handle.to_lowercase()) {
122+
println!("{} is a verifier.", user_handle);
123+
} else {
124+
println!("The user is not a verifier.");
125+
return Err(actix_web::error::ErrorUnauthorized("The user is not a verifier."))
126+
}
127+
}
128+
}
129+
},
130+
Err(e) => {
131+
println!("Failed to get allocator: {:?}", e);
132+
}
133+
}
134+
135+
let res = fut.await?;
136+
return Ok(res)
137+
})
138+
}
139+
}
140+

fplus-http-server/src/router/application.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use actix_web::{get, post, web, HttpResponse, Responder};
22
use fplus_lib::core::{
3-
CompleteGovernanceReviewInfo, CompleteNewApplicationProposalInfo, CreateApplicationInfo,
4-
LDNApplication, RefillInfo, DcReachedInfo, ValidationPullRequestData, GithubQueryParams, ApplicationQueryParams
3+
application::file::VerifierInput, ApplicationQueryParams, CompleteGovernanceReviewInfo, CompleteNewApplicationProposalInfo, CreateApplicationInfo, DcReachedInfo, GithubQueryParams, LDNApplication, RefillInfo, ValidationPullRequestData, VerifierActionsQueryParams
54
};
65

76
#[post("/application")]
@@ -27,20 +26,11 @@ pub async fn single(query: web::Query<ApplicationQueryParams>) -> impl Responder
2726
};
2827
}
2928

30-
#[post("/testz")]
31-
pub async fn testz(
32-
query: web::Query<ApplicationQueryParams>
33-
) -> impl Responder {
34-
println!("testzzzz {:?} {:?}", query.owner, query.repo);
35-
return HttpResponse::Ok()
36-
}
37-
3829
#[post("/application/trigger")]
3930
pub async fn trigger(
4031
query: web::Query<ApplicationQueryParams>,
4132
info: web::Json<CompleteGovernanceReviewInfo>,
4233
) -> impl Responder {
43-
4434
let CompleteGovernanceReviewInfo { actor} = info.into_inner();
4535
let ldn_application = match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await {
4636
Ok(app) => app,
@@ -50,7 +40,7 @@ pub async fn trigger(
5040
};
5141
dbg!(&ldn_application);
5242
match ldn_application
53-
.complete_governance_review(actor, query.id.clone(), query.repo.clone())
43+
.complete_governance_review(actor, query.owner.clone(), query.repo.clone())
5444
.await
5545
{
5646
Ok(app) => HttpResponse::Ok().body(serde_json::to_string_pretty(&app).unwrap()),
@@ -64,7 +54,7 @@ pub async fn trigger(
6454
#[post("/application/propose")]
6555
pub async fn propose(
6656
info: web::Json<CompleteNewApplicationProposalInfo>,
67-
query: web::Query<ApplicationQueryParams>,
57+
query: web::Query<VerifierActionsQueryParams>,
6858
) -> impl Responder {
6959
let CompleteNewApplicationProposalInfo {
7060
signer,
@@ -76,8 +66,14 @@ pub async fn propose(
7666
return HttpResponse::BadRequest().body(e.to_string());
7767
}
7868
};
69+
let updated_signer = VerifierInput {
70+
github_username: query.github_username.clone(), // Use the provided `github_username` parameter
71+
signing_address: signer.signing_address,
72+
created_at: signer.created_at,
73+
message_cid: signer.message_cid,
74+
};
7975
match ldn_application
80-
.complete_new_application_proposal(signer, request_id, query.owner.clone(), query.repo.clone())
76+
.complete_new_application_proposal(updated_signer, request_id, query.owner.clone(), query.repo.clone())
8177
.await
8278
{
8379
Ok(app) => HttpResponse::Ok().body(serde_json::to_string_pretty(&app).unwrap()),
@@ -89,7 +85,7 @@ pub async fn propose(
8985

9086
#[post("/application/approve")]
9187
pub async fn approve(
92-
query: web::Query<ApplicationQueryParams>,
88+
query: web::Query<VerifierActionsQueryParams>,
9389
info: web::Json<CompleteNewApplicationProposalInfo>,
9490
) -> impl Responder {
9591
let CompleteNewApplicationProposalInfo {
@@ -102,8 +98,14 @@ pub async fn approve(
10298
return HttpResponse::BadRequest().body(e.to_string());
10399
}
104100
};
101+
let updated_signer = VerifierInput {
102+
github_username: query.github_username.clone(), // Use the provided `github_username` parameter
103+
signing_address: signer.signing_address,
104+
created_at: signer.created_at,
105+
message_cid: signer.message_cid,
106+
};
105107
match ldn_application
106-
.complete_new_application_approval(signer, request_id, query.owner.clone(), query.repo.clone())
108+
.complete_new_application_approval(updated_signer, request_id, query.owner.clone(), query.repo.clone())
107109
.await
108110
{
109111
Ok(app) => HttpResponse::Ok().body(serde_json::to_string_pretty(&app).unwrap()),

0 commit comments

Comments
 (0)