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.

121 lines
2.6 KiB

7 years ago
7 years ago
7 years ago
7 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
7 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
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
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
  1. use crate::command_runner::CommandRunner;
  2. use crate::symbols::Symbol;
  3. use std::borrow::Borrow;
  4. use std::error::Error;
  5. use std::fs::File as FsFile;
  6. use std::io::Write;
  7. use std::marker::PhantomData;
  8. use std::path::Path;
  9. #[derive(Debug)]
  10. pub struct Cert<_C, C, D, P> {
  11. domain: D,
  12. command_runner: C,
  13. root_cert_path: P,
  14. account_key_path: P,
  15. challenges_path: P,
  16. csr_path: P,
  17. cert_path: P,
  18. phantom: PhantomData<_C>,
  19. }
  20. impl<_C, C, D, P> Cert<_C, C, D, P> {
  21. pub fn new(
  22. domain: D,
  23. command_runner: C,
  24. root_cert_path: P,
  25. account_key_path: P,
  26. challenges_path: P,
  27. csr_path: P,
  28. cert_path: P,
  29. ) -> Self {
  30. Self {
  31. domain,
  32. command_runner,
  33. root_cert_path,
  34. account_key_path,
  35. challenges_path,
  36. csr_path,
  37. cert_path,
  38. phantom: PhantomData::default(),
  39. }
  40. }
  41. }
  42. const DAYS_IN_SECONDS: u32 = 24 * 60 * 60;
  43. impl<_C: CommandRunner, C: Borrow<_C>, D: AsRef<str>, P: AsRef<Path>> Symbol for Cert<_C, C, D, P> {
  44. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  45. if !self.cert_path.as_ref().exists() {
  46. return Ok(false);
  47. }
  48. let output = self.command_runner.borrow().run_with_args(
  49. "openssl",
  50. args![
  51. "x509",
  52. "-in",
  53. self.cert_path.as_ref(),
  54. "-noout",
  55. "-subject",
  56. "-checkend",
  57. (30 * DAYS_IN_SECONDS).to_string(),
  58. ],
  59. )?;
  60. if output.status.success()
  61. && output.stdout
  62. == format!(
  63. "subject=CN = {}\nCertificate will not expire\n",
  64. self.domain.as_ref()
  65. )
  66. .as_bytes()
  67. {
  68. Ok(
  69. self
  70. .command_runner
  71. .borrow()
  72. .run_successfully(
  73. "openssl",
  74. args![
  75. "verify",
  76. "--untrusted",
  77. self.root_cert_path.as_ref(),
  78. self.cert_path.as_ref(),
  79. ],
  80. )
  81. .is_ok(),
  82. )
  83. } else if output.status.code() == Some(1)
  84. && output.stdout
  85. == format!(
  86. "subject=CN = {}\nCertificate will expire\n",
  87. self.domain.as_ref()
  88. )
  89. .as_bytes()
  90. {
  91. Ok(false)
  92. } else {
  93. Err(String::from_utf8(output.stderr)?.into())
  94. }
  95. }
  96. fn execute(&self) -> Result<(), Box<dyn Error>> {
  97. let output = self.command_runner.borrow().get_output(
  98. "acme-tiny",
  99. args![
  100. "--account-key",
  101. self.account_key_path.as_ref(),
  102. "--csr",
  103. self.csr_path.as_ref(),
  104. "--acme-dir",
  105. self.challenges_path.as_ref(),
  106. ],
  107. )?;
  108. let mut file = FsFile::create(self.cert_path.as_ref())?;
  109. file.write_all(&output)?;
  110. Ok(())
  111. }
  112. }
  113. #[cfg(test)]
  114. mod test {}