Browse Source

Change the template engine for TinyTemplate

As discussed in the issue linked below, the template engine needed to be
changed for various reasons. After a long search, it has been decided to
use TinyTemplate since it is the best match so far.

fixes #8
pull/49/head
Rodolphe Bréard 4 years ago
parent
commit
30be12c79f
  1. 2
      acme_common/Cargo.toml
  2. 4
      acme_common/src/error.rs
  3. 2
      acmed/Cargo.toml
  4. 2
      acmed/build.rs
  5. 48
      acmed/config/default_hooks.toml
  6. 15
      acmed/src/hooks.rs
  7. 1
      acmed/src/main.rs
  8. 5
      acmed/src/storage.rs
  9. 12
      acmed/src/template.rs
  10. 46
      man/en/acmed.toml.5

2
acme_common/Cargo.toml

@ -24,7 +24,6 @@ base64 = "0.13"
daemonize = "0.4"
env_logger = "0.8"
glob = "0.3"
handlebars = "3.0"
libc = "0.2"
log = "0.4"
native-tls = "0.2"
@ -33,6 +32,7 @@ openssl-sys = { version = "0.9", optional = true }
punycode = "0.4"
serde_json = "1.0"
syslog = "5.0"
tinytemplate = "1.2"
toml = "0.5"
[target.'cfg(unix)'.dependencies]

4
acme_common/src/error.rs

@ -105,8 +105,8 @@ impl From<glob::PatternError> for Error {
}
}
impl From<handlebars::TemplateRenderError> for Error {
fn from(error: handlebars::TemplateRenderError) -> Self {
impl From<tinytemplate::error::Error> for Error {
fn from(error: tinytemplate::error::Error) -> Self {
format!("template error: {}", error).into()
}
}

2
acmed/Cargo.toml

@ -25,11 +25,11 @@ attohttpc = { version = "0.17", default-features = false, features = ["charsets"
bincode = "1.3"
clap = "2.32"
glob = "0.3"
handlebars = "3.0"
log = "0.4"
nom = { version = "6.0", default-features = false, features = [] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tinytemplate = "1.2"
toml = "0.5"
[target.'cfg(unix)'.dependencies]

2
acmed/build.rs

@ -117,7 +117,7 @@ fn set_default_values() {
set_data_path_if_absent!("ACMED_DEFAULT_CERT_DIR", "certs");
set_env_var_if_absent!(
"ACMED_DEFAULT_CERT_FORMAT",
"{{name}}_{{key_type}}.{{file_type}}.{{ext}}"
"{ name }_{ key_type }.{ file_type }.{ ext }"
);
set_cfg_path_if_absent!("ACMED_DEFAULT_CONFIG_FILE", "acmed.toml");
set_runstate_path_if_absent!("ACMED_DEFAULT_PID_FILE", "acmed.pid");

48
acmed/config/default_hooks.toml

@ -12,7 +12,7 @@
#
# http-01 challenge in "/var/www/{{identifier}}/"
# http-01 challenge in "/var/www/{ identifier }/"
#
[[hook]]
@ -21,7 +21,7 @@ type = ["challenge-http-01"]
cmd = "mkdir"
args = [
"-m", "0755",
"-p", "{{#if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge"
"-p", "{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge"
]
allow_failure = true
@ -29,8 +29,8 @@ allow_failure = true
name = "http-01-echo-echo"
type = ["challenge-http-01"]
cmd = "echo"
args = ["{{proof}}"]
stdout = "{{#if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge/{{file_name}}"
args = ["{ proof }"]
stdout = "{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge/{ file_name }"
[[hook]]
name = "http-01-echo-chmod"
@ -38,7 +38,7 @@ type = ["challenge-http-01"]
cmd = "chmod"
args = [
"a+r",
"{{#if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge/{{file_name}}"
"{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge/{ file_name }"
]
allow_failure = true
@ -48,7 +48,7 @@ type = ["challenge-http-01-clean"]
cmd = "rm"
args = [
"-f",
"{{#if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge/{{file_name}}"
"{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge/{ file_name }"
]
allow_failure = true
@ -71,10 +71,10 @@ name = "tls-alpn-01-tacd-start-tcp"
type = ["challenge-tls-alpn-01"]
cmd = "tacd"
args = [
"--pid-file", "{{#if env.TACD_PID_ROOT}}{{env.TACD_PID_ROOT}}{{else}}/run{{/if}}/tacd_{{identifier}}.pid",
"--domain", "{{identifier_tls_alpn}}",
"--acme-ext", "{{proof}}",
"--listen", "{{#if env.TACD_HOST}}{{env.TACD_HOST}}{{else}}{{identifier}}{{/if}}:{{#if env.TACD_PORT}}{{env.TACD_PORT}}{{else}}5001{{/if}}"
"--pid-file", "{{ if env.TACD_PID_ROOT }}{ env.TACD_PID_ROOT }{{ else }}/run{{ endif }}/tacd_{ identifier }.pid",
"--domain", "{ identifier_tls_alpn }",
"--acme-ext", "{ proof }",
"--listen", "{{ if env.TACD_HOST }}{ env.TACD_HOST }{{ else }}{ identifier }{{ endif }}:{{ if env.TACD_PORT }}{ env.TACD_PORT }{{ else }}5001{{ endif }}"
]
[[hook]]
@ -82,10 +82,10 @@ name = "tls-alpn-01-tacd-start-unix"
type = ["challenge-tls-alpn-01"]
cmd = "tacd"
args = [
"--pid-file", "{{#if env.TACD_PID_ROOT}}{{env.TACD_PID_ROOT}}{{else}}/run{{/if}}/tacd_{{identifier}}.pid",
"--domain", "{{identifier_tls_alpn}}",
"--acme-ext", "{{proof}}",
"--listen", "unix:{{#if env.TACD_SOCK_ROOT}}{{env.TACD_SOCK_ROOT}}{{else}}/run{{/if}}/tacd_{{identifier}}.sock"
"--pid-file", "{{ if env.TACD_PID_ROOT }}{ env.TACD_PID_ROOT }{{ else }}/run{{ endif }}/tacd_{ identifier }.pid",
"--domain", "{ identifier_tls_alpn }",
"--acme-ext", "{ proof }",
"--listen", "unix:{{ if env.TACD_SOCK_ROOT }}{ env.TACD_SOCK_ROOT }{{ else }}/run{{ endif }}/tacd_{ identifier }.sock"
]
[[hook]]
@ -93,7 +93,7 @@ name = "tls-alpn-01-tacd-kill"
type = ["challenge-tls-alpn-01-clean"]
cmd = "pkill"
args = [
"-F", "{{#if env.TACD_PID_ROOT}}{{env.TACD_PID_ROOT}}{{else}}/run{{/if}}/tacd_{{identifier}}.pid",
"-F", "{{ if env.TACD_PID_ROOT }}{ env.TACD_PID_ROOT }{{ else }}/run{{ endif }}/tacd_{ identifier }.pid",
]
allow_failure = true
@ -102,7 +102,7 @@ name = "tls-alpn-01-tacd-rm"
type = ["challenge-tls-alpn-01-clean"]
cmd = "rm"
args = [
"-f", "{{#if env.TACD_PID_ROOT}}{{env.TACD_PID_ROOT}}{{else}}/run{{/if}}/tacd_{{identifier}}.pid",
"-f", "{{ if env.TACD_PID_ROOT }}{ env.TACD_PID_ROOT }{{ else }}/run{{ endif }}/tacd_{ identifier }.pid",
]
allow_failure = true
@ -125,7 +125,7 @@ type = ["file-pre-create", "file-pre-edit"]
cmd = "git"
args = [
"init",
"{{file_directory}}"
"{ file_directory }"
]
[[hook]]
@ -133,8 +133,8 @@ name = "git-add"
type = ["file-post-create", "file-post-edit"]
cmd = "git"
args = [
"-C", "{{file_directory}}",
"add", "{{file_name}}"
"-C", "{ file_directory }",
"add", "{ file_name }"
]
allow_failure = true
@ -143,12 +143,12 @@ name = "git-commit"
type = ["file-post-create", "file-post-edit"]
cmd = "git"
args = [
"-C", "{{file_directory}}",
"-c", "user.name='{{#if env.GIT_USERNAME}}{{env.GIT_USERNAME}}{{else}}ACMEd{{/if}}'",
"-c", "user.email='{{#if env.GIT_EMAIL}}{{env.GIT_EMAIL}}{{else}}acmed@localhost{{/if}}'",
"-C", "{ file_directory }",
"-c", "user.name='{{ if env.GIT_USERNAME }}{ env.GIT_USERNAME }{{ else }}ACMEd{{ endif }}'",
"-c", "user.email='{{ if env.GIT_EMAIL }}{ env.GIT_EMAIL }{{ else }}acmed@localhost{{ endif }}'",
"commit",
"-m", "{{file_name}}",
"--only", "{{file_name}}"
"-m", "{ file_name }",
"--only", "{ file_name }"
]
allow_failure = true

15
acmed/src/hooks.rs

@ -1,7 +1,7 @@
pub use crate::config::HookType;
use crate::logs::HasLogger;
use crate::template::render_template;
use acme_common::error::Error;
use handlebars::Handlebars;
use serde::Serialize;
use std::collections::hash_map::Iter;
use std::collections::{HashMap, HashSet};
@ -102,10 +102,10 @@ impl fmt::Display for Hook {
}
macro_rules! get_hook_output {
($logger: expr, $out: expr, $reg: ident, $data: expr, $hook_name: expr, $out_name: expr) => {{
($logger: expr, $out: expr, $data: expr, $hook_name: expr, $out_name: expr) => {{
match $out {
Some(path) => {
let path = $reg.render_template(path, $data)?;
let path = render_template(path, $data)?;
$logger.trace(&format!(
"hook \"{}\": {}: {}",
$hook_name, $out_name, &path
@ -124,12 +124,11 @@ where
T: Clone + HookEnvData + Serialize,
{
logger.debug(&format!("calling hook \"{}\"", hook.name));
let reg = Handlebars::new();
let mut v = vec![];
let args = match &hook.args {
Some(lst) => {
for fmt in lst.iter() {
let s = reg.render_template(fmt, &data)?;
let s = render_template(fmt, &data)?;
v.push(s);
}
v.as_slice()
@ -144,7 +143,6 @@ where
.stdout(get_hook_output!(
logger,
&hook.stdout,
reg,
&data,
&hook.name,
"stdout"
@ -152,7 +150,6 @@ where
.stderr(get_hook_output!(
logger,
&hook.stderr,
reg,
&data,
&hook.name,
"stderr"
@ -164,7 +161,7 @@ where
.spawn()?;
match &hook.stdin {
HookStdin::Str(s) => {
let data_in = reg.render_template(&s, &data)?;
let data_in = render_template(&s, &data)?;
logger.trace(&format!(
"hook \"{}\": string stdin: {}",
hook.name, &data_in
@ -173,7 +170,7 @@ where
stdin.write_all(data_in.as_bytes())?;
}
HookStdin::File(f) => {
let file_name = reg.render_template(&f, &data)?;
let file_name = render_template(&f, &data)?;
logger.trace(&format!(
"hook \"{}\": file stdin: {}",
hook.name, &file_name

1
acmed/src/main.rs

@ -20,6 +20,7 @@ mod jws;
mod logs;
mod main_event_loop;
mod storage;
mod template;
pub const APP_NAME: &str = "ACMEd";
pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION");

5
acmed/src/storage.rs

@ -1,9 +1,9 @@
use crate::hooks::{self, FileStorageHookData, Hook, HookEnvData, HookType};
use crate::logs::HasLogger;
use crate::template::render_template;
use acme_common::b64_encode;
use acme_common::crypto::{KeyPair, X509Certificate};
use acme_common::error::Error;
use handlebars::Handlebars;
use serde::Serialize;
use std::collections::HashMap;
use std::fmt;
@ -110,8 +110,7 @@ fn get_file_full_path(
file_type: file_type.to_string(),
name: fm.crt_name.to_owned(),
};
let reg = Handlebars::new();
reg.render_template(&fm.crt_name_format, &fmt_data)?
render_template(&fm.crt_name_format, &fmt_data)?
}
};
let mut path = PathBuf::from(&base_path);

12
acmed/src/template.rs

@ -0,0 +1,12 @@
use acme_common::error::Error;
use serde::Serialize;
use tinytemplate::TinyTemplate;
pub fn render_template<T>(template: &str, data: &T) -> Result<String, Error>
where
T: Serialize,
{
let mut reg = TinyTemplate::new();
reg.add_template("reg", template)?;
Ok(reg.render("reg", data)?)
}

46
man/en/acmed.toml.5

@ -118,17 +118,17 @@ Name of the endpoint to use.
Table of environment variables that will be accessible from hooks.
.It Ic file_name_format Ar string
Template used to build the file's name. The template syntax is
.Em Handlebars .
.Em TinyTemplate .
See the
.Sx STANDARDS
section for a link to the
.Em Handlebars
.Em TinyTemplate
specifications. If not specified, the value defined in the
.Em endpoint
element, and then the
.Em global
element, is used. Default is
.Dq {{name}}_{{key_type}}.{{file_type}}.{{ext}} .
.Dq { name }_{ key_type }.{ file_type }.{ ext } .
Possible variables are:
.Bl -tag
.It Ic ext Ar string
@ -401,11 +401,11 @@ and
are considered as template strings whereas
.Em cmd
is not. The template syntax is
.Em Handlebars .
.Em TinyTemplate .
See the
.Sx STANDARDS
section for a link to the
.Em Handlebars
.Em TinyTemplate
specifications.
.Pp
The available types and the associated template variable are described below.
@ -577,10 +577,10 @@ and
environment variables.
.It Pa http-01-echo
This hook is designed to solve the http-01 challenge. For this purpose, it will write the proof into
.Pa {{env.HTTP_ROOT}}/{{identifier}}/.well-known/acme-challenge/{{file_name}} .
.Pa { env.HTTP_ROOT }/{ identifier }/.well-known/acme-challenge/{ file_name } .
.Pp
The web server must be configured so the file
.Pa http://{{identifier}}/.well-known/acme-challenge/{{file_name}}
.Pa http://{ identifier }/.well-known/acme-challenge/{ file_name }
can be accessed from the CA.
.Pp
If
@ -605,7 +605,7 @@ environment variable (default is 5001).
.Pp
.Xr tacd 8
will store its pid into
.Pa {{TACD_PID_ROOT}}/tacd_{{identifier}}.pid .
.Pa { TACD_PID_ROOT }/tacd_{ identifier }.pid .
If
.Ev TACD_PID_ROOT
is not specified, it will be set to
@ -621,7 +621,7 @@ option.
.Pp
.Xr tacd 8
will listen on the unix socket
.Pa {{env.TACD_SOCK_ROOT}}/tacd_{{identifier}}.sock .
.Pa { env.TACD_SOCK_ROOT }/tacd_{ identifier }.sock .
If
.Ev TACD_SOCK_ROOT
is not specified, it will be set to
@ -629,7 +629,7 @@ is not specified, it will be set to
.Pp
.Xr tacd 8
will store its pid into
.Pa {{TACD_PID_ROOT}}/tacd_{{identifier}}.pid .
.Pa { TACD_PID_ROOT }/tacd_{ identifier }.pid .
If
.Ev TACD_PID_ROOT
is not specified, it will be set to
@ -726,15 +726,15 @@ type = ["challenge-http-01"]
cmd = "mkdir"
args = [
"-m", "0755",
"-p", "{{%if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge"
"-p", "{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge"
]
[[hook]]
name = "http-01-echo-echo"
type = ["challenge-http-01"]
cmd = "echo"
args = ["{{proof}}"]
stdout = "{{%if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge/{{file_name}}"
args = ["{ proof }"]
stdout = "{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge/{ file_name }"
[[hook]]
name = "http-01-echo-chmod"
@ -742,7 +742,7 @@ type = ["challenge-http-01-clean"]
cmd = "chmod"
args = [
"a+r",
"{{%if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge/{{file_name}}"
"{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge/{ file_name }"
]
[[hook]]
@ -751,7 +751,7 @@ type = ["challenge-http-01-clean"]
cmd = "rm"
args = [
"-f",
"{{%if env.HTTP_ROOT}}{{env.HTTP_ROOT}}{{else}}/var/www{{/if}}/{{identifier}}/.well-known/acme-challenge/{{file_name}}"
"{{ if env.HTTP_ROOT }}{ env.HTTP_ROOT }{{ else }}/var/www{{ endif }}/{ identifier }/.well-known/acme-challenge/{ file_name }"
]
.Ed
.Pp
@ -784,12 +784,12 @@ args = [
"-f", "noreply.certs@example.net",
"contact@example.net"
]
stdin_str = """Subject: Certificate renewal {{#if is_success}}succeeded{{else}}failed{{/if}} for {{identifiers.[0]}}
stdin_str = """Subject: Certificate renewal {{ if is_success }}succeeded{{ else }}failed{{ endif }} for { identifiers.0 }
The following certificate has {{#unless is_success}}*not* {{/unless}}been renewed.
identifiers: {{#each identifiers}}{{#if @index}}, {{/if}}{{this}}{{/each}}
key type: {{key_type}}
status: {{status}}"""
The following certificate has {{ if not is_success }}*not* {{ endif }}been renewed.
identifiers: {{ for ident in identifiers}}{{ if @index }}, {{ endif }}{ ident }{{ endfor}}
key type: { key_type }
status: { status }"""
.Ed
.Sh SEE ALSO
.Xr acmed 8 ,
@ -805,9 +805,9 @@ status: {{status}}"""
.Re
.It
.Rs
.%A Yehuda Katz
.%T Handlebars
.%U https://handlebarsjs.com/
.%A Brook Heisler
.%T TinyTemplate
.%U https://docs.rs/tinytemplate/latest/tinytemplate/syntax/index.html
.Re
.It
.Rs

Loading…
Cancel
Save