Skip to content

Commit a38c1e0

Browse files
authored
(1) Use the server to send messages between apps when adding an app. (2) Support notifications for multiple apps in the server. (#132)
This PR provides the functionality needed to support multiple (mobile_client) apps to use one camera. Fixes secluso/mobile_client#50
1 parent 10d1a9f commit a38c1e0

8 files changed

Lines changed: 697 additions & 205 deletions

File tree

app_native/examples/app.rs

Lines changed: 46 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,12 @@ use docopt::Docopt;
2020
use std::env;
2121
use std::fs;
2222
use std::fs::File;
23-
use std::io::{self, BufRead, BufReader, Write, Read};
23+
use std::io::{self, BufRead, BufReader, Write};
2424
use std::path::Path;
2525
use std::sync::Arc;
2626
use std::sync::Mutex;
2727
use std::thread;
2828
use std::time::{Duration, SystemTime, UNIX_EPOCH};
29-
use std::net::{TcpListener, TcpStream, SocketAddr};
30-
use std::str::FromStr;
31-
use std::io::ErrorKind;
3229

3330
// This is a simple app that pairs with the Secluso camera, receives motion videos,
3431
// and launches livestream sessions.
@@ -41,7 +38,6 @@ use std::io::ErrorKind;
4138
const CAMERA_ADDR: &str = "127.0.0.1";
4239
const CAMERA_NAME: &str = "Camera";
4340
const DATA_DIR: &str = "example_app_data";
44-
const FIRST_APP_ADDR: &str = "127.0.0.1";
4541

4642
pub const MAX_ALLOWED_MSG_LEN: u64 = 65536;
4743

@@ -94,6 +90,11 @@ fn main() -> io::Result<()> {
9490
let clients: Arc<Mutex<Option<Box<Clients>>>> = Arc::new(Mutex::new(None));
9591
let http_client = HttpClient::new(server_addr, server_username, server_password);
9692

93+
// We assume here that the new secret is shared via
94+
// another channel, e.g., QR code scan.
95+
// Also, a new secret needs to be used for every app added.
96+
let add_app_secret = vec![2u8; NUM_SECRET_BYTES];
97+
9798
if first_time {
9899
if args.flag_reset {
99100
panic!("No state to reset!");
@@ -122,25 +123,19 @@ fn main() -> io::Result<()> {
122123
)
123124
} else {
124125
println!("Sending the add_app request");
125-
let addr = SocketAddr::from_str(&(FIRST_APP_ADDR.to_owned() + ":12350"))
126-
.map_err(|e| io::Error::other(format!("{e}")))?;
127-
128-
let mut stream = TcpStream::connect(&addr)?;
129126

130127
// get key packages
131128
let key_packages_vec = get_key_packages(&mut clients.lock().unwrap())?;
132129

133-
write_varying_len(&mut stream, &key_packages_vec)?;
134-
135-
let new_app_data_vec = read_varying_len(&mut stream)?;
136-
137-
// We assume here that the new secret is shared via
138-
// another channel, e.g., QR code scan.
139-
let new_secret = vec![2u8; NUM_SECRET_BYTES];
130+
println!("About to send add_app request");
131+
http_client.add_app_request("test_add_app_request_token", key_packages_vec)?;
132+
println!("About to wait for add_app response");
133+
let new_app_data_vec = http_client.add_app_check("test_add_app_response_token")?;
134+
println!("Received add_app response");
140135

141136
let epochs: [u64; NUM_MLS_CLIENTS] = join_camera_groups(
142137
&mut clients.lock().unwrap(),
143-
new_secret.clone(),
138+
add_app_secret.clone(),
144139
new_app_data_vec,
145140
)?;
146141

@@ -166,30 +161,35 @@ fn main() -> io::Result<()> {
166161
}
167162
}
168163

169-
let add_app_request: Arc<Mutex<Option<TcpStream>>> = Arc::new(Mutex::new(None));
164+
let add_app_request: Arc<Mutex<Option<Vec<u8>>>> = Arc::new(Mutex::new(None));
170165

171166
if !args.flag_secondary_app {
172167
let add_app_request_clone = Arc::clone(&add_app_request);
168+
let http_client_clone = http_client.clone();
173169

174170
thread::spawn(move || loop {
175-
let listener = TcpListener::bind("0.0.0.0:12350").unwrap();
176-
for incoming in listener.incoming() {
177-
match incoming {
178-
Ok(stream) => {
179-
println!("Incoming connection accepted.");
180-
let mut stream_opt = add_app_request_clone.lock().unwrap();
181-
*stream_opt = Some(stream);
182-
},
183-
184-
Err(e) => {
185-
println!("Incoming connection error: {e}");
186-
}
187-
}
188-
}
171+
println!("About to wait for add_app request");
172+
match http_client_clone.add_app_check("test_add_app_request_token") {
173+
Ok(data) => {
174+
println!("Received add_app request.");
175+
let mut data_opt = add_app_request_clone.lock().unwrap();
176+
*data_opt = Some(data);
177+
},
178+
179+
Err(e) => {
180+
println!("Error listening for add_app requests: {e}");
181+
}
182+
}
189183
});
190184
}
191185

192-
main_loop(clients, http_client, add_app_request, args.flag_num_iters)?;
186+
main_loop(
187+
clients,
188+
http_client,
189+
add_app_request,
190+
args.flag_num_iters,
191+
add_app_secret,
192+
)?;
193193

194194
Ok(())
195195
}
@@ -212,8 +212,9 @@ fn deregister_all(
212212
fn main_loop(
213213
clients: Arc<Mutex<Option<Box<Clients>>>>,
214214
http_client: HttpClient,
215-
add_app_request: Arc<Mutex<Option<TcpStream>>>,
215+
add_app_request: Arc<Mutex<Option<Vec<u8>>>>,
216216
num_iters: usize,
217+
add_app_secret: Vec<u8>,
217218
) -> io::Result<()> {
218219
for iter in 0..num_iters {
219220
thread::sleep(Duration::from_secs(1));
@@ -230,15 +231,16 @@ fn main_loop(
230231
livestream(Arc::clone(&clients), &http_client, 2)?;
231232
}
232233

233-
let mut add_app_stream_opt = add_app_request.lock().unwrap();
234-
if let Some(add_app_stream) = add_app_stream_opt.as_mut() {
234+
let mut add_app_data_opt = add_app_request.lock().unwrap();
235+
if let Some(add_app_data) = add_app_data_opt.as_ref() {
235236
println!("Add app request detected");
236237
handle_add_app_request(
237238
Arc::clone(&clients),
238239
&http_client,
239-
add_app_stream,
240+
add_app_data,
241+
add_app_secret.clone(),
240242
)?;
241-
*add_app_stream_opt = None;
243+
*add_app_data_opt = None;
242244
}
243245
}
244246

@@ -248,15 +250,15 @@ fn main_loop(
248250
fn handle_add_app_request(
249251
clients: Arc<Mutex<Option<Box<Clients>>>>,
250252
http_client: &HttpClient,
251-
stream: &mut TcpStream,
253+
add_app_data: &Vec<u8>,
254+
add_app_secret: Vec<u8>,
252255
) -> io::Result<()> {
253256
println!("handle_add_app_request called");
254-
let new_secret = vec![2u8; NUM_SECRET_BYTES];
255257

256-
let new_app_key_packages_vec = read_varying_len(stream)?;
258+
let new_app_key_packages_vec = add_app_data.clone();
257259

258260
let config_msg_enc =
259-
generate_add_app_request_config_command(&mut clients.lock().unwrap(), new_app_key_packages_vec, new_secret.clone())?;
261+
generate_add_app_request_config_command(&mut clients.lock().unwrap(), new_app_key_packages_vec, add_app_secret.clone())?;
260262

261263
let config_group_name = get_group_name(&mut clients.lock().unwrap(), "config")?;
262264

@@ -286,13 +288,13 @@ fn handle_add_app_request(
286288
let new_app_data_vec = process_add_app_config_response(
287289
&mut clients.lock().unwrap(),
288290
config_response.clone(),
289-
new_secret,
291+
add_app_secret,
290292
).unwrap();
291293

292294
increment_epoch("motion_epoch");
293295
increment_epoch("thumbnail_epoch");
294296

295-
write_varying_len(stream, &new_app_data_vec)?;
297+
http_client.add_app_request("test_add_app_response_token", new_app_data_vec)?;
296298

297299
Ok(())
298300
}
@@ -516,66 +518,3 @@ fn fetch_livestream_chunk(
516518
format!("Error: could not fetch livestream chunk (timeout)!"),
517519
));
518520
}
519-
520-
// FIXME: copied from camera_hub/src/pairing.rs.
521-
fn write_varying_len(stream: &mut TcpStream, msg: &[u8]) -> io::Result<()> {
522-
// FIXME: is u64 necessary?
523-
let len = msg.len() as u64;
524-
let len_data = len.to_be_bytes();
525-
526-
stream.write_all(&len_data)?;
527-
stream.write_all(msg)?;
528-
stream.flush()?;
529-
530-
Ok(())
531-
}
532-
533-
fn read_varying_len(stream: &mut TcpStream) -> io::Result<Vec<u8>> {
534-
let mut len_data = [0u8; 8];
535-
536-
match stream.read_exact(&mut len_data) {
537-
Ok(_) => {}
538-
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
539-
return Err(io::Error::new(
540-
ErrorKind::WouldBlock,
541-
"Length read would block",
542-
));
543-
}
544-
Err(e) => return Err(e),
545-
}
546-
547-
let len = u64::from_be_bytes(len_data);
548-
549-
if len > MAX_ALLOWED_MSG_LEN {
550-
println!("Communicated message length ({len}) exceeds the allowed length ({MAX_ALLOWED_MSG_LEN})");
551-
return Err(io::Error::new(
552-
ErrorKind::InvalidInput,
553-
"Intended message length is too large",
554-
))
555-
}
556-
557-
let mut msg = vec![0u8; len as usize];
558-
let mut offset = 0;
559-
560-
while offset < msg.len() {
561-
match stream.read(&mut msg[offset..]) {
562-
Ok(0) => {
563-
return Err(io::Error::new(
564-
ErrorKind::UnexpectedEof,
565-
"Socket closed during read",
566-
))
567-
}
568-
Ok(n) => {
569-
offset += n;
570-
}
571-
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
572-
// retry a few times with a short delay
573-
thread::sleep(Duration::from_millis(10));
574-
continue;
575-
}
576-
Err(e) => return Err(e),
577-
}
578-
}
579-
580-
Ok(msg)
581-
}

app_native/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use secluso_client_lib::mls_clients::{
1717
CONFIG, FCM, LIVESTREAM, MLS_CLIENT_TAGS, MOTION, NUM_MLS_CLIENTS, THUMBNAIL,
1818
NUM_COMMON_MLS_CLIENTS, NUM_DEDICATED_MLS_CLIENTS,
1919
};
20-
use secluso_client_lib::pairing::{self, MAX_ALLOWED_MSG_LEN};
20+
use secluso_client_lib::pairing::{self, MAX_ALLOWED_MSG_LEN, generate_add_app_secret};
2121
use secluso_client_lib::video::{encrypt_video_file, decrypt_video_file, decrypt_thumbnail_file};
2222
use openmls::prelude::KeyPackage;
2323
use serde::{Deserialize, Serialize};
@@ -783,6 +783,12 @@ pub fn process_heartbeat_config_response(
783783
}
784784
}
785785

786+
pub fn get_add_app_secret() -> io::Result<String> {
787+
generate_add_app_secret()
788+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
789+
790+
}
791+
786792
pub fn get_key_packages(clients: &mut Option<Box<Clients>>) -> io::Result<Vec<u8>> {
787793
if clients.is_none() {
788794
return Err(io::Error::other(

client_lib/src/http_client.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const MAX_COMMAND_FILE_SIZE: u64 = 100 * 1024; // 100 kibibytes
2222
const MAX_CHECK_RESP_SIZE: u64 = 20 * 1024; // 20 kibibytes
2323
const MAX_NOTIFICATION_TARGET_SIZE: u64 = 10 * 1024; // 10 kibibytes
2424
const IOS_NOTIFICATION_RESP_MAX_SIZE: u64 = 10 * 1024; // 10 kibibytes
25+
const MAX_ADD_APP_REQUEST_SIZE: u64 = 100 * 1024; // 100 kibibytes
2526

2627
#[derive(Clone)]
2728
pub struct HttpClient {
@@ -901,6 +902,71 @@ impl HttpClient {
901902

902903
Ok(response_vec)
903904
}
905+
906+
pub fn add_app_check(&self, op: &str) -> io::Result<Vec<u8>> {
907+
let max_size = MAX_ADD_APP_REQUEST_SIZE;
908+
909+
let server_url = format!("{}/add_app_check/{}", self.server_addr, op);
910+
911+
let client = Client::builder()
912+
.timeout(None)
913+
.build()
914+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
915+
916+
let response = self.authorized_headers(client
917+
.get(&server_url))
918+
.send()
919+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
920+
921+
if response.status() == StatusCode::CONFLICT {
922+
Self::give_hint_to_updater();
923+
}
924+
925+
if !response.status().is_success() {
926+
return Err(io::Error::new(
927+
io::ErrorKind::Other,
928+
format!("Server error: {}", response.status()),
929+
));
930+
}
931+
932+
let mut data = Vec::new();
933+
let mut limited = response.take(max_size);
934+
limited.read_to_end(&mut data)?;
935+
936+
if data.len() >= max_size as usize {
937+
return Err(io::Error::new(
938+
io::ErrorKind::Other,
939+
"Add app request exceeded maximum allowed size",
940+
));
941+
}
942+
943+
Ok(data)
944+
}
945+
946+
pub fn add_app_request(&self, op: &str, data: Vec<u8>) -> io::Result<()> {
947+
let server_url = format!("{}/add_app_request/{}", self.server_addr, op);
948+
949+
let client = Client::new();
950+
let response = self.authorized_headers(client
951+
.post(server_url))
952+
.header("Content-Type", "application/octet-stream")
953+
.body(data)
954+
.send()
955+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
956+
957+
if response.status() == StatusCode::CONFLICT {
958+
Self::give_hint_to_updater();
959+
}
960+
961+
if !response.status().is_success() {
962+
return Err(io::Error::new(
963+
io::ErrorKind::Other,
964+
format!("Server error: {}", response.status()),
965+
));
966+
}
967+
968+
Ok(())
969+
}
904970
}
905971

906972
#[cfg(test)]

client_lib/src/pairing.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,25 @@ pub fn generate_raspberry_camera_secret(
185185
Ok(())
186186
}
187187

188+
pub fn generate_add_app_secret() -> anyhow::Result<String> {
189+
let crypto = OpenMlsRustCrypto::default();
190+
let secret = crypto
191+
.crypto()
192+
.random_vec(NUM_SECRET_BYTES)
193+
.context("Failed to generate camera secret bytes")?;
194+
195+
let add_app_secret = CameraSecret {
196+
version: CAMERA_SECRET_VERSION.to_string(),
197+
secret: base64_url::encode(&secret),
198+
wifi_password: None,
199+
};
200+
201+
let qr_content = serde_json::to_string(&add_app_secret)
202+
.context("Failed to serialize add_app secret into JSON")?;
203+
204+
Ok(qr_content)
205+
}
206+
188207
impl App {
189208
pub fn new(key_package: KeyPackage) -> Self {
190209
Self { key_package }

0 commit comments

Comments
 (0)