mod_digest/
lib.rs

1use config::{any_err, get_or_create_sub_module};
2use data_encoding::{
3    BASE32, BASE32HEX, BASE32HEX_NOPAD, BASE32_NOPAD, BASE64, BASE64URL, BASE64URL_NOPAD,
4    BASE64_NOPAD, HEXLOWER,
5};
6use mlua::prelude::LuaUserData;
7use mlua::{Lua, MetaMethod, UserDataFields, UserDataMethods, Value, Variadic};
8use ring::digest::*;
9
10fn digest_recursive(value: &Value, ctx: &mut Context) -> anyhow::Result<()> {
11    match value {
12        Value::String(s) => {
13            ctx.update(&s.as_bytes());
14        }
15        _ => {
16            let json = serde_json::to_string(value)?;
17            ctx.update(json.as_bytes());
18        }
19    }
20    Ok(())
21}
22
23fn digest_helper(
24    algorithm: &'static Algorithm,
25    args: Variadic<Value>,
26) -> anyhow::Result<DigestResult> {
27    let mut ctx = Context::new(algorithm);
28    for item in args.iter() {
29        digest_recursive(item, &mut ctx)?;
30    }
31    let digest = ctx.finish();
32    Ok(DigestResult(digest.as_ref().to_vec()))
33}
34
35struct DigestResult(Vec<u8>);
36
37impl LuaUserData for DigestResult {
38    fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
39        fields.add_field_method_get("hex", |_, this| Ok(HEXLOWER.encode(&this.0)));
40
41        fields.add_field_method_get("base32", |_, this| Ok(BASE32.encode(&this.0)));
42        fields.add_field_method_get("base32_nopad", |_, this| Ok(BASE32_NOPAD.encode(&this.0)));
43
44        fields.add_field_method_get("base32hex", |_, this| Ok(BASE32HEX.encode(&this.0)));
45        fields.add_field_method_get("base32hex_nopad", |_, this| {
46            Ok(BASE32HEX_NOPAD.encode(&this.0))
47        });
48
49        fields.add_field_method_get("base64", |_, this| Ok(BASE64.encode(&this.0)));
50        fields.add_field_method_get("base64_nopad", |_, this| Ok(BASE64_NOPAD.encode(&this.0)));
51
52        fields.add_field_method_get("base64url", |_, this| Ok(BASE64URL.encode(&this.0)));
53        fields.add_field_method_get("base64url_nopad", |_, this| {
54            Ok(BASE64URL_NOPAD.encode(&this.0))
55        });
56
57        fields.add_field_method_get("bytes", |lua, this| lua.create_string(&this.0));
58    }
59
60    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
61        methods.add_meta_method(MetaMethod::ToString, |_, this, _: ()| {
62            Ok(HEXLOWER.encode(&this.0))
63        });
64    }
65}
66
67pub fn register(lua: &Lua) -> anyhow::Result<()> {
68    let digest_mod = get_or_create_sub_module(lua, "digest")?;
69
70    digest_mod.set(
71        "sha1",
72        lua.create_function(|_, args: Variadic<Value>| {
73            digest_helper(&SHA1_FOR_LEGACY_USE_ONLY, args).map_err(any_err)
74        })?,
75    )?;
76    digest_mod.set(
77        "sha256",
78        lua.create_function(|_, args: Variadic<Value>| {
79            digest_helper(&SHA256, args).map_err(any_err)
80        })?,
81    )?;
82    digest_mod.set(
83        "sha384",
84        lua.create_function(|_, args: Variadic<Value>| {
85            digest_helper(&SHA384, args).map_err(any_err)
86        })?,
87    )?;
88    digest_mod.set(
89        "sha512",
90        lua.create_function(|_, args: Variadic<Value>| {
91            digest_helper(&SHA512, args).map_err(any_err)
92        })?,
93    )?;
94    digest_mod.set(
95        "sha512_256",
96        lua.create_function(|_, args: Variadic<Value>| {
97            digest_helper(&SHA512_256, args).map_err(any_err)
98        })?,
99    )?;
100
101    Ok(())
102}