mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Restructure some of the folder structure in unshell-server
This commit is contained in:
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
log_debug = ["unshell-lib/log_debug"]
|
||||
obfuscate = ["unshell-lib/obfuscate"]
|
||||
obfuscate = ["unshell-lib/obfuscate", "unshell-obfuscate/obfuscate"]
|
||||
|
||||
[dependencies]
|
||||
unshell-lib = {path = "../../unshell-lib", default-featues = false}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
cargo clean
|
||||
|
||||
OBFUSCATION_KEY=abc123abc \
|
||||
cargo build --release
|
||||
|
||||
@@ -10,8 +12,10 @@ declare -a headers=(
|
||||
".shstrtab" #- Section header string table (only needed by tools like readelf)
|
||||
".note.gnu.bu" ".note.gnu.build-id" # - Build ID note
|
||||
".eh_frame" ".eh_frame_hdr" # Exception handling info (can break C++ exceptions if removed)
|
||||
".gnu.version" ".gnu.version_r" # Symbol versioning (may be needed for some shared libraries)
|
||||
".gnu.hash" # Hash table for symbol lookup optimization
|
||||
".gnu.version"
|
||||
#".gnu.version_r"
|
||||
# Symbol versioning (may be needed for some shared libraries)
|
||||
#".gnu.hash" # Hash table for symbol lookup optimization
|
||||
)
|
||||
|
||||
# TODO: Implement FAKE section header comments and information
|
||||
|
||||
@@ -15,6 +15,8 @@ use unshell_lib::{
|
||||
|
||||
use crate::client_runtime::ClientRuntime;
|
||||
|
||||
pub use unshell_lib::logger::setup_logger;
|
||||
|
||||
pub extern "C" fn test1() {
|
||||
warn!("Test1 called xxxxxxxxxxx");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use bincode::{Decode, Encode};
|
||||
|
||||
use crate::config::RuntimeConfig;
|
||||
|
||||
/// Mostly temporary server message type
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub enum Announcement {
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Debug};
|
||||
// use bincode::{Decode, Encode};
|
||||
// use serde::{Deserialize, Serialize};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
// use bincode::{Decode, Encode};
|
||||
|
||||
use crate::{ModuleError, ModuleRuntime};
|
||||
|
||||
|
||||
@@ -5,12 +5,11 @@ impl Manager {
|
||||
match announcement {
|
||||
Announcement::TestAnnouncement(str) => {
|
||||
println!("Got test announcement: {}", str)
|
||||
}
|
||||
// Announcement::GetRuntimes => todo!(),
|
||||
// Announcement::GetRuntimesAck(_) => todo!(),
|
||||
// Announcement::StartRuntime(runtime_config) => todo!(),
|
||||
// Announcement::StartRuntimeAck(_) => todo!(),
|
||||
_ => {}
|
||||
} // Announcement::GetRuntimes => todo!(),
|
||||
// Announcement::GetRuntimesAck(_) => todo!(),
|
||||
// Announcement::StartRuntime(runtime_config) => todo!(),
|
||||
// Announcement::StartRuntimeAck(_) => todo!(),
|
||||
// _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ unshell-lib = {path = "../unshell-lib", default-features = false}
|
||||
unshell-obfuscate = {path = "../unshell-obfuscate"}
|
||||
|
||||
[profile.release]
|
||||
strip = true # Strip symbols from the binary
|
||||
opt-level = "z" # Optimize for size
|
||||
lto = true # Link tree optimization
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
debug = false # Remove debug
|
||||
trim-paths="all"
|
||||
# strip = true # Strip symbols from the binary
|
||||
# opt-level = "z" # Optimize for size
|
||||
# lto = true # Link tree optimization
|
||||
# codegen-units = 1
|
||||
# panic = "abort"
|
||||
# debug = false # Remove debug
|
||||
# trim-paths="all"
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
# cargo run --no-default-features $@ --release # $(ls ../*/target/release/*.so)
|
||||
|
||||
OBFUSCATION_KEY=abc123abc \
|
||||
RUSTFLAGS="-Zlocation-detail=none -Zfmt-debug=none" \
|
||||
cargo +nightly build \
|
||||
-Z build-std=std,panic_abort \
|
||||
-Z build-std-features="optimize_for_size" \
|
||||
$@ \
|
||||
--profile release
|
||||
|
||||
cargo build $@ --profile release
|
||||
|
||||
# RUSTFLAGS="-Zlocation-detail=none -Zfmt-debug=none" \
|
||||
# cargo +nightly build \
|
||||
# -Z build-std=std,panic_abort \
|
||||
# -Z build-std-features="optimize_for_size" \
|
||||
# $@ \
|
||||
# --profile release
|
||||
|
||||
+37
-30
@@ -1,10 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use std::{any::Any, collections::HashMap, fs::File, io::Read};
|
||||
|
||||
use static_init::dynamic;
|
||||
use unshell_lib::{
|
||||
ModuleError,
|
||||
config::{PayloadConfig, RuntimeConfig},
|
||||
module::Manager,
|
||||
module::{Manager, Module},
|
||||
};
|
||||
use unshell_obfuscate::{obs, symbol};
|
||||
|
||||
@@ -34,36 +34,43 @@ fn main() {
|
||||
|
||||
debug!("Initialized");
|
||||
|
||||
match || -> Result<(), ModuleError> {
|
||||
// let args = std::env::args();
|
||||
|
||||
// TEMPORARY, load the module paths from command line args.
|
||||
// let mut modules = Vec::new();
|
||||
// for arg in args.skip(1) {
|
||||
// debug!("Loading module: {}", arg);
|
||||
|
||||
// let mut file = File::open(arg).map_err(|e| ModuleError::Error(e.to_string().into()))?;
|
||||
// let mut buffer = Vec::new();
|
||||
// file.read_to_end(&mut buffer)
|
||||
// .map_err(|e| ModuleError::Error(e.to_string().into()))?;
|
||||
|
||||
// modules.push(Module::new_bytes(&buffer)?)
|
||||
|
||||
// // modules.push(Module::new(&arg)?)
|
||||
// }
|
||||
|
||||
// let modules = vec
|
||||
|
||||
// Run the manager, this is blocking.
|
||||
let manager = Manager::start(&PAYLOAD_CONFIG, Vec::new());
|
||||
|
||||
Manager::join(manager);
|
||||
|
||||
Ok(())
|
||||
}() {
|
||||
match run() {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
debug!("ERROR! {:?}", e);
|
||||
error!("ERROR! '{:?}'", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = std::env::args();
|
||||
|
||||
// TEMPORARY, load the module paths from command line args.
|
||||
let mut modules = Vec::new();
|
||||
for arg in args.skip(1) {
|
||||
// debug!("Loading module: {}", arg);
|
||||
|
||||
// let mut file = File::open(arg).map_err(|e| ModuleError::Error(e.to_string().into()))?;
|
||||
// let mut buffer = Vec::new();
|
||||
// file.read_to_end(&mut buffer)
|
||||
// .map_err(|e| ModuleError::Error(e.to_string().into()))?;
|
||||
|
||||
debug!("Initializing module: {}", arg);
|
||||
let module = Module::new(&arg)?;
|
||||
|
||||
modules.push(module);
|
||||
|
||||
// modules.push(Module::new(&arg)?)
|
||||
}
|
||||
|
||||
// let modules = vec
|
||||
|
||||
debug!("Starting manager...");
|
||||
|
||||
// Run the manager, this is blocking.
|
||||
let manager = Manager::start(&PAYLOAD_CONFIG, modules);
|
||||
|
||||
Manager::join(manager);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -9,11 +9,7 @@ use unshell_lib::{debug, info};
|
||||
|
||||
// axum_extra::
|
||||
|
||||
use crate::{
|
||||
api::{auth, structs::CurrentUser},
|
||||
logger::Logger,
|
||||
server::Server,
|
||||
};
|
||||
use crate::{auth, auth::structs::CurrentUser, logger::Logger, server::Server};
|
||||
|
||||
macro_rules! route_get {
|
||||
($router:expr, $path:expr, $func:expr) => {{
|
||||
@@ -1,20 +0,0 @@
|
||||
use chrono::Duration;
|
||||
use jsonwebtoken::{DecodingKey, EncodingKey};
|
||||
use static_init::dynamic;
|
||||
extern crate unshell_lib;
|
||||
|
||||
pub mod app;
|
||||
mod auth;
|
||||
mod structs;
|
||||
|
||||
pub use structs::CurrentUser;
|
||||
|
||||
static EXPIRE_DURATION: Duration = Duration::hours(12);
|
||||
|
||||
#[dynamic]
|
||||
static JWT_SECRET: String = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
|
||||
|
||||
#[dynamic]
|
||||
static JWT_ENCODING_KEY: EncodingKey = EncodingKey::from_secret(JWT_SECRET.as_bytes());
|
||||
#[dynamic]
|
||||
static JWT_DECODING_KEY: DecodingKey = DecodingKey::from_secret(JWT_SECRET.as_bytes());
|
||||
@@ -1,3 +1,5 @@
|
||||
pub mod structs;
|
||||
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::{Json, Request},
|
||||
@@ -10,10 +12,9 @@ use jsonwebtoken::{Header, TokenData, Validation, decode, encode};
|
||||
use serde_json::{Value, json};
|
||||
use unshell_lib::{debug, info};
|
||||
|
||||
use crate::api::{
|
||||
EXPIRE_DURATION, JWT_DECODING_KEY, JWT_ENCODING_KEY,
|
||||
structs::{AuthError, Cliams, CurrentUser, SignInData},
|
||||
};
|
||||
use crate::{EXPIRE_DURATION, JWT_DECODING_KEY, JWT_ENCODING_KEY};
|
||||
|
||||
use structs::{AuthError, Cliams, CurrentUser, SignInData};
|
||||
|
||||
pub fn hash_password(password: &str) -> Result<String, bcrypt::BcryptError> {
|
||||
let hash = hash(password, DEFAULT_COST)?;
|
||||
@@ -1,8 +1,4 @@
|
||||
mod blob;
|
||||
// pub mod interface;
|
||||
|
||||
pub use blob::Blob;
|
||||
// pub use interface::InterfaceWrapper;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@@ -27,7 +23,6 @@ struct ComponentMetadata {
|
||||
// Other components that can be pointed to by this component
|
||||
#[serde(default)]
|
||||
child_components: Vec<PathBuf>,
|
||||
// config: Option<HashMap<String, ConfigStructField>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize)]
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
// #![macro_use]
|
||||
|
||||
mod api;
|
||||
mod auth;
|
||||
mod config;
|
||||
pub mod logger;
|
||||
mod modules;
|
||||
mod server;
|
||||
|
||||
pub use api::app::start_api;
|
||||
|
||||
pub use server::Server;
|
||||
|
||||
use static_init::dynamic;
|
||||
|
||||
#[static_init::dynamic]
|
||||
pub static DATABASE_TREES: Vec<&'static str> = vec!["users"];
|
||||
|
||||
@@ -24,3 +23,18 @@ pub static SERVER_CONFIG: unshell_lib::config::PayloadConfig = unshell_lib::conf
|
||||
components: Vec::new(),
|
||||
runtime_config: Vec::new(),
|
||||
};
|
||||
|
||||
// Constants for server config
|
||||
pub use api::start_api;
|
||||
use chrono::Duration;
|
||||
use jsonwebtoken::{DecodingKey, EncodingKey};
|
||||
|
||||
static EXPIRE_DURATION: Duration = Duration::hours(12);
|
||||
|
||||
#[dynamic]
|
||||
static JWT_SECRET: String = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
|
||||
|
||||
#[dynamic]
|
||||
static JWT_ENCODING_KEY: EncodingKey = EncodingKey::from_secret(JWT_SECRET.as_bytes());
|
||||
#[dynamic]
|
||||
static JWT_DECODING_KEY: DecodingKey = DecodingKey::from_secret(JWT_SECRET.as_bytes());
|
||||
|
||||
@@ -1,42 +1,33 @@
|
||||
use axum::extract::{Path, State};
|
||||
use axum::{Extension, Json};
|
||||
use chrono::Local;
|
||||
use unshell_lib::debug;
|
||||
// use lazy_static::lazy_static;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::path::PathBuf;
|
||||
use unshell_lib::debug;
|
||||
|
||||
use crate::Server;
|
||||
use crate::api::CurrentUser;
|
||||
use crate::auth::structs::CurrentUser;
|
||||
|
||||
// --- Constants ---
|
||||
/// The directory where log files will be stored.
|
||||
const LOG_DIR: &str = "logs";
|
||||
|
||||
/// The maximum number of logs to return in one call to `poll_logs`.
|
||||
const LOG_COUNT: usize = 100;
|
||||
|
||||
/// The full path to the log file.
|
||||
/// Initialized once based on the startup time.
|
||||
#[static_init::dynamic]
|
||||
static LOG_FILE_PATH: PathBuf = {
|
||||
// 1. Determine the log directory path
|
||||
let log_dir_path = PathBuf::from(LOG_DIR);
|
||||
|
||||
// 2. Create the log directory if it does not exist
|
||||
if let Err(e) = fs::create_dir_all(&log_dir_path) {
|
||||
eprintln!("Error creating log directory {:?}: {}", log_dir_path, e);
|
||||
// Panic or handle error as appropriate for your application's needs
|
||||
// Panicking here to ensure the logger can't be used if the path is invalid/unwritable
|
||||
|
||||
panic!("Failed to initialize log directory.");
|
||||
}
|
||||
|
||||
// 3. Generate the unique filename based on the current local time
|
||||
let now = Local::now();
|
||||
let filename = format!("{}.log", now.format("%Y%m%d_%H%M%S"));
|
||||
|
||||
// 4. Combine the directory path and the filename
|
||||
log_dir_path.join(filename)
|
||||
};
|
||||
|
||||
@@ -44,19 +35,9 @@ static LOG_FILE_PATH: PathBuf = {
|
||||
pub struct Logger;
|
||||
|
||||
impl Logger {
|
||||
/// Writes a log entry to the current log file.
|
||||
///
|
||||
/// The log entry includes a timestamp and the provided message.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `message` - The string content of the log entry.
|
||||
pub fn log(message: String) {
|
||||
// 1. Format the complete log line with timestamp
|
||||
let log_line = format!("{}\n", message);
|
||||
|
||||
// 2. Open the file in append mode, creating it if it doesn't exist.
|
||||
// The file path is guaranteed to be valid due to the `lazy_static` initialization.
|
||||
match OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
@@ -74,65 +55,38 @@ impl Logger {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads and returns the most recent logs from the file.
|
||||
///
|
||||
/// The total number of logs returned is limited by `LOG_COUNT`.
|
||||
/// The `offset` determines how far back in history to start reading.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `offset` - The number of most recent logs to skip.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `Vec<String>` containing the logs, or an empty `Vec` on failure.
|
||||
pub fn poll_logs(offset: usize) -> Vec<String> {
|
||||
// Array of String is not a idiomatic return type in Rust,
|
||||
// so we return a Vector, which serves the same purpose.
|
||||
// The size constraint (LOG_COUNT) is applied internally.
|
||||
match File::open(&*LOG_FILE_PATH) {
|
||||
Ok(file) => {
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
// Collect all lines into a vector
|
||||
let lines: Vec<String> = reader
|
||||
.lines()
|
||||
.filter_map(|line| line.ok()) // Ignore lines that fail to read
|
||||
.collect();
|
||||
|
||||
// Determine the starting index for the slice (from the end of the vector)
|
||||
// This logic correctly handles the offset and LOG_COUNT limits.
|
||||
|
||||
let total_lines = lines.len();
|
||||
if offset >= total_lines {
|
||||
// Offset is past the beginning of the file, return nothing
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// Start from the end, minus the offset, minus the number of logs to read.
|
||||
// We use checked subtraction to prevent panic if it would result in a negative number.
|
||||
let start_index = total_lines
|
||||
.checked_sub(offset)
|
||||
.and_then(|i| i.checked_sub(LOG_COUNT))
|
||||
.unwrap_or(0); // If either subtraction fails, start from 0
|
||||
.unwrap_or(0);
|
||||
|
||||
// End index is determined by subtracting the offset from the total length.
|
||||
let end_index = total_lines.checked_sub(offset).unwrap_or(total_lines);
|
||||
|
||||
// Get the slice of the lines
|
||||
let slice = &lines[start_index..end_index];
|
||||
|
||||
slice.iter().cloned().collect()
|
||||
}
|
||||
Err(e) => {
|
||||
// Return an empty vector and print an error message if the file cannot be read
|
||||
eprintln!("Error reading log file {:?}: {}", *LOG_FILE_PATH, e);
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Route the "keys" api for each tree
|
||||
pub async fn poll_logs_api(
|
||||
State(_): State<Server>,
|
||||
Extension(_): Extension<CurrentUser>,
|
||||
@@ -144,54 +98,3 @@ impl Logger {
|
||||
Json(serde_json::to_value(result).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
// --- Example Usage ---
|
||||
|
||||
// fn main() {
|
||||
// // Write some logs
|
||||
// Logger::log("Application started.".to_string());
|
||||
// Logger::log("Configuration loaded.".to_string());
|
||||
|
||||
// for i in 1..=20 {
|
||||
// Logger::log(format!("Processing request #{}", i));
|
||||
// }
|
||||
|
||||
// Logger::log("Task completed.".to_string());
|
||||
|
||||
// // --- Test 1: Get the 10 most recent logs (offset 0) ---
|
||||
// println!("--- Most Recent Logs (LOG_COUNT={}) ---", LOG_COUNT);
|
||||
// let recent_logs = Logger::poll_logs(0);
|
||||
// for log in &recent_logs {
|
||||
// println!("{}", log);
|
||||
// }
|
||||
|
||||
// // The output should be:
|
||||
// // [timestamp] Task completed.
|
||||
// // [timestamp] Processing request #20
|
||||
// // [timestamp] Processing request #19
|
||||
// // ...
|
||||
// // [timestamp] Processing request #12
|
||||
|
||||
// println!(
|
||||
// "\n--- Logs from the past (Offset 15, LOG_COUNT={}) ---",
|
||||
// LOG_COUNT
|
||||
// );
|
||||
// // --- Test 2: Skip the 15 most recent logs, then get the next 10 ---
|
||||
// let historical_logs = Logger::poll_logs(15);
|
||||
// for log in &historical_logs {
|
||||
// println!("{}", log);
|
||||
// }
|
||||
|
||||
// // The output should be:
|
||||
// // [timestamp] Processing request #6
|
||||
// // [timestamp] Processing request #5
|
||||
// // ...
|
||||
// // [timestamp] Application started.
|
||||
|
||||
// println!("\n--- Testing a high offset (Offset 100) ---");
|
||||
// // --- Test 3: Test an offset that goes beyond the log file length ---
|
||||
// let empty_logs = Logger::poll_logs(100);
|
||||
// if empty_logs.is_empty() {
|
||||
// println!("Correctly returned empty set for high offset.");
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde_json::Value;
|
||||
use sled::Tree;
|
||||
use unshell_lib::{debug, error};
|
||||
|
||||
use crate::{api::CurrentUser, server::Server};
|
||||
use crate::{auth::structs::CurrentUser, server::Server};
|
||||
|
||||
impl Server {
|
||||
fn get_tree(&self, tree_name: &str) -> Result<Tree, String> {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::{
|
||||
Extension, Json,
|
||||
extract::{Path, State},
|
||||
@@ -8,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use unshell_lib::debug;
|
||||
|
||||
use crate::{Server, api::CurrentUser};
|
||||
use crate::{Server, auth::structs::CurrentUser};
|
||||
|
||||
pub trait Tree {
|
||||
fn is_folder() -> bool {
|
||||
|
||||
Reference in New Issue
Block a user