469 lines
14 KiB
D
469 lines
14 KiB
D
module daster;
|
||
|
||
import vibe.vibe;
|
||
import singlog;
|
||
import readconf;
|
||
|
||
import core.stdc.stdlib : exit, EXIT_SUCCESS, EXIT_FAILURE;
|
||
import std.stdio: writefln;
|
||
import std.getopt;
|
||
import std.file;
|
||
import std.path;
|
||
import std.algorithm;
|
||
import std.array;
|
||
|
||
import verinfo;
|
||
import pgdb;
|
||
import structures;
|
||
import response;
|
||
|
||
import requests.numbers;
|
||
import requests.sms;
|
||
import requests.ussd;
|
||
import requests.server;
|
||
import requests.authorization;
|
||
|
||
static ServerInfo serverInfo;
|
||
static AuthData serverAuthData;
|
||
|
||
private void showVersion() {
|
||
writefln("daster версия %s, собрано %s", getDasterVersion(), __DATE__);
|
||
}
|
||
|
||
void page404(HTTPServerRequest req, HTTPServerResponse res, HTTPServerErrorInfo error) {
|
||
res.render!("404.dt", req, error);
|
||
}
|
||
|
||
int main(string[] args) {
|
||
log.level(log.INFORMATION)
|
||
.output(log.SYSLOG)
|
||
.color(true);
|
||
|
||
bool flagVersion;
|
||
string flagSettings;
|
||
|
||
try {
|
||
auto opt = getopt(
|
||
args,
|
||
config.bundling,
|
||
config.caseSensitive,
|
||
"settings|s",
|
||
"<файл> Путь к файлу конфигурации settings.conf",
|
||
&flagSettings,
|
||
"version|v",
|
||
"Текущая версия программы",
|
||
&flagVersion
|
||
);
|
||
if (opt.helpWanted) {
|
||
showVersion();
|
||
defaultGetoptPrinter(
|
||
"Использование: daster [ОПЦИИ]...\n",
|
||
opt.options
|
||
);
|
||
return EXIT_SUCCESS;
|
||
}
|
||
if (flagVersion) {
|
||
showVersion();
|
||
return EXIT_SUCCESS;
|
||
}
|
||
} catch (GetOptException e) {
|
||
showVersion();
|
||
log.c(e.msg);
|
||
log.i("Попробуйте 'daster -h' для дополнительной информации");
|
||
log.i("https://git.zhirov.kz/alexander/daster");
|
||
return EXIT_FAILURE;
|
||
}
|
||
|
||
if (!flagSettings.length)
|
||
flagSettings = "./settings.conf";
|
||
|
||
if (!flagSettings.exists) {
|
||
log.c("Файл конфигурации не найден: " ~ flagSettings);
|
||
exit(1);
|
||
}
|
||
|
||
rc.read(flagSettings);
|
||
|
||
auto webHost = rcWebHost();
|
||
serverInfo = ServerInfo(webHost.title);
|
||
|
||
if (webHost.loglevel != -1) log.level(webHost.loglevel);
|
||
if (webHost.logoutput) log.output(webHost.logoutput);
|
||
if (webHost.logfile.length) log.file(webHost.logfile);
|
||
|
||
rcAsteriskDB();
|
||
rcAuth();
|
||
|
||
auto router = new URLRouter;
|
||
router.post("/", &postReq);
|
||
router.get("/", &getReq);
|
||
router.get("*", serveStaticFiles(buildPath(webHost.data, "public")));
|
||
router.get("*", serveStaticFiles(buildPath(webHost.data, "images")));
|
||
router.get("*", serveStaticFiles(buildPath(webHost.data, "js")));
|
||
router.get("*", serveStaticFiles(buildPath(webHost.data, "jq")));
|
||
|
||
auto memorySessionStore = new MemorySessionStore;
|
||
|
||
auto settingsHTTP = new HTTPServerSettings;
|
||
auto settingsHTTPS = new HTTPServerSettings;
|
||
|
||
if (webHost.http) {
|
||
settingsHTTP.errorPageHandler = toDelegate(&page404);
|
||
settingsHTTP.sessionStore = memorySessionStore;
|
||
settingsHTTP.port = webHost.http;
|
||
settingsHTTP.bindAddresses = ["::1"] ~ webHost.addresses;
|
||
}
|
||
|
||
if (webHost.https) {
|
||
settingsHTTPS.errorPageHandler = toDelegate(&page404);
|
||
settingsHTTPS.sessionStore = memorySessionStore;
|
||
settingsHTTPS.port = webHost.https;
|
||
settingsHTTPS.bindAddresses = ["::1"] ~ webHost.addresses;
|
||
settingsHTTPS.tlsContext = createTLSContext(TLSContextKind.server);
|
||
settingsHTTPS.tlsContext.useCertificateChainFile(webHost.cert);
|
||
settingsHTTPS.tlsContext.usePrivateKeyFile(webHost.key);
|
||
}
|
||
|
||
startWebServer(webHost, settingsHTTP, settingsHTTPS, router);
|
||
|
||
return EXIT_SUCCESS;
|
||
}
|
||
|
||
void startWebServer(WebHost wh, HTTPServerSettings http, HTTPServerSettings https, URLRouter router)
|
||
{
|
||
if (wh.http && wh.https) {
|
||
auto listenerHTTP = listenHTTP(http, router);
|
||
auto listenerHTTPS = listenHTTP(https, router);
|
||
scope (exit) { listenerHTTP.stopListening(); }
|
||
scope (exit) { listenerHTTPS.stopListening(); }
|
||
runApplication();
|
||
} else if (wh.http) {
|
||
auto listenerHTTP = listenHTTP(http, router);
|
||
scope (exit) { listenerHTTP.stopListening(); }
|
||
runApplication();
|
||
} else if (wh.https) {
|
||
auto listenerHTTPS = listenHTTP(https, router);
|
||
scope (exit) { listenerHTTPS.stopListening(); }
|
||
runApplication();
|
||
}
|
||
}
|
||
|
||
void getReq(HTTPServerRequest req, HTTPServerResponse res) {
|
||
if (req.session) {
|
||
auto user = req.session.get!UserData("user");
|
||
if (user.login) {
|
||
renderMainPage(req, res);
|
||
return;
|
||
}
|
||
}
|
||
|
||
render!("authorization.dt", serverInfo)(res);
|
||
}
|
||
|
||
void renderMainPage(HTTPServerRequest req, HTTPServerResponse res) {
|
||
render!("index.dt", serverInfo)(res);
|
||
}
|
||
|
||
void postReq(HTTPServerRequest req, HTTPServerResponse res) {
|
||
if (req.method != HTTPMethod.POST) return;
|
||
|
||
auto jsr = req.json;
|
||
string query = jsr["query"].get!string;
|
||
|
||
if (query.empty) return;
|
||
|
||
if (query != "login" && !checkAuth(req)) {
|
||
res.send(
|
||
true,
|
||
"Сессия не существует. Перезагрузите страницу"
|
||
);
|
||
return;
|
||
}
|
||
|
||
log.d("%s: json request %s".format(req.clientAddress.toAddressString(), jsr.to!string));
|
||
|
||
switch (query) {
|
||
case "login":
|
||
login(req, res, serverAuthData);
|
||
break;
|
||
case "logout":
|
||
logout(req, res);
|
||
break;
|
||
case "listnumbergroups":
|
||
getListNumberGroups(req, res);
|
||
break;
|
||
case "listgroupnumbers":
|
||
getListGroupNumbers(req, res);
|
||
break;
|
||
case "viewnumber":
|
||
getViewNumber(req, res);
|
||
break;
|
||
case "addnumber":
|
||
getAddNumber(req, res);
|
||
break;
|
||
case "writenumber":
|
||
sendWriteNumber(req, res);
|
||
break;
|
||
case "updatenumber":
|
||
sendUpdateNumber(req, res);
|
||
break;
|
||
case "delnumber":
|
||
sendDelNumber(req, res);
|
||
break;
|
||
case "listsmsgroups":
|
||
getListSMSGroups(req, res);
|
||
break;
|
||
case "listgroupsms":
|
||
getListGroupSMS(req, res);
|
||
break;
|
||
case "viewsms":
|
||
getViewSMS(req, res);
|
||
break;
|
||
case "delsms":
|
||
sendDelSMS(req, res);
|
||
break;
|
||
case "listussdgroups":
|
||
getListUSSDGroups(req, res);
|
||
break;
|
||
case "listgroupussd":
|
||
getListGroupUSSD(req, res);
|
||
break;
|
||
case "viewussd":
|
||
getViewUSSD(req, res);
|
||
break;
|
||
case "delussd":
|
||
sendDelUSSD(req, res);
|
||
break;
|
||
case "serverinfo":
|
||
getServerInfo(req, res);
|
||
break;
|
||
case "writeserverinfo":
|
||
sendWriteServerInfo(req, res);
|
||
break;
|
||
default:
|
||
res.redirect("/");
|
||
}
|
||
}
|
||
|
||
void rcAsteriskDB() {
|
||
ConfigSection asteriskDB;
|
||
|
||
try {
|
||
asteriskDB = rc[]["daster-db"];
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки daster-db");
|
||
exit(1);
|
||
}
|
||
|
||
if (asteriskDB["host"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки daster-db.host");
|
||
exit(1);
|
||
}
|
||
|
||
if (asteriskDB["port"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки daster-db.port");
|
||
exit(1);
|
||
}
|
||
|
||
if (asteriskDB["dbname"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки daster-db.dbname");
|
||
exit(1);
|
||
}
|
||
|
||
if (asteriskDB["user"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки daster-db.user");
|
||
exit(1);
|
||
}
|
||
|
||
try {
|
||
pgsql(
|
||
"hostaddr=" ~ asteriskDB["host"] ~
|
||
" port=" ~ asteriskDB["port"] ~
|
||
" dbname=" ~ asteriskDB["dbname"] ~
|
||
" user=" ~ asteriskDB["user"] ~
|
||
" password=" ~ asteriskDB["password"]
|
||
);
|
||
} catch (Exception e) {
|
||
log.c(e.msg);
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
WebHost rcWebHost() {
|
||
WebHost wh;
|
||
ConfigSection webHost;
|
||
|
||
try {
|
||
webHost = rc[]["web-host"];
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host");
|
||
exit(1);
|
||
}
|
||
|
||
if (webHost["addresses"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.addresses");
|
||
exit(1);
|
||
}
|
||
|
||
try {
|
||
wh.addresses = webHost["addresses"].to!string.split(',').map!(a => a.strip).array;
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.addresses");
|
||
exit(1);
|
||
}
|
||
|
||
if (webHost["http"].empty && webHost["https"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.[http|https]:
|
||
должен быть указан хотя бы один протокол");
|
||
exit(1);
|
||
}
|
||
|
||
if (!webHost["http"].empty) {
|
||
try {
|
||
wh.http = webHost["http"].to!ushort;
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.http");
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
if (!webHost["https"].empty) {
|
||
try {
|
||
wh.https = webHost["https"].to!ushort;
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.https");
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
if (!webHost["https"].empty) {
|
||
if (webHost["cert"].empty || webHost["key"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.[cert|key]:
|
||
необходимо указать сертификат и ключ для использования https протокола"
|
||
);
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
try {
|
||
wh.cert = webHost["cert"];
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.cert");
|
||
exit(1);
|
||
}
|
||
|
||
try {
|
||
wh.key = webHost["key"];
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.key");
|
||
exit(1);
|
||
}
|
||
|
||
if (!webHost["data"].empty) {
|
||
string data;
|
||
|
||
try {
|
||
data = webHost["data"];
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.data");
|
||
exit(1);
|
||
}
|
||
|
||
if (data.exists) {
|
||
if (!buildPath(data, "public").exists) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: public");
|
||
exit(1);
|
||
}
|
||
if (!buildPath(data, "js").exists) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: js");
|
||
exit(1);
|
||
}
|
||
if (!buildPath(data, "images").exists) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: images");
|
||
exit(1);
|
||
}
|
||
} else {
|
||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: " ~ data);
|
||
exit(1);
|
||
}
|
||
|
||
wh.data = data;
|
||
}
|
||
|
||
if (!webHost["title"].empty) {
|
||
try {
|
||
wh.title = webHost["title"];
|
||
} catch (Exception e) {
|
||
log.w("Заголовок не был установлен - web-host.title");
|
||
}
|
||
}
|
||
|
||
if (!webHost["loglevel"].empty) {
|
||
try {
|
||
wh.loglevel = webHost["loglevel"].to!int;
|
||
if (wh.loglevel < 0 || wh.loglevel > 6)
|
||
throw new Exception("несуществующий уровень");
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.loglevel: " ~ e.msg);
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
if (!webHost["logoutput"].empty) {
|
||
try {
|
||
wh.logoutput = webHost["logoutput"]
|
||
.to!string.split(',')
|
||
.map!((a) {
|
||
auto flag = a.strip.to!int;
|
||
|
||
if ([1, 2, 4].canFind(flag))
|
||
return flag;
|
||
|
||
log.c("В конфигурационном файле не верны настройки web-host.logoutput");
|
||
exit(1);
|
||
})
|
||
.fold!((a, b) => a | b);
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.logoutput");
|
||
exit(1);
|
||
}
|
||
|
||
if (wh.logoutput & 4) {
|
||
if (webHost["logfile"].empty) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.logfile");
|
||
exit(1);
|
||
}
|
||
|
||
try {
|
||
wh.logfile = webHost["logfile"];
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки web-host.logfile");
|
||
exit(1);
|
||
}
|
||
}
|
||
}
|
||
|
||
return wh;
|
||
}
|
||
|
||
void rcAuth() {
|
||
ConfigSection auth;
|
||
|
||
try {
|
||
auth = rc[]["auth"];
|
||
} catch (Exception e) {
|
||
log.c("В конфигурационном файле не верны настройки auth");
|
||
exit(1);
|
||
}
|
||
|
||
if (auth["login"].empty)
|
||
log.w("Логин не был установлен - auth.login");
|
||
else
|
||
serverAuthData.login = auth["login"];
|
||
|
||
if (auth["password"].empty)
|
||
log.w("Пароль не был установлен - auth.password");
|
||
else
|
||
serverAuthData.password = auth["password"];
|
||
}
|