Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6dcfb65686 | |||
| fef1380d3a | |||
| ceeef351fd |
@@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
All notable changes to KAT are documented here.
|
All notable changes to KAT are documented here.
|
||||||
|
|
||||||
|
## [1.1.1] - 2026-02-13
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **UI updates** — Vulnerability panel (green border when vuln found, green “encryption broken” text); signal action menu shows TX Lock/Unlock/Trunk/Panic only for encoder-capable captures (unknown/decoded get Replay only).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [1.1.0] - 2026-02-13
|
## [1.1.0] - 2026-02-13
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
Generated
+1
-1
@@ -444,7 +444,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kat"
|
name = "kat"
|
||||||
version = "1.0.2"
|
version = "1.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"atty",
|
"atty",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "kat"
|
name = "kat"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Keyfob Analysis Toolkit - HackRF/RTL-SDR signal capture, decode, and transmit (HackRF only)"
|
description = "Keyfob Analysis Toolkit - HackRF/RTL-SDR signal capture, decode, and transmit (HackRF only)"
|
||||||
authors = ["KAT Team"]
|
authors = ["KAT Team"]
|
||||||
|
|||||||
+30
-5
@@ -1006,12 +1006,18 @@ impl App {
|
|||||||
|
|
||||||
// -- Signal Action Menu helpers --
|
// -- Signal Action Menu helpers --
|
||||||
|
|
||||||
/// Signal actions shown in the menu: all if HackRF (TX), else only export and delete.
|
/// Signal actions shown in the menu. With HackRF: Replay always; Lock/Unlock/Trunk/Panic only when
|
||||||
|
/// the selected capture is encoder-capable (unknown or decoded-only signals get Replay only).
|
||||||
|
/// Without TX (e.g. RTL-SDR): only export and delete.
|
||||||
pub fn available_signal_actions(&self) -> Vec<SignalAction> {
|
pub fn available_signal_actions(&self) -> Vec<SignalAction> {
|
||||||
if self.radio.as_ref().map_or(false, |r| r.supports_tx()) {
|
let has_tx = self.radio.as_ref().map_or(false, |r| r.supports_tx());
|
||||||
SignalAction::ALL.to_vec()
|
let encoder_capable = self
|
||||||
} else {
|
.selected_capture
|
||||||
SignalAction::ALL
|
.and_then(|idx| self.captures.get(idx))
|
||||||
|
.map_or(false, |c| c.status == crate::capture::CaptureStatus::EncoderCapable);
|
||||||
|
|
||||||
|
if !has_tx {
|
||||||
|
return SignalAction::ALL
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|a| {
|
.filter(|a| {
|
||||||
matches!(
|
matches!(
|
||||||
@@ -1020,6 +1026,25 @@ impl App {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
.copied()
|
.copied()
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if encoder_capable {
|
||||||
|
SignalAction::ALL.to_vec()
|
||||||
|
} else {
|
||||||
|
// Unknown or decoded-only: only Replay + export + delete (no TX Lock/Unlock/Trunk/Panic)
|
||||||
|
SignalAction::ALL
|
||||||
|
.iter()
|
||||||
|
.filter(|a| {
|
||||||
|
!matches!(
|
||||||
|
a,
|
||||||
|
SignalAction::Lock
|
||||||
|
| SignalAction::Unlock
|
||||||
|
| SignalAction::Trunk
|
||||||
|
| SignalAction::Panic
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.copied()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-1
@@ -314,8 +314,22 @@ fn render_vulnerability_panel(
|
|||||||
capture.model.as_deref(),
|
capture.model.as_deref(),
|
||||||
capture.region.as_deref(),
|
capture.region.as_deref(),
|
||||||
);
|
);
|
||||||
|
let vuln_found = capture.status == CaptureStatus::EncoderCapable || !vulns.is_empty();
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
|
// When we can encode, the encryption is broken — complete emulation is available.
|
||||||
|
if capture.status == CaptureStatus::EncoderCapable {
|
||||||
|
let emu_style = Style::default()
|
||||||
|
.fg(Color::Green)
|
||||||
|
.add_modifier(Modifier::BOLD);
|
||||||
|
lines.push(Line::from(Span::styled(
|
||||||
|
" Encryption is broken — Complete emulation of the keyfob is available",
|
||||||
|
emu_style,
|
||||||
|
)));
|
||||||
|
lines.push(Line::from(Span::raw("")));
|
||||||
|
}
|
||||||
|
|
||||||
if vulns.is_empty() {
|
if vulns.is_empty() {
|
||||||
let has_meta = capture.year.is_some()
|
let has_meta = capture.year.is_some()
|
||||||
|| capture.make.is_some()
|
|| capture.make.is_some()
|
||||||
@@ -350,9 +364,10 @@ fn render_vulnerability_panel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let border_color = if vuln_found { Color::Green } else { Color::Yellow };
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_style(Style::default().fg(Color::Yellow))
|
.border_style(Style::default().fg(border_color))
|
||||||
.title(" Vulnerability ");
|
.title(" Vulnerability ");
|
||||||
let inner = block.inner(area);
|
let inner = block.inner(area);
|
||||||
frame.render_widget(block, area);
|
frame.render_widget(block, area);
|
||||||
|
|||||||
Reference in New Issue
Block a user