diff --git a/dub.json b/dub.json index dcc38e8..d1e1943 100644 --- a/dub.json +++ b/dub.json @@ -5,9 +5,9 @@ "copyright": "Copyright © 2023, Alexander Zhirov", "dependencies": { "vibe-d": "~>0.9", - "singlog": "~>0.3.2", + "singlog": "~>0.4.0", "arsd-official:postgres": "~>10.9.10", - "readconf": "~>0.3.1" + "readconf": "~>0.4.0" }, "buildTypes": { "debug": { diff --git a/dub.selections.json b/dub.selections.json index a6ee273..08bea5a 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -10,9 +10,9 @@ "mir-linux-kernel": "1.0.1", "openssl": "3.3.0", "openssl-static": "1.0.2+3.0.8", - "readconf": "0.3.1", - "silly": "1.1.1", - "singlog": "0.3.2", + "readconf": "0.4.0", + "silly": "1.2.0-dev.2", + "singlog": "0.4.0", "stdx-allocator": "2.77.5", "taggedalgebraic": "0.11.22", "vibe-core": "2.2.0", diff --git a/js/authorization.js b/js/authorization.js new file mode 100644 index 0000000..4edab3f --- /dev/null +++ b/js/authorization.js @@ -0,0 +1,48 @@ +$(document).ready(function () { + noticer = new Noticer; + + $("#authorization").button({ icon: "ui-icon-home" }); + + $("#login, #password").on('keypress',function(e) { + if(e.which == 13) { + authorization() + } + }); + + $("#authorization").click(() => { + authorization() + }); + + $("body").fadeTo(500, 1); +}); + +function authorization() { + request().then((data) => { + data.error ? noticer.error(data.message) : (window.location.href = "."); + }).catch((e) => { + noticer.error(e.message); + }); +} + +async function request() { + let login = $("#login").val(); + let password = $("#password").val(); + + let response = await fetch('.', { + method: 'POST', + headers: { + 'Content-Type': 'application/json;charset=utf-8' + }, + body: JSON.stringify({ + login: login, + password: password, + query: "login" + }) + }); + + if (!response.ok) + throw new Error(`Произошла неизвестаня ошибка: ${response.status}`); + + const data = await response.json(); + return data; +} diff --git a/js/script.js b/js/script.js index 583147f..7a00ef9 100644 --- a/js/script.js +++ b/js/script.js @@ -58,6 +58,14 @@ $(document).ready(function () { e.key == "Escape" && ($(this).val(""), lists[$("#tabs").tabs( "option", "active" )]()) }); + $("#logout").click(() => { + request('logout', 'json').then(data => { + data.error ? noticer.error(data.message) : (window.location.href = "."); + }).catch(error => { + noticer.error(error.message); + }); + }); + loadNumbers(); loadSMS(); loadUSSD(); @@ -129,7 +137,10 @@ function pEmpty(text) { function loadNumbers() { request('listnumbergroups', 'text').then(data => { - data.error ? noticer.error(data.message) : generateListNumberGroups(data); + if (isJSON(data) && JSON.parse(data).error) + noticer.error(JSON.parse(data).message); + else + generateListNumberGroups(data); }).catch(error => { noticer.error(error.message); }); @@ -161,8 +172,8 @@ function generateListGroupNumbers(panel) { } request('listgroupnumbers', 'json', { group: panel.data("group-name") }).then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); + if (data.error) + noticer.error(data.message); else { numbers = data; showListNumbers(panel); @@ -347,7 +358,10 @@ function delNumber(panel, currentWindow) { function loadSMS() { request('listsmsgroups', 'text').then(data => { - data.error ? noticer.error(data.message) : generateListSMSGroups(data); + if (isJSON(data) && JSON.parse(data).error) + noticer.error(JSON.parse(data).message); + else + generateListSMSGroups(data); }).catch(error => { noticer.error(error.message); }); @@ -379,8 +393,8 @@ function generateListGroupSMS(panel) { } request('listgroupsms', 'json', { to: panel.data("to") }).then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); + if (data.error) + noticer.error(data.message); else { sms = data; showListSMS(panel); @@ -483,7 +497,10 @@ function delSMS(panel, currentWindow) { function loadUSSD() { request('listussdgroups', 'text').then(data => { - data.error ? noticer.error(data.message) : generateListUSSDGroups(data); + if (isJSON(data) && JSON.parse(data).error) + noticer.error(JSON.parse(data).message); + else + generateListUSSDGroups(data); }).catch(error => { noticer.error(error.message); }); @@ -515,8 +532,8 @@ function generateListGroupUSSD(panel) { } request('listgroupussd', 'json', { to: panel.data("to") }).then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); + if (data.error) + noticer.error(data.message); else { ussd = data; showListUSSD(panel); @@ -618,7 +635,10 @@ function delUSSD(panel, currentWindow) { function loadServerInfo() { request('serverinfo', 'text').then(data => { - data.error ? noticer.error(data.message) : showServerInfo(data); + if (isJSON(data) && JSON.parse(data).error) + noticer.error(JSON.parse(data).message); + else + showServerInfo(data); }).catch(error => { noticer.error(error.message); }); diff --git a/public/authorization.css b/public/authorization.css new file mode 100644 index 0000000..2b1cf94 --- /dev/null +++ b/public/authorization.css @@ -0,0 +1,64 @@ +@font-face { + font-family: Scada; + src: url(Scada-Regular.ttf); +} + +body { + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + overflow: hidden; + margin-top: -5%; + color: #333; + opacity: 0; + font-family: Scada; +} + +div.form { + display: flex; + flex-direction: column; + align-items: center; +} + +.div-button { + display: flex; + justify-content: center; + margin-top: 10px; +} + +input { + text-align: center; + color: #333; + border: 1px solid#c5c5c5; + height: 30px; +} + +input:hover { + border: 1px solid #999; + box-shadow: 1px 1px 10px 1px #ccc; +} + +.input-focus:focus { + outline: none; + box-shadow: 1px 1px 10px 1px #666; + border: 1px solid #555; +} + +.logo { + background-image: url("favicon.png"); + min-width: 128px; + min-height: 128px; + background-size: contain; + margin-bottom: 20px; +} + +.title { + margin: 30px; + color:#333333 +} + +.label { + text-align: right; + padding-right: 10px; +} diff --git a/settings.conf.sample b/settings.conf.sample index 2b48a48..538d199 100644 --- a/settings.conf.sample +++ b/settings.conf.sample @@ -10,6 +10,10 @@ loglevel => 0 ; 0 - debug, 1 - crit, 2 logoutput => 1, 4 ; 1 - syslog, 2 - stout, 4 - file => example: 1,2 or 1,2,4 logfile => /var/log/daster.log ; if log-output set with 4 +[auth] +login => +password => + [daster-db] host => 127.0.0.1 port => 5432 diff --git a/source/daster.d b/source/daster.d index 01789f6..020c75f 100644 --- a/source/daster.d +++ b/source/daster.d @@ -15,13 +15,16 @@ 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__); @@ -32,8 +35,9 @@ void page404(HTTPServerRequest req, HTTPServerResponse res, HTTPServerErrorInfo } int main(string[] args) { - log.level(log.INFORMATION); - log.output(log.SYSLOG); + log.level(log.INFORMATION) + .output(log.SYSLOG) + .color(true); bool flagVersion; string flagSettings; @@ -88,6 +92,7 @@ int main(string[] args) { if (webHost.logfile.length) log.file(webHost.logfile); rcAsteriskDB(); + rcAuth(); auto router = new URLRouter; router.post("/", &postReq); @@ -144,16 +149,15 @@ void startWebServer(WebHost wh, HTTPServerSettings http, HTTPServerSettings http } void getReq(HTTPServerRequest req, HTTPServerResponse res) { - // if (req.session) { - // auto user = req.session.get!UserData("userData"); - // if (user.loggedIn) { - // renderMainPage(req, res); - // return; - // } - // } + if (req.session) { + auto user = req.session.get!UserData("user"); + if (user.login) { + renderMainPage(req, res); + return; + } + } - // render!("index.dt", serverInfo)(res); - renderMainPage(req, res); + render!("authorization.dt", serverInfo)(res); } void renderMainPage(HTTPServerRequest req, HTTPServerResponse res) { @@ -168,23 +172,23 @@ void postReq(HTTPServerRequest req, HTTPServerResponse res) { if (query.empty) return; - // if (query != "authorization" && !checkAuth(req)) { - // res.send( - // true, - // "Сессия не существует. Перезагрузите страницу" - // ); - // return; - // } + if (query != "login" && !checkAuth(req)) { + res.send( + true, + "Сессия не существует. Перезагрузите страницу" + ); + return; + } log.d("json request: " ~ jsr.to!string); switch (query) { - // case "authorization": - // authorization(req, res); - // break; - // case "logout": - // logout(req, res); - // break; + case "login": + login(req, res, serverAuthData); + break; + case "logout": + logout(req, res); + break; case "listnumbergroups": getListNumberGroups(req, res); break; @@ -441,3 +445,24 @@ WebHost rcWebHost() { 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"]; +} diff --git a/source/requests/authorization.d b/source/requests/authorization.d new file mode 100644 index 0000000..e046886 --- /dev/null +++ b/source/requests/authorization.d @@ -0,0 +1,47 @@ +module requests.authorization; + +import vibe.vibe; +import response; +import structures; +import singlog; + +void login(HTTPServerRequest req, HTTPServerResponse res, AuthData serverAuthData) { + auto userAuthData = deserializeJson!AuthData(req.json); + + if (!(serverAuthData.login == userAuthData.login && + serverAuthData.password == userAuthData.password)) { + log.i(("Данные авторизации не верны: %s").format(req.json)); + res.send( + true, + "Данные авторизации не верны" + ); + return; + } + + auto user = UserData(true); + + req.session = res.startSession(); + req.session.set!UserData("user", user); + + log.i("Авторизация успешно пройдена"); + + res.send(); +} + +void logout(HTTPServerRequest req, HTTPServerResponse res) { + req.session.set!UserData("user", UserData.init); + res.terminateSession(); + + log.i("Выход из системы"); + + res.send(); +} + +bool checkAuth(HTTPServerRequest req) { + if (req.session) + return req.session.get!UserData("user").login; + + log.d("Отсутствует авторизация"); + + return false; +} diff --git a/source/structures.d b/source/structures.d index 04c2a95..b38058d 100644 --- a/source/structures.d +++ b/source/structures.d @@ -4,6 +4,15 @@ struct ServerInfo { string name; } +struct AuthData { + string login; + string password; +} + +struct UserData { + bool login = false; +} + struct WebHost { string[] addresses; ushort http = 0; diff --git a/source/version_.d b/source/version_.d index 0492867..e8028ea 100644 --- a/source/version_.d +++ b/source/version_.d @@ -1,3 +1,3 @@ module version_; -enum dasterVersion = "v0.0.9"; +enum dasterVersion = "v0.0.10"; diff --git a/views/authorization.dt b/views/authorization.dt new file mode 100644 index 0000000..6eb8540 --- /dev/null +++ b/views/authorization.dt @@ -0,0 +1,26 @@ +doctype html +head + title #{serverInfo.name}: авторизация + link(rel='icon', type='image/png', sizes='128x128', href='favicon.png') + link(rel='stylesheet', type='text/css', href='jquery-ui.min.css') + link(rel='stylesheet', type='text/css', href='authorization.css') + script(src='jquery-3.7.0.min.js') + script(src='jquery-ui.min.js') + script(src='noticer.min.js') + script(src='authorization.js') +body + div.form + div.logo + div.title #{serverInfo.name} + table + tbody + tr + td.label Логин: + td + input.input-focus#login(type='text') + tr + td.label Пароль: + td + input.input-focus#password(type='password') + div.div-button + button#authorization Войти