From 2037d9af038a841ca9a94eea1b85d0d198b61613 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Mon, 22 Feb 2021 12:01:24 +0100 Subject: [PATCH] api-viewer: show permissions --- docs/api-viewer/PBSAPI.js | 66 ++++++++++++++++++++++++++------------ src/bin/docgen.rs | 67 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 22 deletions(-) diff --git a/docs/api-viewer/PBSAPI.js b/docs/api-viewer/PBSAPI.js index b728e302..60296a28 100644 --- a/docs/api-viewer/PBSAPI.js +++ b/docs/api-viewer/PBSAPI.js @@ -110,6 +110,45 @@ Ext.onReady(function() { return path.replace(/^.*\/_upgrade_(\/)?/, "/"); }; + var permission_text = function(permission) { + let permhtml = ""; + + if (permission.user) { + if (!permission.description) { + if (permission.user === 'world') { + permhtml += "Accessible without any authentication."; + } else if (permission.user === 'all') { + permhtml += "Accessible by all authenticated users."; + } else { + permhtml += 'Onyl accessible by user "' + + permission.user + '"'; + } + } + } else if (permission.check) { + permhtml += "
Check: " +
+		Ext.htmlEncode(Ext.JSON.encode(permission.check))  + "
"; + } else if (permission.userParam) { + permhtml += `
Check if user matches parameter '${permission.userParam}'`; + } else if (permission.or) { + permhtml += "
Or
"; + Ext.Array.each(permission.or, function(sub_permission) { + permhtml += permission_text(sub_permission); + }) + permhtml += "
"; + } else if (permission.and) { + permhtml += "
And
"; + Ext.Array.each(permission.and, function(sub_permission) { + permhtml += permission_text(sub_permission); + }) + permhtml += "
"; + } else { + //console.log(permission); + permhtml += "Unknown systax!"; + } + + return permhtml; + }; + var render_docu = function(data) { var md = data.info; @@ -339,28 +378,13 @@ Ext.onReady(function() { permhtml += "
" + Ext.htmlEncode(info.permissions.description) + "
"; } + permhtml += permission_text(info.permissions); + } - if (info.permissions.user) { - if (!info.permissions.description) { - if (info.permissions.user === 'world') { - permhtml += "Accessible without any authentication."; - } else if (info.permissions.user === 'all') { - permhtml += "Accessible by all authenticated users."; - } else { - permhtml += 'Onyl accessible by user "' + - info.permissions.user + '"'; - } - } - } else if (info.permissions.check) { - permhtml += "
Check: " +
-			    Ext.htmlEncode(Ext.JSON.encode(info.permissions.check))  + "
"; - } else { - permhtml += "Unknown systax!"; - } - } - if (!info.allowtoken) { - permhtml += "
This API endpoint is not available for API tokens." - } + // we do not have this information for PBS api + //if (!info.allowtoken) { + // permhtml += "
This API endpoint is not available for API tokens." + //} sections.push({ title: 'Required permissions', diff --git a/src/bin/docgen.rs b/src/bin/docgen.rs index 8a60f3a0..1499fee0 100644 --- a/src/bin/docgen.rs +++ b/src/bin/docgen.rs @@ -9,6 +9,9 @@ use proxmox::{ SchemaPropertyEntry, ApiStringFormat, }, + router::{ + ApiAccess, + }, format::{ dump_enum_properties, dump_section_config, @@ -18,12 +21,16 @@ use proxmox::{ ApiHandler, Router, SubRoute, + Permission, }, }; use proxmox_backup::{ api2, - config, + config::{ + self, + acl::PRIVILEGES, + }, }; fn get_args() -> (String, Vec) { @@ -235,6 +242,51 @@ pub fn dump_property_schema( data } +fn dump_api_permission(permission: &Permission) -> Value { + + match permission { + Permission::Superuser => json!({ "user": "root@pam" }), + Permission::User(user) => json!({ "user": user }), + Permission::Anybody => json!({ "user": "all" }), + Permission::World => json!({ "user": "world" }), + Permission::UserParam(param) => json!({ "userParam": param }), + Permission::Group(group) => json!({ "group": group }), + Permission::WithParam(param, sub_permission) => { + json!({ + "withParam": { + "name": param, + "permissions": dump_api_permission(sub_permission), + }, + }) + } + Permission::Privilege(name, value, partial) => { + + let mut privs = Vec::new(); + for (name, v) in PRIVILEGES { + if (value & v) != 0 { + privs.push(name.to_string()); + } + } + + json!({ + "check": { + "path": name, + "privs": privs, + "partial": partial, + } + }) + } + Permission::And(list) => { + let list: Vec = list.iter().map(|p| dump_api_permission(p)).collect(); + json!({ "and": list }) + } + Permission::Or(list) => { + let list: Vec = list.iter().map(|p| dump_api_permission(p)).collect(); + json!({ "or": list }) + } + } +} + fn dump_api_method_schema( method: &str, api_method: &ApiMethod, @@ -251,6 +303,19 @@ fn dump_api_method_schema( } data["returns"] = returns; + match api_method.access { + ApiAccess { description: None, permission: Permission::Superuser } => { + // no need to output default + } + ApiAccess { description, permission } => { + let mut permissions = dump_api_permission(permission); + if let Some(description) = description { + permissions["description"] = description.into(); + } + data["permissions"] = permissions; + } + } + let mut method = method; if let ApiHandler::AsyncHttp(_) = api_method.handler {