1use crate::highlighter::CompiledHighlightRule;
7use regex::{Regex, RegexSet};
8use serde::{Deserialize, Deserializer};
9use std::{collections::HashMap, path::PathBuf};
10
11#[derive(Debug, Deserialize)]
13#[serde(deny_unknown_fields)]
14pub struct Config {
15 #[serde(default)]
17 pub settings: Settings,
18 #[serde(default)]
20 pub auth_settings: AuthSettings,
21 #[serde(default)]
23 pub interactive_settings: Option<InteractiveSettings>,
24 pub palette: HashMap<String, String>,
26 pub rules: Vec<HighlightRule>,
28 #[serde(default)]
30 pub metadata: Metadata,
31}
32
33#[derive(Debug, Deserialize)]
35#[serde(deny_unknown_fields)]
36pub struct Settings {
37 #[serde(default)]
39 pub remove_secrets: Option<Vec<String>>,
40 #[serde(default = "default_show_title")]
42 pub show_title: bool,
43 #[serde(default)]
45 pub debug_mode: bool,
46 #[serde(default)]
48 pub ssh_logging: bool,
49}
50
51impl Default for Settings {
52 fn default() -> Self {
53 Self {
54 remove_secrets: None,
55 show_title: true,
56 debug_mode: false,
57 ssh_logging: false,
58 }
59 }
60}
61
62#[derive(Debug, Clone, Deserialize)]
64#[serde(deny_unknown_fields)]
65pub struct AuthSettings {
66 #[serde(default = "default_idle_timeout_seconds")]
68 pub idle_timeout_seconds: u64,
69 #[serde(default = "default_session_timeout_seconds")]
71 pub session_timeout_seconds: u64,
72 #[serde(default = "default_direct_password_autologin")]
74 pub direct_password_autologin: bool,
75 #[serde(default = "default_tui_password_autologin")]
77 pub tui_password_autologin: bool,
78}
79
80impl Default for AuthSettings {
81 fn default() -> Self {
82 Self {
83 idle_timeout_seconds: default_idle_timeout_seconds(),
84 session_timeout_seconds: default_session_timeout_seconds(),
85 direct_password_autologin: default_direct_password_autologin(),
86 tui_password_autologin: default_tui_password_autologin(),
87 }
88 }
89}
90
91#[derive(Debug, Deserialize, Default)]
93#[serde(deny_unknown_fields)]
94pub struct InteractiveSettings {
95 #[serde(default = "default_history_buffer")]
97 pub history_buffer: usize,
98 #[serde(default = "default_host_tree_uncollapsed")]
101 pub host_tree_uncollapsed: bool,
102 #[serde(default = "default_info_view")]
104 pub info_view: bool,
105 #[serde(default = "default_host_view_size", deserialize_with = "deserialize_host_view_size")]
107 pub host_view_size: u16,
108 #[serde(default = "default_info_view_size", deserialize_with = "deserialize_info_view_size")]
110 pub info_view_size: u16,
111 #[serde(default = "default_remote_clipboard_write")]
114 pub allow_remote_clipboard_write: bool,
115 #[serde(default = "default_remote_clipboard_max_bytes", deserialize_with = "deserialize_remote_clipboard_max_bytes")]
117 pub remote_clipboard_max_bytes: usize,
118}
119
120fn default_show_title() -> bool {
121 true
122}
123
124fn default_history_buffer() -> usize {
125 1000
126}
127
128fn default_idle_timeout_seconds() -> u64 {
129 900
130}
131
132fn default_session_timeout_seconds() -> u64 {
133 28_800
134}
135
136fn default_direct_password_autologin() -> bool {
137 true
138}
139
140fn default_tui_password_autologin() -> bool {
141 true
142}
143
144fn default_host_tree_uncollapsed() -> bool {
145 false
146}
147
148fn default_info_view() -> bool {
149 true
150}
151
152fn default_host_view_size() -> u16 {
153 25
154}
155
156fn default_info_view_size() -> u16 {
157 40
158}
159
160fn default_remote_clipboard_write() -> bool {
161 false
162}
163
164fn default_remote_clipboard_max_bytes() -> usize {
165 4096
166}
167
168fn deserialize_host_view_size<'de, D>(deserializer: D) -> Result<u16, D::Error>
169where
170 D: Deserializer<'de>,
171{
172 let value = u16::deserialize(deserializer)?;
174 Ok(value.clamp(10, 70))
175}
176
177fn deserialize_info_view_size<'de, D>(deserializer: D) -> Result<u16, D::Error>
178where
179 D: Deserializer<'de>,
180{
181 let value = u16::deserialize(deserializer)?;
183 Ok(value.clamp(10, 80))
184}
185
186fn deserialize_remote_clipboard_max_bytes<'de, D>(deserializer: D) -> Result<usize, D::Error>
187where
188 D: Deserializer<'de>,
189{
190 let value = usize::deserialize(deserializer)?;
192 Ok(value.clamp(64, 1_048_576))
193}
194
195#[derive(Debug, Deserialize)]
197#[serde(deny_unknown_fields)]
198pub struct HighlightRule {
199 pub regex: String,
201 pub color: String,
203 #[serde(default)]
205 pub description: Option<String>,
206 #[serde(default)]
208 pub bg_color: Option<String>,
209}
210
211#[derive(Debug, Deserialize, Default)]
213#[serde(deny_unknown_fields)]
214pub struct Metadata {
215 #[serde(default)]
217 pub config_path: PathBuf,
218 pub session_name: String,
220 #[serde(skip)]
222 pub(crate) compiled_rules: Vec<CompiledHighlightRule>,
223 #[serde(skip)]
225 pub compiled_rule_set: Option<RegexSet>,
226 #[serde(skip)]
228 pub compiled_secret_patterns: Vec<Regex>,
229 #[serde(skip)]
231 pub version: u64,
232}