config_definition.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. #![allow(clippy::field_reassign_with_default)]
  2. use schemars::JsonSchema;
  3. use serde::{Deserialize, Serialize};
  4. use serde_json::Value as JsonValue;
  5. use serde_with::skip_serializing_none;
  6. use std::collections::HashMap;
  7. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  8. #[serde(untagged)]
  9. pub enum BundleTarget {
  10. All(Vec<String>),
  11. One(String),
  12. }
  13. #[skip_serializing_none]
  14. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  15. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  16. pub struct DebConfig {
  17. pub depends: Option<Vec<String>>,
  18. #[serde(default)]
  19. pub use_bootstrapper: bool,
  20. }
  21. #[skip_serializing_none]
  22. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  23. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  24. pub struct MacConfig {
  25. pub frameworks: Option<Vec<String>>,
  26. pub minimum_system_version: Option<String>,
  27. pub exception_domain: Option<String>,
  28. pub license: Option<String>,
  29. #[serde(default)]
  30. pub use_bootstrapper: bool,
  31. pub signing_identity: Option<String>,
  32. pub entitlements: Option<String>,
  33. }
  34. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  35. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  36. pub struct WindowsConfig {
  37. pub digest_algorithm: Option<String>,
  38. pub certificate_thumbprint: Option<String>,
  39. pub timestamp_url: Option<String>,
  40. }
  41. #[skip_serializing_none]
  42. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  43. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  44. pub struct PackageConfig {
  45. /// App name. Automatically converted to kebab-case on Linux.
  46. pub product_name: Option<String>,
  47. /// App version.
  48. pub version: Option<String>,
  49. }
  50. #[skip_serializing_none]
  51. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  52. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  53. pub struct BundleConfig {
  54. /// Whether we should build your app with tauri-bundler or plain `cargo build`
  55. pub active: bool,
  56. /// The bundle targets, currently supports ["deb", "app", "msi", "appimage", "dmg"] or "all"
  57. pub targets: Option<BundleTarget>,
  58. /// The app's identifier
  59. pub identifier: Option<String>,
  60. /// The app's icons
  61. pub icon: Option<Vec<String>>,
  62. /// App resources to bundle.
  63. /// Each resource is a path to a file or directory.
  64. /// Glob patterns are supported.
  65. pub resources: Option<Vec<String>>,
  66. pub copyright: Option<String>,
  67. pub category: Option<String>,
  68. pub short_description: Option<String>,
  69. pub long_description: Option<String>,
  70. #[serde(default)]
  71. pub deb: DebConfig,
  72. #[serde(rename = "macOS", default)]
  73. pub macos: MacConfig,
  74. pub external_bin: Option<Vec<String>>,
  75. #[serde(default)]
  76. pub windows: WindowsConfig,
  77. }
  78. /// A CLI argument definition
  79. #[skip_serializing_none]
  80. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  81. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  82. pub struct CliArg {
  83. /// The short version of the argument, without the preceding -.
  84. ///
  85. /// NOTE: Any leading - characters will be stripped, and only the first non - character will be used as the short version.
  86. pub short: Option<char>,
  87. /// The unique argument name
  88. pub name: String,
  89. /// The argument description which will be shown on the help information.
  90. /// Typically, this is a short (one line) description of the arg.
  91. pub description: Option<String>,
  92. /// The argument long description which will be shown on the help information.
  93. /// Typically this a more detailed (multi-line) message that describes the argument.
  94. pub long_description: Option<String>,
  95. /// Specifies that the argument takes a value at run time.
  96. ///
  97. /// NOTE: values for arguments may be specified in any of the following methods
  98. /// - Using a space such as -o value or --option value
  99. /// - Using an equals and no space such as -o=value or --option=value
  100. /// - Use a short and no space such as -ovalue
  101. pub takes_value: Option<bool>,
  102. /// Specifies that the argument may appear more than once.
  103. ///
  104. /// - For flags, this results in the number of occurrences of the flag being recorded.
  105. /// For example -ddd or -d -d -d would count as three occurrences.
  106. /// - For options there is a distinct difference in multiple occurrences vs multiple values.
  107. /// For example, --opt val1 val2 is one occurrence, but two values. Whereas --opt val1 --opt val2 is two occurrences.
  108. pub multiple: Option<bool>,
  109. /// specifies that the argument may appear more than once.
  110. pub multiple_occurrences: Option<bool>,
  111. ///
  112. pub number_of_values: Option<u64>,
  113. /// Specifies a list of possible values for this argument.
  114. /// At runtime, the CLI verifies that only one of the specified values was used, or fails with an error message.
  115. pub possible_values: Option<Vec<String>>,
  116. /// Specifies the minimum number of values for this argument.
  117. /// For example, if you had a -f <file> argument where you wanted at least 2 'files',
  118. /// you would set `minValues: 2`, and this argument would be satisfied if the user provided, 2 or more values.
  119. pub min_values: Option<u64>,
  120. /// Specifies the maximum number of values are for this argument.
  121. /// For example, if you had a -f <file> argument where you wanted up to 3 'files',
  122. /// you would set .max_values(3), and this argument would be satisfied if the user provided, 1, 2, or 3 values.
  123. pub max_values: Option<u64>,
  124. /// Sets whether or not the argument is required by default.
  125. ///
  126. /// - Required by default means it is required, when no other conflicting rules have been evaluated
  127. /// - Conflicting rules take precedence over being required.
  128. pub required: Option<bool>,
  129. /// Sets an arg that override this arg's required setting
  130. /// i.e. this arg will be required unless this other argument is present.
  131. pub required_unless_present: Option<String>,
  132. /// Sets args that override this arg's required setting
  133. /// i.e. this arg will be required unless all these other arguments are present.
  134. pub required_unless_present_all: Option<Vec<String>>,
  135. /// Sets args that override this arg's required setting
  136. /// i.e. this arg will be required unless at least one of these other arguments are present.
  137. pub required_unless_present_any: Option<Vec<String>>,
  138. /// Sets a conflicting argument by name
  139. /// i.e. when using this argument, the following argument can't be present and vice versa.
  140. pub conflicts_with: Option<String>,
  141. /// The same as conflictsWith but allows specifying multiple two-way conflicts per argument.
  142. pub conflicts_with_all: Option<Vec<String>>,
  143. /// Tets an argument by name that is required when this one is present
  144. /// i.e. when using this argument, the following argument must be present.
  145. pub requires: Option<String>,
  146. /// Sts multiple arguments by names that are required when this one is present
  147. /// i.e. when using this argument, the following arguments must be present.
  148. pub requires_all: Option<Vec<String>>,
  149. /// Allows a conditional requirement with the signature [arg, value]
  150. /// the requirement will only become valid if `arg`'s value equals `${value}`.
  151. pub requires_if: Option<Vec<String>>,
  152. /// Allows specifying that an argument is required conditionally with the signature [arg, value]
  153. /// the requirement will only become valid if the `arg`'s value equals `${value}`.
  154. pub required_if_eq: Option<Vec<String>>,
  155. /// Requires that options use the --option=val syntax
  156. /// i.e. an equals between the option and associated value.
  157. pub require_equals: Option<bool>,
  158. /// The positional argument index, starting at 1.
  159. ///
  160. /// The index refers to position according to other positional argument.
  161. /// It does not define position in the argument list as a whole. When utilized with multiple=true,
  162. /// only the last positional argument may be defined as multiple (i.e. the one with the highest index).
  163. pub index: Option<u64>,
  164. }
  165. /// describes a CLI configuration
  166. #[skip_serializing_none]
  167. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  168. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  169. pub struct CliConfig {
  170. /// command description which will be shown on the help information
  171. description: Option<String>,
  172. /// command long description which will be shown on the help information
  173. long_description: Option<String>,
  174. /// adds additional help information to be displayed in addition to auto-generated help
  175. /// this information is displayed before the auto-generated help information.
  176. /// this is often used for header information
  177. before_help: Option<String>,
  178. /// adds additional help information to be displayed in addition to auto-generated help
  179. /// this information is displayed after the auto-generated help information
  180. /// this is often used to describe how to use the arguments, or caveats to be noted.
  181. after_help: Option<String>,
  182. /// list of args for the command
  183. args: Option<Vec<CliArg>>,
  184. /// list of subcommands of this command.
  185. ///
  186. /// subcommands are effectively sub-apps, because they can contain their own arguments, subcommands, usage, etc.
  187. /// they also function just like the app command, in that they get their own auto generated help and usage
  188. subcommands: Option<HashMap<String, CliConfig>>,
  189. }
  190. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  191. #[serde(untagged)]
  192. pub enum Port {
  193. /// Port with a numeric value.
  194. Value(u16),
  195. /// Random port.
  196. Random,
  197. }
  198. /// The window configuration object.
  199. #[skip_serializing_none]
  200. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  201. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  202. pub struct WindowConfig {
  203. /// The window identifier.
  204. pub label: Option<String>,
  205. /// The window webview URL.
  206. pub url: Option<String>,
  207. /// The horizontal position of the window's top left corner
  208. pub x: Option<f64>,
  209. /// The vertical position of the window's top left corner
  210. pub y: Option<f64>,
  211. /// The window width.
  212. pub width: Option<f64>,
  213. /// The window height.
  214. pub height: Option<f64>,
  215. /// The min window width.
  216. pub min_width: Option<f64>,
  217. /// The min window height.
  218. pub min_height: Option<f64>,
  219. /// The max window width.
  220. pub max_width: Option<f64>,
  221. /// The max window height.
  222. pub max_height: Option<f64>,
  223. /// Whether the window is resizable or not.
  224. #[serde(default)]
  225. pub resizable: bool,
  226. /// The window title.
  227. pub title: Option<String>,
  228. /// Whether the window starts as fullscreen or not.
  229. #[serde(default)]
  230. pub fullscreen: bool,
  231. /// Whether the window is transparent or not.
  232. #[serde(default)]
  233. pub transparent: bool,
  234. /// Whether the window is maximized or not.
  235. #[serde(default)]
  236. pub maximized: bool,
  237. /// Whether the window is visible or not.
  238. #[serde(default = "default_visible")]
  239. pub visible: bool,
  240. /// Whether the window should have borders and bars.
  241. #[serde(default = "default_decorations")]
  242. pub decorations: bool,
  243. /// Whether the window should always be on top of other windows.
  244. #[serde(default)]
  245. pub always_on_top: bool,
  246. }
  247. fn default_visible() -> bool {
  248. true
  249. }
  250. fn default_decorations() -> bool {
  251. true
  252. }
  253. #[skip_serializing_none]
  254. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  255. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  256. pub struct SecurityConfig {
  257. pub csp: Option<String>,
  258. }
  259. trait Allowlist {
  260. fn to_features(&self) -> Vec<&str>;
  261. }
  262. macro_rules! check_feature {
  263. ($self:ident, $features:ident, $flag:ident, $feature_name: expr) => {
  264. if $self.$flag {
  265. $features.push($feature_name)
  266. }
  267. };
  268. }
  269. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  270. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  271. struct FsAllowlistConfig {
  272. #[serde(default)]
  273. all: bool,
  274. #[serde(default)]
  275. read_text_file: bool,
  276. #[serde(default)]
  277. read_binary_file: bool,
  278. #[serde(default)]
  279. write_file: bool,
  280. #[serde(default)]
  281. write_binary_file: bool,
  282. #[serde(default)]
  283. read_dir: bool,
  284. #[serde(default)]
  285. copy_file: bool,
  286. #[serde(default)]
  287. create_dir: bool,
  288. #[serde(default)]
  289. remove_dir: bool,
  290. #[serde(default)]
  291. remove_file: bool,
  292. #[serde(default)]
  293. rename_file: bool,
  294. #[serde(default)]
  295. path: bool,
  296. }
  297. impl Allowlist for FsAllowlistConfig {
  298. fn to_features(&self) -> Vec<&str> {
  299. if self.all {
  300. vec!["fs-all"]
  301. } else {
  302. let mut features = Vec::new();
  303. check_feature!(self, features, read_text_file, "fs-read-text-file");
  304. check_feature!(self, features, read_binary_file, "fs-read-binary-file");
  305. check_feature!(self, features, write_file, "fs-write-file");
  306. check_feature!(self, features, write_binary_file, "fs-write-binary-file");
  307. check_feature!(self, features, read_dir, "fs-read-dir");
  308. check_feature!(self, features, copy_file, "fs-copy-file");
  309. check_feature!(self, features, create_dir, "fs-create-dir");
  310. check_feature!(self, features, remove_dir, "fs-remove-dir");
  311. check_feature!(self, features, remove_file, "fs-remove-file");
  312. check_feature!(self, features, rename_file, "fs-rename-file");
  313. check_feature!(self, features, path, "fs-path");
  314. features
  315. }
  316. }
  317. }
  318. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  319. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  320. struct WindowAllowlistConfig {
  321. #[serde(default)]
  322. all: bool,
  323. #[serde(default)]
  324. create: bool,
  325. }
  326. impl Allowlist for WindowAllowlistConfig {
  327. fn to_features(&self) -> Vec<&str> {
  328. if self.all {
  329. vec!["window-all"]
  330. } else {
  331. let mut features = Vec::new();
  332. check_feature!(self, features, create, "window-create");
  333. features
  334. }
  335. }
  336. }
  337. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  338. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  339. struct ShellAllowlistConfig {
  340. #[serde(default)]
  341. all: bool,
  342. #[serde(default)]
  343. execute: bool,
  344. #[serde(default)]
  345. open: bool,
  346. }
  347. impl Allowlist for ShellAllowlistConfig {
  348. fn to_features(&self) -> Vec<&str> {
  349. if self.all {
  350. vec!["shell-all"]
  351. } else {
  352. let mut features = Vec::new();
  353. check_feature!(self, features, execute, "shell-execute");
  354. check_feature!(self, features, open, "shell-open");
  355. features
  356. }
  357. }
  358. }
  359. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  360. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  361. struct DialogAllowlistConfig {
  362. #[serde(default)]
  363. all: bool,
  364. #[serde(default)]
  365. open: bool,
  366. #[serde(default)]
  367. save: bool,
  368. }
  369. impl Allowlist for DialogAllowlistConfig {
  370. fn to_features(&self) -> Vec<&str> {
  371. if self.all {
  372. vec!["dialog-all"]
  373. } else {
  374. let mut features = Vec::new();
  375. check_feature!(self, features, open, "dialog-open");
  376. check_feature!(self, features, save, "dialog-save");
  377. features
  378. }
  379. }
  380. }
  381. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  382. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  383. struct HttpAllowlistConfig {
  384. #[serde(default)]
  385. all: bool,
  386. #[serde(default)]
  387. request: bool,
  388. }
  389. impl Allowlist for HttpAllowlistConfig {
  390. fn to_features(&self) -> Vec<&str> {
  391. if self.all {
  392. vec!["http-all"]
  393. } else {
  394. let mut features = Vec::new();
  395. check_feature!(self, features, request, "http-request");
  396. features
  397. }
  398. }
  399. }
  400. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  401. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  402. struct NotificationAllowlistConfig {
  403. #[serde(default)]
  404. all: bool,
  405. }
  406. impl Allowlist for NotificationAllowlistConfig {
  407. fn to_features(&self) -> Vec<&str> {
  408. if self.all {
  409. vec!["notification-all"]
  410. } else {
  411. vec![]
  412. }
  413. }
  414. }
  415. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  416. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  417. struct GlobalShortcutAllowlistConfig {
  418. #[serde(default)]
  419. all: bool,
  420. }
  421. impl Allowlist for GlobalShortcutAllowlistConfig {
  422. fn to_features(&self) -> Vec<&str> {
  423. if self.all {
  424. vec!["global-shortcut-all"]
  425. } else {
  426. vec![]
  427. }
  428. }
  429. }
  430. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  431. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  432. struct AllowlistConfig {
  433. #[serde(default)]
  434. all: bool,
  435. #[serde(default)]
  436. fs: FsAllowlistConfig,
  437. #[serde(default)]
  438. window: WindowAllowlistConfig,
  439. #[serde(default)]
  440. shell: ShellAllowlistConfig,
  441. #[serde(default)]
  442. dialog: DialogAllowlistConfig,
  443. #[serde(default)]
  444. http: HttpAllowlistConfig,
  445. #[serde(default)]
  446. notification: NotificationAllowlistConfig,
  447. #[serde(default)]
  448. global_shortcut: GlobalShortcutAllowlistConfig,
  449. }
  450. impl Allowlist for AllowlistConfig {
  451. fn to_features(&self) -> Vec<&str> {
  452. if self.all {
  453. vec!["api-all"]
  454. } else {
  455. let mut features = Vec::new();
  456. features.extend(self.fs.to_features());
  457. features.extend(self.window.to_features());
  458. features.extend(self.shell.to_features());
  459. features.extend(self.dialog.to_features());
  460. features.extend(self.http.to_features());
  461. features.extend(self.notification.to_features());
  462. features.extend(self.global_shortcut.to_features());
  463. features
  464. }
  465. }
  466. }
  467. /// The Tauri configuration object.
  468. #[skip_serializing_none]
  469. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  470. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  471. pub struct TauriConfig {
  472. /// The windows configuration.
  473. #[serde(default)]
  474. pub windows: Vec<WindowConfig>,
  475. /// The CLI configuration.
  476. pub cli: Option<CliConfig>,
  477. /// The bundler configuration.
  478. #[serde(default)]
  479. pub bundle: BundleConfig,
  480. #[serde(default)]
  481. allowlist: AllowlistConfig,
  482. pub security: Option<SecurityConfig>,
  483. }
  484. impl TauriConfig {
  485. #[allow(dead_code)]
  486. pub fn features(&self) -> Vec<&str> {
  487. self.allowlist.to_features()
  488. }
  489. }
  490. /// The Build configuration object.
  491. #[skip_serializing_none]
  492. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  493. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  494. pub struct BuildConfig {
  495. /// the app's dev server URL, or the path to the directory containing an index.html file
  496. #[serde(default = "default_dev_path")]
  497. pub dev_path: String,
  498. /// the path to the app's dist dir. This path must contain your index.html file.
  499. #[serde(default = "default_dist_dir")]
  500. pub dist_dir: String,
  501. /// a shell command to run before `tauri dev` kicks in
  502. pub before_dev_command: Option<String>,
  503. /// a shell command to run before `tauri build` kicks in
  504. pub before_build_command: Option<String>,
  505. /// Whether we should inject the Tauri API on `window.__TAURI__` or not.
  506. #[serde(default)]
  507. pub with_global_tauri: bool,
  508. }
  509. fn default_dev_path() -> String {
  510. "".to_string()
  511. }
  512. fn default_dist_dir() -> String {
  513. "../dist".to_string()
  514. }
  515. type JsonObject = HashMap<String, JsonValue>;
  516. /// The tauri.conf.json mapper.
  517. #[skip_serializing_none]
  518. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  519. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  520. pub struct Config {
  521. /// Package settings.
  522. #[serde(default)]
  523. pub package: PackageConfig,
  524. /// The Tauri configuration.
  525. #[serde(default)]
  526. pub tauri: TauriConfig,
  527. /// The build configuration.
  528. #[serde(default = "default_build")]
  529. pub build: BuildConfig,
  530. /// The plugins config.
  531. #[serde(default)]
  532. pub plugins: HashMap<String, JsonObject>,
  533. }
  534. fn default_build() -> BuildConfig {
  535. BuildConfig {
  536. dev_path: default_dev_path(),
  537. dist_dir: default_dist_dir(),
  538. before_dev_command: None,
  539. before_build_command: None,
  540. with_global_tauri: false,
  541. }
  542. }