From f7718edc7fe2a050cbfbdde2b2ad005142155e35 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Sat, 11 Feb 2023 12:07:29 -0800 Subject: [PATCH] `moonfire-nvr login --permissions`: take JSON This improves usability and shrinks the binary: 12.0 MiB to 11.0 MiB just now. --- CHANGELOG.md | 2 ++ server/src/cmds/login.rs | 52 ++++++++++++++++++++++++++++++++++------ server/src/json.rs | 8 +++---- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b9395..5bb27c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. * `DELETE /users/` endpoint to delete a user * improved API documentation in [`ref/api.md`](ref/api.md). * first draft of a web UI for user administration. Rough edges expected! +* `moonfire-nvr login --permissions` now accepts the JSON format documented + in `ref/api.md`, not an undocumented plaintext protobuf format. ## 0.7.5 (2022-05-09) diff --git a/server/src/cmds/login.rs b/server/src/cmds/login.rs index fa1dc00..4acc4f3 100644 --- a/server/src/cmds/login.rs +++ b/server/src/cmds/login.rs @@ -13,15 +13,18 @@ use std::os::unix::fs::OpenOptionsExt as _; use std::path::PathBuf; use std::str::FromStr; -fn parse_perms(perms: String) -> Result { - protobuf::text_format::parse_from_str(&perms) +fn parse_perms(perms: String) -> Result { + serde_json::from_str(&perms) } fn parse_flags(flags: String) -> Result, Error> { - flags.split(',').map(SessionFlag::from_str).collect() + flags + .split(',') + .map(|f| SessionFlag::from_str(f.trim())) + .collect() } -#[derive(Bpaf, Debug)] +#[derive(Bpaf, Debug, PartialEq, Eq)] pub struct Args { /// Directory holding the SQLite3 index database. /// @@ -29,11 +32,12 @@ pub struct Args { #[bpaf(argument("PATH"), fallback_with(crate::default_db_dir))] db_dir: PathBuf, - /// Creates a session with the given permissions. + /// Creates a session with the given permissions, as a JSON object. /// + /// E.g. `{"viewVideo": true}`. See `ref/api.md` for a description of `Permissions`. /// If unspecified, uses user's default permissions. #[bpaf(argument::("PERMS"), parse(parse_perms), optional)] - permissions: Option, + permissions: Option, /// Restricts this cookie to the given domain. #[bpaf(argument("DOMAIN"))] @@ -68,7 +72,10 @@ pub fn run(args: Args) -> Result { let u = l .get_user(&args.username) .ok_or_else(|| format_err!("no such user {:?}", &args.username))?; - let permissions = args.permissions.as_ref().unwrap_or(&u.permissions).clone(); + let permissions = args + .permissions + .map(db::Permissions::from) + .unwrap_or_else(|| u.permissions.clone()); let creation = db::auth::Request { when_sec: Some(db.clocks().realtime().sec), user_agent: None, @@ -143,6 +150,37 @@ fn curl_cookie(cookie: &str, flags: i32, domain: &str) -> String { mod tests { use super::*; + use bpaf::Parser; + + #[test] + fn parse_args() { + let args = args() + .to_options() + .run_inner(bpaf::Args::from(&[ + "--permissions", + "{\"viewVideo\": true}", + "--session-flags", + "http-only, same-site", + "--username", + "slamb", + ])) + .unwrap(); + assert_eq!( + args, + Args { + db_dir: crate::default_db_dir().unwrap(), + domain: None, + curl_cookie_jar: None, + permissions: Some(crate::json::Permissions { + view_video: true, + ..Default::default() + }), + session_flags: vec![SessionFlag::HttpOnly, SessionFlag::SameSite], + username: "slamb".to_owned(), + } + ); + } + #[test] fn test_curl_cookie() { assert_eq!( diff --git a/server/src/json.rs b/server/src/json.rs index ae992a7..8560b90 100644 --- a/server/src/json.rs +++ b/server/src/json.rs @@ -594,16 +594,16 @@ where #[serde(rename_all = "camelCase")] pub struct Permissions { #[serde(default)] - view_video: bool, + pub view_video: bool, #[serde(default)] - read_camera_configs: bool, + pub read_camera_configs: bool, #[serde(default)] - update_signals: bool, + pub update_signals: bool, #[serde(default)] - admin_users: bool, + pub admin_users: bool, } impl From for db::schema::Permissions {