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}