diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml new file mode 100644 index 0000000..dee0719 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -0,0 +1,62 @@ +name: Bug Report +description: File a bug report. +title: "[Bug]: " +type: Bug +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: input + attributes: + label: Rayhunter Version + description: | + Which version did you install? + placeholder: v0.2.6 + - type: input + attributes: + label: Capture Date + description: | + YYYY-MM-DD + placeholder: 2025-05-01 + validations: + required: true + - type: input + attributes: + label: Capture Location + description: | + (If comfortable disclosing) What region or country were you in? + placeholder: Washington State + validations: + required: false + - type: input + attributes: + label: Device and Model + description: | + Device you installed Rayhunter on to. + placeholder: Orbic RC400L + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened? + description: | + What steps did you take to get to your issue? + placeholder: Tell us what you see! + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behavior + description: Rayhunter's behavior differed from what I expected because. + placeholder: "What was expected?" + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Rayhunter data captures (QMDL and PCAP logs) or error codes + render: shell diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 0000000..35b33e2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Rayhunter Mattermost + url: https://opensource.eff.org/signup_user_complete/?id=6iqur37ucfrctfswrs14iscobw&md=link&sbr=su + about: If you're having trouble using Rayhunter and aren't sure you've found a bug or request for a new feature, please first try asking for help here. There is a much larger community there of people familiar with the project who will be able to more quickly answer your questions. + - name: Rayhunter Security Policy + url: https://github.com/EFForg/rayhunter/security/advisories/new + about: Please report security vulnerabilities here. diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml new file mode 100644 index 0000000..1e2a35a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -0,0 +1,27 @@ +name: Feature Request +description: Suggest a new feature or improvement to Rayhunter +title: "[Feature Request]: " +labels: ["enhancement"] +body: + - type: textarea + id: problem + attributes: + label: What problem does this feature solve or what does it enhance? + description: Explain what this feature addresses, ors the benefit it provides. + placeholder: For example, "Currently, users have to manually do X, which is time-consuming." + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: Describe the solution you'd like to see implemented. + placeholder: For example, "Implement a new button that automatically does X." + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Have you considered any alternative solutions? + placeholder: For example, "We considered Y, but Z is a better approach because..." diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..348f0ac --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,6 @@ +## Pull Request Checklist + +- [ ] The Rayhunter team has recently expressed interest in reviewing a PR for this. If not, this PR may be closed due our limited resources and need to prioritize how we spend them. +- [ ] Added or updated any documentation as needed to support the changes in this PR. +- [ ] Code has been linted and run through `cargo fmt` +- [ ] If any new functionality has been added, unit tests were also added diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 88a8e3d..decffc9 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -16,6 +16,8 @@ jobs: platform: - name: ubuntu-24 os: ubuntu-latest + - name: ubuntu-24-aarch64 + os: ubuntu-24.04-arm - name: macos-arm os: macos-latest - name: macos-intel diff --git a/Cargo.lock b/Cargo.lock index 42d5423..9492106 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1645,9 +1645,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 083f6aa..6097927 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -22,7 +22,7 @@ path = "src/check.rs" rayhunter = { path = "../lib" } toml = "0.8.8" serde = { version = "1.0.193", features = ["derive"] } -tokio = { version = "1.35.1", features = ["full"] } +tokio = { version = "1.44.2", features = ["full"] } axum = "0.7.3" futures-core = "0.3.30" thiserror = "1.0.52" diff --git a/bin/src/daemon.rs b/bin/src/daemon.rs index fdde56a..e9e92be 100644 --- a/bin/src/daemon.rs +++ b/bin/src/daemon.rs @@ -184,7 +184,6 @@ async fn main() -> Result<(), RayhunterError> { debug_mode: config.debug_mode, analysis_status_lock, analysis_sender: analysis_tx, - colorblind_mode: config.colorblind_mode, }); run_server(&task_tracker, &config, state, server_shutdown_rx).await; diff --git a/bin/src/diag.rs b/bin/src/diag.rs index 5b3899f..1009c66 100644 --- a/bin/src/diag.rs +++ b/bin/src/diag.rs @@ -130,11 +130,7 @@ pub async fn start_recording(State(state): State>) -> Result<(S state.diag_device_ctrl_sender.send(DiagDeviceCtrlMessage::StartRecording((qmdl_writer, analysis_file))).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send stop recording message: {}", e)))?; - let display_state = if state.colorblind_mode { - display::DisplayState::RecordingCBM - } else { - display::DisplayState::Recording - }; + let display_state = display::DisplayState::Recording; state.ui_update_sender.send(display_state).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?; diff --git a/bin/src/display/generic_framebuffer.rs b/bin/src/display/generic_framebuffer.rs index 1c7666f..4e9c950 100644 --- a/bin/src/display/generic_framebuffer.rs +++ b/bin/src/display/generic_framebuffer.rs @@ -1,15 +1,15 @@ use image::{codecs::gif::GifDecoder, imageops::FilterType, AnimationDecoder, DynamicImage}; -use std::time::Duration; use std::io::Cursor; +use std::time::Duration; use crate::config; use crate::display::DisplayState; use log::{error, info}; -use tokio::sync::oneshot; use tokio::sync::mpsc::Receiver; -use tokio_util::task::TaskTracker; +use tokio::sync::oneshot; use tokio::sync::oneshot::error::TryRecvError; +use tokio_util::task::TaskTracker; use std::thread::sleep; @@ -21,17 +21,16 @@ pub struct Dimensions { pub width: u32, } - #[allow(dead_code)] #[derive(Copy, Clone)] pub enum Color { - Red , - Green , - Blue , - White , - Black , - Cyan , - Yellow , + Red, + Green, + Blue, + White, + Black, + Cyan, + Yellow, Pink, } @@ -50,12 +49,17 @@ impl Color { } } -impl From for Color{ - fn from(state: DisplayState) -> Self { +impl Color { + fn from_state(state: DisplayState, colorblind_mode: bool) -> Self { match state { DisplayState::Paused => Color::White, - DisplayState::Recording => Color::Green, - DisplayState::RecordingCBM => Color::Blue, + DisplayState::Recording => { + if colorblind_mode { + Color::Blue + } else { + Color::Green + } + } DisplayState::WarningDetected => Color::Red, } } @@ -74,9 +78,8 @@ pub trait GenericFramebuffer: Send + 'static { let mut width = img.width(); let mut height = img.height(); let resized_img: DynamicImage; - if height > dimensions.height || - width > dimensions.width { - resized_img = img.resize( dimensions.width, dimensions.height, FilterType::CatmullRom); + if height > dimensions.height || width > dimensions.width { + resized_img = img.resize(dimensions.width, dimensions.height, FilterType::CatmullRom); width = dimensions.width.min(resized_img.width()); height = dimensions.height.min(resized_img.height()); } else { @@ -91,9 +94,7 @@ pub trait GenericFramebuffer: Send + 'static { } } - self.write_buffer( - &buf, - ); + self.write_buffer(&buf); } fn draw_gif(&mut self, img_buffer: &[u8]) { @@ -131,64 +132,69 @@ pub fn update_ui( config: &config::Config, mut fb: impl GenericFramebuffer, mut ui_shutdown_rx: oneshot::Receiver<()>, - mut ui_update_rx: Receiver + mut ui_update_rx: Receiver, ) { static IMAGE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/static/images/"); - let mut display_color: Color; let display_level = config.ui_level; if display_level == 0 { info!("Invisible mode, not spawning UI."); } - if config.colorblind_mode { - display_color = Color::Blue; - } else { - display_color = Color::Green; - } + let colorblind_mode = config.colorblind_mode; + let mut display_color = Color::from_state(DisplayState::Recording, colorblind_mode); task_tracker.spawn_blocking(move || { // this feels wrong, is there a more rusty way to do this? let mut img: Option<&[u8]> = None; if display_level == 2 { - img = Some(IMAGE_DIR.get_file("orca.gif").expect("failed to read orca.gif").contents()); + img = Some( + IMAGE_DIR + .get_file("orca.gif") + .expect("failed to read orca.gif") + .contents(), + ); } else if display_level == 3 { - img = Some(IMAGE_DIR.get_file("eff.png").expect("failed to read eff.png").contents()); + img = Some( + IMAGE_DIR + .get_file("eff.png") + .expect("failed to read eff.png") + .contents(), + ); } loop { match ui_shutdown_rx.try_recv() { Ok(_) => { info!("received UI shutdown"); break; - }, - Err(TryRecvError::Empty) => {}, - Err(e) => panic!("error receiving shutdown message: {e}") + } + Err(TryRecvError::Empty) => {} + Err(e) => panic!("error receiving shutdown message: {e}"), } match ui_update_rx.try_recv() { - Ok(state) => { - display_color = state.into(); - }, - Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {}, - Err(e) => error!("error receiving framebuffer update message: {e}") + Ok(state) => { + display_color = Color::from_state(state, colorblind_mode); + } + Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {} + Err(e) => error!("error receiving framebuffer update message: {e}"), } - match display_level { + match display_level { 2 => { fb.draw_gif(img.unwrap()); - }, - 3 => { - fb.draw_img(img.unwrap()) - }, + } + 3 => fb.draw_img(img.unwrap()), 128 => { fb.draw_line(Color::Cyan, 128); fb.draw_line(Color::Pink, 102); fb.draw_line(Color::White, 76); fb.draw_line(Color::Pink, 50); fb.draw_line(Color::Cyan, 25); - }, - _ => { // this branch id for ui_level 1, which is also the default if an - // unknown value is used + } + _ => { + // this branch id for ui_level 1, which is also the default if an + // unknown value is used fb.draw_line(display_color, 2); - }, + } }; sleep(Duration::from_millis(1000)); } diff --git a/bin/src/display/mod.rs b/bin/src/display/mod.rs index 175ccd6..124ef71 100644 --- a/bin/src/display/mod.rs +++ b/bin/src/display/mod.rs @@ -19,7 +19,6 @@ pub enum DisplayState { Recording, Paused, WarningDetected, - RecordingCBM, } #[cfg(all(feature = "orbic", feature = "tplink"))] diff --git a/bin/src/display/tplink_onebit.rs b/bin/src/display/tplink_onebit.rs index 32f0dd7..1058db9 100644 --- a/bin/src/display/tplink_onebit.rs +++ b/bin/src/display/tplink_onebit.rs @@ -160,7 +160,6 @@ pub fn update_ui( match ui_update_rx.try_recv() { Ok(DisplayState::Paused) => pixels = paused(), Ok(DisplayState::Recording) => pixels = smiling(), - Ok(DisplayState::RecordingCBM) => pixels = smiling(), Ok(DisplayState::WarningDetected) => pixels = frowning(), Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {}, Err(e) => { diff --git a/bin/src/server.rs b/bin/src/server.rs index 4835ea3..cc3a1bd 100644 --- a/bin/src/server.rs +++ b/bin/src/server.rs @@ -1,5 +1,5 @@ use axum::body::Body; -use axum::http::header::{CONTENT_TYPE, self}; +use axum::http::header::{self, CONTENT_LENGTH, CONTENT_TYPE}; use axum::extract::State; use axum::http::{StatusCode, HeaderValue}; use axum::response::{Response, IntoResponse}; @@ -23,7 +23,6 @@ pub struct ServerState { pub analysis_status_lock: Arc>, pub analysis_sender: Sender, pub debug_mode: bool, - pub colorblind_mode: bool, } pub async fn get_qmdl(State(state): State>, Path(qmdl_name): Path) -> Result { @@ -36,7 +35,10 @@ pub async fn get_qmdl(State(state): State>, Path(qmdl_name): Pa let limited_qmdl_file = qmdl_file.take(entry.qmdl_size_bytes as u64); let qmdl_stream = ReaderStream::new(limited_qmdl_file); - let headers = [(CONTENT_TYPE, "application/octet-stream")]; + let headers = [ + (CONTENT_TYPE, "application/octet-stream"), + (CONTENT_LENGTH, &entry.qmdl_size_bytes.to_string()), + ]; let body = Body::from_stream(qmdl_stream); Ok((headers, body).into_response()) } diff --git a/dist/install.sh b/dist/install.sh index 025ead1..b0e848f 100755 --- a/dist/install.sh +++ b/dist/install.sh @@ -100,7 +100,11 @@ test_rayhunter() { ##### Main ##### ##### ##### ##### if [[ `uname -s` == "Linux" ]]; then - export SERIAL_PATH="./serial-ubuntu-24/serial" + if [[ `uname -m` == "arm64" ]]; then + export SERIAL_PATH="./serial-ubuntu-24-aarch64/serial" + elif [[ `uname -m` == "x86_64" ]]; then + export SERIAL_PATH="./serial-ubuntu-24/serial" + fi export PLATFORM_TOOLS="platform-tools-latest-linux.zip" elif [[ `uname -s` == "Darwin" ]]; then if [[ `uname -m` == "arm64" ]]; then @@ -109,7 +113,8 @@ elif [[ `uname -s` == "Darwin" ]]; then export SERIAL_PATH="./serial-macos-intel/serial" fi export PLATFORM_TOOLS="platform-tools-latest-darwin.zip" - xattr -d com.apple.quarantine "$SERIAL_PATH" + # if we've already deleted this attribute, xattr errors out + xattr -d com.apple.quarantine "$SERIAL_PATH" || echo else echo "This script only supports Linux or macOS" exit 1 diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 8213150..d40b001 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -26,7 +26,7 @@ nix = { version = "0.29.0", features = ["feature"] } pcap-file-tokio = "0.1.0" thiserror = "1.0.50" telcom-parser = { path = "../telcom-parser" } -tokio = { version = "1.35.1", features = ["full"] } +tokio = { version = "1.44.2", features = ["full"] } futures-core = "0.3.30" futures = "0.3.30" serde = { version = "1.0.197", features = ["derive"] } diff --git a/rootshell/src/main.rs b/rootshell/src/main.rs index 9ed5fe6..f06c95b 100644 --- a/rootshell/src/main.rs +++ b/rootshell/src/main.rs @@ -10,27 +10,27 @@ use std::env; use nix::unistd::Gid; fn main() { - let mut args = env::args(); + let mut args = env::args(); - // Android's "paranoid network" feature restricts network access to - // processes in specific groups. More info here: - // https://www.elinux.org/Android_Security#Paranoid_network-ing - #[cfg(target_arch = "arm")] { - let gids = &[ - Gid::from_raw(3003), // AID_INET - Gid::from_raw(3004), // AID_NET_RAW - ]; - nix::unistd::setgroups(gids).expect("setgroups failed"); - } + // Android's "paranoid network" feature restricts network access to + // processes in specific groups. More info here: + // https://www.elinux.org/Android_Security#Paranoid_network-ing + #[cfg(target_arch = "arm")] { + let gids = &[ + Gid::from_raw(3003), // AID_INET + Gid::from_raw(3004), // AID_NET_RAW + ]; + nix::unistd::setgroups(gids).expect("setgroups failed"); + } - // discard argv[0] - let _ = args.next(); - // This call will only return if there is an error - let error = Command::new("/bin/bash") - .args(args) - .uid(0) - .gid(0) - .exec(); - eprintln!("Error running command: {error}"); - std::process::exit(1); + // discard argv[0] + let _ = args.next(); + // This call will only return if there is an error + let error = Command::new("/bin/bash") + .args(args) + .uid(0) + .gid(0) + .exec(); + eprintln!("Error running command: {error}"); + std::process::exit(1); } diff --git a/serial/Cargo.toml b/serial/Cargo.toml index f69b4be..127bfea 100644 --- a/serial/Cargo.toml +++ b/serial/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" [dependencies] anyhow = "1.0.97" nusb = "0.1.13" -tokio = { version = "1.44.1", features = ["macros", "rt", "time"] } +tokio = { version = "1.44.2", features = ["macros", "rt", "time"] }