mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-05-01 09:59:57 -07:00
Merge remote-tracking branch 'origin/main' into build-features
This commit is contained in:
62
.github/ISSUE_TEMPLATE/bug.yaml
vendored
Normal file
62
.github/ISSUE_TEMPLATE/bug.yaml
vendored
Normal file
@@ -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
|
||||
8
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
@@ -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.
|
||||
27
.github/ISSUE_TEMPLATE/feature.yaml
vendored
Normal file
27
.github/ISSUE_TEMPLATE/feature.yaml
vendored
Normal file
@@ -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..."
|
||||
6
.github/pull_request_template.md
vendored
Normal file
6
.github/pull_request_template.md
vendored
Normal file
@@ -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
|
||||
2
.github/workflows/build-release.yml
vendored
2
.github/workflows/build-release.yml
vendored
@@ -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
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -130,11 +130,7 @@ pub async fn start_recording(State(state): State<Arc<ServerState>>) -> 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)))?;
|
||||
|
||||
|
||||
@@ -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<DisplayState> 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<DisplayState>
|
||||
mut ui_update_rx: Receiver<DisplayState>,
|
||||
) {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ pub enum DisplayState {
|
||||
Recording,
|
||||
Paused,
|
||||
WarningDetected,
|
||||
RecordingCBM,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "orbic", feature = "tplink"))]
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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<RwLock<AnalysisStatus>>,
|
||||
pub analysis_sender: Sender<AnalysisCtrlMessage>,
|
||||
pub debug_mode: bool,
|
||||
pub colorblind_mode: bool,
|
||||
}
|
||||
|
||||
pub async fn get_qmdl(State(state): State<Arc<ServerState>>, Path(qmdl_name): Path<String>) -> Result<Response, (StatusCode, String)> {
|
||||
@@ -36,7 +35,10 @@ pub async fn get_qmdl(State(state): State<Arc<ServerState>>, 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())
|
||||
}
|
||||
|
||||
9
dist/install.sh
vendored
9
dist/install.sh
vendored
@@ -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
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
Reference in New Issue
Block a user