| 1 | use super::*; |
| 2 | |
| 3 | pub struct Host { |
| 4 | members: Arc<Members>, |
| 5 | pairing: Mutex<Option<Live>>, |
| 6 | } |
| 7 | |
| 8 | #[allow(clippy::type_complexity)] |
| 9 | struct Members { |
| 10 | me: Hello, |
| 11 | notebook: String, |
| 12 | reach: Option<Reach>, |
| 13 | relay: Option<String>, |
| 14 | sharing: Mutex<Sharing>, |
| 15 | changes: Mutex<()>, |
| 16 | pending: Mutex<BTreeMap<[u8; 16], (Arc<Hello>, Line)>>, |
| 17 | access: Mutex<HashMap<[u8; 16], Live>>, |
| 18 | room: Mutex<Option<Live>>, |
| 19 | served: Arc<Served>, |
| 20 | events: Arc<dyn Fn() + Send + Sync>, |
| 21 | keep: Box<dyn Fn(&Sharing) -> io::Result<()> + Send + Sync>, |
| 22 | } |
| 23 | |
| 24 | impl Host { |
| 25 | /// Shares a notebook, keeping every credential change before granting or revoking access. |
| 26 | #[allow(clippy::too_many_arguments)] |
| 27 | pub fn start( |
| 28 | storage: Box<dyn Storage>, |
| 29 | me: Hello, |
| 30 | sharing: Sharing, |
| 31 | notebook: &str, |
| 32 | reach: Option<Reach>, |
| 33 | relay: Option<&str>, |
| 34 | events: impl Fn() + Send + Sync + 'static, |
| 35 | keep: impl Fn(&Sharing) -> io::Result<()> + Send + Sync + 'static, |
| 36 | ) -> io::Result<Self> { |
| 37 | keep(&sharing)?; |
| 38 | let members = Arc::new(Members { |
| 39 | me, |
| 40 | notebook: notebook.to_owned(), |
| 41 | reach, |
| 42 | relay: relay.map(str::to_owned), |
| 43 | sharing: Mutex::new(sharing), |
| 44 | changes: Mutex::default(), |
| 45 | pending: Mutex::default(), |
| 46 | access: Mutex::default(), |
| 47 | room: Mutex::default(), |
| 48 | served: Arc::new(Served { |
| 49 | storage, |
| 50 | images: Mutex::default(), |
| 51 | snapshots: Mutex::default(), |
| 52 | puts: Mutex::default(), |
| 53 | guests: Mutex::default(), |
| 54 | writers: Mutex::default(), |
| 55 | host: Mutex::default(), |
| 56 | room: Mutex::default(), |
| 57 | }), |
| 58 | events: Arc::new(events), |
| 59 | keep: Box::new(keep), |
| 60 | }); |
| 61 | let sharing = members.sharing.lock().unwrap().clone(); |
| 62 | members.presence(sharing.secret)?; |
| 63 | for device in &sharing.members { |
| 64 | members.open(device.secret)?; |
| 65 | } |
| 66 | let pairing = Mutex::new(Some(members.pair(&sharing)?)); |
| 67 | Ok(Self { members, pairing }) |
| 68 | } |
| 69 | |
| 70 | pub fn code(&self) -> Option<String> { |
| 71 | let mut pairing = self.pairing.lock().unwrap(); |
| 72 | let pairing = pairing.as_mut()?; |
| 73 | let mut sharing = self.members.sharing.lock().unwrap(); |
| 74 | if pairing.burned() { |
| 75 | let mut next = sharing.clone(); |
| 76 | next.code = super::super::code::secret().ok()?; |
| 77 | (self.members.keep)(&next).ok()?; |
| 78 | *pairing = self.members.pair(&next).ok()?; |
| 79 | *sharing = next; |
| 80 | } |
| 81 | let code = pairing.code(); |
| 82 | if let Some(code) = &code |
| 83 | && *code != sharing.code |
| 84 | { |
| 85 | let mut next = sharing.clone(); |
| 86 | next.code = code.clone(); |
| 87 | (self.members.keep)(&next).ok()?; |
| 88 | *sharing = next; |
| 89 | } |
| 90 | code |
| 91 | } |
| 92 | |
| 93 | pub fn sharing(&self) -> Sharing { |
| 94 | self.code(); |
| 95 | self.members.sharing.lock().unwrap().clone() |
| 96 | } |
| 97 | |
| 98 | pub fn relayed(&self) -> Relayed { |
| 99 | self.pairing |
| 100 | .lock() |
| 101 | .unwrap() |
| 102 | .as_ref() |
| 103 | .map_or(Relayed::Unknown, Live::relayed) |
| 104 | } |
| 105 | |
| 106 | pub fn guests(&self) -> Vec<Peer> { |
| 107 | self.members |
| 108 | .room |
| 109 | .lock() |
| 110 | .unwrap() |
| 111 | .as_ref() |
| 112 | .map(Live::peers) |
| 113 | .unwrap_or_default() |
| 114 | } |
| 115 | |
| 116 | pub fn devices(&self) -> Vec<(Device, bool)> { |
| 117 | let sharing = self.members.sharing.lock().unwrap(); |
| 118 | let access = self.members.access.lock().unwrap(); |
| 119 | sharing |
| 120 | .members |
| 121 | .iter() |
| 122 | .map(|device| { |
| 123 | let connected = access |
| 124 | .get(&device.secret) |
| 125 | .is_some_and(|live| !live.peers().is_empty()); |
| 126 | (device.clone(), connected) |
| 127 | }) |
| 128 | .collect() |
| 129 | } |
| 130 | |
| 131 | pub fn requests(&self) -> Vec<Arc<Hello>> { |
| 132 | self.members |
| 133 | .pending |
| 134 | .lock() |
| 135 | .unwrap() |
| 136 | .values() |
| 137 | .map(|(hello, _)| Arc::clone(hello)) |
| 138 | .collect() |
| 139 | } |
| 140 | |
| 141 | pub fn approve(&self, approve: bool) -> io::Result<()> { |
| 142 | let mut sharing = self.members.sharing.lock().unwrap(); |
| 143 | let mut next = sharing.clone(); |
| 144 | next.approve = approve; |
| 145 | (self.members.keep)(&next)?; |
| 146 | *sharing = next; |
| 147 | drop(sharing); |
| 148 | if !approve { |
| 149 | for hello in self.requests() { |
| 150 | self.allow(&hello.peer)?; |
| 151 | } |
| 152 | } |
| 153 | (self.members.events)(); |
| 154 | Ok(()) |
| 155 | } |
| 156 | |
| 157 | pub fn allow(&self, peer: &[u8; 16]) -> io::Result<()> { |
| 158 | let pending = self.members.pending.lock().unwrap().remove(peer); |
| 159 | if let Some((hello, line)) = pending { |
| 160 | if let Err(error) = self.members.grant(&hello, &line) { |
| 161 | self.members |
| 162 | .pending |
| 163 | .lock() |
| 164 | .unwrap() |
| 165 | .insert(*peer, (hello, line)); |
| 166 | return Err(error); |
| 167 | } |
| 168 | (self.members.events)(); |
| 169 | } |
| 170 | Ok(()) |
| 171 | } |
| 172 | |
| 173 | pub fn decline(&self, peer: &[u8; 16]) { |
| 174 | if let Some((_, line)) = self.members.pending.lock().unwrap().remove(peer) { |
| 175 | let _ = line.send(kind::APPROVAL, &wire::Approval::Declined); |
| 176 | (self.members.events)(); |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | pub fn remove(&self, secret: &[u8; 16]) -> io::Result<()> { |
| 181 | let _change = self.members.changes.lock().unwrap(); |
| 182 | let mut sharing = self.members.sharing.lock().unwrap(); |
| 183 | if !sharing |
| 184 | .members |
| 185 | .iter() |
| 186 | .any(|device| device.secret == *secret) |
| 187 | { |
| 188 | return Ok(()); |
| 189 | } |
| 190 | let mut next = sharing.clone(); |
| 191 | next.members.retain(|device| device.secret != *secret); |
| 192 | getrandom::fill(&mut next.secret) |
| 193 | .map_err(|_| io::Error::other("System random source failed"))?; |
| 194 | next.code = super::super::code::secret()?; |
| 195 | (self.members.keep)(&next)?; |
| 196 | *sharing = next.clone(); |
| 197 | drop(sharing); |
| 198 | let removed = self.members.access.lock().unwrap().remove(secret); |
| 199 | if let Some(removed) = removed { |
| 200 | for peer in removed.peers() { |
| 201 | self.members.served.forget(&peer.hello.peer); |
| 202 | } |
| 203 | removed.leave("removed"); |
| 204 | } |
| 205 | self.members.presence(next.secret)?; |
| 206 | *self.pairing.lock().unwrap() = Some(self.members.pair(&next)?); |
| 207 | let access = self.members.access.lock().unwrap(); |
| 208 | for device in &next.members { |
| 209 | if let Some(live) = access.get(&device.secret) { |
| 210 | live.sender().send( |
| 211 | kind::WELCOME, |
| 212 | &self.members.welcome(&next, device.secret), |
| 213 | None, |
| 214 | ); |
| 215 | } |
| 216 | } |
| 217 | (self.members.events)(); |
| 218 | Ok(()) |
| 219 | } |
| 220 | |
| 221 | pub fn set_presence(&self, presence: Presence) { |
| 222 | if let Some(room) = &*self.members.room.lock().unwrap() { |
| 223 | room.set_presence(presence); |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | pub fn on_changed(&self, listener: crate::session::Listener) { |
| 228 | *self.members.served.host.lock().unwrap() = Some(listener); |
| 229 | } |
| 230 | |
| 231 | pub fn touched(&self, paths: &[String]) { |
| 232 | for path in paths { |
| 233 | self.members.served.changed_here(path); |
| 234 | } |
| 235 | self.members.served.tell(paths); |
| 236 | } |
| 237 | |
| 238 | pub fn stop(&self) { |
| 239 | let _change = self.members.changes.lock().unwrap(); |
| 240 | drop(self.pairing.lock().unwrap().take()); |
| 241 | self.members.pending.lock().unwrap().clear(); |
| 242 | let access = std::mem::take(&mut *self.members.access.lock().unwrap()); |
| 243 | for (_, live) in access { |
| 244 | live.leave(STOPPED); |
| 245 | } |
| 246 | drop(self.members.room.lock().unwrap().take()); |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | impl Members { |
| 251 | fn welcome(&self, sharing: &Sharing, secret: [u8; 16]) -> Welcome { |
| 252 | Welcome { |
| 253 | share: sharing.share, |
| 254 | secret, |
| 255 | room: sharing.secret, |
| 256 | notebook: self.notebook.clone(), |
| 257 | host: self.me.name.clone(), |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | fn presence(self: &Arc<Self>, secret: [u8; 16]) -> io::Result<()> { |
| 262 | let told = Arc::clone(&self.events); |
| 263 | let live = Live::start( |
| 264 | self.me.clone(), |
| 265 | &Room::Notebook(secret), |
| 266 | self.reach, |
| 267 | self.relay.as_deref(), |
| 268 | move |_| told(), |
| 269 | )?; |
| 270 | *self.served.room.lock().unwrap() = Some(live.sender()); |
| 271 | *self.room.lock().unwrap() = Some(live); |
| 272 | Ok(()) |
| 273 | } |
| 274 | |
| 275 | fn open(self: &Arc<Self>, secret: [u8; 16]) -> io::Result<()> { |
| 276 | let members = Arc::downgrade(self); |
| 277 | let live = Live::start( |
| 278 | Hello { |
| 279 | serves: Some(self.sharing.lock().unwrap().share), |
| 280 | ..self.me.clone() |
| 281 | }, |
| 282 | &Room::Notebook(secret), |
| 283 | self.reach, |
| 284 | self.relay.as_deref(), |
| 285 | move |event| { |
| 286 | let Some(members) = members.upgrade() else { |
| 287 | return; |
| 288 | }; |
| 289 | match event { |
| 290 | Event::Met(hello, line) => { |
| 291 | let sharing = members.sharing.lock().unwrap(); |
| 292 | if !sharing.members.iter().any(|device| device.secret == secret) { |
| 293 | line.hang_up("removed"); |
| 294 | return; |
| 295 | } |
| 296 | members.served.admit(hello.peer, line); |
| 297 | let _ = line.send(kind::WELCOME, &members.welcome(&sharing, secret)); |
| 298 | } |
| 299 | Event::Left(hello) => members.served.forget(&hello.peer), |
| 300 | Event::Frame { from, kind, body } |
| 301 | if wire::KNOWN.contains(&kind) && kind > 256 && kind != kind::REPLY => |
| 302 | { |
| 303 | members.served.queue(&from.peer, kind, body) |
| 304 | } |
| 305 | Event::Changed => (members.events)(), |
| 306 | _ => {} |
| 307 | } |
| 308 | }, |
| 309 | )?; |
| 310 | self.access.lock().unwrap().insert(secret, live); |
| 311 | Ok(()) |
| 312 | } |
| 313 | |
| 314 | fn grant(self: &Arc<Self>, hello: &Hello, line: &Line) -> io::Result<()> { |
| 315 | let _change = self.changes.lock().unwrap(); |
| 316 | if self.room.lock().unwrap().is_none() { |
| 317 | return Err(io::ErrorKind::NotConnected.into()); |
| 318 | } |
| 319 | let mut secret = [0; 16]; |
| 320 | getrandom::fill(&mut secret) |
| 321 | .map_err(|_| io::Error::other("System random source failed"))?; |
| 322 | if self.sharing.lock().unwrap().members.len() >= 64 { |
| 323 | return Err(io::ErrorKind::ResourceBusy.into()); |
| 324 | } |
| 325 | self.open(secret)?; |
| 326 | let kept = (|| -> io::Result<Welcome> { |
| 327 | let mut sharing = self.sharing.lock().unwrap(); |
| 328 | let mut next = sharing.clone(); |
| 329 | next.members.push(Device { |
| 330 | secret, |
| 331 | name: hello.name.clone(), |
| 332 | device: hello.device.clone(), |
| 333 | }); |
| 334 | (self.keep)(&next)?; |
| 335 | *sharing = next; |
| 336 | Ok(self.welcome(&sharing, secret)) |
| 337 | })(); |
| 338 | let welcome = match kept { |
| 339 | Ok(welcome) => welcome, |
| 340 | Err(error) => { |
| 341 | drop(self.access.lock().unwrap().remove(&secret)); |
| 342 | return Err(error); |
| 343 | } |
| 344 | }; |
| 345 | line.send(kind::WELCOME, &welcome)?; |
| 346 | (self.events)(); |
| 347 | Ok(()) |
| 348 | } |
| 349 | |
| 350 | fn pair(self: &Arc<Self>, sharing: &Sharing) -> io::Result<Live> { |
| 351 | let members = Arc::downgrade(self); |
| 352 | Live::start( |
| 353 | Hello { |
| 354 | serves: None, |
| 355 | ..self.me.clone() |
| 356 | }, |
| 357 | &Room::share(&sharing.code, &sharing.password), |
| 358 | self.reach, |
| 359 | self.relay.as_deref(), |
| 360 | move |event| { |
| 361 | let Some(members) = members.upgrade() else { |
| 362 | return; |
| 363 | }; |
| 364 | match event { |
| 365 | Event::Met(hello, line) => { |
| 366 | if members.sharing.lock().unwrap().approve { |
| 367 | let mut pending = members.pending.lock().unwrap(); |
| 368 | if pending.len() < 32 { |
| 369 | pending.insert(hello.peer, (Arc::clone(hello), line.clone())); |
| 370 | let _ = line.send(kind::APPROVAL, &wire::Approval::Pending); |
| 371 | } else { |
| 372 | let _ = line.send(kind::APPROVAL, &wire::Approval::Failed); |
| 373 | } |
| 374 | drop(pending); |
| 375 | (members.events)(); |
| 376 | } else if let Err(error) = members.grant(hello, line) { |
| 377 | eprintln!("Live Share: could not admit a device: {error}"); |
| 378 | let _ = line.send(kind::APPROVAL, &wire::Approval::Failed); |
| 379 | } |
| 380 | } |
| 381 | Event::Left(hello) => { |
| 382 | members.pending.lock().unwrap().remove(&hello.peer); |
| 383 | (members.events)(); |
| 384 | } |
| 385 | Event::Changed => (members.events)(), |
| 386 | _ => {} |
| 387 | } |
| 388 | }, |
| 389 | ) |
| 390 | } |
| 391 | } |