feat(web): allow specifying ip/port/cert/key through the cli (#4314)

* feat(web): allow specifying ip/port/cert/key through the cli

* fix no-web
This commit is contained in:
Aram Drevekenin 2025-07-23 10:56:10 +02:00 committed by GitHub
parent 91716979e0
commit 25a684e094
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 83 additions and 13 deletions

View file

@ -1,4 +1,5 @@
use dialoguer::Confirm; use dialoguer::Confirm;
use std::net::IpAddr;
use std::{fs::File, io::prelude::*, path::PathBuf, process, time::Duration}; use std::{fs::File, io::prelude::*, path::PathBuf, process, time::Duration};
#[cfg(feature = "web_server_capability")] #[cfg(feature = "web_server_capability")]
@ -159,7 +160,14 @@ pub(crate) fn start_server(path: PathBuf, debug: bool) {
} }
#[cfg(feature = "web_server_capability")] #[cfg(feature = "web_server_capability")]
pub(crate) fn start_web_server(opts: CliArgs, run_daemonized: bool) { pub(crate) fn start_web_server(
opts: CliArgs,
run_daemonized: bool,
ip: Option<IpAddr>,
port: Option<u16>,
cert: Option<PathBuf>,
key: Option<PathBuf>,
) {
// TODO: move this outside of this function // TODO: move this outside of this function
let (config, _layout, config_options, _config_without_layout, _config_options_without_layout) = let (config, _layout, config_options, _config_without_layout, _config_options_without_layout) =
match Setup::from_cli_args(&opts) { match Setup::from_cli_args(&opts) {
@ -174,12 +182,27 @@ pub(crate) fn start_web_server(opts: CliArgs, run_daemonized: bool) {
process::exit(1); process::exit(1);
}, },
}; };
start_web_client_impl(
start_web_client_impl(config, config_options, opts.config, run_daemonized); config,
config_options,
opts.config,
run_daemonized,
ip,
port,
cert,
key,
);
} }
#[cfg(not(feature = "web_server_capability"))] #[cfg(not(feature = "web_server_capability"))]
pub(crate) fn start_web_server(_opts: CliArgs, _run_daemonized: bool) { pub(crate) fn start_web_server(
_opts: CliArgs,
_run_daemonized: bool,
_ip: Option<IpAddr>,
_port: Option<u16>,
_cert: Option<PathBuf>,
_key: Option<PathBuf>,
) {
log::error!( log::error!(
"This version of Zellij was compiled without web server support, cannot run web server!" "This version of Zellij was compiled without web server support, cannot run web server!"
); );

View file

@ -231,7 +231,14 @@ fn main() {
} else if let Some(Command::Web(web_opts)) = &opts.command { } else if let Some(Command::Web(web_opts)) = &opts.command {
if web_opts.get_start() { if web_opts.get_start() {
let daemonize = web_opts.daemonize; let daemonize = web_opts.daemonize;
commands::start_web_server(opts, daemonize); commands::start_web_server(
opts.clone(),
daemonize,
web_opts.ip,
web_opts.port,
web_opts.cert.clone(),
web_opts.key.clone(),
);
} else if web_opts.stop { } else if web_opts.stop {
match commands::stop_web_server() { match commands::stop_web_server() {
Ok(()) => { Ok(()) => {

View file

@ -67,6 +67,10 @@ pub fn start_web_client(
config_options: Options, config_options: Options,
config_file_path: Option<PathBuf>, config_file_path: Option<PathBuf>,
run_daemonized: bool, run_daemonized: bool,
custom_ip: Option<IpAddr>,
custom_port: Option<u16>,
custom_server_cert: Option<PathBuf>,
custom_server_key: Option<PathBuf>,
) { ) {
std::panic::set_hook({ std::panic::set_hook({
Box::new(move |info| { Box::new(move |info| {
@ -87,12 +91,15 @@ pub fn start_web_client(
std::process::exit(2); std::process::exit(2);
}) })
}); });
let web_server_ip = config_options let web_server_ip = custom_ip.unwrap_or_else(|| {
.web_server_ip config_options
.unwrap_or_else(|| IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); .web_server_ip
let web_server_port = config_options.web_server_port.unwrap_or_else(|| 8082); .unwrap_or_else(|| IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)))
let web_server_cert = &config.options.web_server_cert; });
let web_server_key = &config.options.web_server_key; let web_server_port =
custom_port.unwrap_or_else(|| config_options.web_server_port.unwrap_or_else(|| 8082));
let web_server_cert = custom_server_cert.or_else(|| config.options.web_server_cert.clone());
let web_server_key = custom_server_key.or_else(|| config.options.web_server_key.clone());
let has_https_certificate = web_server_cert.is_some() && web_server_key.is_some(); let has_https_certificate = web_server_cert.is_some() && web_server_key.is_some();
if let Err(e) = should_use_https( if let Err(e) = should_use_https(
@ -274,8 +281,8 @@ pub async fn serve_web_client(
fn daemonize_web_server( fn daemonize_web_server(
web_server_ip: IpAddr, web_server_ip: IpAddr,
web_server_port: u16, web_server_port: u16,
web_server_cert: &Option<PathBuf>, web_server_cert: Option<PathBuf>,
web_server_key: &Option<PathBuf>, web_server_key: Option<PathBuf>,
) -> (Runtime, std::net::TcpListener, Option<RustlsConfig>) { ) -> (Runtime, std::net::TcpListener, Option<RustlsConfig>) {
let (mut exit_message_tx, exit_message_rx) = pipe().unwrap(); let (mut exit_message_tx, exit_message_rx) = pipe().unwrap();
let (mut exit_status_tx, mut exit_status_rx) = pipe().unwrap(); let (mut exit_status_tx, mut exit_status_rx) = pipe().unwrap();

View file

@ -6,6 +6,7 @@ use crate::{
}; };
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::net::IpAddr;
use std::path::PathBuf; use std::path::PathBuf;
use url::Url; use url::Url;
@ -144,6 +145,38 @@ pub struct WebCli {
/// List token names and their creation dates (cannot show actual tokens) /// List token names and their creation dates (cannot show actual tokens)
#[clap(long, value_parser, exclusive(true), display_order = 8)] #[clap(long, value_parser, exclusive(true), display_order = 8)]
pub list_tokens: bool, pub list_tokens: bool,
/// The ip address to listen on locally for connections (defaults to 127.0.0.1)
#[clap(
long,
value_parser,
conflicts_with_all(&["stop", "status", "create-token", "revoke-token", "revoke-all-tokens"]),
display_order = 9
)]
pub ip: Option<IpAddr>,
/// The port to listen on locally for connections (defaults to 8082)
#[clap(
long,
value_parser,
conflicts_with_all(&["stop", "status", "create-token", "revoke-token", "revoke-all-tokens"]),
display_order = 10
)]
pub port: Option<u16>,
/// The path to the SSL certificate (required if not listening on 127.0.0.1)
#[clap(
long,
value_parser,
conflicts_with_all(&["stop", "status", "create-token", "revoke-token", "revoke-all-tokens"]),
display_order = 11
)]
pub cert: Option<PathBuf>,
/// The path to the SSL key (required if not listening on 127.0.0.1)
#[clap(
long,
value_parser,
conflicts_with_all(&["stop", "status", "create-token", "revoke-token", "revoke-all-tokens"]),
display_order = 12
)]
pub key: Option<PathBuf>,
} }
impl WebCli { impl WebCli {