11// jkcoxson
22
33use backend:: Backend ;
4+ use bytes:: BufMut ;
5+ use futures:: TryStreamExt ;
46use log:: { info, warn} ;
57use plist_plus:: Plist ;
68use serde_json:: Value ;
79use std:: { net:: SocketAddr , str:: FromStr , sync:: Arc } ;
810use tokio:: sync:: Mutex ;
9- use warp:: { filters:: BoxedFilter , http:: Uri , path:: FullPath , redirect, Filter , Rejection , Reply } ;
11+ use warp:: {
12+ filters:: BoxedFilter ,
13+ http:: Uri ,
14+ multipart:: { FormData , Part } ,
15+ path:: FullPath ,
16+ redirect, Filter , Rejection , Reply ,
17+ } ;
1018
1119mod backend;
1220mod client;
@@ -24,6 +32,7 @@ async fn main() {
2432 let static_dir = config. static_path . clone ( ) ;
2533 let current_dir = std:: env:: current_dir ( ) . expect ( "failed to read current directory" ) ;
2634 let backend = Arc :: new ( Mutex :: new ( backend:: Backend :: load ( & config) ) ) ;
35+ let upload_backend = backend. clone ( ) ;
2736 let potential_backend = backend. clone ( ) ;
2837 let potential_follow_up_backend = backend. clone ( ) ;
2938 let status_backend = backend. clone ( ) ;
@@ -44,6 +53,13 @@ async fn main() {
4453 ) )
4554 } ) ;
4655
56+ // Upload route
57+ let upload_route = warp:: path ( "upload" )
58+ . and ( warp:: post ( ) )
59+ . and ( warp:: multipart:: form ( ) . max_length ( 5_000_000 ) )
60+ . and ( warp:: filters:: addr:: remote ( ) )
61+ . and_then ( move |form, addr| upload_file ( form, addr, upload_backend. clone ( ) ) ) ;
62+
4763 // Potential route
4864 let potential_route = warp:: path ( "potential" )
4965 . and ( warp:: get ( ) )
@@ -84,6 +100,7 @@ async fn main() {
84100 let routes = root_redirect ( )
85101 . or ( warp:: fs:: dir ( current_dir. join ( static_dir) ) )
86102 . or ( status_route)
103+ . or ( upload_route)
87104 . or ( potential_route)
88105 . or ( potential_follow_up_route)
89106 . or ( list_apps_route)
@@ -121,6 +138,95 @@ async fn version_route() -> Result<impl Reply, Rejection> {
121138 Ok ( "0.1.2" )
122139}
123140
141+ async fn upload_file (
142+ form : FormData ,
143+ address : Option < SocketAddr > ,
144+ backend : Arc < Mutex < Backend > > ,
145+ ) -> Result < impl Reply , Rejection > {
146+ let lock = backend. lock ( ) . await ;
147+ let parts: Vec < Part > = match form. try_collect ( ) . await {
148+ Ok ( parts) => parts,
149+ Err ( _) => return Ok ( packets:: upload_response ( false , "Form error" ) ) ,
150+ } ;
151+
152+ for p in parts {
153+ if p. name ( ) == "file" {
154+ let value = match p
155+ . stream ( )
156+ . try_fold ( Vec :: new ( ) , |mut vec, data| {
157+ vec. put ( data) ;
158+ async move { Ok ( vec) }
159+ } )
160+ . await
161+ {
162+ Ok ( value) => value,
163+ Err ( _) => return Ok ( packets:: upload_response ( false , "File error" ) ) ,
164+ } ;
165+
166+ // Get string from value
167+ let value = match String :: from_utf8 ( value) {
168+ Ok ( value) => value,
169+ Err ( _) => {
170+ return Ok ( packets:: upload_response ( false , "Unable to read file" ) ) ;
171+ }
172+ } ;
173+ // Attempt to parse it as an Apple Plist
174+ let plist: Plist = Plist :: from_xml ( value. clone ( ) ) . unwrap ( ) ;
175+ let udid = match plist. dict_get_item ( "UDID" ) {
176+ Ok ( s) => match s. get_string_val ( ) {
177+ Ok ( s) => s,
178+ Err ( _) => {
179+ return Ok ( packets:: upload_response (
180+ false ,
181+ "Unable to read UDID from Plist" ,
182+ ) ) ;
183+ }
184+ } ,
185+ _ => {
186+ return Ok ( packets:: upload_response ( false , "Invalid pairing file!" ) ) ;
187+ }
188+ } ;
189+ let address = match address {
190+ Some ( address) => address,
191+ None => {
192+ return Ok ( packets:: upload_response ( false , "No address provided" ) ) ;
193+ }
194+ } ;
195+ let plist: Plist = Plist :: from_xml ( value) . unwrap ( ) ;
196+ // Save the plist to the plist storage directory
197+ match lock. write_pairing_file ( plist. to_string ( ) , & udid) {
198+ Ok ( _) => { }
199+ Err ( _) => {
200+ return Ok ( packets:: upload_response (
201+ false ,
202+ "Unable to save pairing file" ,
203+ ) ) ;
204+ }
205+ }
206+ drop ( lock) ;
207+ // Make sure that the client is valid before adding it to the backend
208+ match backend:: Backend :: test_new_client ( & address. ip ( ) . to_string ( ) , & udid) . await {
209+ Ok ( _) => { }
210+ Err ( _) => {
211+ return Ok ( packets:: upload_response (
212+ false ,
213+ "Device did not respond to pairing test" ,
214+ ) ) ;
215+ }
216+ }
217+ let mut lock = backend. lock ( ) . await ;
218+ match lock. register_client ( address. ip ( ) . to_string ( ) , udid. clone ( ) ) {
219+ Ok ( _) => { }
220+ Err ( _) => {
221+ return Ok ( packets:: upload_response ( false , "Client already registered" ) ) ;
222+ }
223+ }
224+ return Ok ( packets:: upload_response ( true , "" ) ) ;
225+ }
226+ }
227+ return Ok ( packets:: upload_response ( false , "No file found" ) ) ;
228+ }
229+
124230async fn potential_pair (
125231 addr : Option < SocketAddr > ,
126232 backend : Arc < Mutex < Backend > > ,
0 commit comments