A library for writing host-specific, single-binary configuration management and deployment tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.0 KiB

7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
5 years ago
5 years ago
7 years ago
7 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
5 years ago
5 years ago
7 years ago
7 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
7 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
  1. use std::error::Error;
  2. use std::fmt;
  3. use std::path::PathBuf;
  4. use crate::command_runner::CommandRunner;
  5. use crate::resources::Resource;
  6. use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  7. pub struct SelfSignedTlsCert<'a, D: AsRef<str>, C: CommandRunner> {
  8. domain: D,
  9. command_runner: &'a C,
  10. }
  11. impl<'a, D: AsRef<str>, C: CommandRunner> SelfSignedTlsCert<'a, D, C> {
  12. pub fn new(domain: D, command_runner: &'a C) -> Self {
  13. SelfSignedTlsCert {
  14. domain,
  15. command_runner,
  16. }
  17. }
  18. fn get_key_path(&self) -> PathBuf {
  19. format!("/etc/ssl/private/{}.key", self.domain.as_ref()).into()
  20. }
  21. fn get_cert_path(&self) -> PathBuf {
  22. format!("/etc/ssl/local_certs/{}.chained.crt", self.domain.as_ref()).into()
  23. }
  24. }
  25. impl<D: AsRef<str>, C: CommandRunner> fmt::Display for SelfSignedTlsCert<'_, D, C> {
  26. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  27. write!(f, "SelfSignedTlsCert {}", self.domain.as_ref())
  28. }
  29. }
  30. const DAYS_IN_SECONDS: u32 = 24 * 60 * 60;
  31. impl<D: AsRef<str>, C: CommandRunner> Symbol for SelfSignedTlsCert<'_, D, C> {
  32. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  33. if !self.get_cert_path().exists() {
  34. return Ok(false);
  35. }
  36. let output = self.command_runner.run_with_args(
  37. "openssl",
  38. args![
  39. "x509",
  40. "-in",
  41. self.get_cert_path(),
  42. "-noout",
  43. "-subject",
  44. "-checkend",
  45. (30 * DAYS_IN_SECONDS).to_string(),
  46. ],
  47. )?;
  48. println!("{}", output.status.code().unwrap());
  49. match output.status.code() {
  50. Some(0) => Ok(
  51. output.stdout
  52. == format!(
  53. "subject=CN = {}\nCertificate will not expire\n",
  54. self.domain.as_ref()
  55. )
  56. .as_bytes(),
  57. ),
  58. Some(_) => {
  59. if output.stdout
  60. == format!(
  61. "subject=CN = {}\nCertificate will expire\n",
  62. self.domain.as_ref()
  63. )
  64. .as_bytes()
  65. {
  66. Ok(false)
  67. } else {
  68. Err("Exit code non-zero, but wrong stdout".to_string().into())
  69. }
  70. }
  71. _ => Err("Apparently killed by signal".to_string().into()),
  72. }
  73. }
  74. fn execute(&self) -> Result<(), Box<dyn Error>> {
  75. self.command_runner.run_successfully(
  76. "openssl",
  77. args![
  78. "req",
  79. "-x509",
  80. "-sha256",
  81. "-days",
  82. "90",
  83. "-key",
  84. self.get_key_path(),
  85. "-out",
  86. self.get_cert_path(),
  87. "-subj",
  88. format!("/CN={}", self.domain.as_ref()),
  89. ],
  90. )
  91. }
  92. fn get_prerequisites(&self) -> Vec<Resource> {
  93. vec![Resource::new("file", self.get_key_path().to_str().unwrap())]
  94. }
  95. fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b> {
  96. Box::new(SymbolAction::new(runner, self))
  97. }
  98. fn into_action<'b>(self: Box<Self>, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b>
  99. where
  100. Self: 'b,
  101. {
  102. Box::new(OwnedSymbolAction::new(runner, *self))
  103. }
  104. }
  105. #[cfg(test)]
  106. mod test {}