chiark / gitweb /
wip new account etc.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 24 Oct 2020 00:30:24 +0000 (01:30 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 24 Oct 2020 00:30:24 +0000 (01:30 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/accounts.rs
src/cmdlistener.rs
src/commands.rs

index 8540c47e39611f76e4a6f5ff26459d04ae3ef652..42399964be50b2607441c3a3ef7ef56a9fa88f76 100644 (file)
@@ -16,6 +16,7 @@ pub enum AccountScope {
 }
 
 type AS = AccountScope;
+type ME = MgmtError;
 
 #[derive(Debug,Clone)]
 #[derive(Eq,PartialEq,Ord,PartialOrd,Hash)]
@@ -188,9 +189,9 @@ impl AccountRecord {
   }
 
   #[throws(MgmtError)]
-  pub fn insert_entry<T, F>(account: AccountName,
-                            _auth: Authorisation<AccountName>,
-                            data: AccountRecord)
+  pub fn insert_entry(account: AccountName,
+                      _auth: Authorisation<AccountName>,
+                      data: AccountRecord)
   {
     let entry = ACCOUNTS.write().unwrap_or_default().entry(account);
     use hash_map::Entry::*;
index d5c2ce05c6dc3757f6b8b7376f8e94fe6a247818..f39fd308d467bd76cd6cf750fe070f967a95e570 100644 (file)
@@ -48,6 +48,7 @@ struct CommandStream<'d> {
   euid : Result<Uid, ConnectionEuidDiscoverEerror>,
   desc : &'d str,
   account : Option<AccountSpecified>,
+  superuser: Option<Authorisation<authproofs::Global>>,
   chan : MgmtChannel,
   who: Who,
 }
@@ -78,6 +79,30 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse {
   match cmd {
     Noop => Fine,
 
+    SetSuperuser(enable) => {
+      if !enable {
+        cs.superuser = None;
+      } else {
+        let auth = authorise_scope_direct(cs, &AccountScope::Server)?;
+        cs.superuser = Some(auth.therefore_ok());
+      }
+      Fine
+    },
+
+    CreateAccont(AccountDetails { account, nick, timezone, access }) => {
+      let auth = authorise_for_account(cs, &account)?;
+      let access = access
+        .map(Into::into)
+        .unwrap_or_else(|| Arc::new(PlayerAccessUnset) as Arc<_>);
+      let record = AccountRecord {
+        nick, access,
+        timezone: timezone.unwrap_or_default(),
+        tokens_revealed: default(),
+      };
+      AccountRecord::insert_entry(account, auth, record)?;
+      Fine
+    }
+
     SetAccount(wanted_account) => {
       let auth = authorise_scope_direct(cs, &wanted_account.scope)?;
       cs.account = Some(AccountSpecified {
@@ -88,10 +113,6 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse {
       Fine
     },
 
-    CreateAccont(AccountDetails) => {
-      let authorised = authorise_for_account(cs, &game)?;
-    }
-
     CreateGame { game, insns } => {
       let authorised = authorise_by_account(cs, &game)?;
 
@@ -620,6 +641,7 @@ impl CommandListener {
         let cs = CommandStream {
           account: None, desc: &desc,
           chan, euid: euid.map(Uid::from_raw),
+          superuser: None,
           who: Who,
         };
         cs.mainloop()?;
@@ -665,6 +687,10 @@ impl CommandStream<'_> {
 
 
 impl CommandStream<'_> {
+  pub fn is_superuser<T:Serialize>(&self) -> Option<Authorisation<T>> {
+    self.superuser.map(Into::into)
+  }
+  
   #[throws(MgmtError)]
   pub fn check_acl_modify_pieces<'ig>(
     &mut self,
@@ -746,15 +772,24 @@ impl CommandStream<'_> {
 }
 
 #[throws(MgmtError)]
-fn authorise_by_account(cs: &CommandStream, wanted: &InstanceName)
-                        -> Authorisation<InstanceName> {
+fn authorise_for_account(cs: &CommandStream, wanted: &AccountName)
+                        -> Authorisation<AccountName> {
+  if let Some(y) = cs.is_superuser() { return y }
+
   let currently = &cs.current_account()?;
-  if currently.account != wanted.account {
+  if &currently.account != wanted {
     throw!(MgmtError::AuthorisationError)
   }
   Authorisation::authorised(wanted)
 }
 
+#[throws(MgmtError)]
+fn authorise_by_account(cs: &CommandStream, wanted: &InstanceName)
+                        -> Authorisation<InstanceName> {
+  authorise_for_account(cs, &wanted.account)?
+    .therefore_ok()
+}
+
 #[throws(MgmtError)]
 fn authorise_scope_direct(cs: &CommandStream, wanted: &AccountScope)
                           -> Authorisation<AccountScope> {
@@ -766,6 +801,8 @@ fn authorise_scope_direct(cs: &CommandStream, wanted: &AccountScope)
 #[throws(AuthorisationError)]
 fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope)
                    -> Authorisation<AccountScope> {
+  if let Some(y) = cs.is_superuser() { return y }
+
   match &wanted {
 
     AccountScope::Server => {
@@ -856,6 +893,9 @@ pub use authproofs::Unauthorised;
 mod authproofs {
   use crate::imports::*;
 
+  #[derive(Copy,Clone,Debug)]
+  pub struct Global;
+
   #[derive(Debug,Copy,Clone)]
   pub struct Unauthorised<T,A> (T, PhantomData<A>);
   impl<T,A> Unauthorised<T,A> {
@@ -890,6 +930,13 @@ mod authproofs {
     }
   }
 
+  impl<T:Serialize> From<Authorisation<Global>> for Authorisation<T> {
+    // ^ we need a bound not met by Global or we conflict with From<T> for T
+    fn from(global: Authorisation<Global>) -> Self {
+      global.therefore_ok()
+    }
+  }
+
   impl From<anyhow::Error> for AuthorisationError {
     fn from(a: anyhow::Error) -> AuthorisationError {
       AuthorisationError(format!("{}",a))
index 8f74fea5d3ddd1567c0d7175906454bca927140a..6eb1a25338d455f5e6613669a305a5cf995fce1e 100644 (file)
@@ -7,6 +7,7 @@ use crate::imports::*;
 #[derive(Debug,Serialize,Deserialize)]
 pub enum MgmtCommand {
   Noop,
+  SetSuperuser(bool),
 
   CreateAccont(AccountDetails),
   UpdateAccont(AccountDetails),