Skip to content

Commit

Permalink
asdf
Browse files Browse the repository at this point in the history
  • Loading branch information
cycle-five committed Jul 7, 2024
1 parent 52c00f4 commit a0b66fe
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 37 deletions.
6 changes: 3 additions & 3 deletions crack-core/src/commands/bf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ pub async fn bf(

/// Run a brainfk program. Program and input string maybe empty,
/// no handling is done for invalid programs.
pub async fn bf_internal<'ctx>(
ctx: Context<'ctx>,
pub async fn bf_internal(
ctx: Context<'_>,
program: String,
input: String,
) -> Result<ReplyHandle<'ctx>, CrackedError> {
) -> Result<ReplyHandle<'_>, CrackedError> {
tracing::info!("program: {program}, input: {input}");
let mut bf = BrainfuckProgram::new(program);

Expand Down
14 changes: 13 additions & 1 deletion crack-voting/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,16 @@ serde = { version = "1.0", features = ["derive"] }
chrono = { version = "0.4", features = ["serde"] }
tokio = { workspace = true }
tracing = { workspace = true }
sqlx = { workspace = true }

sqlx = { version = "0.7.4", default-features = false, features = [
"runtime-tokio",
"postgres",
"migrate",
] }

[dev-dependencies]
sqlx = { version = "0.7.4", default-features = false, features = [
"runtime-tokio",
"postgres",
"migrate",
] }
99 changes: 66 additions & 33 deletions crack-voting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,34 @@ use lazy_static::lazy_static;
use std::env;
use warp::{body::BodyDeserializeError, http::StatusCode, path, reject, Filter, Rejection, Reply};

const WEBHOOK_SECRET_DEFAULT: &str = "my-that-secret";
const DATABASE_URL_DEFAULT: &str = "postgres://postgres:mysecretpassword@localhost/postgres";

lazy_static! {
static ref WEBHOOK_SECRET: String =
env::var("WEBHOOK_SECRET").unwrap_or(WEBHOOK_SECRET_DEFAULT.to_string());
static ref DATABASE_URL: String =
env::var("DATABASE_URL").unwrap_or(DATABASE_URL_DEFAULT.to_string());
}

/// Struct to hold the context for the voting server.
#[derive(Debug, Clone)]
pub struct VotingContext {
pool: sqlx::PgPool,
secret: String,
}

/// Implement the `VotingContext`.
impl VotingContext {
async fn new() -> Self {
let pool = sqlx::PgPool::connect(&DATABASE_URL)
.await
.expect("failed to connect to database");
let secret = get_secret().to_string();
VotingContext { pool, secret }
}
}

/// NewClass for the Webhook to store in the database.
#[derive(Debug, serde::Deserialize, serde::Serialize, sqlx::FromRow, Clone, PartialEq, Eq)]
pub struct CrackedWebhook {
Expand All @@ -26,30 +54,27 @@ impl std::error::Error for Unauthorized {}

/// Custom error type for unauthorized requests.
#[derive(Debug)]
struct SQLX(sqlx::Error);
struct Sqlx(sqlx::Error);

impl warp::reject::Reject for SQLX {}
impl warp::reject::Reject for Sqlx {}

impl std::fmt::Display for SQLX {
impl std::fmt::Display for Sqlx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0.to_string())
}
}

impl std::error::Error for SQLX {}

lazy_static! {
static ref WEBHOOK_SECRET: String =
env::var("WEBHOOK_SECRET").unwrap_or("missing secret".to_string());
}

impl std::error::Error for Sqlx {}
/// Get the webhook secret from the environment.
fn get_secret() -> &'static str {
&WEBHOOK_SECRET
}

///
async fn write_webhook_to_db(pool: sqlx::PgPool, webhook: Webhook) -> Result<(), sqlx::Error> {
/// Write the received webhook to the database.
async fn write_webhook_to_db(
ctx: &'static VotingContext,
webhook: Webhook,
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"INSERT INTO vote_webhook
(bot_id, user_id, kind, is_weekend, query, created_at)
Expand All @@ -62,13 +87,13 @@ async fn write_webhook_to_db(pool: sqlx::PgPool, webhook: Webhook) -> Result<(),
webhook.is_weekend,
webhook.query,
)
.execute(&pool)
.execute(&ctx.pool)
.await?;
Ok(())
}

/// Create a filter that checks the `Authorization` header against the secret.
fn header(secret: &'static str) -> impl Filter<Extract = (), Error = Rejection> + Clone {
fn header(secret: &str) -> impl Filter<Extract = (), Error = Rejection> + Clone + '_ {
warp::header::<String>("authorization")
.and_then(move |val: String| async move {
if val == secret {
Expand All @@ -82,34 +107,36 @@ fn header(secret: &'static str) -> impl Filter<Extract = (), Error = Rejection>
.untuple_one()
}

async fn process_webhook(hook: Webhook) -> Result<impl Reply, Rejection> {
let pool = sqlx::PgPool::connect(&env::var("DATABASE_URL").unwrap())
.await
.unwrap();
write_webhook_to_db(pool, hook.clone())
.await
.map_err(SQLX)?;
/// Async function to process the received webhook.
async fn process_webhook(
ctx: &'static VotingContext,
hook: Webhook,
) -> Result<impl Reply, Rejection> {
write_webhook_to_db(ctx, hook.clone()).await.map_err(Sqlx)?;
println!("{:?}", hook);
Ok(warp::reply())
}
/// Create a filter that handles the webhook.
async fn get_webhook() -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
let secret = get_secret();
async fn get_webhook(
ctx: &'static VotingContext,
) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
println!("get_webhook");

warp::post()
.and(path!("dbl" / "webhook"))
.and(header(secret))
.and(header(&ctx.secret))
.and(warp::body::json())
.and_then(move |hook: Webhook| async move { process_webhook(hook).await })
.and_then(move |hook: Webhook| async move { process_webhook(ctx, hook).await })
.recover(custom_error)
}

/// Run the server.
pub async fn run() {
warp::serve(get_webhook().await)
pub async fn run() -> &'static VotingContext {
let ctx = Box::leak(Box::new(VotingContext::new().await));
warp::serve(get_webhook(ctx).await)
.run(([127, 0, 0, 1], 3030))
.await;
ctx
}

/// Custom error handling for the server.
Expand All @@ -131,21 +158,27 @@ async fn custom_error(err: Rejection) -> Result<impl Reply, Rejection> {

#[cfg(test)]
mod test {
use super::*;
use warp::http::StatusCode;
use super::{get_secret, get_webhook};
use super::{StatusCode, VotingContext, Webhook};

pub static MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!("./test_migrations");

#[tokio::test]
//#[sqlx::test(migrator = "MIGRATOR")]
#[sqlx::test]
async fn test_bad_req() {
let ctx = Box::leak(Box::new(VotingContext::new().await));
let res = warp::test::request()
.method("POST")
.path("/dbl/webhook")
.reply(&get_webhook().await)
.reply(&get_webhook(ctx).await)
.await;
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
}

#[tokio::test]
//#[sqlx::test(migrator = "MIGRATOR")]
#[sqlx::test]
async fn test_authorized() {
let ctx = Box::leak(Box::new(VotingContext::new().await));
let res = warp::test::request()
.method("POST")
.path("/dbl/webhook")
Expand All @@ -157,7 +190,7 @@ mod test {
is_weekend: false,
query: Some("test".to_string()),
})
.reply(&get_webhook().await)
.reply(&get_webhook(ctx).await)
.await;
assert_eq!(res.status(), StatusCode::OK);
}
Expand Down
12 changes: 12 additions & 0 deletions crack-voting/test_migrations/20240705083637_crack_voting.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- Add migration script here
CREATE TYPE WEBHOOK_KIND AS ENUM('upvote', 'test');
CREATE TABLE vote_webhook (
id SERIAL PRIMARY KEY,
bot_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
kind WEBHOOK_KIND NOT NULL,
is_weekend BOOLEAN NOT NULL,
query TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_vote_webhook_user_id FOREIGN KEY (user_id) REFERENCES "user"(id)
);
3 changes: 3 additions & 0 deletions migrations/20240707101455_rename.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Add migration script here
ALTER TABLE IF EXISTS VOTE_WEBHOOK
RENAME TO vote_webhook;

0 comments on commit a0b66fe

Please sign in to comment.