///|
/// Request signing and the two body layouts every message is rendered from.
/// String/JSON/encoding helpers live in chensuiyi/fndash, time formatting
/// in chensuiyi/dateku.
///|
/// HMAC-SHA256, base64-encoded: the shared half of the two Chinese chat
/// platforms' request signing.
fn hmac_sha256_base64(key : String, message : String) -> String {
let mac = @crypto.hmac(
@crypto.SHA256::new(),
@utf8.encode(key)[:],
@utf8.encode(message)[:],
)
@base64.encode(mac.unsafe_reinterpret_as_bytes())
}
///|
/// DingTalk signs `timestamp + "\n" + secret` with the secret as the key, and
/// carries the timestamp in milliseconds.
fn dingtalk_signature(secret : String, timestamp_ms : UInt64) -> String {
@fndash.url_encode(
hmac_sha256_base64(secret, timestamp_ms.to_string() + "\n" + secret),
)
}
///|
/// Feishu signs the *empty* message with `timestamp + "\n" + secret` as the key
/// (the inverse of DingTalk) and carries the timestamp in seconds.
fn feishu_signature(secret : String, timestamp_s : UInt64) -> String {
hmac_sha256_base64(timestamp_s.to_string() + "\n" + secret, "")
}
///|
fn field_lines(msg : Message, bullet : String) -> String {
let buf = StringBuilder()
for pair in msg.fields {
let (key, value) = pair
buf.write_string("\n" + bullet + key + ": " + value)
}
buf.to_string()
}
///|
fn plain_body(msg : Message, ctx : Context) -> String {
msg.title +
"\n" +
msg.body +
field_lines(msg, "") +
"\n\n--\n" +
ctx.product +
" @ " +
ctx.host
}
///|
fn markdown_body(msg : Message, ctx : Context) -> String {
"**" +
msg.title +
"**\n\n" +
msg.body +
field_lines(msg, "- ") +
"\n\n> " +
ctx.product +
" @ " +
ctx.host
}