Add a basic permission system based on lua stdlib loading

This commit is contained in:
Mm2PL 2023-01-31 15:00:46 +01:00
parent 5191f4c9eb
commit 1cc849b9f7
No known key found for this signature in database
GPG key ID: 94AC9B80EFA15ED9
3 changed files with 71 additions and 3 deletions

View file

@ -73,19 +73,52 @@ bool PluginController::tryLoadFromDir(const QDir &pluginDir)
this->load(index, pluginDir, PluginMeta(doc.object())); this->load(index, pluginDir, PluginMeta(doc.object()));
return true; return true;
} }
void PluginController::openLibrariesFor(lua_State *L, PluginMeta meta)
{
// copied from linit.c
static const std::array<luaL_Reg, 11> loadedlibs = {
luaL_Reg{LUA_GNAME, luaopen_base},
luaL_Reg{LUA_LOADLIBNAME, luaopen_package},
luaL_Reg{LUA_COLIBNAME, luaopen_coroutine},
luaL_Reg{LUA_TABLIBNAME, luaopen_table},
luaL_Reg{LUA_IOLIBNAME, luaopen_io},
luaL_Reg{LUA_OSLIBNAME, luaopen_os},
luaL_Reg{LUA_STRLIBNAME, luaopen_string},
luaL_Reg{LUA_MATHLIBNAME, luaopen_math},
luaL_Reg{LUA_UTF8LIBNAME, luaopen_utf8},
luaL_Reg{LUA_DBLIBNAME, luaopen_debug},
luaL_Reg{NULL, NULL},
};
for (const auto &reg : loadedlibs)
{
if (meta.libraryPermissions.contains(QString(reg.name)))
{
luaL_requiref(L, reg.name, reg.func, int(true));
lua_pop(L, 1);
}
}
}
void PluginController::load(QFileInfo index, QDir pluginDir, PluginMeta meta) void PluginController::load(QFileInfo index, QDir pluginDir, PluginMeta meta)
{ {
qCDebug(chatterinoLua) << "Running lua file" << index; qCDebug(chatterinoLua) << "Running lua file" << index;
lua_State *l = luaL_newstate(); lua_State *l = luaL_newstate();
luaL_openlibs(l); this->openLibrariesFor(l, meta);
this->loadChatterinoLib(l); this->loadChatterinoLib(l);
auto pluginName = pluginDir.dirName(); auto pluginName = pluginDir.dirName();
auto plugin = std::make_unique<Plugin>(pluginName, l, meta, pluginDir); auto plugin = std::make_unique<Plugin>(pluginName, l, meta, pluginDir);
this->plugins_.insert({pluginName, std::move(plugin)}); this->plugins_.insert({pluginName, std::move(plugin)});
luaL_dofile(l, index.absoluteFilePath().toStdString().c_str()); int err = luaL_dofile(l, index.absoluteFilePath().toStdString().c_str());
if (err != 0)
{
qCWarning(chatterinoLua)
<< "Failed to load" << pluginName << "plugin from" << index << ": "
<< lua::humanErrorText(l, err);
return;
}
qCInfo(chatterinoLua) << "Loaded" << pluginName << "plugin from" << index; qCInfo(chatterinoLua) << "Loaded" << pluginName << "plugin from" << index;
} }

View file

@ -29,6 +29,8 @@ struct PluginMeta {
QString homepage; QString homepage;
std::vector<QString> tags; std::vector<QString> tags;
std::set<QString> libraryPermissions;
explicit PluginMeta(const QJsonObject &obj) explicit PluginMeta(const QJsonObject &obj)
: name(obj.value("name").toString()) : name(obj.value("name").toString())
, description(obj.value("description").toString()) , description(obj.value("description").toString())
@ -37,7 +39,11 @@ struct PluginMeta {
{ {
for (const auto &t : obj.value("tags").toArray()) for (const auto &t : obj.value("tags").toArray())
{ {
tags.push_back(t.toString()); this->tags.push_back(t.toString());
}
for (const auto &t : obj.value("library_permissions").toArray())
{
this->libraryPermissions.insert(t.toString());
} }
} }
}; };
@ -121,6 +127,9 @@ public:
private: private:
void load(QFileInfo index, QDir pluginDir, PluginMeta meta); void load(QFileInfo index, QDir pluginDir, PluginMeta meta);
void loadChatterinoLib(lua_State *l); void loadChatterinoLib(lua_State *l);
// This function adds lua standard libraries into the state
void openLibrariesFor(lua_State *L, PluginMeta meta);
bool tryLoadFromDir(const QDir &pluginDir); bool tryLoadFromDir(const QDir &pluginDir);
std::map<QString, std::unique_ptr<Plugin>> plugins_; std::map<QString, std::unique_ptr<Plugin>> plugins_;
}; };

View file

@ -49,6 +49,32 @@ PluginsPage::PluginsPage()
pl->addRow("Homepage", homepage); pl->addRow("Homepage", homepage);
QString libString;
bool hasDangerous = false;
for (const auto &library : plugin->meta.libraryPermissions)
{
if (!libString.isEmpty())
{
libString += ", ";
}
if (library == "os" || library == "io")
{
hasDangerous = true;
}
libString += library;
}
if (hasDangerous)
{
libString += "\nDetected potentially dangerous libraries used, be "
"careful with this plugin";
}
auto *libs = new QLabel(libString);
if (hasDangerous)
{
libs->setStyleSheet("color: red");
}
pl->addRow("Used libraries", libs);
auto *reload = new QPushButton("Reload"); auto *reload = new QPushButton("Reload");
QObject::connect(reload, &QPushButton::pressed, [name = codename]() { QObject::connect(reload, &QPushButton::pressed, [name = codename]() {
getApp()->plugins->reload(name); getApp()->plugins->reload(name);