diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh new file mode 100644 index 0000000..1f0c2b5 --- /dev/null +++ b/scripts/run_tests.sh @@ -0,0 +1,40 @@ +#!/bin/bash +cd "$(dirname "$0")"/.. + +containers=$(docker ps -a | grep -c 'hacker-challenge') + +if (( "$containers" < 10 )); then + echo you are supposed to run this after you run ./scripts/testnet.sh + exit 1 +fi + +set -e + +echo -n "Checking if containers connected to each other... " +for i in {2..12} +do + ip="172.17.0.${i}" + curl -s "${ip}:31372" | grep -e true -e false -c | grep 12 > /dev/null || + echo Container at ip ${ip} did not connect to all other containers. +done +echo OK! + +echo -n "Checking if containers can sign data... " +for i in {2..12} +do + ip="172.17.0.${i}" + random_key=$(curl -s "${ip}:31372" | grep true | tail -1 | awk '{ print $4 }') + message="ValyDoesNotLikeMyCodeSoHeIsSilentAboutIt" + status=$(curl -sG \ + -o /dev/null -w "%{http_code}\n" \ + --data-urlencode "pubkey=${random_key}" \ + --data-urlencode "something=${message}" \ + "172.17.0.${i}:31372/sign") + + if (( "$status" != "200" )); then + echo Container at ip ${ip} could not sign string with key ${random_key} + exit 1 + fi + +done +echo OK! diff --git a/scripts/testnet.sh b/scripts/testnet.sh index c8439fc..db6f5df 100755 --- a/scripts/testnet.sh +++ b/scripts/testnet.sh @@ -19,3 +19,8 @@ do --env INIT_NODES="172.17.0.2 172.17.0.3 172.17.0.4" \ hacker-challenge:latest done + +cd .. +echo sleeping 3 seconds before starting tests... +sleep 10 +source ./scripts/run_tests.sh diff --git a/src/datastore.rs b/src/datastore.rs index 74c6117..2d408f3 100644 --- a/src/datastore.rs +++ b/src/datastore.rs @@ -219,16 +219,20 @@ impl Store { let ip = "localhost".to_string(); let updated_at = std::time::SystemTime::now(); let public = false; - self.update_node( - ip.clone(), - NodeInfo { - pubkey, - updated_at, - public, - }, - ) - .await; self.add_key(pubkey, keypair_raw.clone()).await; + if let Some(old_data) = self + .update_node( + ip.clone(), + NodeInfo { + pubkey, + updated_at, + public, + }, + ) + .await + { + self.remove_key(&old_data.pubkey).await; + }; let updated_at = Some(prost_types::Timestamp::from(updated_at)); NodeUpdate { ip, diff --git a/src/http_server.rs b/src/http_server.rs index 36eece5..132e876 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -1,9 +1,26 @@ -use crate::datastore::Store; +use crate::datastore::{SigningError, Store}; use std::sync::Arc; use salvo::affix; use salvo::prelude::*; +enum SignError { + NoPubkey, + NoMessage, + Store(SigningError), +} +#[async_trait] +impl Writer for SignError { + async fn write(self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) { + res.status_code(StatusCode::BAD_REQUEST); + match self { + SignError::NoPubkey => res.render("pubkey must be specified as GET param"), + SignError::NoMessage => res.render("something must be specified as GET param"), + SignError::Store(e) => res.render(format!("{e}")), + }; + } +} + #[handler] async fn homepage(depot: &mut Depot) -> String { let ds = depot.obtain::>().unwrap(); @@ -11,21 +28,21 @@ async fn homepage(depot: &mut Depot) -> String { } #[handler] -async fn sign(req: &mut Request, depot: &mut Depot) -> String { +async fn sign(req: &mut Request, depot: &mut Depot) -> Result { let ds = depot.obtain::>().unwrap(); let pubkey = match req.query::("pubkey") { Some(k) => k, - None => return "pubkey must be specified as GET param".to_string(), + None => return Err(SignError::NoPubkey), }; let something = match req.query::("something") { Some(k) => k, - None => return "something must be specified as GET param".to_string(), + None => return Err(SignError::NoMessage), }; match ds.sign_message_with_key(&something, &pubkey).await { - Ok(s) => s, - Err(e) => e.to_string(), + Ok(s) => Ok(s), + Err(e) => Err(SignError::Store(e)), } }