#!/usr/bin/env lua5.3 print"Ikibooru Installer\n" do local st, res = pcall(io.popen, "uname -s", "r") if not st or res:read"*l" ~= "Linux" then print"Only Linux is supported by the installer at this moment." return end end if not os.getenv"SUDO_COMMAND" then print"Please run under sudo or as root." return end local baad = false if not pcall(require, "lfs") then print"LuaFileSystem not installed." print"Install manually or using LuaRocks (package name 'luafilesystem')" print"" baad = true end if not pcall(require, "zlib") or not require"zlib"._COPYRIGHT or not (require"zlib"._COPYRIGHT:match"Maher" or require"zlib"._COPYRIGHT:match"Dionizio") then print"lua-zlib not installed." print"Install manually or using LuaRocks (package name 'lua-zlib')" print"" baad = true end if not pcall(require, "openssl") or require"openssl".VERSION_NUMBER == nil then print"luaossl not installed." print"Install manually or using LuaRocks (package name 'luaossl')" print"" baad = true end if not pcall(require, "posix.fcntl") then print"LuaPOSIX not installed." print"Install manually or using LuaRocks (package name 'luaposix')" print"" baad = true end if not pcall(require, "socket.url") then print"LuaSocket not installed." print"Install manually or using LuaRocks (package name 'luasocket')" print"" baad = true end if not pcall(require, "luasql.mysql") or not require"luasql.mysql".mysql() then print"luasql-mysql not installed." print"Install manually or using LuaRocks (package name 'luasql-mysql')" print"" baad = true end if not pcall(require, "mimetypes") then print"mimetypes not installed." print"Install manually or using LuaRocks (package name 'mimetypes')" print"" baad = true end local magickprefix if #io.popen"magick convert":read"*a" > 0 then magickprefix = "magick " elseif #io.popen"convert":read"*a" > 0 then magickprefix = "" else print"ImageMagick not installed." print"Install manually or via your system's package manager." print"" baad = true end os.execute"adduser --shell /bin/sh --disabled-password ikibooru" io.stdout:write"MySQL host: " local mysqladdr = io.read"*l" io.stdout:write"MySQL user: " local mysqluser = io.read"*l" io.stdout:write"MySQL password: " local mysqlpass = io.read"*l" local SQLConn = require"luasql.mysql".mysql():connect("", mysqluser, mysqlpass, mysqladdr) if not SQLConn then print"Could not connect to MySQL database." baad = true; end if baad then return end print"" local port repeat io.stdout:write"Port to run on (external connections to which must be blocked): " port = tonumber(io.read"*l") until tonumber(port) ~= nil port = tostring(port) io.stdout:write"Public URI prefix (e.g. https://foo.bar): " local domname = io.read"*l" print"" print"The following parameters are required for the administrator account (user id 0):" io.stdout:write"E-mail address (must be real): " local adminusereml = io.read"*l" io.stdout:write"Display name: " local adminuserdispname = io.read"*l" print"" print"Enter member exclusivity:" print"1. Only admin can invite" print"2. Mods can invite" print"3. Any member can invite" print"4. Public registration; mods must approve" print"5. Public registration without approval (not recommended)" local membexcl while true do membexcl = tonumber(io.read"*l") if membexcl and membexcl % 1 == 0 then if membexcl >= 1 and membexcl <= 5 then break end end print"Try again." end print"" io.stdout:write"Max number of files per object: " local maxfilesperobj while true do maxfilesperobj = tonumber(io.read"*l") if maxfilesperobj and maxfilesperobj % 1 == 0 and maxfilesperobj > 0 then break end print"Try again." end io.stdout:write"Max total object size (in kB): " local maxtotalobjsize while true do maxtotalobjsize = tonumber(io.read"*l") if maxtotalobjsize and maxtotalobjsize % 1 == 0 and maxtotalobjsize > 0 then break end print"Try again." end os.execute"mkdir /home/ikibooru/ikibooru" os.execute"cp -r ./* /home/ikibooru/ikibooru" os.execute"mkdir -p /home/ikibooru/ikibooru/objd" os.execute"rm -r /home/ikibooru/ikibooru/objd/*" os.execute"rm /home/ikibooru/ikibooru/install.lua" -- Not /dev/urandom. System might be new and unseeded. os.execute"dd if=/dev/random of=/home/ikibooru/ikibooru/objkey bs=16 count=1" os.execute"chown -R ikibooru:ikibooru /home/ikibooru/*" os.execute"find /home/ikibooru/ -type f -exec chmod 444 {} \;" os.execute"find /home/ikibooru/ -type d -exec chmod 555 {} \;" os.execute"chmod 440 /home/ikibooru/ikibooru/objkey" -- # These files need writability os.execute"find /home/ikibooru/ikibooru/objd/ -type d -exec chmod 755 {} \;" os.execute"chmod 644 /home/ikibooru/ikibooru/static/tagcats.css" local cfg = io.open("/home/ikibooru/ikibooru/cfg.lua", "wb") cfg:write(string.format([[-- THIS FILE IS AUTO-GENERATED. EDIT WITH CAUTION. return {["domain"]=%q,["sqlh"]=%q,["sqlu"]=%q,["sqlp"]=%q,["port"]=%q,["maxfilesperobj"]=%q,["membexcl"]=%q,["maxtotalobjsize"]=%q,["magickprefix"]=%q,["tc"]={[1]={["name"]="",["col"]=14096010,},[2]={["name"]="",["col"]=6616647,},[3]={["name"]="",["col"]=13138224,},[4]={["name"]="",["col"]=13395600,},[5]={["name"]="",["col"]=15294904,},[6]={["name"]="",["col"]=3314361,},[7]={["name"]="",["col"]=5624104,},[8]={["name"]="",["col"]=12888753,},[9]={["name"]="",["col"]=4660286,},[10]={["name"]="",["col"]=9294073,},[11]={["name"]="",["col"]=8009393,},[12]={["name"]="",["col"]=10550703,},[13]={["name"]="",["col"]=6120067,},[14]={["name"]="",["col"]=8613437,},[15]={["name"]="",["col"]=15975763,},[16]={["name"]="",["col"]=15371202,},[17]={["name"]="",["col"]=10665472,},[18]={["name"]="",["col"]=12034245,},[19]={["name"]="",["col"]=2375696,},[20]={["name"]="",["col"]=10183247,},[21]={["name"]="",["col"]=273478,},[22]={["name"]="",["col"]=4074963,},[23]={["name"]="",["col"]=2302363,},[24]={["name"]="",["col"]=13491847,},[25]={["name"]="",["col"]=2628638,},[26]={["name"]="",["col"]=6726730,},[27]={["name"]="",["col"]=2177522,},[28]={["name"]="",["col"]=1825508,},[29]={["name"]="",["col"]=16759172,},[30]={["name"]="",["col"]=3661743,},[31]={["name"]="",["col"]=8605577,},[32]={["name"]="",["col"]=14077967,},["n"]=32,},["smtpauth"]=true,["sitename"]="Ikibooru",["codever"]=0,["dbver"]=0,["ruleset"]="",["sendfile"]="",["sendfileprefix"]="",["enable18plus"]=false}]], domname, mysqladdr, mysqluser, mysqlpass, port, maxfilesperobj, membexcl, maxtotalobjsize, magickprefix)) cfg:close() cfg = nil os.execute"chmod 640 /home/ikibooru/ikibooru/cfg.lua" os.execute"chown -R root:root /home/ikibooru/ikibooru/uninstall.lua" SQLConn:execute[[CREATE DATABASE ikibooru CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;]] SQLConn:execute[[USE ikibooru;]] SQLConn:execute[[CREATE TABLE `tags` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `category` tinyint(3) unsigned NOT NULL, `adultonly` BIT NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;]] SQLConn:execute[[CREATE TABLE `users` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `displayname` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, `createtime` datetime NOT NULL, `privs` tinyint(4) unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;]] SQLConn:execute[[CREATE TABLE `objects` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `owner` bigint(20) unsigned NULL, `approved` bit(1) NOT NULL, `published` bit(1) NOT NULL, `createtime` datetime NOT NULL, PRIMARY KEY (`id`), FULLTEXT KEY `objects_name_IDX` (`name`), KEY `objects_FK_owner` (`owner`), CONSTRAINT `objects_FK_owner` FOREIGN KEY (`owner`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;]] SQLConn:execute[[CREATE TABLE `comments` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `objid` bigint(20) unsigned NOT NULL, `authorid` bigint(20) unsigned NOT NULL, `createtime` datetime NOT NULL, `content` text NOT NULL, PRIMARY KEY (`id`), KEY `comments_FK_objid` (`objid`), KEY `comments_FK_authorid` (`authorid`), CONSTRAINT `comments_FK_objid` FOREIGN KEY (`objid`) REFERENCES `objects` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `comments_FK_authorid` FOREIGN KEY (`authorid`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;]] SQLConn:execute[[CREATE TABLE `objtag` ( `objid` bigint(20) unsigned NOT NULL, `tagid` bigint(20) unsigned NOT NULL, PRIMARY KEY (`objid`,`tagid`), KEY `objtag_FK_objid` (`objid`), KEY `objtag_FK_tagid` (`tagid`), CONSTRAINT `objtag_FK_objid` FOREIGN KEY (`objid`) REFERENCES `objects` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `objtag_FK_tagid` FOREIGN KEY (`tagid`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;]] SQLConn:execute[[CREATE TABLE `reports` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `reporter` bigint(20) unsigned NOT NULL, `reportee` bigint(20) unsigned NOT NULL, `createtime` datetime NOT NULL, `content` text DEFAULT NULL, `status` tinyint(4) NOT NULL, PRIMARY KEY (`id`), KEY `reports_FK_reporter` (`reporter`), KEY `reports_FK_reportee` (`reportee`), CONSTRAINT `reports_FK_reportee` FOREIGN KEY (`reportee`) REFERENCES `users` (`id`), CONSTRAINT `reports_FK_reporter` FOREIGN KEY (`reporter`) REFERENCES `users` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;]] SQLConn:execute(string.format([[INSERT INTO ikibooru.users (displayname, email, createtime, privs) VALUES ("%s", "%s", "%s", 255);]], SQLConn:escape(adminuserdispname), SQLConn:escape(adminusereml), os.date("!%Y-%m-%d %H:%M:%S"))) if pcall(io.popen, "systemd --version") then local systemd while true do io.stdout:write"Register systemd service (y/n): " local o = io.read"*l":lower() if o == "y" then systemd = true break elseif o == "n" then systemd = false break end print"Try again." end if systemd then local external = false while true do io.stdout:write"Is MySQL server external (y/n): " local o = io.read"*l":lower() if o == "y" then external = true break elseif o == "n" then external = false break end print"Try again." end local service = io.open("/etc/systemd/system/ikibooru.service", "wb") service:write(string.format([[[Unit] Description=Ikibooru fileboard %s [Service] Type=simple Restart=on-failure ExecStart=lua5.3 main.lua WorkingDirectory=/home/ikibooru/ikibooru User=ikibooru Group=ikibooru]], external and "" or "After=mysql.target")) service:close() os.execute"systemctl daemon-reload" print"Done. Service can be started via 'systemctl start ikibooru'." end end print"" print"Installation complete. Remember: Ikibooru is only an HTTP server. It must be used together with a relay or reverse proxy."