config.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. use btlib::bterr;
  2. // SPDX-License-Identifier: AGPL-3.0-or-later
  3. use super::DEFAULT_CONFIG;
  4. use std::{net::IpAddr, path::PathBuf, str::FromStr};
  5. struct StrParser<'a>(&'a str);
  6. impl<'a> StrParser<'a> {
  7. fn assert(&mut self, token: &str) -> btlib::Result<()> {
  8. if self.0.starts_with(token) {
  9. self.0 = &self.0[token.len()..];
  10. Ok(())
  11. } else {
  12. Err(bterr!("string does not start with {token}"))
  13. }
  14. }
  15. fn consume_up_to(&mut self, stop: char) -> btlib::Result<&str> {
  16. let mut count = 0;
  17. for c in self.0.chars() {
  18. if c == stop {
  19. break;
  20. }
  21. count += 1;
  22. }
  23. let output = &self.0[..count];
  24. let new_start = self.0.len().min(count + 1);
  25. self.0 = &self.0[new_start..];
  26. Ok(output)
  27. }
  28. fn remaining(&self) -> &str {
  29. self.0
  30. }
  31. }
  32. pub enum CredStoreCfg {
  33. File {
  34. path: PathBuf,
  35. },
  36. Tpm {
  37. tpm_state_path: PathBuf,
  38. tabrmd: String,
  39. },
  40. }
  41. impl FromStr for CredStoreCfg {
  42. type Err = btlib::Error;
  43. fn from_str(value: &str) -> Result<Self, Self::Err> {
  44. let mut parser = StrParser(value);
  45. parser.assert("kind=")?;
  46. let kind = parser.consume_up_to(',')?;
  47. match kind {
  48. "file" => {
  49. parser.assert("path=")?;
  50. let path = PathBuf::from(parser.remaining());
  51. Ok(CredStoreCfg::File { path })
  52. }
  53. "tpm" => {
  54. parser.assert("tpm_state_path=")?;
  55. let tpm_state_path = PathBuf::from(parser.consume_up_to(',')?);
  56. let tabrmd = parser.remaining().to_string();
  57. Ok(CredStoreCfg::Tpm {
  58. tpm_state_path,
  59. tabrmd,
  60. })
  61. }
  62. _ => Err(bterr!(
  63. "unrecognized CredStore kind (expected 'file' or 'tpm'): {kind}"
  64. )),
  65. }
  66. }
  67. }
  68. pub struct Config {
  69. pub cred_store_cfg: CredStoreCfg,
  70. pub ip_addr: IpAddr,
  71. pub block_dir: PathBuf,
  72. }
  73. impl Config {
  74. pub fn builder() -> ConfigBuilder {
  75. ConfigBuilder::new()
  76. }
  77. }
  78. trait OptionExt<'a> {
  79. fn str_unwrap_or(self, default: &'a str) -> &'a str;
  80. }
  81. impl<'a> OptionExt<'a> for &'a Option<String> {
  82. fn str_unwrap_or(self, default: &'a str) -> &'a str {
  83. self.as_ref().map(|e| e.as_str()).unwrap_or(default)
  84. }
  85. }
  86. #[derive(Default)]
  87. pub struct ConfigBuilder {
  88. pub cred_store: Option<String>,
  89. pub ip_addr: Option<String>,
  90. pub block_dir: Option<String>,
  91. }
  92. impl ConfigBuilder {
  93. pub fn new() -> Self {
  94. Self::default()
  95. }
  96. pub fn with_cred_store(mut self, cred_store: Option<String>) -> Self {
  97. self.cred_store = cred_store;
  98. self
  99. }
  100. pub fn with_ip_addr(mut self, ip_addr: Option<String>) -> Self {
  101. self.ip_addr = ip_addr;
  102. self
  103. }
  104. pub fn with_block_dir(mut self, block_dir: Option<String>) -> Self {
  105. self.block_dir = block_dir;
  106. self
  107. }
  108. pub fn build(self) -> Config {
  109. let cred_store_cfg =
  110. CredStoreCfg::from_str(self.cred_store.str_unwrap_or(DEFAULT_CONFIG.cred_store))
  111. .unwrap();
  112. let ip_addr = IpAddr::from_str(self.ip_addr.str_unwrap_or(DEFAULT_CONFIG.ip_addr)).unwrap();
  113. let block_dir = PathBuf::from(self.block_dir.str_unwrap_or(DEFAULT_CONFIG.block_dir));
  114. Config {
  115. cred_store_cfg,
  116. ip_addr,
  117. block_dir,
  118. }
  119. }
  120. }
  121. pub struct ConfigRef<'a> {
  122. pub cred_store: &'a str,
  123. pub ip_addr: &'a str,
  124. pub block_dir: &'a str,
  125. }
  126. pub struct Envvars<'a> {
  127. pub cred_store: &'a str,
  128. pub ip_addr: &'a str,
  129. pub block_dir: &'a str,
  130. }