Skip to content

Commit

Permalink
Merge pull request #277 from stakwork/fix-auth
Browse files Browse the repository at this point in the history
Fix auth
  • Loading branch information
tobi-bams authored Aug 30, 2024
2 parents dbbdf49 + e8e5527 commit 7cc836c
Show file tree
Hide file tree
Showing 18 changed files with 557 additions and 92 deletions.
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ services:
- BACKUP_KEY=$BACKUP_KEY
- BACKUP=$BACKUP
- FEATURE_FLAG_TEXT_EMBEDDINGS=$FEATURE_FLAG_TEXT_EMBEDDINGS
- SUPER_URL=$SUPER_URL
- SUPER_TOKEN=$SUPER_TOKEN

networks:
sphinx-swarm:
Expand Down
2 changes: 2 additions & 0 deletions second-brain.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ services:
- JARVIS_FEATURE_FLAG_SCHEMA=$JARVIS_FEATURE_FLAG_SCHEMA
- BACKUP_KEY=$BACKUP_KEY
- BACKUP=$BACKUP
- SUPER_TOKEN=$SUPER_TOKEN
- FEATURE_FLAG_TEXT_EMBEDDINGS=$FEATURE_FLAG_TEXT_EMBEDDINGS
- SUPER_URL=$SUPER_URL

networks:
sphinx-swarm:
Expand Down
2 changes: 2 additions & 0 deletions sphinx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ services:
- TESTING_ONLY_ADD_TO_SENDER=$TESTING_ONLY_ADD_TO_SENDER # mixer testing
- SWARM_UPDATER_PASSWORD=$SWARM_UPDATER_PASSWORD
- TRIBES_HOST=$TRIBES_HOST
- SUPER_TOKEN=$SUPER_TOKEN
- SUPER_URL=$SUPER_URL

networks:
sphinx-swarm:
Expand Down
24 changes: 24 additions & 0 deletions src/bin/super/auth_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use rocket::request::{FromRequest, Outcome, Request};

#[derive(Debug)]
pub enum SuperAuthError {}

#[derive(Clone)]
pub struct VerifySuperToken {
pub token: Option<String>,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for VerifySuperToken {
type Error = SuperAuthError;

async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
if let Some(token) = request.headers().get_one("x-super-token") {
return Outcome::Success(VerifySuperToken {
token: Some(token.to_string()),
});
} else {
Outcome::Success(VerifySuperToken { token: None })
}
}
}
76 changes: 76 additions & 0 deletions src/bin/super/cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", content = "data")]
pub enum Cmd {
Swarm(SwarmCmd),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LoginInfo {
pub username: String,
pub password: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ChangePasswordInfo {
pub user_id: u32,
pub old_pass: String,
pub password: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AddNewSwarmInfo {
pub host: String,
pub instance: String,
pub description: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AddNewSwarmInfoAPI {
pub host: String,
pub instance: String,
pub description: String,
pub username: String,
pub password: String,
pub token: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UpdateSwarmInfo {
pub id: String,
pub host: String,
pub instance: String,
pub description: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DeleteSwarmInfo {
pub host: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ChildSwarm {
pub password: String,
pub host: String,
pub username: String,
pub token: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "cmd", content = "content")]
pub enum SwarmCmd {
GetConfig,
Login(LoginInfo),
ChangePassword(ChangePasswordInfo),
AddNewSwarm(AddNewSwarmInfo),
UpdateSwarm(UpdateSwarmInfo),
DeleteSwarm(DeleteSwarmInfo),
SetChildSwarm(ChildSwarm),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AddSwarmResponse {
pub success: bool,
pub message: String,
}
166 changes: 90 additions & 76 deletions src/bin/super/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
mod auth_token;
mod checker;
mod cmd;
mod routes;
mod state;
mod util;

use cmd::AddSwarmResponse;
use cmd::{Cmd, SwarmCmd};
use sphinx_swarm::utils::getenv;
use state::RemoteStack;
use state::Super;
use util::add_new_swarm_details;

use crate::checker::swarm_checker;
use anyhow::{Context, Result};
use anyhow::{anyhow, Context, Result};
use rocket::tokio;
use serde::{Deserialize, Serialize};
use sphinx_swarm::routes;
use routes::launch_rocket;
use sphinx_swarm::config::Role;
use sphinx_swarm::utils;
use sphinx_swarm::{auth, events, logs, rocket_utils::CmdRequest};
use std::collections::HashMap;
Expand All @@ -16,6 +25,8 @@ use tokio::sync::{mpsc, Mutex};

#[rocket::main]
async fn main() -> Result<()> {
dotenv::dotenv().ok();

sphinx_swarm::utils::setup_logs();

let project = "super";
Expand Down Expand Up @@ -43,7 +54,7 @@ async fn main() -> Result<()> {

let event_tx = events::new_event_chan();

let _r = routes::launch_rocket(tx.clone(), log_txs, event_tx).await?;
let _r = launch_rocket(tx.clone(), log_txs, event_tx).await?;

Ok(())
}
Expand All @@ -59,64 +70,61 @@ pub async fn put_config_file(project: &str, rs: &Super) {
utils::put_yaml(&path, rs).await;
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", content = "data")]
pub enum Cmd {
Swarm(SwarmCmd),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LoginInfo {
pub username: String,
pub password: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ChangePasswordInfo {
pub user_id: u32,
pub old_pass: String,
pub password: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AddNewSwarmInfo {
pub host: String,
pub instance: String,
pub description: String,
}
fn access(cmd: &Cmd, state: &Super, user_id: &Option<u32>) -> bool {
// login needs no auth
if let Cmd::Swarm(c) = cmd {
if let SwarmCmd::Login(_) = c {
return true;
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UpdateSwarmInfo {
pub id: String,
pub host: String,
pub instance: String,
pub description: String,
}
if let SwarmCmd::SetChildSwarm(info) = c {
//get x-super-token
let token = getenv("SUPER_TOKEN").unwrap_or("".to_string());
if token.is_empty() {
return false;
}
//verify token
if token != info.token {
return false;
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DeleteSwarmInfo {
pub host: String,
}
return true;
}
}
// user id required if not SwarmCmd::Login
if user_id.is_none() {
return false;
}
let user_id = user_id.unwrap();
let user = state.users.iter().find(|u| u.id == user_id);
// user required
if user.is_none() {
return false;
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "cmd", content = "content")]
pub enum SwarmCmd {
GetConfig,
Login(LoginInfo),
ChangePassword(ChangePasswordInfo),
AddNewSwarm(AddNewSwarmInfo),
UpdateSwarm(UpdateSwarmInfo),
DeleteSwarm(DeleteSwarmInfo),
return match user.unwrap().role {
Role::Super => true,
Role::Admin => false,
};
}

// tag is the service name
pub async fn super_handle(proj: &str, cmd: Cmd, _tag: &str) -> Result<String> {
pub async fn super_handle(
proj: &str,
cmd: Cmd,
_tag: &str,
user_id: &Option<u32>,
) -> Result<String> {
// conf can be mutated in place
let mut state = state::STATE.lock().await;
// println!("STACK {:?}", stack);

let mut must_save_stack = false;

if !access(&cmd, &state, user_id) {
return Err(anyhow!("access denied"));
}

let ret = match cmd {
Cmd::Swarm(swarm_cmd) => match swarm_cmd {
SwarmCmd::GetConfig => {
Expand Down Expand Up @@ -154,30 +162,20 @@ pub async fn super_handle(proj: &str, cmd: Cmd, _tag: &str) -> Result<String> {
}
}
SwarmCmd::AddNewSwarm(swarm) => {
let mut hm = HashMap::new();
match state.find_swarm_by_host(&swarm.host) {
Some(_swarm) => {
hm.insert("success", "false");
hm.insert("message", "swarm already exist");
}
None => {
let new_swarm = RemoteStack {
host: swarm.host,
note: Some(swarm.description),
ec2: Some(swarm.instance),
user: None,
pass: None,
};
state.add_remote_stack(new_swarm);
must_save_stack = true;
hm.insert("success", "true");
hm.insert("message", "Swarm added successfully");
}
}
let swarm_detail = RemoteStack {
host: swarm.host,
user: Some("".to_string()),
pass: Some("".to_string()),
ec2: Some(swarm.instance),
note: Some(swarm.description),
};

let hm = add_new_swarm_details(&mut state, swarm_detail, &mut must_save_stack);

Some(serde_json::to_string(&hm)?)
}
SwarmCmd::UpdateSwarm(swarm) => {
let mut hm = HashMap::new();
let hm: AddSwarmResponse;
match state.stacks.iter().position(|u| u.host == swarm.id) {
Some(ui) => {
state.stacks[ui] = RemoteStack {
Expand All @@ -188,12 +186,16 @@ pub async fn super_handle(proj: &str, cmd: Cmd, _tag: &str) -> Result<String> {
pass: state.stacks[ui].pass.clone(),
};
must_save_stack = true;
hm.insert("success", "true");
hm.insert("message", "Swarm updated successfully");
hm = AddSwarmResponse {
success: true,
message: "Swarm updated successfully".to_string(),
};
}
None => {
hm.insert("success", "false");
hm.insert("message", "swarm does not exist");
hm = AddSwarmResponse {
success: false,
message: "swarm does not exist".to_string(),
};
}
}

Expand All @@ -214,6 +216,18 @@ pub async fn super_handle(proj: &str, cmd: Cmd, _tag: &str) -> Result<String> {
}
Some(serde_json::to_string(&hm)?)
}
SwarmCmd::SetChildSwarm(c) => {
let swarm_details = RemoteStack {
host: c.host,
note: Some("".to_string()),
pass: Some(c.password),
user: Some(c.username),
ec2: Some("".to_string()),
};
let hm = add_new_swarm_details(&mut state, swarm_details, &mut must_save_stack);

Some(serde_json::to_string(&hm)?)
}
},
};

Expand All @@ -228,7 +242,7 @@ pub fn spawn_super_handler(proj: &str, mut rx: mpsc::Receiver<CmdRequest>) {
tokio::spawn(async move {
while let Some(msg) = rx.recv().await {
if let Ok(cmd) = serde_json::from_str::<Cmd>(&msg.message) {
match super_handle(&project, cmd, &msg.tag).await {
match super_handle(&project, cmd, &msg.tag, &msg.user_id).await {
Ok(res) => {
let _ = msg.reply_tx.send(res);
}
Expand Down
Loading

0 comments on commit 7cc836c

Please sign in to comment.