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