-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Fix the command handling of NM * Fix tests * Add the command to start * Thanks, clippy! * fix non windows * formatting * casing
- Loading branch information
Showing
4 changed files
with
231 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
|
||
|
||
use std::error::Error; | ||
use serde_json::{Value, json}; | ||
|
||
/** | ||
* Handles commands that are sent from | ||
* [Extension] === > [NativeMessagingBridge] | ||
* | ||
* Returns true if the command was handled, in which case it should | ||
* *not* be forwarded to the VPN Client. | ||
* | ||
* Will attempt to print to STDOUT in case a command needs a response. | ||
* | ||
*/ | ||
pub fn handle(val:&Value)-> Result<bool,Box<dyn Error>>{ | ||
let obj = val.as_object().ok_or("Not an object")?; | ||
// Type of command is in {t:'doThing'} | ||
let cmd = obj.get_key_value("t").ok_or("Missing obj.t")?; | ||
|
||
match cmd.1.as_str().ok_or("T is not a string")? { | ||
"bridge_ping" =>{ | ||
crate::io::write_output(std::io::stdout(),&json!({"status": "bridge_pong"})) | ||
.expect("Unable to Write to STDOUT?"); | ||
Ok(true) | ||
} | ||
"start" =>{ | ||
let out = launcher::start_vpn(); | ||
crate::io::write_output(std::io::stdout(),&out) | ||
.expect("Unable to Write to STDOUT?"); | ||
Ok(true) | ||
} | ||
_ =>{ | ||
// We did not handle this. | ||
Ok(false) | ||
} | ||
} | ||
} | ||
|
||
|
||
#[cfg(target_os = "windows")] | ||
mod launcher { | ||
const CLIENT_PATH: &str = "C:\\Program Files\\Mozilla\\Mozilla VPN\\Mozilla VPN.exe"; | ||
|
||
use std::os::windows::process::CommandExt; | ||
use std::process::Command; | ||
|
||
use serde_json::json; | ||
|
||
const CREATE_NEW_PROCESS_GROUP: u32 = 0x200; // CREATE_NEW_PROCESS_GROUP | ||
const DETACHED_PROCESS: u32 = 0x00000008; // DETACHED_PROCESS | ||
|
||
pub fn start_vpn() -> serde_json::Value{ | ||
let result = Command::new(CLIENT_PATH) | ||
.args(["-foreground"]) | ||
.creation_flags(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS) | ||
.spawn(); | ||
|
||
match result { | ||
Ok(_) => json!("{status:'requested_start'}"), | ||
Err(_) => json!("{error:'start_failed'}"), | ||
} | ||
} | ||
|
||
|
||
} | ||
|
||
#[cfg(not(target_os = "windows"))] | ||
mod launcher { | ||
use serde_json::json; | ||
pub fn start_vpn() -> serde_json::Value{ | ||
json!("{error:'start_unsupported!'}") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; | ||
|
||
|
||
use serde_json::{json, Value}; | ||
use std::io::{Cursor, Read, Write}; | ||
use std::mem::size_of; | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
#[derive(PartialEq)] | ||
enum ReaderState { | ||
ReadingLength, | ||
ReadingBuffer, | ||
} | ||
|
||
pub struct Reader { | ||
state: ReaderState, | ||
buffer: Vec<u8>, | ||
length: usize, | ||
} | ||
|
||
impl Reader { | ||
pub fn new() -> Reader { | ||
Reader { | ||
state: ReaderState::ReadingLength, | ||
buffer: Vec::new(), | ||
length: 0, | ||
} | ||
} | ||
|
||
pub fn read_input<R: Read>(&mut self, mut input: R) -> Option<Value> { | ||
// Until we are able to read things from the stream... | ||
loop { | ||
if self.state == ReaderState::ReadingLength { | ||
assert!(self.buffer.len() < size_of::<u32>()); | ||
|
||
let mut buffer = vec![0; size_of::<u32>() - self.buffer.len()]; | ||
match input.read(&mut buffer) { | ||
Ok(size) => { | ||
// Maybe we have read just part of the buffer. Let's append | ||
// only what we have been read. | ||
buffer.truncate(size); | ||
self.buffer.append(&mut buffer); | ||
|
||
// Not enough data yet. | ||
if self.buffer.len() < size_of::<u32>() { | ||
continue; | ||
} | ||
|
||
// Let's convert our buffer into a u32. | ||
let mut rdr = Cursor::new(&self.buffer); | ||
self.length = rdr.read_u32::<NativeEndian>().unwrap() as usize; | ||
if self.length == 0 { | ||
continue; | ||
} | ||
|
||
self.state = ReaderState::ReadingBuffer; | ||
self.buffer = Vec::with_capacity(self.length); | ||
} | ||
_ => return None, | ||
} | ||
} | ||
|
||
if self.state == ReaderState::ReadingBuffer { | ||
assert!(self.length > 0); | ||
assert!(self.buffer.len() < self.length); | ||
|
||
let mut buffer = vec![0; self.length - self.buffer.len()]; | ||
match input.read(&mut buffer) { | ||
Ok(size) => { | ||
// Maybe we have read just part of the buffer. Let's append | ||
// only what we have been read. | ||
buffer.truncate(size); | ||
self.buffer.append(&mut buffer); | ||
|
||
// Not enough data yet. | ||
if self.buffer.len() < self.length { | ||
continue; | ||
} | ||
|
||
match serde_json::from_slice(&self.buffer) { | ||
Ok(value) => { | ||
self.buffer.clear(); | ||
self.state = ReaderState::ReadingLength; | ||
return Some(value); | ||
} | ||
_ => { | ||
self.buffer.clear(); | ||
self.state = ReaderState::ReadingLength; | ||
continue; | ||
} | ||
} | ||
} | ||
_ => return None, | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
pub fn write_output<W: Write>(mut output: W, value: &Value) -> Result<(), std::io::Error> { | ||
let msg = serde_json::to_string(value)?; | ||
let len = msg.len(); | ||
output.write_u32::<NativeEndian>(len as u32)?; | ||
output.write_all(msg.as_bytes())?; | ||
output.flush()?; | ||
Ok(()) | ||
} | ||
|
||
pub fn write_vpn_down(error: bool) { | ||
let field = if error { "error" } else { "status" }; | ||
let value = json!({field: "vpn-client-down"}); | ||
write_output(std::io::stdout(), &value).expect("Unable to write to STDOUT"); | ||
} | ||
|
||
pub fn write_vpn_up() { | ||
let value = json!({"status": "vpn-client-up"}); | ||
write_output(std::io::stdout(), &value).expect("Unable to write to STDOUT"); | ||
} |
Oops, something went wrong.