From: Ian Jackson Date: Thu, 22 Oct 2020 21:07:38 +0000 (+0100) Subject: wip new account etc., before sort out access_reset etc. X-Git-Tag: otter-0.2.0~610 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=fe6c9421c67d32fbaca5c1fd1d328fa6d47ce14f;p=otter.git wip new account etc., before sort out access_reset etc. Signed-off-by: Ian Jackson --- diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index 07b2f062..bdbbef0f 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -59,6 +59,14 @@ struct AccountSpecified { auth: Authorisation, } +enum PermissionCheckHow<'p> { + Instance, + InstanceOrOnlyAffectedAccount(&'p AccountName), + InstanceOrOnlyAffectedPlayer(PlayerId), +} + +type PCH<'p> = PermissionCheckHow<'p>; + // ========== management API ========== // ---------- management command implementations @@ -173,11 +181,28 @@ fn execute_game_insn(cs: &CommandStream, (U{ pcs: vec![], log: vec![], raw: None }, resp) } + impl<'cs> CommandStream<'cs> { + #[throws(MgmtError)] + fn check_acl_manip_player_access( + &mut self, + ig: &mut Unauthorised, + player: PlayerId, + perm: TablePermission, + ) -> (&mut InstanceGuard, Authorisation) { + let (ig, auth) = self.check_acl(ig, + PCH::InstanceOrOnlyAffectedPlayer(player), + &[perm])?; + fn auth_map(n: &InstanceName) -> &AccountName { &n.account } + let auth = auth.map(&auth_map); + (ig, auth) + } + } + let y = match update { Noop { } => readonly(cs,ig, &[], |ig| Fine), Insn::SetTableSize(size) => { - let ig = cs.check_acl(ig, &[TP::ChangePieces])?; + let ig = cs.check_acl(ig, PCH::Instance, &[TP::ChangePieces])?.0; ig.gs.table_size = size; (U{ pcs: vec![], log: vec![ LogEntry { @@ -190,7 +215,7 @@ fn execute_game_insn(cs: &CommandStream, Insn::AddPlayer(add) => { // todo some kind of permissions check for player too - let ig = cs.check_acl(ig, &[TP::AddPlayer])?; + let ig = cs.check_acl(ig, PCH::Instance, &[TP::AddPlayer])?.0; let nick = add.nick.ok_or(ME::ParameterMissing)?; let logentry = LogEntry { html: Html(format!("{} added a player: {}", &who, @@ -240,7 +265,9 @@ fn execute_game_insn(cs: &CommandStream, RemovePlayer(account) => { // todo let you remove yourself unconditionally - let ig = cs.check_acl(ig, &[TP::RemovePlayer])?; + let ig = cs.check_acl(ig, + PCH::InstanceOrOnlyAffectedAccount(&account), + &[TP::RemovePlayer])?.0; let player = ig.gs.players.iter() .filter_map(|(k,v)| if v == &account { Some(k) } else { None }) .next() @@ -277,7 +304,10 @@ fn execute_game_insn(cs: &CommandStream, }), ResetPlayerAccess(player) => { - let token = ig.player_access_reset(player)?; + let (ig, auth) = cs.check_acl_manip_player_access + (ig, player, TP::ResetOthersAccess)?; + + let token = ig.player_access_reset(player, auth)?; (U{ pcs: vec![], log: vec![], raw: None }, @@ -285,6 +315,9 @@ fn execute_game_insn(cs: &CommandStream, } RedeliverPlayerAccess(player) => { + let (ig, auth) = cs.check_acl_manip_player_access + (ig, player, TP::RedeliverOthersAccess)?; + let token = ig.player_access_redeliver(player)?; (U{ pcs: vec![], log: vec![], @@ -614,14 +647,44 @@ impl CommandStream<'_> { self.desc, ae.0); MgmtError::AuthorisationError } +} +impl CommandStream<'_> { #[throws(MgmtError)] pub fn check_acl>>( &mut self, ig: &mut Unauthorised, + how: PermissionCheckHow<'_>, p: P, - ) -> &mut InstanceGuard { + ) -> (&mut InstanceGuard, Authorisation) { + + let subject_is = |object_account|{ + if let Some(ref subject_account_spec) = self.account { + if subject_account_spec.account == object_account { + let auth : Authorisation + = Authorisation::authorise_any(); + return auth; + } + } + return None; + }; + + if let Some(auth) = match how { + PCH::InstanceOrOnlyAffectedAccount(object_account) => { + subject_is(object_account) + }, + PCH::InstanceOrOnlyAffectedPlayer(object_player) => { + if let Some(object_account) = ig.gs.players.get(object_player) { + subject_is(object_account) + } else { + None + } + }, + } { + return self.by_mut(auth); + } + let p = p.into(); let auth = { let subject = &self.account.as_ref()?.cooked; @@ -632,7 +695,7 @@ impl CommandStream<'_> { }; eacl.check(subject, p)? }; - self.by_mut(auth); + (self.by_mut(auth), auth) } } @@ -774,6 +837,9 @@ mod authproofs { pub fn therefore_ok(self) -> Authorisation { Authorisation(PhantomData) } + + pub fn map(self, f: &fn(&T) -> &U) -> Authorisation { + } } impl From for AuthorisationError { diff --git a/src/global.rs b/src/global.rs index 03823a90..0a3b934c 100644 --- a/src/global.rs +++ b/src/global.rs @@ -613,7 +613,14 @@ impl InstanceGuard<'_> { ident : player }; 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 }; @@ -622,35 +629,6 @@ impl InstanceGuard<'_> { report.cloned() } - #[throws(MgmtError)] - pub fn players_access_report(&mut self, players: &[PlayerId]) - -> Vec> { - let mut wanted = { - let mut wanted = SecondarySlotMap::new(); - for &player in players { - wanted.insert(player, vec![]); - } - let global = GLOBAL.players.read().unwrap(); - for token in &self.tokens_players.tr { - (||{ - let iad = global.get(token)?; - let e = wanted.get_mut(iad.ident)?; - e.push(token.clone()); - Some(()) - })(); - } - wanted - }; - #[allow(clippy::or_fun_call)] - let out = players.iter().map(|&player| { - let mut tokens = wanted.remove(player) - .unwrap_or(vec![] /* dupe, somehow */); - tokens.sort_unstable(); - tokens - }).collect(); - out - } - 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 diff --git a/src/spec.rs b/src/spec.rs index bbb18ad2..ac21b38e 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -81,6 +81,8 @@ pub enum TablePermission { ViewPublic, AddPlayer, ChangePieces, + ResetOthersAccess, + RedeliverOthersAccess, RemovePlayer, ChangeACL, }