sn0int 0.25.0

Semi-automatic OSINT framework and package manager
Documentation
use crate::errors::*;
use crate::engine::ctx::State;
use crate::hlua::{self, AnyLuaValue};
use crate::xml;
use std::sync::Arc;


pub fn xml_decode(lua: &mut hlua::Lua, state: Arc<dyn State>) {
    lua.set("xml_decode", hlua::function1(move |x: String| -> Result<AnyLuaValue> {
        xml::decode(&x)
            .map_err(|err| state.set_error(err))
    }))
}

#[inline]
fn key_is(key: &AnyLuaValue, expected: &str) -> bool {
    match key {
        AnyLuaValue::LuaString(key) => key.as_str() == expected,
        _ => false,
    }
}

#[inline]
fn get_children(xml: AnyLuaValue) -> Option<AnyLuaValue> {
    match xml {
        AnyLuaValue::LuaArray(arr) => {
            for (key, value) in arr {
                if key_is(&key, "children") {
                    return Some(value);
                }
            }

            None
        }
        _ => None,
    }
}

#[inline]
fn match_element_name(xml: &AnyLuaValue, name: &str) -> bool {
    match xml {
        AnyLuaValue::LuaArray(arr) => {
            for (key, value) in arr {
                if key_is(key, "name") {
                    match value {
                        AnyLuaValue::LuaString(key) => {
                            return key.as_str() == name
                        },
                        _ => return false,
                    }
                }
            }

            false
        },
        _ => false,
    }
}

pub fn xml_named(lua: &mut hlua::Lua, _state: Arc<dyn State>) {
    lua.set("xml_named", hlua::function2(move |xml: AnyLuaValue, name: String| -> AnyLuaValue {
        if let Some(AnyLuaValue::LuaArray(arr)) = get_children(xml) {
            for (_, value) in arr {
                if match_element_name(&value, &name) {
                    return value;
                }
            }
        }

        AnyLuaValue::LuaNil
    }))
}

#[cfg(test)]
mod tests {
    use crate::engine::ctx::Script;

    #[test]
    fn verify_xml_decode() {
        let script = Script::load_unchecked(r#"
        function run()
            x = xml_decode('<body><foo fizz="buzz">bar</foo></body>')
            if last_err() then return end
            print(x)

            body = x['children'][1]
            if body['name'] ~= 'body' then
                return 'wrong body tag name'
            end

            foo = xml_named(body, 'foo')
            if foo['name'] ~= 'foo' then
                return 'foo has wrong tag name'
            end
            if foo['attrs']['fizz'] ~= 'buzz' then
                return 'foo has wrong fizz attribute'
            end
            if foo['text'] ~= 'bar' then
                return 'foo has wrong inner text'
            end
            if foo['children'][1] then
                return 'foo has unexpected children'
            end
        end
        "#).expect("Failed to load script");
        script.test().expect("Script failed");
    }
}