1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::config::Config;
use crate::errors::*;
use crate::engine::{ctx, Environment};
use crate::ipc::child::DummyIpcChild;
use crate::engine::ctx::{State, LuaState};
use crate::geoip::{Maxmind, AsnDB, GeoIP};
use crate::hlua::{Lua, AnyLuaValue};
use crate::paths;
use crate::psl::PslReader;
use crate::shell::readline::Readline;
use crate::runtime::format_lua;
use chrootable_https::Resolver;
use std::collections::HashMap;
use std::sync::Arc;

mod complete;
use self::complete::ReplCompleter;
mod tokenize;

pub struct Repl<'a> {
    rl: Readline<ReplCompleter>,
    lua: Lua<'a>,
    state: Arc<LuaState>,
}

impl<'a> Repl<'a> {
    pub fn new(lua: Lua<'a>, state: Arc<LuaState>) -> Repl<'a> {
        let rl = Readline::with(ReplCompleter::default());
        Repl {
            rl,
            lua,
            state,
        }
    }

    fn update_globals(&mut self) {
        let mut globals = Vec::new();
        for item in self.lua.globals_table().iter::<String, AnyLuaValue>() {
            if let Some((k, _)) = item {
                globals.push(k);
            }
        }
        if let Some(helper) = self.rl.helper_mut() {
            debug!("updating globals: {:?}", globals);
            helper.set(globals);
        }
    }

    pub fn run(&mut self) {
        loop {
            self.update_globals();

            match self.rl.readline("> ") {
                Ok(line) => {
                    self.rl.add_history_entry(line.as_str());
                    self.exec(&line);
                },
                Err(_) => break,
            }
        }
    }

    pub fn exec(&mut self, line: &str) {
        match self.lua.execute::<AnyLuaValue>(line) {
            Ok(val) => {
                if val != AnyLuaValue::LuaNil {
                    let mut out = String::new();
                    format_lua(&mut out, &val);
                    println!("{}", out);
                }
                if let Some(err) = self.state.last_error() {
                    println!("Error: {}", err);
                    self.state.clear_error();
                }
            },
            Err(err) => {
                println!("Fatal: {}", err);
            }
        }
    }
}

pub fn run(config: &Config) -> Result<()> {
    let keyring = Vec::new();
    let dns_config = Resolver::from_system_v4()?;
    let proxy = config.network.proxy;

    let cache_dir = paths::cache_dir()?;
    let psl = PslReader::open(&cache_dir)?;
    let geoip = GeoIP::try_open_reader(&cache_dir)?;
    let asn = AsnDB::try_open_reader(&cache_dir)?;

    let env = Environment {
        verbose: 0, // this doesn't do anything since we use a dummy ipc child
        keyring,
        dns_config,
        proxy,
        options: HashMap::new(),
        blobs: Vec::new(),
        psl,
        geoip,
        asn,
    };

    let tx = DummyIpcChild::create();
    let (lua, state) = ctx::ctx(env, tx);
    let mut repl = Repl::new(lua, state);

    println!(r#":: sn0int v{} lua repl
Assign variables with `a = sn0int_version()` and `return a` to print
Read the docs at https://sn0int.readthedocs.io/en/stable/reference.html
"#, env!("CARGO_PKG_VERSION"));

    repl.run();

    Ok(())
}