From: Ian Jackson Date: Fri, 23 Oct 2020 20:25:42 +0000 (+0100) Subject: wip new account etc. X-Git-Tag: otter-0.2.0~609 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=6bb0340e44f519cdc5a860d56c850fd52858db36;p=otter.git wip new account etc. Signed-off-by: Ian Jackson --- diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index bdbbef0f..c0fa3849 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -176,7 +176,7 @@ fn execute_game_insn(cs: &CommandStream, f: F ) -> ExecuteGameInsnResults { - let ig = cs.check_acl(p)?; + let ig = cs.check_acl(ig, PCH::InstanceOnly, p)?; let resp = f(ig); (U{ pcs: vec![], log: vec![], raw: None }, resp) } @@ -318,7 +318,7 @@ fn execute_game_insn(cs: &CommandStream, let (ig, auth) = cs.check_acl_manip_player_access (ig, player, TP::RedeliverOthersAccess)?; - let token = ig.player_access_redeliver(player)?; + let token = ig.player_access_redeliver(player, auth)?; (U{ pcs: vec![], log: vec![], raw: None }, @@ -343,8 +343,8 @@ fn execute_game_insn(cs: &CommandStream, */ DeletePiece(piece) => { - let modperm = ig.modify_pieces(); - let p = ig.pieces.as_mut(modperm) + let (ig, modperm, _) = cs.check_acl_modify_pieces(ig)?; + let p = ig.ipieces.as_mut(modperm) .remove(piece).ok_or(ME::PieceNotFound)?; let gs = &mut ig.gs; let pc = gs.pieces.as_mut(modperm).remove(piece); @@ -360,7 +360,7 @@ fn execute_game_insn(cs: &CommandStream, }, AddPieces(PiecesSpec{ pos,posd,count,face,pinned,info }) => { - let modperm = ig.modify_pieces(); + let (ig, modperm, _) = cs.check_acl_modify_pieces(ig)?; let ig = &mut **ig; let gs = &mut ig.gs; let count = count.unwrap_or(1); @@ -389,7 +389,7 @@ fn execute_game_insn(cs: &CommandStream, throw!(SpecError::PosOffTable); } let piece = gs.pieces.as_mut(modperm).insert(pc); - ig.pieces.as_mut(modperm).insert(piece, p); + ig.ipieces.as_mut(modperm).insert(piece, p); updates.push((piece, PieceUpdateOp::Insert(()))); pos += posd; } @@ -651,14 +651,26 @@ impl CommandStream<'_> { impl CommandStream<'_> { + #[throws(MgmtError)] + pub fn check_acl_modify_pieces( + &mut self, + ig: &mut Unauthorised, + ) -> (&mut InstanceGuard, ModifyingPieces, Authorisation) + { + let p = &[TP::ChangePieces]; + let (ig, auth) = self.check_acl(self, PCH::Instance, p)?; + let modperm = ig.modify_pieces(); + (ig, modperm, auth) + } + #[throws(MgmtError)] pub fn check_acl>>( &mut self, ig: &mut Unauthorised, how: PermissionCheckHow<'_>, p: P, - ) -> (&mut InstanceGuard, Authorisation) { - + ) -> (&mut InstanceGuard, Authorisation) + { let subject_is = |object_account|{ if let Some(ref subject_account_spec) = self.account { if subject_account_spec.account == object_account { diff --git a/src/commands.rs b/src/commands.rs index 6aee2344..8f74fea5 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -152,6 +152,7 @@ pub enum MgmtError { GameCorrupted, AccountNotFound, PlayerNotFound, + AuthorisationUninitialised, PieceNotFound, LimitExceeded, ServerFailure(String), diff --git a/src/global.rs b/src/global.rs index 0a3b934c..e7a76e1b 100644 --- a/src/global.rs +++ b/src/global.rs @@ -9,6 +9,8 @@ use crate::imports::*; use std::sync::PoisonError; use slotmap::dense as sm; +type ME = MgmtError; + // ---------- newtypes and type aliases ---------- visible_slotmap_key!{ ClientId('C') } @@ -572,15 +574,13 @@ impl InstanceGuard<'_> { } #[throws(MgmtError)] - pub fn player_access_reset(&mut self, player: PlayerId, - authorised: Authorisation) - -> Option { - // xxx call this function when access changes - + fn player_access_reset_redeliver(&mut self, player: PlayerId, + authorised: Authorisation, + reset: bool) + -> Option { let pst = self.c.g.iplayers.get(player) .ok_or(MgmtError::PlayerNotFound)? .pst; - self.save_access_now()?; let access = AccountRecord::with_entry_mut( &pst.account, authorised, @@ -600,27 +600,55 @@ impl InstanceGuard<'_> { Ok::<_,MgmtError>(access.clone()) }).map_err(|(e,_)|e)??; - let token = access - .override_token() - .cloned() - .unwrap_or_else(||{ - RawToken::new_random() - // xxx disconnect everyone else - }); + if reset { + self.save_access_now()?; + } - let iad = InstanceAccessDetails { - gref : self.gref.clone(), - ident : player + let token : RawToken = if reset { + + let token = access + .override_token() + .cloned() + .unwrap_or_else(||{ + RawToken::new_random() + // xxx disconnect everyone else + }); + + let iad = InstanceAccessDetails { + gref : self.gref.clone(), + ident : player + }; + self.token_register(token.clone(), iad); + + token + + } else { + + let tokens : ArrayVec<[&RawToken;2]> = { + let players = GLOBAL.players.read().unwrap(); + self.tokens_players.tr.iter(). + filter(|&token| (||{ + let iad = players.get(token)?; + if iad.ident != player { return None } + if ! Arc::ptr_eq(&iad.gref.0, &self.gref.0) { return None } + Some(()) + })() == Some(())) + .take(2) + .collect() + }; + + let token = match tokens.as_slice() { + [] => throw!(ME::AuthorisationUninitialised), + [&token] => token, + _ => { + warn!("duplicate token for {}", player); + throw!(ME::ServerFailure("duplicate token".to_string())); + }, + }; + + token.clone() }; - self.token_register(token.clone(), iad); - self.access_redeliver(player, token, authorised)? - } - #[throws(MgmtError)] - fn access_redeliver(&mut self, player: PlayerId, - token: &RawToken, - authorised: Authorisation) - -> Option { let report = AccessTokenReport { url: format!("http://localhost:8000/{}", token.0), // xxx }; @@ -629,6 +657,21 @@ impl InstanceGuard<'_> { report.cloned() } + #[throws(MgmtError)] + pub fn player_access_reset(&mut self, player: PlayerId, + auth: Authorisation) + -> Option { + // xxx call this function when access method changes + self.player_access_reset_redeliver(player, auth, true)? + } + + #[throws(MgmtError)] + pub fn player_access_redeliver(&mut self, player: PlayerId, + auth: Authorisation) + -> Option { + self.player_access_reset_redeliver(player, auth, false)? + } + pub fn modify_pieces(&mut self) -> ModifyingPieces { self.save_game_and_access_later(); // want this to be borrowed from self, so that we tie it properly