ic-web/server/main.lua

412 lines
17 KiB
Lua
Raw Normal View History

-- ─────────────────────────────────────────────────────────────────────────────
-- ic-web Netzwerkereignisse, Exports, Konsolenbefehle
--
-- Jedes Ereignis ist frei aufrufbar und deshalb gedrosselt. Rechte werden
-- ausnahmslos serverseitig aus der Anmeldung abgeleitet; der Client erfaehrt
-- nur das Ergebnis.
-- ─────────────────────────────────────────────────────────────────────────────
local S = ICWeb.Sites
local D = ICWeb.Domains
local M = ICWeb.Manage
local A = ICWeb.Auth
local DB = ICWeb.DB
local FW = ICWeb.FW
local function reply(src, reqId, ok, data, err)
TriggerClientEvent('ic-web:client:response', src, reqId,
{ ok = ok == true, data = data, error = err })
end
-- ── Anmeldung ────────────────────────────────────────────────────────────────
RegisterNetEvent('ic-web:server:login', function(reqId, username, password)
local src = source
-- Eng gedrosselt: die Sperre je Benutzername greift erst nach fuenf
-- Versuchen, diese hier bremst das Durchprobieren vieler Benutzernamen.
if not ICWeb.ThrottleOk(src, 'login', 8, 60000) then
return reply(src, reqId, false, nil, 'Zu viele Versuche, bitte kurz warten.')
end
local session, err = A.Login(src, username, password)
reply(src, reqId, session ~= nil, session, err)
end)
RegisterNetEvent('ic-web:server:logout', function(reqId)
local src = source
A.Logout(src)
reply(src, reqId, true)
end)
-- Wer bin ich gerade? Ohne Anmeldung: data = nil, aber ok = true.
RegisterNetEvent('ic-web:server:session', function(reqId)
local src = source
if not ICWeb.ThrottleOk(src, 'session', 20, 10000) then return end
reply(src, reqId, true, {
session = A.Public(src),
themes = Config.Themes,
tlds = Config.Domain.allowedTlds,
imageHosts = Config.ImageHosts,
provider = Config.MainAdmin.providerName,
selfService = Config.SelfRegistration.enabled,
})
end)
RegisterNetEvent('ic-web:server:changePassword', function(reqId, accountId, password)
local src = source
if not ICWeb.ThrottleOk(src, 'passwd', 5, 60000) then return end
local ok, err = M.SetAccountPassword(src, accountId, password)
if ok then FW.Notify(src, 'Passwort geändert.') end
reply(src, reqId, ok, nil, err)
end)
-- ── Lesen: jeder darf ────────────────────────────────────────────────────────
RegisterNetEvent('ic-web:server:getSite', function(reqId, domain, slug)
local src = source
if not ICWeb.ThrottleOk(src, 'get', 30, 10000) then return end
local site, err = S.GetPublic(domain, slug)
reply(src, reqId, site ~= nil, site, err)
end)
-- ── Eigene Domaenen ──────────────────────────────────────────────────────────
RegisterNetEvent('ic-web:server:listMine', function(reqId)
local src = source
if not ICWeb.ThrottleOk(src, 'listMine', 10, 10000) then return end
reply(src, reqId, true, S.ListMine(src))
end)
RegisterNetEvent('ic-web:server:getEditable', function(reqId, domain)
local src = source
if not ICWeb.ThrottleOk(src, 'getEditable', 20, 10000) then return end
local site, err = S.GetForEditor(src, domain)
reply(src, reqId, site ~= nil, site, err)
end)
-- ── Selbstanmeldung einer Domaene (nur wenn eingeschaltet) ───────────────────
RegisterNetEvent('ic-web:server:register', function(reqId, domain, title)
local src = source
if not ICWeb.ThrottleOk(src, 'register', 3, 60000) then
return reply(src, reqId, false, nil, 'Zu viele Versuche, bitte kurz warten.')
end
local site, err, credentials = D.Register(src, domain, title)
if not site then
ICWeb.Log.Write(src, 'domain.rejected', { domain = tostring(domain), reason = err }, 'warn')
return reply(src, reqId, false, nil, err)
end
FW.Notify(src, ('Domäne %s registriert.'):format(site.domain))
reply(src, reqId, true, {
domain = site.domain, title = site.title, credentials = credentials,
})
end)
-- ── Bearbeiten ───────────────────────────────────────────────────────────────
RegisterNetEvent('ic-web:server:savePage', function(reqId, domain, slug, title, blocks)
local src = source
if not ICWeb.ThrottleOk(src, 'save', 20, 60000) then
return reply(src, reqId, false, nil, 'Zu viele Speichervorgänge, bitte kurz warten.')
end
local ok, err = S.SavePage(src, domain, slug, title, blocks)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:deletePage', function(reqId, domain, slug)
local src = source
if not ICWeb.ThrottleOk(src, 'delete', 10, 60000) then return end
local ok, err = S.DeletePage(src, domain, slug)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:updateSite', function(reqId, domain, data)
local src = source
if not ICWeb.ThrottleOk(src, 'update', 20, 60000) then return end
if type(data) ~= 'table' then return reply(src, reqId, false, nil, 'Ungültige Daten.') end
local ok, err = S.UpdateSite(src, domain, data)
reply(src, reqId, ok, nil, err)
end)
-- ── Melden ───────────────────────────────────────────────────────────────────
-- Ohne Anmeldung: jeder Spieler soll eine Seite melden koennen.
RegisterNetEvent('ic-web:server:report', function(reqId, domain, slug, reason)
local src = source
if not ICWeb.ThrottleOk(src, 'report', 5, 60000) then return end
local ok, err = S.Report(src, domain, slug, reason)
if ok then FW.Notify(src, 'Meldung eingegangen. Danke.') end
reply(src, reqId, ok, nil, err)
end)
-- ── Postfaecher im Mailclient ───────────────────────────────────────────────
-- Ein Postfach freischalten ist eine Passwortpruefung wie die Anmeldung und
-- deshalb genauso eng gedrosselt.
RegisterNetEvent('ic-web:server:openMailbox', function(reqId, username, password)
local src = source
if not ICWeb.ThrottleOk(src, 'openMailbox', 8, 60000) then
return reply(src, reqId, false, nil, 'Zu viele Versuche, bitte kurz warten.')
end
local ok, err = A.OpenMailbox(src, username, password)
if ok then FW.Notify(src, 'Postfach hinzugefügt.') end
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:closeMailbox', function(reqId, username)
local src = source
if not ICWeb.ThrottleOk(src, 'closeMailbox', 20, 60000) then return end
local ok, err = A.CloseMailbox(src, username)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:listMailboxes', function(reqId)
local src = source
if not ICWeb.ThrottleOk(src, 'listMailboxes', 20, 10000) then return end
reply(src, reqId, true, A.ListOpenMailboxes(src))
end)
-- ── Zugaenge je Domaene ─────────────────────────────────────────────────────
RegisterNetEvent('ic-web:server:listAccounts', function(reqId, domain)
local src = source
if not ICWeb.ThrottleOk(src, 'accounts', 20, 10000) then return end
local list, err = M.ListAccounts(src, domain)
reply(src, reqId, list ~= nil, list, err)
end)
RegisterNetEvent('ic-web:server:createAccount',
function(reqId, domain, username, password, role, displayName)
local src = source
if not ICWeb.ThrottleOk(src, 'createAccount', 10, 60000) then return end
local account, err = M.CreateAccount(src, domain, username, password, role, displayName)
reply(src, reqId, account ~= nil, account, err)
end)
RegisterNetEvent('ic-web:server:setAccountPassword', function(reqId, accountId, password)
local src = source
if not ICWeb.ThrottleOk(src, 'setPassword', 10, 60000) then return end
local ok, err = M.SetAccountPassword(src, accountId, password)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:setAccountActive', function(reqId, accountId, active)
local src = source
if not ICWeb.ThrottleOk(src, 'setActive', 20, 60000) then return end
local ok, err = M.SetAccountActive(src, accountId, active == true)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:setAccountRole', function(reqId, accountId, role)
local src = source
if not ICWeb.ThrottleOk(src, 'setRole', 20, 60000) then return end
local ok, err = M.SetAccountRole(src, accountId, role)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:deleteAccount', function(reqId, accountId)
local src = source
if not ICWeb.ThrottleOk(src, 'deleteAccount', 10, 60000) then return end
local ok, err = M.DeleteAccount(src, accountId)
reply(src, reqId, ok, nil, err)
end)
-- ── Anbieterebene ───────────────────────────────────────────────────────────
RegisterNetEvent('ic-web:server:adminListSites', function(reqId)
local src = source
if not ICWeb.ThrottleOk(src, 'adminList', 20, 10000) then return end
local list, err = M.AdminListSites(src)
reply(src, reqId, list ~= nil, list, err)
end)
RegisterNetEvent('ic-web:server:adminListAccounts', function(reqId)
local src = source
if not ICWeb.ThrottleOk(src, 'adminAccounts', 20, 10000) then return end
local list, err = M.AdminListAccounts(src)
reply(src, reqId, list ~= nil, list, err)
end)
RegisterNetEvent('ic-web:server:adminListJobs', function(reqId)
local src = source
if not ICWeb.ThrottleOk(src, 'adminJobs', 10, 10000) then return end
local list, err = M.AdminListJobs(src)
reply(src, reqId, list ~= nil, list, err)
end)
RegisterNetEvent('ic-web:server:adminRegister',
function(reqId, domain, title, ownerId, adminUser, adminPassword)
local src = source
if not ICWeb.ThrottleOk(src, 'adminRegister', 10, 60000) then return end
local site, err, credentials = M.AdminRegister(src, domain, title, ownerId,
adminUser, adminPassword)
reply(src, reqId, site ~= nil,
site and { domain = site.domain, credentials = credentials } or nil, err)
end)
RegisterNetEvent('ic-web:server:adminSetBlocked', function(reqId, domain, blocked)
local src = source
if not ICWeb.ThrottleOk(src, 'adminBlock', 20, 60000) then return end
local ok, err = M.AdminSetBlocked(src, domain, blocked == true)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:adminSetOwner', function(reqId, domain, ownerId)
local src = source
if not ICWeb.ThrottleOk(src, 'adminOwner', 10, 60000) then return end
local ok, err = M.AdminSetOwner(src, domain, ownerId)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:adminDeleteSite', function(reqId, domain)
local src = source
if not ICWeb.ThrottleOk(src, 'adminDelete', 5, 60000) then return end
local ok, err = M.AdminDeleteSite(src, domain)
reply(src, reqId, ok, nil, err)
end)
RegisterNetEvent('ic-web:server:adminListReports', function(reqId)
local src = source
if not ICWeb.ThrottleOk(src, 'adminReports', 20, 10000) then return end
local list, err = M.AdminListReports(src)
reply(src, reqId, list ~= nil, list, err)
end)
RegisterNetEvent('ic-web:server:adminSetReportStatus', function(reqId, id, status)
local src = source
if not ICWeb.ThrottleOk(src, 'adminReportStatus', 30, 60000) then return end
local ok, err = M.AdminSetReportStatus(src, id, status)
reply(src, reqId, ok, nil, err)
end)
-- ── Konsolenbefehle ─────────────────────────────────────────────────────────
-- Kein IC-Weg, sondern die Notbremse des Serverbetreibers. Absichtlich nur in
-- der Serverkonsole und fuer Serveradmins nicht ueber die Anmeldung.
local function consoleAllowed(src)
if not src or src == 0 then return true end
return FW.IsAdmin(src)
end
RegisterCommand('webpasswd', function(src, args)
if not consoleAllowed(src) then return end
local username = tostring(args[1] or ''):lower()
local password = tostring(args[2] or '')
if username == '' or password == '' then
print('[ic-web] /webpasswd <benutzer@domaene> <neues-passwort>')
return
end
local account = DB.GetAccountByUsername(username)
if not account then print('[ic-web] Zugang nicht gefunden.') return end
local ok, err = A.SetPassword(account.id, password)
print(ok and ('[ic-web] Passwort von %s geändert.'):format(username)
or ('[ic-web] Fehlgeschlagen: %s'):format(tostring(err)))
end, true)
RegisterCommand('webaccounts', function(src)
if not consoleAllowed(src) then return end
local rows = DB.GetAllAccounts()
print(('[ic-web] %d Zugänge:'):format(#rows))
for _, a in ipairs(rows) do
print((' %-34s %-11s %-22s %s'):format(
a.username, a.role, a.domain or '',
ICWeb.Bool(a.active) and 'aktiv' or 'gesperrt'))
end
end, true)
RegisterCommand('webreports', function(src)
if not consoleAllowed(src) then return end
local reports = DB.GetOpenReports()
if #reports == 0 then print('[ic-web] Keine offenen Meldungen.') return end
print(('[ic-web] %d offene Meldungen:'):format(#reports))
for _, r in ipairs(reports) do
print((' #%d %-24s %-10s %s'):format(
r.id, r.domain, r.page_slug or '-', (r.reason or ''):sub(1, 60)))
end
print('[ic-web] Sperren mit /webblock <domain>, erledigen mit /webreport done <id>')
end, true)
RegisterCommand('webblock', function(src, args)
if not consoleAllowed(src) then return end
local domain = tostring(args[1] or ''):lower()
local site = DB.GetSiteByDomain(domain)
if not site then print('[ic-web] Domäne nicht gefunden.') return end
local blocked = not ICWeb.Bool(site.blocked)
DB.SetBlocked(site.id, blocked)
ICWeb.Log.Write(src, blocked and 'site.blocked' or 'site.unblocked', { domain = domain }, 'warn')
print(('[ic-web] %s ist jetzt %s.'):format(domain, blocked and 'gesperrt' or 'frei'))
end, true)
RegisterCommand('webreport', function(src, args)
if not consoleAllowed(src) then return end
local action = tostring(args[1] or '')
local id = tonumber(args[2])
if (action ~= 'done' and action ~= 'dismiss') or not id then
print('[ic-web] /webreport done <id> oder /webreport dismiss <id>')
return
end
DB.SetReportStatus(id, action == 'done' and 'reviewed' or 'dismissed')
print(('[ic-web] Meldung #%d als %s markiert.'):format(id, action))
end, true)
-- ── Exports fuer andere Resources ────────────────────────────────────────────
exports('GetSite', function(domain, slug)
return S.GetPublic(domain, slug)
end)
exports('DomainExists', function(domain)
return DB.GetSiteByDomain(tostring(domain or ''):lower()) ~= nil
end)
exports('GetSitesForJob', function(job)
return DB.GetSitesForOwner('job', job)
end)
-- Wer ist an diesem Bildschirm angemeldet? pc-live nutzt das, um das Postfach
-- des Zugangs zu oeffnen statt des persoenlichen.
exports('GetSession', function(src)
return A.Public(src)
end)
-- ── Start ────────────────────────────────────────────────────────────────────
AddEventHandler('onResourceStart', function(res)
if res ~= GetCurrentResourceName() then return end
if GetResourceState('ic-mail') ~= 'started' then
print('[ic-web] ^3Hinweis^7: ic-mail läuft nicht Domänen werden ohne Postfächer angelegt.')
end
A.EnsureMainAdmin()
A.CleanupStaleMailAccess()
DB.PruneLoginFails(86400)
local sites = MySQL.single.await('SELECT COUNT(*) AS n FROM ic_web_sites')
print(('[ic-web] bereit. %d Domänen registriert.'):format((sites and sites.n) or 0))
end)