Kaydet (Commit) 4fed109d authored tarafından mertcelen's avatar mertcelen

-SNMP Support added.

Table single row issue fixed.
-Extension support email now contains liman version.
-Server control port control can now be bypassed with -1.
-Modules will now contain letter if they are start with number(to prevent problems with js)
üst 349ab07a
<?php
namespace App\Classes\Connector;
use App\UserSettings;
/**
* Class SNMPConnector
* @package App\Classes
*/
class SNMPConnector implements Connector
{
/**
* @var mixed
*/
protected $connection;
protected $server;
protected $ssh;
protected $key;
protected $user_id;
protected $username;
protected $securityLevel;
protected $authProtocol;
protected $authPassword;
protected $privacyProtocol;
protected $privacyPassword;
public static $verifyCommands = [
"iso.3.6.1.2.1.1.1.0"
];
/**
* SNMPConnector constructor.
* @param \App\Server $server
* @param null $user_id
*/
public function __construct(\App\Server $server, $user_id)
{
$this->server = $server;
$this->username = $this->getCredential("username");
$this->securityLevel = $this->getCredential("SNMPsecurityLevel");
$this->authProtocol = $this->getCredential("SNMPauthProtocol");
$this->authPassword = $this->getCredential("SNMPauthPassword");
$this->privacyProtocol = $this->getCredential("SNMPprivacyProtocol");
$this->privacyPassword = $this->getCredential("SNMPprivacyPassword");
}
public function execute($command, $flag = true)
{
return snmp3_get($this->server->ip_address, $this->username, $this->securityLevel, $this->authProtocol, $this->authPassword, $this->privacyProtocol, $this->privacyPassword, $command);
}
/**
* @param $script
* @param $parameters
* @param null $extra
* @return string
*/
public function runScript($script, $parameters, $runAsRoot = false)
{
}
public function sendFile($localPath, $remotePath, $permissions = 0644)
{
}
public function receiveFile($localPath, $remotePath)
{
}
/**
* @param \App\Server $server
* @param $username
* @param $password
* @param $user_id
* @param $key
* @return bool
*/
public static function create(
\App\Server $server,
$username,
$password,
$user_id,
$key,
$port = null
) {
}
public static function verify($ip_address, $username, $password, $port)
{
}
public static function createSnmp()
{
return true;
}
public static function verifySnmp($ip_address, $username, $securityLevel, $authProtocol, $authPassword, $privacyProtocol, $privacyPassword ){
foreach(SNMPConnector::$verifyCommands as $command){
try{
$flag = snmp3_get($ip_address, $username, $securityLevel, $authProtocol, $authPassword, $privacyProtocol, $privacyPassword, $command);
}catch(\Exception $e){
return respond($e->getMessage(),201);
}
}
if(isset($flag)){
return respond("SNMP bağlantısı doğrulandı.", 200);
}
return respond(
"$username,$securityLevel,$authProtocol,$authPassword,$privacyProtocol,$privacyPassword,$ip_address",
201
);
return isset($flag);
}
private function getCredential($name)
{
$object = UserSettings::where([
'user_id' => user()->id,
'server_id' => server()->id,
'name' => $name,
])->first();
if(!$object){
dd([
'user_id' => user()->id,
'server_id' => server()->id,
'name' => $name,
]);
abort(
504,
"Bu sunucu için SNMP anahtarınız yok. Kasa üzerinden bir anahtar ekleyebilirsiniz."
);
}
return lDecrypt($object["value"]);
}
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Server;
use App\AdminNotification;
use App\Certificate;
use App\Classes\Connector\SSHConnector;
use App\Classes\Connector\SNMPConnector;
use App\Classes\Connector\SSHCertificateConnector;
use App\Classes\Connector\WinRMConnector;
use App\Http\Controllers\Controller;
......@@ -95,6 +96,26 @@ class AddController extends Controller
"name" => "clientPassword",
"value" => $encryptedPassword,
]);
}else if(server()->type == "snmp"){
$targetValues = [
"username","SNMPsecurityLevel","SNMPauthProtocol","SNMPauthPassword","SNMPprivacyProtocol","SNMPprivacyPassword"
];
$encKey = env('APP_KEY') . user()->id . server()->id;
foreach($targetValues as $target){
$encrypted = openssl_encrypt(
Str::random(16) . base64_encode(request($target)),
'aes-256-cfb8',
$encKey,
0,
Str::random(16)
);
UserSettings::create([
"server_id" => $this->server->id,
"user_id" => user()->id,
"name" => $target,
"value" => $encrypted,
]);
}
}
// Run required function for specific type.
......@@ -119,6 +140,9 @@ class AddController extends Controller
case "linux_certificate":
$next = $this->linux_certificate();
break;
case "snmp":
$next = $this->snmp();
break;
default:
$next = respond("Sunucu türü bulunamadı.", 404);
break;
......@@ -145,6 +169,27 @@ class AddController extends Controller
return $this->grantPermissions();
}
private function snmp()
{
$flag = SNMPConnector::createSnmp(
$this->server,
request('username'),
request('SNMPsecurityLevel'),
request('SNMPauthProtocol'),
request('SNMPauthPassword'),
request('SNMPprivacyProtocol'),
request('SNMPprivacyPassword'),
user()->id,
);
if (!$flag) {
$this->server->delete();
return respond("SNMP Hatası", 400);
}
return $this->grantPermissions();
}
private function linux_certificate()
{
$flag = SSHCertificateConnector::create(
......
......@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Server;
use App\Classes\Connector\SSHConnector;
use App\Classes\Connector\SNMPConnector;
use App\Classes\Connector\SSHCertificateConnector;
use App\Classes\Connector\WinRMConnector;
use App\Server;
......@@ -12,6 +13,9 @@ class MainController extends Controller
{
public function checkAccess()
{
if(request('port') == -1){
return respond("Sunucuya başarıyla erişim sağlandı.", 200);
}
$status = @fsockopen(
request('hostname'),
request('port'),
......@@ -68,6 +72,16 @@ class MainController extends Controller
request('password'),
request('port')
);
} elseif( request('key_type') == "snmp"){
return SNMPConnector::verifySnmp(
request('ip_address'),
request('username'),
request('SNMPsecurityLevel'),
request('SNMPauthProtocol'),
request('SNMPauthPassword'),
request('SNMPprivacyProtocol'),
request('SNMPprivacyPassword'),
);
}
return respond("Bu anahtara göre bir yapı bulunamadı.", 201);
}
......
......@@ -29,7 +29,7 @@ class OneController extends Controller
}
$outputs = [
"hostname" => $server->run("hostname"),
"hostname" => $server->getHostname(),
"version" => $server->getVersion(),
];
......@@ -76,14 +76,18 @@ class OneController extends Controller
public function serviceCheck()
{
if (is_numeric(extension()->service)) {
$status = @fsockopen(
server()->ip_address,
extension()->service,
$errno,
$errstr,
intval(config('liman.server_connection_timeout')) / 1000
);
$flag = is_resource($status);
if(extension()->service == -1){
$flag = true;
}else{
$status = @fsockopen(
server()->ip_address,
extension()->service,
$errno,
$errstr,
intval(config('liman.server_connection_timeout')) / 1000
);
$flag = is_resource($status);
}
} else {
$flag = server()->isRunning(extension()->service);
}
......@@ -988,7 +992,8 @@ class OneController extends Controller
if (
server()->type == "linux_ssh" ||
server()->type == "windows_powershell" ||
server()->type == "linux_certificate"
server()->type == "linux_certificate" ||
server()->type == "snmp"
) {
return respond("Bu sunucuda yükseltme yapılamaz.", 201);
}
......
......@@ -25,8 +25,7 @@ Route::post('/sunucu/isimKontrol', 'Server\MainController@verifyName')
->middleware('parameters:server_name');
Route::post('/sunucu/anahtarKontrol', 'Server\MainController@verifyKey')
->name('server_verify_key')
->middleware('parameters:ip_address,username,password,port');
->name('server_verify_key');
// Remove Server Route
......
......@@ -158,11 +158,16 @@ if (!function_exists('settingsModuleButtons')) {
foreach (searchModuleFiles('settings.blade.php') as $file) {
$foo = substr($file, 15);
$name = substr($foo, 0, strpos($foo, "/"));
$hrefName = $name;
if(is_numeric($name[0])){
$hrefName = "l-" . $name;
}
$str .=
"<li class=\"nav-item\">
<a id\"" .
<a id=\"" .
$name .
"tab\" class=\"nav-link\" data-toggle=\"tab\" href=\"#$name\">$name</a>
"tab\" class=\"nav-link\" data-toggle=\"tab\" href=\"#$hrefName\">$name</a>
</li>";
}
return $str;
......@@ -841,6 +846,9 @@ if (!function_exists('setBaseDn')) {
if (!function_exists('checkPort')) {
function checkPort($ip, $port)
{
if($port == -1){
return true;
}
$fp = @fsockopen($ip, $port, $errno, $errstr, 0.1);
if (!$fp) {
return false;
......
......@@ -34,7 +34,7 @@ class Server
$errstr,
intval(config('liman.server_connection_timeout')) / 1000
);
if (is_resource($status)) {
if (is_resource($status) || server()->control_port == -1) {
return $next($request);
} else {
$message = __(":server_name isimli sunucuya erişim sağlanamadı!", [
......
......@@ -15,7 +15,7 @@ class ServerApi
$errstr,
intval(config('liman.server_connection_timeout')) / 1000
);
if (is_resource($status)) {
if (is_resource($status) || server()->control_port == -1) {
return $next($request);
} else {
return respond(
......
......@@ -4,6 +4,7 @@ namespace App;
use App\Classes\Connector\Connector;
use App\Classes\Connector\SSHConnector;
use App\Classes\Connector\SNMPConnector;
use App\Classes\Connector\SSHCertificateConnector;
use App\Classes\Connector\WinRMConnector;
use Illuminate\Database\Eloquent\Model;
......@@ -36,12 +37,16 @@ class Server extends Model
private function connector()
{
if ($this->type == "linux_ssh") {
return new SSHConnector($this, auth()->id());
return new SSHConnector($this, user()->id);
} elseif ($this->type == "windows_powershell") {
return new WinRMConnector($this, auth()->id());
return new WinRMConnector($this, user()->id);
} elseif ($this->type == "linux_certificate") {
return new SSHCertificateConnector($this, auth()->id());
} else {
return new SSHCertificateConnector($this, user()->id);
} elseif ($this->type == "snmp") {
return new SNMPConnector($this,user()->id);
}
else {
abort(
504,
"Bu sunucuda komut çalıştırmak için bir bağlantınız yok."
......@@ -57,7 +62,7 @@ class Server extends Model
public function run($command, $log = true)
{
if (!$this->canRunCommand()) {
return false;
return respond("Bu sunucuda komut çalıştıramazsınız!",504);
}
// Execute and return outputs.
......@@ -106,6 +111,9 @@ class Server extends Model
public function isRunning($service_name)
{
if ($this->type == "windows" || $this->type == "linux") {
if($this->control_port == -1){
return true;
}
return is_resource(
@fsockopen(
$this->ip_address,
......@@ -130,6 +138,9 @@ class Server extends Model
*/
public function isAlive()
{
if($this->control_port == -1){
return true;
}
// Simply Check Port If It's Alive
if (
is_resource(
......@@ -186,7 +197,8 @@ class Server extends Model
{
return $this->type == "linux_ssh" ||
$this->type == "linux_certificate" ||
$this->type == "windows_powershell";
$this->type == "windows_powershell" ||
$this->type == "snmp";
}
public function isLinux()
......@@ -203,8 +215,8 @@ class Server extends Model
public function getVersion()
{
if (!$this->canRunCommand()) {
return false;
if (!$this->canRunCommand() || $this->type == "snmp") {
return "";
}
if ($this->isLinux()) {
......@@ -216,4 +228,13 @@ class Server extends Model
$this->run("(Get-WmiObject Win32_OperatingSystem).name")[0]
);
}
public function getHostname()
{
if (!$this->canRunCommand() || $this->type == "snmp") {
return "";
}
return $this->run("hostname");
}
}
......@@ -19,7 +19,7 @@ Date : $1
Architecture: amd64
Priority: important
Description: Liman System Manager
Depends: zip, unzip, dnsutils, nginx, php7.3-fpm, php7.3-curl, php7.3, php7.3-sqlite3, php7.3-ldap, php7.3-mbstring, php7.3-xml, php7.3-zip, php7.3-ssh2, php7.3-posix, libnginx-mod-http-headers-more-filter, php7.3-smbclient, krb5-user, smbclient, libssl1.1, acl, novnc, supervisor, expect, php-mongodb, php7.3-gd, rsyslog, python3.7, python3-jinja2, python3-requests, python3-crypto, python3-paramiko, python3-tornado
Depends: zip, unzip, dnsutils, nginx, php7.3-fpm, php7.3-curl, php7.3, php7.3-sqlite3, php7.3-ldap, php7.3-mbstring, php7.3-xml, php7.3-snmp, php7.3-zip, php7.3-ssh2, php7.3-posix, libnginx-mod-http-headers-more-filter, php7.3-smbclient, krb5-user, smbclient, libssl1.1, acl, novnc, supervisor, expect, php-mongodb, php7.3-gd, rsyslog, python3.7, python3-jinja2, python3-requests, python3-crypto, python3-paramiko, python3-tornado
""" > DEBIAN/control
cd ../
......
......@@ -10,6 +10,7 @@
"ext-ldap": "*",
"ext-openssl": "*",
"ext-posix": "*",
"ext-snmp": "*",
"ext-ssh2": "*",
"ext-xml": "*",
"ext-zip": "*",
......
This diff is collapsed.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/ejs@3.0.1/ejs.min.js" integrity="sha256-UBBPCOEPxc2jDuQMgYvzemO9GqrRd0UkYHVwl78VbqI=" crossorigin="anonymous"></script>
</head>
<script>
let people = ['geddy', 'neil', 'alex'],
html = ejs.render('<%= people.join(", "); %>', {people: people});
console.log(html);
</script>
<body>
<pre id="mainData" style="display: none;">
</pre>
</body>
</html>
\ No newline at end of file
......@@ -151,7 +151,7 @@
"Güncelleniyor...": "Updating...",
" rol grubunun ayarları": " rol grubunun ayarları",
"Kullanıcılar": "Users",
"Tam yetkili yönetici hesabı ile giriş yaptınız, sisteme zarar verebilirsiniz.": "You are logged in with a fully authorized administrator account, you can damage the system.",
"Tam yetkili ana yönetici hesabı ile giriş yaptınız, sisteme zarar verebilirsiniz.": "You are logged in with a fully authorized administrator account, you can damage the system.",
"Liman Sistem Yönetimi": "Liman System Manager",
"Tümünü Seç": "Tümünü Seç",
"Tümünü Kaldır": "Tümünü Kaldır",
......@@ -360,7 +360,7 @@
"Tüm Sunucular": "All Servers",
"Okunmamış :count mesajınız var.": "You have :count unread messages",
"Hiç okunmamış mesajınız yok": "You have no unread messages",
"Tam Yetkili Yönetici Hesabı İle Giriş Yaptınız.": "You have logged in with full authorized admin user.",
"Tam Yetkili Yönetici Ana Hesabı İle Giriş Yaptınız.": "You have logged in with full authorized admin user.",
"Anahtarlar": "Keys",
"Versiyon : ": "Version : ",
"Giriş Tarihi : ": "Login date : ",
......
......@@ -16,7 +16,7 @@
@if(count($tokens) > 0)
<button data-toggle="tooltip" title="Sorgu Oluştur" class="btn btn-primary" onclick="showRequestRecords()"><i class="fa fa-book"></i></button>
@endif
<button data-toggle="tooltip" title="Destek Al" class="btn btn-primary" onclick="location.href = 'mailto:{{env('APP_NOTIFICATION_EMAIL')}}?subject={{env('BRAND_NAME')}} {{extension()->display_name}} {{extension()->version}}'"><i class="fas fa-headset"></i></button>
<button data-toggle="tooltip" title="Destek Al" class="btn btn-primary" onclick="location.href = 'mailto:{{env('APP_NOTIFICATION_EMAIL')}}?subject={{env('BRAND_NAME')}} {{getVersion()}} - {{extension()->display_name}} {{extension()->version}}'"><i class="fas fa-headset"></i></button>
</div>
@include('errors')
......
......@@ -84,6 +84,7 @@
@isset($setCurrentVariable)
var {{$setCurrentVariable}};
@endisset
@if(count($value) > 0)
$.contextMenu({
selector: '#{{$rand}} tbody tr',
callback: function (key, options) {
......@@ -112,6 +113,7 @@
@endforeach
}
});
@endif
</script>
@endif
@endif
......@@ -2,7 +2,7 @@
<div class="content-wrapper">
@if(auth()->check() && user()->email == "administrator@liman.dev")
<div class="alert alert-danger customAlert">
<b>{{__("Tam yetkili yönetici hesabı ile giriş yaptınız, sisteme zarar verebilirsiniz.")}}</b>
<b>{{__("Tam yetkili ana yönetici hesabı ile giriş yaptınız, sisteme zarar verebilirsiniz.")}}</b>
</div>
@endif
<!-- Content Header (Page header) -->
......
......@@ -92,7 +92,8 @@
<h4>{{__("Sunucunuzun Portu")}}</h4>
<h6>{{__("Sunucunuzun açık olup olmadığını algılamak için kontrol edilebilecek bir port girin.")}}</h6>
<pre>{{__("SSH : 22\nWinRM : 5986\nActive Directory, Samba : 636")}}</pre>
<input id="serverControlPort" type="number" name="port" class="form-control" placeholder="{{__("Kontrol Portu Girin (Yalnızca Sayı).")}}" required min="1">
<input id="serverControlPort" type="number" name="port" class="form-control" placeholder="{{__("Kontrol Portu Girin (Yalnızca Sayı).")}}" required min="-1">
<small><i>{{__("Eğer hedefiniz UDP protokolü üzerinden dinliyorsa bu kontrolü atlamak için -1 girebilirsiniz.")}}</i></small>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">{{__("Bağlantıyı Kontrol Et")}}</button>
......@@ -148,6 +149,7 @@
<option value="linux_ssh" selected>{{__("SSH")}}</option>
<option value="linux_certificate">{{__("SSH Anahtarı")}}</option>
<option value="windows_powershell">{{__("WinRM")}}</option>
<option value="snmp">{{__("SNMP")}}</option>
</select>
</div><hr>
<h4>{{__("Kullanıcı Adı")}}</h4>
......@@ -157,9 +159,31 @@
<label id="certificateInformLabel">{{__("Anahtarınızın çalışabilmesi için şifreli olmaması ve sudo komutlarını çalıştırması için sudoers dosyasında NOPASSWD olarak eklenmiş olması gerekmektedir.")}}</label>
<textarea class="form-control" name="password" id="keyPasswordCert" cols="30" rows="10" required disabled></textarea>
<input id="keyPassword" type="password" name="password" class="form-control" placeholder="{{__("Şifre")}}" required disabled><br>
<div id="snmpWrapper" style="display: none">
<h4>{{__("Bağlantı Türü")}}</h4>
<select id="SNMPsecurityLevel" name="SNMPsecurityLevel" class="select2 snmp-input" disabled>
<option value="noAuthNoPriv">noAuthNoPriv</option>
<option value="authNoPriv">authNoPriv</option>
<option value="authPriv" selected>authPriv</option>
</select><br>
<h4>{{__("Giriş Protokolü")}}</h4>
<select id="SNMPauthProtocol" name="SNMPauthProtocol" class="select2 snmp-input" disabled>
<option value="MD5">MD5</option>
<option value="SHA">SHA</option>
</select><br>
<h4>{{__("Giriş Parolası")}}</h4>
<input id="SNMPauthPassword" name="SNMPauthPassword" type="password" class="form-control snmp-input" placeholder="{{__("Giriş Parolası")}}" required disabled><br>
<h4>{{__("Gizlilik Protokolü")}}</h4>
<select id="SNMPprivacyProtocol" name="SNMPprivacyProtocol" class="select2 snmp-input" disabled>
<option value="DES">DES</option>
<option value="AES">AES</option>
</select><br>
<h4>{{__("Gizlilik Parolası")}}</h4>
<input id="SNMPprivacyPassword" name="SNMPprivacyPassword" type="password" class="form-control snmp-input" placeholder="{{__("Gizlilik Parolası")}}" required disabled><br>
</div>
<h4>{{__("Port")}}</h4>
<small>{{__("Eğer bilmiyorsanız varsayılan olarak bırakabilirsiniz.")}}</small>
<input id="port" type="number" name="port" class="form-control" placeholder="{{__("Port")}}" required disabled min="0" value="22"><br>
<input id="port" type="number" name="port" class="form-control snmp-input" placeholder="{{__("Port")}}" required disabled min="0" value="22"><br>
</div>
</div>
......@@ -242,8 +266,9 @@
$("#generalTab").css('color','red');
});
}
function checkKey(form) {
let helper;
function checkKey(form) {
let option = $("#useKey");
if(option.is(':checked') === false){
isKeyOK = true;
......@@ -252,6 +277,7 @@
return false;
}
let data = new FormData(form);
helper = data;
data.append('ip_address',$("#serverHostName").val());
showSwal('{{__("Kontrol Ediliyor...")}}','info');
return request('{{route('server_verify_key')}}',data,function (response) {
......@@ -294,26 +320,41 @@
$("#passwordPrompt").fadeIn(0);
function setPort(select) {
if(select.value === "windows_powershell"){
$("#port").val("5986");
$("#keyPasswordCert").fadeOut(0).attr("disabled","true");
$("#certificateInformLabel").fadeOut(0);
$("#keyPassword").fadeIn(0).removeAttr("disabled");
$("#certificatePrompt").fadeOut(0);
$("#passwordPrompt").fadeIn(0);
$("#snmpWrapper").fadeOut();
$(".snmp-input").attr("disabled","true");
$("#port").val("5986").removeAttr("disabled");
}else if(select.value === "linux_ssh"){
$("#port").val("22");
$("#keyPasswordCert").fadeOut(0).attr("disabled","true");
$("#keyPassword").fadeIn(0).removeAttr("disabled");
$("#certificateInformLabel").fadeOut(0);
$("#passwordPrompt").fadeIn(0);
$("#certificatePrompt").fadeOut(0);
$("#snmpWrapper").fadeOut();
$(".snmp-input").attr("disabled","true");
$("#port").val("22").removeAttr("disabled");
}else if(select.value === "linux_certificate"){
$("#port").val("22");
$("#keyPasswordCert").fadeIn(0).removeAttr("disabled");
$("#certificateInformLabel").fadeIn(0);
$("#passwordPrompt").fadeOut(0);
$("#keyPassword").fadeOut(0).attr("disabled","true");
$("#certificatePrompt").fadeIn(0);
$("#snmpWrapper").fadeOut();
$(".snmp-input").attr("disabled","true");
$("#port").val("22").removeAttr("disabled");
}else if(select.value === "snmp"){
$("#keyPasswordCert").fadeOut(0).attr("disabled","true");
$("#certificateInformLabel").fadeOut(0).attr("disabled","true");
$("#passwordPrompt").fadeOut(0).attr("disabled","true");
$("#keyPassword").fadeOut(0).attr("disabled","true");
$("#certificatePrompt").fadeOut(0).attr("disabled","true");
$(".snmp-input").removeAttr("disabled");
$("#snmpWrapper").fadeIn();
$("#port").val("161").attr("disabled","true");
}
}
......@@ -342,9 +383,16 @@
form.append('username',$("#keyUsername").val());
if($("#keyType").val() == "linux_certificate"){
form.append('password',$("#keyPasswordCert").val());
}else if($("#keyType").val() == "snmp"){
form.append("SNMPsecurityLevel",$("#SNMPsecurityLevel").val());
form.append("SNMPauthProtocol",$("#SNMPauthProtocol").val());
form.append("SNMPauthPassword",$("#SNMPauthPassword").val());
form.append("SNMPprivacyProtocol",$("#SNMPprivacyProtocol").val());
form.append("SNMPprivacyPassword",$("#SNMPprivacyPassword").val());
}else{
form.append('password',$("#keyPassword").val());
}
form.append('type',$("#keyType").val());
form.append('key_port',$("#port").val());
}else{
......
......@@ -28,9 +28,9 @@
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#update">{{__("Güncelleme")}}</a>
</li>
<li class="nav-item">
<!-- <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#changeLog">{{__("Son Değişiklikler")}}</a>
</li>
</li> -->
<!-- <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#rsyslog" onclick="readLogs()">{{__("Log Yönetimi")}}</a>
</li> -->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment