mod_digest/
lib.rs

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