chiark / gitweb /
wip new account etc.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 23 Oct 2020 20:25:42 +0000 (21:25 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 23 Oct 2020 20:25:42 +0000 (21:25 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/cmdlistener.rs
src/commands.rs
src/global.rs

index bdbbef0f8956888ac2fbf8bb2c0886544dad5f51..c0fa3849543ea6c54a9ceeff61a19fa6f207ee24 100644 (file)
@@ -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<InstanceGuard, InstanceName>,
+  ) -> (&mut InstanceGuard, ModifyingPieces, Authorisation<InstanceName>)
+  {
+    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<P: Into<PermSet<TablePermission>>>(
     &mut self,
     ig: &mut Unauthorised<InstanceGuard, InstanceName>,
     how: PermissionCheckHow<'_>,
     p: P,
-  ) -> (&mut InstanceGuard, Authorisation<InstanceName>) {
-
+  ) -> (&mut InstanceGuard, Authorisation<InstanceName>)
+  {
     let subject_is = |object_account|{
       if let Some(ref subject_account_spec) = self.account {
         if subject_account_spec.account == object_account {
index 6aee23442f3dec817f2820eb72641e07b74c43d9..8f74fea5d3ddd1567c0d7175906454bca927140a 100644 (file)
@@ -152,6 +152,7 @@ pub enum MgmtError {
   GameCorrupted,
   AccountNotFound,
   PlayerNotFound,
+  AuthorisationUninitialised,
   PieceNotFound,
   LimitExceeded,
   ServerFailure(String),
index 0a3b934cc497464e8f248545da38fe4c96d4e360..e7a76e1b1812edddc09e1974e9d0ef3a24912a1f 100644 (file)
@@ -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<AccountName>)
-                             -> Option<AccessTokenReport> {
-    // xxx call this function when access changes
-
+  fn player_access_reset_redeliver(&mut self, player: PlayerId,
+                                   authorised: Authorisation<AccountName>,
+                                   reset: bool)
+                                   -> Option<AccessTokenReport> {
     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<AccountName>)
-                      -> Option<AccessTokenReport> {
     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<AccountName>)
+                             -> Option<AccessTokenReport> {
+    // 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<AccountName>)
+                                 -> Option<AccessTokenReport> {
+    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