From: Ian Jackson Date: Sat, 7 Nov 2020 21:20:12 +0000 (+0000) Subject: wip new game joining X-Git-Tag: otter-0.2.0~549 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=960606763e6dad8d2c8ebcca3a60e98a852bedf1;p=otter.git wip new game joining Signed-off-by: Ian Jackson --- diff --git a/src/accounts.rs b/src/accounts.rs index 3ca4d13f..e931b0c8 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -46,7 +46,7 @@ impl AccountScope { (&'out self, ns: NS, mut f: F) { const ENCODE : percent_encoding::AsciiSet = - percent_encoding::NON_ALPHANUMERIC.remove(b':'); + percent_encoding::NON_ALPHANUMERIC; match &self { AS::Server => { @@ -59,6 +59,7 @@ impl AccountScope { }, }; for n in ns { + f(":")?; for frag in utf8_percent_encode(n, &ENCODE) { f(frag)?; } diff --git a/src/bin/otter.rs b/src/bin/otter.rs index 49a9412f..af88ef45 100644 --- a/src/bin/otter.rs +++ b/src/bin/otter.rs @@ -354,8 +354,40 @@ fn connect(ma: &MainOpts) -> Conn { chan } +const PLAYER_ALWAYS_PERMS : &[Perm] = [ + TP::TestExistence, + TP::ViewPublic, + TP::AddPlayer, +]; + +const PLAYER_DEFAULT_PERMS : &[Perm] = [ + TP::ChangePiecse +]; + fn setup_table(ma: &MainOpts, chan: &mut ConnForGame, - spec: &TableSpec) -> Result<(),AE> { + spec: &TableSpec, purge_old_players: bool) -> Result<(),AE> { + let TableSpec { players, player_perms, timezone } = spec; + let mut player_perms = player_perms.clone() + .unwrap_or(PLAYER_DEFAULT_PERMS.iter().collect()); + player_perms.extend(PLAYER_ALWAYS_PERMS.iter()); + + let mut acl = + players.iter().map(|tps| AclEntry { + account_glob: tps.account_glob(); + allow: player_perms.clone(), + deny: default() + }) + .chain( + spec.acl.iter() + ) + .collect(); + + let mut insns = vec![]; + insns.push(MGI::SetACL { acl }); + isnns.push(MGI::SetTimezone { tz: timezone.clone() }); + + + let (_, nick2id) = chan.get_info()?; #[derive(Default)] @@ -366,7 +398,6 @@ fn setup_table(ma: &MainOpts, chan: &mut ConnForGame, .map(|(nick,id)| (nick, St { id, old: true, new: false })) .collect(); - let mut insns = vec![]; for pspec in &spec.players { let nick = pspec.nick.unwrap_or_else(|| pspec.account.default_nick()); let st = nick2st.entry(nick.clone()).or_default(); diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index 7178d3de..8884b43e 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -295,17 +295,16 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>( Fine, ig) } - Insn::AddPlayer { - account, + Insn::JoinGame { details: MgmtPlayerDetails { timezone, nick } } => { - // todo some kind of permissions check for player too + let account = &cs.current_account()?.notional_account; + let (_arecord, acctid) = ag.lookup(account)?; let (ig, auth) = cs.check_acl(ag, ig, PCH::Instance, &[TP::AddPlayer])?; - let (_arecord, acctid) = ag.lookup(&account)?; let nick = nick.ok_or(ME::ParameterMissing)?; let logentry = LogEntry { - html: Html(format!("{} added a player: {}", &who, - htmlescape::encode_minimal(&nick))), + html: Html(format!("{} ({}) joined the game", + &nick, &account)), }; let timezone = timezone.as_ref().map(String::as_str) .unwrap_or(""); @@ -324,7 +323,7 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>( (U{ pcs: vec![], log: vec![ logentry ], raw: None }, - Resp::AddPlayer { account, nick, player, token: atr }, + Resp::JoinGame { nick, player, token: atr }, ig) }, diff --git a/src/commands.rs b/src/commands.rs index 66b9b4bc..23e1d7e6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -78,9 +78,12 @@ pub enum MgmtGameInstruction { // xxx ^ prevent use of Fixed when not wanted RedeliverPlayerAccess(PlayerId), - AddPlayer { account: AccountName, details: MgmtPlayerDetails }, + JoinGame { details: MgmtPlayerDetails }, UpdatePlayer { player: PlayerId, details: MgmtPlayerDetails }, RemovePlayer { player: PlayerId }, + + SetACL { acl: Acl }, + SetTimezone { tz: String }, } // xxx facilitator name? @@ -98,9 +101,10 @@ pub enum MgmtGameResponse { Pieces(Vec), - AddPlayer { - #[serede(flatten)] info: MgmtPlayerInfo, - player: PlayerId, token: Option, + JoinGame { + nick: String, + player: PlayerId, + token: Option, }, PlayerAccessToken(Option), } diff --git a/src/spec.rs b/src/spec.rs index 39d7c075..9b2afc5d 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -61,14 +61,15 @@ display_as_debug!{SpecError} #[derive(Debug,Serialize,Deserialize)] pub struct TableSpec { #[serde(default)] pub players: Vec, - #[serde(default)] pub acl: Acl, + pub player_perms: Option>, + #[serde(default)] pub acl: Acl, pub timezone: Option, } #[derive(Debug,Serialize,Deserialize)] #[serde(rename_all="snake_case")] pub enum TablePlayerSpec { - Account(String), + Account(AccountName), AccountGlob(String), Local(String), AllLocal, @@ -266,6 +267,23 @@ pub mod implementation { const NOT_FOUND : MgmtError = MgmtError::GameNotFound; } + impl TablePlayerSpec { + fn account_glob(&self) -> String { + fn scope_glob(scope: AccountScope) -> String { + foramt!("{}:*", &scope) + } + match self { + Account(account) => account.to_string(), + AccountGlob(s) => s.clone(), + Local(user) => scope_glob(AS::Unix { user: user.clone() }), + AllLocal => { + // abuse that usernames are not encoded + scope_glob(AS::Unix { user: "*".clone() }) + }, + } + } + } + type TDE = TokenDeliveryError; pub fn raw_token_debug_as_str(s: &str, f: &mut fmt::Formatter)