#include <vector>
#include <initializer_list>
#include <string.h>
#include <sched.h>
#include <unistd.h>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <filesystem>
#include <sys/mount.h>
#include <sys/capability.h>
#include <exile.hpp>
#include "../logger.h"
#include "../utils.h"
#include "../random.h"

#include "sandbox-linux.h"

bool SandboxLinux::supported()
{
	std::fstream stream;
	stream.open("/proc/sys/kernel/unprivileged_userns_clone");
	if(stream.is_open())
	{
		std::string str;
		stream >> str;
		if(str[0] == '0')
		{
			Logger::error() << "Please write '1' to /proc/sys/kernel/unprivileged_userns_clone in order to enable "
							   "sandboxing support on this system";
			return false;
		}
	}
	return true;
}
bool SandboxLinux::enable(std::vector<std::string> fsPaths)
{
	std::sort(fsPaths.begin(), fsPaths.end(),
			  [](const std::string &a, const std::string &b) { return a.length() < b.length(); });

	struct exile_policy *policy = exile_init_policy();
	if(policy == NULL)
	{
		Logger::error() << "Failed to init sandboxing policy (worker) ";
		return false;
	}
	for(unsigned int i = 0; i < fsPaths.size(); i++)
	{
		exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ | EXILE_FS_ALLOW_ALL_WRITE, fsPaths[i].c_str());
	}
	policy->drop_caps = 1;
	policy->not_dumpable = 1;
	policy->no_new_privs = 1;
	policy->mount_path_policies_to_chroot = 1;
	policy->vow_promises = exile_vows_from_str("stdio wpath cpath rpath inet unix thread");
	if(exile_enable_policy(policy) != 0)
	{
		Logger::error() << "Sandbox: Activation of exile failed!";
		exile_free_policy(policy);
		return false;
	}
	exile_free_policy(policy);
	return true;
}