Maarten van Gompel: 1 Add parameter to set touch grid resolution. 5 files changed, 100 insertions(+), 72 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~mil/sxmo-devel/patches/56241/mbox | git am -3Learn more about email & git
A higher resolution increases the number of passcode permutations. Resolution can be set from 1 (1x1 = 1 quadrant, touch anywhere to unlock, insecure) to 4 (4x4 = 16 quadrants). The default remains 2x2 = 4 quadrants. Quadrants are numbered horizontal-first, starting from 1. Except for resolution 4, where they start from 0 and are counted in hexademical up to f. Each character in a passcode corresponds to a quadrant. Passcodes can have arbitrary length (like before). See the README for further explanation. --- This patch should again be applied on top of my previous peanutbutter patches. Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 28 +++++++++-- src/main.rs | 16 ++++++ src/touch_pass.rs | 124 ++++++++++++++++++++++------------------------ 5 files changed, 100 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a247b2b..6bf5783 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -455,7 +455,7 @@ dependencies = [ [[package]] name = "peanutbutter" -version = "0.4.1" +version = "0.5.0" dependencies = [ "cairo-rs", "chrono", diff --git a/Cargo.toml b/Cargo.toml index f75dc1a..d732892 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "peanutbutter" -version = "0.4.1" +version = "0.5.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 9993fea..dfd527f 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ When peanutbutter crashes, ssh into your phone and check the `/tmp/peanutbutter. # Controls -The screen is segregated into 4 corners: +By default, the screen is segregated into 4 quadrants (resolution 2): 1. Top left 2. Top right @@ -89,7 +89,29 @@ mistake, simply start tapping the sequence anew. A touch will be acknowledged by flipping the background, this provides only provides a indication whether the touch was registered, not whether it is a -valid touch in the passcode sequence. +valid touch in the passcode sequence. The feedback will be over the entire screen +and will not specifically highlight the quadrant you tapped (as a security measure). +Visual feedback can be disabled entirely by passing the `-F` or `--nofeedback` option. + +Another way to increase security, is to set the parameter `-3` to change the +resolution to 3 (3x3 = 9 quadrants). Which takes the following configuration: + +``` +1 2 3 +4 5 6 +7 8 9 +``` + +You can even go up to `-4`, which will give you this next configuration (4x4 = +16 quadrants): + +``` +0 1 2 3 +4 5 6 7 +8 9 a b +c d e f +``` + # Safety @@ -101,6 +123,4 @@ Try `pkill peanutbutter`. FAQ: https://lists.sr.ht/~anjan/public-inbox/%3CD08OUBZEXWSQ.3M648R47PDJC1@matfyz.cz%3E#%3CD2UYYQ6C2LQG.1KYZEAJ0X2Z2N@momi.ca%3E -- Clean up code (compiler warnings) -- Package - Show an incoming call and pickup easily via lock screen diff --git a/src/main.rs b/src/main.rs index 5bc7994..8a08f79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ fn main() { let mut nofeedback = false; let mut statuscommand: Option<Vec<String>> = None; let mut parsefont = false; + let mut resolution = 2; let mut fontname: String = "Sans".into(); for argument in env::args().skip(1) { match argument.as_str() { @@ -30,6 +31,10 @@ fn main() { "-F" | "--nofeedback" => nofeedback = true, "-s" | "--statuscommand" => statuscommand = Some(Vec::new()), "-f" | "--font" => parsefont = true, + "-1" => resolution = 1, + "-2" => resolution = 2, + "-3" => resolution = 3, + "-4" => resolution = 4, "-h" | "--help" => { eprintln!("Options:"); eprintln!( @@ -39,6 +44,16 @@ fn main() { eprintln!(" -F / --nofeedback Disable touch feedback"); eprintln!(" -f / --font [font Set font family"); eprintln!(" -s / --statuscommand [command] Run this command for a status line, it should run continuously and each new output line will become the status line"); + eprintln!(" -1 1x1 touch grid (insecure)"); + eprintln!( + " -2 2x2 touch grid (1=topleft, 4=bottomright)" + ); + eprintln!( + " -3 3x3 touch grid (1=topleft, 9=bottomright)" + ); + eprintln!( + " -4 4x4 touch grid (0=topleft, f=bottomright)" + ); std::process::exit(0); } "-v" | "--version" => { @@ -117,6 +132,7 @@ fn main() { way_state.width.unwrap(), way_state.height.unwrap(), passcode.as_deref(), + resolution, )); //single blocking dispatch before the main loop diff --git a/src/touch_pass.rs b/src/touch_pass.rs index e951def..e07c318 100644 --- a/src/touch_pass.rs +++ b/src/touch_pass.rs @@ -1,105 +1,97 @@ use std::collections::VecDeque; -use std::fmt; -//in numeric representation (quadrants): 1132 -const DEFAULT_PASSCODE: [PasscodeItem; 4] = [ - PasscodeItem::TopLeft, - PasscodeItem::TopLeft, - PasscodeItem::BottomLeft, - PasscodeItem::TopRight, -]; +//in numeric representation (quadrants): 1132 , with 4 quadrants this corresponds to topleft, topright, bottomleft, bottomright +const DEFAULT_PASSCODE: [u8; 4] = [1, 1, 3, 2]; -#[derive(Copy, Clone, PartialEq, Debug)] -enum PasscodeItem { - TopLeft, - TopRight, - BottomLeft, - BottomRight, -} - -impl TryFrom<char> for PasscodeItem { - type Error = &'static str; - fn try_from(value: char) -> Result<Self, Self::Error> { - match value { - '1' => Ok(PasscodeItem::TopLeft), - '2' => Ok(PasscodeItem::TopRight), - '3' => Ok(PasscodeItem::BottomLeft), - '4' => Ok(PasscodeItem::BottomRight), - _ => Err("invalid quadrant for passcodeitem: use 1 (topleft), 2 (topright), 3 (bottomleft) ,4 (bottomright)") - } - } -} - -impl fmt::Display for PasscodeItem { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - PasscodeItem::TopLeft => write!(f, "TOP LEFT"), - PasscodeItem::TopRight => write!(f, "TOP RIGHT"), - PasscodeItem::BottomLeft => write!(f, "BOTTOM LEFT"), - PasscodeItem::BottomRight => write!(f, "BOTTOM RIGHT"), +fn read_passcode_char(value: char, resolution: u8) -> Result<u8, &'static str> { + match value { + '0' if resolution == 4 => Ok(0), + '1' => Ok(1), + '2' if resolution >= 2 => Ok(2), + '3' if resolution >= 2 => Ok(3), + '4' if resolution >= 2 => Ok(4), + '5' if resolution >= 3 => Ok(5), + '6' if resolution >= 3 => Ok(6), + '7' if resolution >= 3 => Ok(7), + '8' if resolution >= 3 => Ok(8), + '9' if resolution >= 3 => Ok(9), + 'A' | 'a' if resolution == 4 => Ok(10), + 'B' | 'b' if resolution == 4 => Ok(11), + 'C' | 'c' if resolution == 4 => Ok(12), + 'D' | 'd' if resolution == 4 => Ok(13), + 'E' | 'e' if resolution == 4 => Ok(14), + 'F' | 'f' if resolution == 4 => Ok(15), + _ => { + if resolution == 2 { + Err("invalid quadrant for passcodeitem: 1 (topleft), 2 (topright), 3 (bottomleft), 4 (bottomright)") + } else if resolution == 3 { + Err("invalid quadrant for passcodeitem: use 1 (topleft),2,3 (topright),4,5 (center),6,7 (bottomleft),8,9 (bottomright)") + } else if resolution == 4 { + Err("invalid quadrant for passcodeitem: use 0 (topleft),1,2,3(topright),4,5,6,7,8,9,a,b,c (bottomleft),d,e,f (bottomright)") + } else { + Err("invalid quadrant for passcodeitem") + } } } } #[derive(Clone, PartialEq, Debug)] pub struct TouchState { - passcode: Vec<PasscodeItem>, - touches: VecDeque<PasscodeItem>, + passcode: Vec<u8>, + touches: VecDeque<u8>, + resolution: u8, max_touches: usize, - half_width: f64, - half_height: f64, + grid_width: f64, + grid_height: f64, } impl TouchState { - pub fn new(width: i32, height: i32, passcode: Option<&str>) -> Self { + pub fn new(width: i32, height: i32, passcode: Option<&str>, resolution: u8) -> Self { + if resolution < 1 || resolution > 4 { + panic!("Invalid resolution"); + } Self { passcode: if let Some(passcode) = passcode { passcode .chars() - .map(|x| x.try_into().expect("Invalid passcode")) + .map(|x| read_passcode_char(x, resolution).expect("Invalid passcode")) .collect() + } else if resolution == 1 { + vec![1] } else { DEFAULT_PASSCODE.iter().copied().collect() }, touches: VecDeque::new(), + resolution, max_touches: if let Some(passcode) = passcode { passcode.chars().count() + } else if resolution == 1 { + 1 } else { DEFAULT_PASSCODE.len() }, - half_width: width as f64 / 2.0, - half_height: height as f64 / 2.0, + grid_width: width as f64 / (resolution as f64), + grid_height: height as f64 / (resolution as f64), } } pub fn resize(&mut self, width: i32, height: i32) { - self.half_width = width as f64 / 2.0; - self.half_height = height as f64 / 2.0; + self.grid_width = width as f64 / (self.resolution as f64); + self.grid_height = height as f64 / (self.resolution as f64); } pub fn add_touch(&mut self, x_val: f64, y_val: f64) -> bool { - let touch: Option<PasscodeItem> = if x_val < self.half_width && y_val < self.half_height { - Some(PasscodeItem::TopLeft) - } else if x_val > self.half_width && y_val < self.half_height { - Some(PasscodeItem::TopRight) - } else if x_val < self.half_width && y_val > self.half_height { - Some(PasscodeItem::BottomLeft) - } else if x_val > self.half_width && y_val > self.half_height { - Some(PasscodeItem::BottomRight) - } else { - None - }; + let startindex: u8 = if self.resolution == 4 { 0 } else { 1 }; - if let Some(touch) = touch { - self.touches.push_back(touch); - while self.touches.len() > self.max_touches { - self.touches.pop_front(); - } - true - } else { - eprintln!("unknown touch!"); - false + let x = (x_val / self.grid_width).floor() as u8; + let y = (y_val / self.grid_height).floor() as u8; + let code = y * self.resolution + x + startindex; + + self.touches.push_back(code); + while self.touches.len() > self.max_touches { + self.touches.pop_front(); } + true } pub fn is_pass_valid(&self) -> bool { -- 2.47.1
Thanks! To git@git.sr.ht:~anjan/peanutbutter f02fa612..3d78f0e2 master -> master