Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
feat: project validation (#99)
Browse files Browse the repository at this point in the history
* feat: project validation

* fix: tests

* fix: clippy and fmt

* fix: get rid of unwraps

* fix: move auth into extractor

* fix: fmt and clippy

* fix: change to auth header

* fix: add extractors.rs

* Update src/registry.rs

Co-authored-by: Chris Smith <1979423+chris13524@users.noreply.github.com>

* fix: fmt

---------

Co-authored-by: Chris Smith <1979423+chris13524@users.noreply.github.com>
  • Loading branch information
Rakowskiii and chris13524 committed Jul 26, 2023
1 parent ac6fc45 commit ded66ce
Show file tree
Hide file tree
Showing 21 changed files with 688 additions and 83 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,12 @@ jobs:
run: cargo test --test integration
env:
ENVIRONMENT: ${{ inputs.environment }}
TEST_PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}
TEST_PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}
CAST_PROJECT_SECRET: ${{ secrets.CAST_PROJECT_SECRET }}

# Run validate swift
- name: Run validate swift
uses: ./.github/workflows/validate_swift.yml
with:
notify-endpoint: ${{ inputs.environment == 'PROD' && 'cast.walletconnect.com' || 'staging.cast.walletconnect.com' }}
relay-endpoint: ${{ inputs.environment == 'PROD' && 'relay.walletconnect.com' || 'staging.relay.walletconnect.com' }}
135 changes: 135 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ build = "build.rs"

[dependencies]
wc = { git = "https://github.com/WalletConnect/utils-rs.git", tag = "v0.1.0", features = ["full"] }
cerberus = { git = "https://github.com/WalletConnect/cerberus.git"}

tokio = { version = "1", features = ["full"] }
axum = { version = "0.6", features = ["json"] }
axum = { version = "0.6", features = ["json", "headers"] }
tower = "0.4"
tower-http = { version = "0.3", features = ["trace", "cors"] }
hyper = "0.14"
Expand Down Expand Up @@ -90,6 +91,8 @@ pnet_datalink = "0.33.0"
ipnet = "2.8.0"
once_cell = "1.18.0"
lazy_static = "1.4.0"
rmp-serde = "1.1.1"
deadpool-redis = "0.12.0"

[dev-dependencies]
test-context = "0.1"
Expand Down
17 changes: 16 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use {
crate::networking,
crate::{networking, storage::redis::Addr as RedisAddr},
serde::Deserialize,
std::{net::IpAddr, str::FromStr},
};
Expand All @@ -17,6 +17,14 @@ pub struct Configuration {
pub project_id: String,
pub relay_url: String,
pub cast_url: String,

pub registry_url: String,
pub registry_auth_token: String,

pub auth_redis_addr_read: Option<String>,
pub auth_redis_addr_write: Option<String>,
pub redis_pool_size: u32,

#[serde(default = "default_is_test", skip)]
/// This is an internal flag to disable logging, cannot be defined by user
pub is_test: bool,
Expand All @@ -41,6 +49,13 @@ impl Configuration {
pub fn log_level(&self) -> tracing::Level {
tracing::Level::from_str(self.log_level.as_str()).expect("Invalid log level")
}

pub fn auth_redis_addr(&self) -> Option<RedisAddr> {
match (&self.auth_redis_addr_read, &self.auth_redis_addr_write) {
(None, None) => None,
(addr_read, addr_write) => Some(RedisAddr::from((addr_read, addr_write))),
}
}
}

fn default_port() -> u16 {
Expand Down
9 changes: 9 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ pub enum Error {

#[error(transparent)]
Other(#[from] anyhow::Error),

#[error(transparent)]
Redis(#[from] crate::storage::error::StorageError),

#[error(transparent)]
InvalidHeaderValue(#[from] hyper::header::InvalidHeaderValue),

#[error(transparent)]
ToStrError(#[from] hyper::header::ToStrError),
}

impl IntoResponse for Error {
Expand Down
84 changes: 84 additions & 0 deletions src/extractors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use {
crate::state::AppState,
async_trait::async_trait,
axum::{
extract::{FromRequestParts, Path},
headers::{authorization::Bearer, Authorization},
http::request::Parts,
TypedHeader,
},
hyper::StatusCode,
serde_json::json,
std::{collections::HashMap, sync::Arc},
tracing::warn,
};

/// Extracts project_id from uri and project_secret from Authorization header.
/// Verifies their correctness against registry and returns AuthedProjectId
/// struct.
pub struct AuthedProjectId(pub String, pub String);

#[async_trait]
impl FromRequestParts<Arc<AppState>> for AuthedProjectId {
type Rejection = (StatusCode, String);

async fn from_request_parts(
parts: &mut Parts,
state: &Arc<AppState>,
) -> Result<Self, Self::Rejection> {
let Path(path_args) = Path::<HashMap<String, String>>::from_request_parts(parts, state)
.await
.map_err(|_| {
(
StatusCode::BAD_REQUEST,
json!({
"reason": "Invalid project_id. Please make sure to include project_id in uri. "
}).to_string(),
)
})?;

let TypedHeader(project_secret) = TypedHeader::<Authorization::<Bearer>>::from_request_parts(parts, state).await.map_err(|_| {
(
StatusCode::UNAUTHORIZED,
json!({
"reason": "Unauthorized. Please make sure to include project secret in Authorization header. "
}).to_string(),
)
})?;

let project_id = path_args
.get("project_id")
.ok_or((
StatusCode::BAD_REQUEST,
json!({"reason": "Invalid data for authentication".to_string()}).to_string(),
))?
.to_string();

let authenticated = state
.registry
.is_authenticated(&project_id, project_secret.token())
.await
.map_err(|e| {
warn!(?e, "Failed to authenticate project");
(
StatusCode::BAD_REQUEST,
"Invalid data for authentication".to_string(),
)
})?;

if !authenticated {
return Err((
StatusCode::UNAUTHORIZED,
json!({
"reason": "Invalid project_secret. Please make sure to include proper project secret in Authorization header."
})
.to_string(),
));
};

Ok(AuthedProjectId(
project_id,
project_secret.token().to_string(),
))
}
}
Loading

0 comments on commit ded66ce

Please sign in to comment.