summaryrefslogtreecommitdiffstats
path: root/zellij-server/src/panes
diff options
context:
space:
mode:
authorJae-Heon Ji <32578710+jaeheonji@users.noreply.github.com>2023-08-12 22:35:42 +0900
committerGitHub <noreply@github.com>2023-08-12 15:35:42 +0200
commitc8ddb23297e2f4fc900b8286d57e2808ae6a4fdb (patch)
treec96d26c8bfc24172374aefe88624b78c6890663f /zellij-server/src/panes
parenta1903b6b048f8257fc16ffd09e19c825248cb9d6 (diff)
feat: add plugin permission system (#2624)
* WIP: add exaple of permission ui * feat: add request permission ui * feat: add caching permission in memory * feat: add permission check * feat: add file caching * fix: changes request * feat(ui): new status bar mode (#2619) * supermode prototype * fix integration tests * fix tests * style(fmt): rustfmt * docs(changelog): status-bar supermode * fix(rendering): occasional glitches while resizing (#2621) * docs(changelog): resize glitches fix * chore(version): bump development version * Fix colored pane frames in mirrored sessions (#2625) * server/panes/tiled: Fix colored frames in mirrored sessions. Colored frames were previously ignored because they were treated like floating panes when rendering tiled panes. * CHANGELOG: Add PR #2625 * server/tab/unit: Fix unit tests for server. * fix(sessions): use custom lists of adjectives and nouns for generating session names (#2122) * Create custom lists of adjectives and nouns for generating session names * move word lists to const slices * add logic to retry name generation * refactor - reuse the name generator - iterator instead of for loop --------- Co-authored-by: Thomas Linford <linford.t@gmail.com> * docs(changelog): generate session names with custom words list * feat(plugins): make plugins configurable (#2646) * work * make every plugin entry point configurable * make integration tests pass * make e2e tests pass * add test for plugin configuration * add test snapshot * add plugin config parsing test * cleanups * style(fmt): rustfmt * style(comment): remove commented code * docs(changelog): configurable plugins * style(fmt): rustfmt * touch up ui * fix: don't save permission data in memory * feat: load cached permission * test: add example test (WIP) * fix: issue event are always denied * test: update snapshot * apply formatting * refactor: update default cache function * test: add more new test * apply formatting * Revert "apply formatting" This reverts commit a4e93703fbfdb6865131daa1c8b90fc5c36ab25e. * apply format * fix: update cache path * apply format * fix: cache path * fix: update log level * test for github workflow * Revert "test for github workflow" This reverts commit 01eff3bc5d1627a4e60bc6dac8ebe5500bc5b56e. * refactor: permission cache * fix(test): permission grant/deny race condition * style(fmt): rustfmt * style(fmt): rustfmt * configure permissions * permission denied test * snapshot * add ui for small plugins * style(fmt): rustfmt * some cleanups --------- Co-authored-by: Aram Drevekenin <aram@poor.dev> Co-authored-by: har7an <99636919+har7an@users.noreply.github.com> Co-authored-by: Kyle Sutherland-Cash <kyle.sutherlandcash@gmail.com> Co-authored-by: Thomas Linford <linford.t@gmail.com> Co-authored-by: Thomas Linford <tlinford@users.noreply.github.com>
Diffstat (limited to 'zellij-server/src/panes')
-rw-r--r--zellij-server/src/panes/floating_panes/mod.rs8
-rw-r--r--zellij-server/src/panes/plugin_pane.rs101
-rw-r--r--zellij-server/src/panes/tiled_panes/mod.rs2
3 files changed, 102 insertions, 9 deletions
diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs
index 2de5b74eb..1f2d770bb 100644
--- a/zellij-server/src/panes/floating_panes/mod.rs
+++ b/zellij-server/src/panes/floating_panes/mod.rs
@@ -295,7 +295,7 @@ impl FloatingPanes {
pane.render_full_viewport();
}
}
- pub fn set_pane_frames(&mut self, os_api: &mut Box<dyn ServerOsApi>) -> Result<()> {
+ pub fn set_pane_frames(&mut self, _os_api: &mut Box<dyn ServerOsApi>) -> Result<()> {
let err_context =
|pane_id: &PaneId| format!("failed to activate frame on pane {pane_id:?}");
@@ -392,7 +392,7 @@ impl FloatingPanes {
self.set_force_render();
}
- pub fn resize_pty_all_panes(&mut self, os_api: &mut Box<dyn ServerOsApi>) -> Result<()> {
+ pub fn resize_pty_all_panes(&mut self, _os_api: &mut Box<dyn ServerOsApi>) -> Result<()> {
for pane in self.panes.values_mut() {
resize_pty!(pane, os_api, self.senders, self.character_cell_size)
.with_context(|| format!("failed to resize PTY in pane {:?}", pane.pid()))?;
@@ -403,7 +403,7 @@ impl FloatingPanes {
pub fn resize_active_pane(
&mut self,
client_id: ClientId,
- os_api: &mut Box<dyn ServerOsApi>,
+ _os_api: &mut Box<dyn ServerOsApi>,
strategy: &ResizeStrategy,
) -> Result<bool> {
// true => successfully resized
@@ -838,7 +838,7 @@ impl FloatingPanes {
self.focus_pane_for_all_clients(focused_pane);
}
}
- pub fn switch_active_pane_with(&mut self, os_api: &mut Box<dyn ServerOsApi>, pane_id: PaneId) {
+ pub fn switch_active_pane_with(&mut self, _os_api: &mut Box<dyn ServerOsApi>, pane_id: PaneId) {
if let Some(active_pane_id) = self.first_active_floating_pane_id() {
let current_position = self.panes.get(&active_pane_id).unwrap();
let prev_geom = current_position.position_and_size();
diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs
index 465529609..b4e3461e2 100644
--- a/zellij-server/src/panes/plugin_pane.rs
+++ b/zellij-server/src/panes/plugin_pane.rs
@@ -1,11 +1,11 @@
-use std::collections::HashMap;
+use std::collections::{BTreeSet, HashMap};
use std::time::Instant;
use crate::output::{CharacterChunk, SixelImageChunk};
use crate::panes::{grid::Grid, sixel::SixelImageStore, LinkHandler, PaneId};
use crate::plugins::PluginInstruction;
use crate::pty::VteBytes;
-use crate::tab::Pane;
+use crate::tab::{AdjustedInput, Pane};
use crate::ui::{
loading_indication::LoadingIndication,
pane_boundaries_frame::{FrameParams, PaneFrame},
@@ -13,6 +13,7 @@ use crate::ui::{
use crate::ClientId;
use std::cell::RefCell;
use std::rc::Rc;
+use zellij_utils::data::{PermissionStatus, PermissionType, PluginPermission};
use zellij_utils::pane_size::{Offset, SizeInPixels};
use zellij_utils::position::Position;
use zellij_utils::{
@@ -25,6 +26,15 @@ use zellij_utils::{
vte,
};
+macro_rules! style {
+ ($fg:expr) => {
+ ansi_term::Style::new().fg(match $fg {
+ PaletteColor::Rgb((r, g, b)) => ansi_term::Color::RGB(r, g, b),
+ PaletteColor::EightBit(color) => ansi_term::Color::Fixed(color),
+ })
+ };
+}
+
macro_rules! get_or_create_grid {
($self:ident, $client_id:ident) => {{
let rows = $self.get_content_rows();
@@ -73,6 +83,7 @@ pub(crate) struct PluginPane {
pane_frame_color_override: Option<(PaletteColor, Option<String>)>,
invoked_with: Option<Run>,
loading_indication: LoadingIndication,
+ requesting_permissions: Option<PluginPermission>,
debug: bool,
}
@@ -121,6 +132,7 @@ impl PluginPane {
pane_frame_color_override: None,
invoked_with,
loading_indication,
+ requesting_permissions: None,
debug,
};
for client_id in currently_connected_clients {
@@ -181,6 +193,14 @@ impl Pane for PluginPane {
}
fn handle_plugin_bytes(&mut self, client_id: ClientId, bytes: VteBytes) {
self.set_client_should_render(client_id, true);
+
+ let mut vte_bytes = bytes;
+ if let Some(plugin_permission) = &self.requesting_permissions {
+ vte_bytes = self
+ .display_request_permission_message(plugin_permission)
+ .into();
+ }
+
let grid = get_or_create_grid!(self, client_id);
// this is part of the plugin contract, whenever we update the plugin and call its render function, we delete the existing viewport
@@ -193,14 +213,36 @@ impl Pane for PluginPane {
.vte_parsers
.entry(client_id)
.or_insert_with(|| vte::Parser::new());
- for &byte in &bytes {
+
+ for &byte in &vte_bytes {
vte_parser.advance(grid, byte);
}
+
self.should_render.insert(client_id, true);
}
fn cursor_coordinates(&self) -> Option<(usize, usize)> {
None
}
+ fn adjust_input_to_terminal(&mut self, input_bytes: Vec<u8>) -> Option<AdjustedInput> {
+ if let Some(requesting_permissions) = &self.requesting_permissions {
+ let permissions = requesting_permissions.permissions.clone();
+ match input_bytes.as_slice() {
+ // Y or y
+ &[89] | &[121] => Some(AdjustedInput::PermissionRequestResult(
+ permissions,
+ PermissionStatus::Granted,
+ )),
+ // N or n
+ &[78] | &[110] => Some(AdjustedInput::PermissionRequestResult(
+ permissions,
+ PermissionStatus::Denied,
+ )),
+ _ => None,
+ }
+ } else {
+ Some(AdjustedInput::WriteBytesToTerminal(input_bytes))
+ }
+ }
fn position_and_size(&self) -> PaneGeom {
self.geom
}
@@ -233,6 +275,9 @@ impl Pane for PluginPane {
fn set_selectable(&mut self, selectable: bool) {
self.selectable = selectable;
}
+ fn request_permissions_from_user(&mut self, permissions: Option<PluginPermission>) {
+ self.requesting_permissions = permissions;
+ }
fn render(
&mut self,
client_id: Option<ClientId>,
@@ -595,4 +640,54 @@ impl PluginPane {
self.handle_plugin_bytes(client_id, bytes.clone());
}
}
+ fn display_request_permission_message(&self, plugin_permission: &PluginPermission) -> String {
+ let bold_white = style!(self.style.colors.white).bold();
+ let cyan = style!(self.style.colors.cyan).bold();
+ let orange = style!(self.style.colors.orange).bold();
+ let green = style!(self.style.colors.green).bold();
+
+ let mut messages = String::new();
+ let permissions: BTreeSet<PermissionType> =
+ plugin_permission.permissions.clone().into_iter().collect();
+
+ let min_row_count = permissions.len() + 4;
+
+ if self.rows() >= min_row_count {
+ messages.push_str(&format!(
+ "{} {} {}\n",
+ bold_white.paint("Plugin"),
+ cyan.paint(&plugin_permission.name),
+ bold_white.paint("asks permission to:"),
+ ));
+ permissions.iter().enumerate().for_each(|(i, p)| {
+ messages.push_str(&format!(
+ "\n\r{}. {}",
+ bold_white.paint(&format!("{}", i + 1)),
+ orange.paint(p.display_name())
+ ));
+ });
+
+ messages.push_str(&format!(
+ "\n\n\r{} {}",
+ bold_white.paint("Allow?"),
+ green.paint("(y/n)"),
+ ));
+ } else {
+ messages.push_str(&format!(
+ "{} {}. {} {}\n",
+ bold_white.paint("This plugin asks permission to:"),
+ orange.paint(
+ permissions
+ .iter()
+ .map(|p| p.to_string())
+ .collect::<Vec<_>>()
+ .join(", ")
+ ),
+ bold_white.paint("Allow?"),
+ green.paint("(y/n)"),
+ ));
+ }
+
+ messages
+ }
}
diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs
index 9aca1af4a..736c16bc9 100644
--- a/zellij-server/src/panes/tiled_panes/mod.rs
+++ b/zellij-server/src/panes/tiled_panes/mod.rs
@@ -68,7 +68,6 @@ pub struct TiledPanes {
draw_pane_frames: bool,
panes_to_hide: HashSet<PaneId>,
fullscreen_is_active: bool,
- os_api: Box<dyn ServerOsApi>,
senders: ThreadSenders,
window_title: Option<String>,
client_id_to_boundaries: HashMap<ClientId, Boundaries>,
@@ -105,7 +104,6 @@ impl TiledPanes {
draw_pane_frames,
panes_to_hide: HashSet::new(),
fullscreen_is_active: false,
- os_api,
senders,
window_title: None,
client_id_to_boundaries: HashMap::new(),