initial code comit

This commit is contained in:
2018-11-22 21:02:44 +03:00
parent dda0488d4b
commit 801bbd37b7
117 changed files with 7612 additions and 0 deletions

62
system/action/index.php Normal file
View File

@@ -0,0 +1,62 @@
<?php
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
require_once('../settings.php');
$action = filter_input(INPUT_GET, 'do', FILTER_SANITIZE_STRING);
if ($action === 'reboot') {
// echo shell_exec("systemctl halt -i");
if (REBOOT_ENABLED) {
echo $lang->translate('reboot_in_progress') . '<br>';
echo shell_exec('sudo shutdown -r');
} else {
echo $lang->translate('reboot_prohibited') . '<br>';
}
} else if ($action === 'shutdown') {
if (SHUTDOWN_ENABLED) {
echo $lang->translate('shutdown_in_progress') . '<br>';
echo shell_exec('sudo halt -p');
} else {
echo $lang->translate('shutdown_prohibited') . '<br>';
}
} else if ($action === 'setup') {
$def_lang = filter_input(INPUT_GET, 'default_language', FILTER_SANITIZE_STRING);
$dim_on_create = filter_input(INPUT_GET, 'dim_on_create', FILTER_SANITIZE_NUMBER_INT) == 1;
$chk_f_rights = filter_input(INPUT_GET, 'chk_files_rights', FILTER_SANITIZE_NUMBER_INT) == 1;
$max_hdd_temp = filter_input(INPUT_GET, 'max_hdd_temp', FILTER_SANITIZE_NUMBER_INT);
$chk_hdd_temp_int = filter_input(INPUT_GET, 'chk_temp_interval', FILTER_SANITIZE_NUMBER_INT);
$chk_smart_int = filter_input(INPUT_GET, 'chk_smart_interval', FILTER_SANITIZE_NUMBER_INT);
$chk_users_online_int = filter_input(INPUT_GET, 'chk_users_online_interval', FILTER_SANITIZE_NUMBER_INT);
$user_cfg->set_value('lang', $def_lang);
$user_cfg->set_value('dim_on_create', $dim_on_create);
$user_cfg->set_value('check_files_rights', $chk_f_rights);
$user_cfg->set_value('max_hdd_temp', $max_hdd_temp);
$user_cfg->set_value('check_hdd_temp_interval', $chk_hdd_temp_int);
$user_cfg->set_value('check_smart_interval', $chk_smart_int);
$user_cfg->set_value('check_users_online_interval', $chk_users_online_int);
$uc_saved = $user_cfg->save();
/* Apps list */
$enabled_apps = array();
foreach ($_GET["app_caption"] as $item => $val) {
if (isset($_GET["app_enabled"][$item]) && (bool)$_GET["app_enabled"][$item]) {
$app_cap = filter_var($_GET["app_caption"][$item], FILTER_SANITIZE_STRING);
$app_name = filter_var($_GET["app_name"][$item], FILTER_SANITIZE_STRING);
$enabled_apps[$app_cap] = $app_name;
}
}
$app = new \CAI\CAICP\Applications(CP_ROOT_REL);
$app->set($enabled_apps);
$apps_saved = $app->save();
if ($uc_saved && $apps_saved) {
echo 'true';
} else {
echo 'false';
}
}

11
system/apps/apps.json Normal file
View File

@@ -0,0 +1,11 @@
{
"Plex" : "plex",
"Transmission" : "transmission",
"Resilio sync" : "rslsync",
"NextCloud" : "nextcloud",
"OwnCloud" : "owncloud",
"Files downloader" : "cai_downloader",
"OpenFire" : "openfire",
"phpMyAdmin" : "phpmyadmin",
"phpPgAdmin" : "phppgadmin"
}

View File

@@ -0,0 +1,16 @@
{
"app_name" : "app_cai_downloader",
"caption" : "Files downloader",
"version" : "1.0.20170705",
"author" : "Alexander I. Chebykin",
"http_uri" : "system/apps/cai_downloader/",
"use_http" : true,
"https_uri" : "system/apps/cai_downloader/",
"use_https" : true,
"frame_support" : true,
"require_php" : true,
"require" : [
{"data" : "php"},
{"data" : "curl"}
]
}

View File

@@ -0,0 +1,32 @@
.full_width {width: 100%}
.hidden {opacity: 0;}
.td_label {width: 100px;}
.del_rec {
position: absolute;
right: 15px;
cursor: pointer;
}
#in_submit {margin: 10px auto;}
#div_download,
#div_log,
.div_log_rec {transition: all 0.5s ease-out 0.1s;}
.div_log_rec span {margin-right: 20px;}
fieldset {
border-width: 1px;
border-color: #ddd;
}
hr {
margin: 5px 0;
padding: 0;
border: 0;
height: 1px;
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background: linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0, 0));
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* CAI CP v.1
*
* @module : Download application
* @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
* @copyright : Copyright (c) 2016-2017 Alexander I. Chebykin
* @version : 1.0
* @build date : 2017-07-17
* @license : MIT
* @link : https://github.com/CAI79/CAI-CP
******************************************************************/
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
require_once('../../../settings.php');
/* Places to store files by type */
$ParentDir = array('.gif' => 'images/_animations/',
'.jpg' => 'images/', '.jpeg' => 'images/', '.png' => 'images/',
'.tif' => 'images/', '.tiff' => 'images/',
'.avi' => 'video/', '.flv' => 'video/', '.mkv' => 'video/',
'.mp4' => 'video/', '.mpeg' => 'video/', '.mpg' => 'video/',
'.exe' => 'soft/', '.msi' => 'soft/',
'.7z' => 'archives/', '.iso' => 'archives/', '.rar' => 'archives/',
'.tar' => 'archives/', '.zip' => 'archives/');
/* Filter parameters */
$Dir = str_replace(array('.', '/', '~', '\\', ' ', '%'),
'_',
filter_input(INPUT_POST, 'dir', FILTER_SANITIZE_STRING)
);
$Overwrite = (int)filter_input(INPUT_POST, 'overwrite', FILTER_SANITIZE_NUMBER_INT);
$URI = filter_input(INPUT_POST, 'uri', FILTER_SANITIZE_URL);
$SubstrPos = 0;
$PDir = '';
foreach ($ParentDir as $Key => $Val) {
if (mb_stripos($URI, $Key) !== false){
$SPos = mb_stripos($URI, $Key);
if ($SubstrPos == 0) {
$SubstrPos = $SPos;
$PDir = $Val;
} else {
if ($SubstrPos < $Pos && $Pos > 0) {
$SubstrPos = $Pos;
$PDir = $Val;
}
}
}
}
if ($Overwrite !== 1 && file_exists(str_replace('\ ', ' ', FILE_DOWNLOAD_DIR) . $PDir . $Dir . '/')) {
$i = 1;
while (file_exists(str_replace('\ ', ' ', FILE_DOWNLOAD_DIR) . $PDir . $Dir . '/' . $i)) {
$i++;
}
$Dir .= '/' . $i;
}
echo exec(sprintf('bash -c "%s > /dev/null 2>&1 &"',
sprintf("./scripts/app.sh %s %s",
FILE_DOWNLOAD_DIR . $PDir . $Dir,
$URI)
)
);
echo '[langDownloadStarted]';

View File

@@ -0,0 +1,3 @@
#! /bin/bash
mkdir -p "$1" && cd "$1" && curl -L -S -O $2 >> download.log 2>&1 &
# mkdir -p "$1" && cd "$1" && curl -L -O $2 > /dev/null 2>&1 &

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>Files downloader app for CAI CP</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/downloader.css" type="text/css" />
</head>
<body>
<div id="div_download" class="hidden">
<form id="frm_submit" method="post" action="exec/">
<table class="full_width">
<tr><td class="td_label"><label id="lbl_uri" for="uri">[langURI]: </label></td><td><input class="full_width" name="uri" id="uri" type="url" placeholder="http://domain.local/image[1-10].jpg" autofocus required></td></tr>
<tr><td class="td_label"><label id="lbl_dir" for="dir">[langDir]: </label></td><td><input class="full_width" name="dir" id="dir" type="text"></td></tr>
</table>
<input id="lang" name="lang" type="hidden" value="en">
<input name="overwrite" id="overwrite" type="checkbox" value="1"><label id="lbl_overwrite" for="overwrite"> [langOverwrite]</label><br>
<input id="in_submit" type="submit" value="[langGo]">
</form>
</div>
<div id="div_log" class="hidden">
<fieldset id="fs_log">
<legend id="lgn_log">Log</legend>
<div id="div_log_recs"></div>
</fieldset>
</div>
<script src="js/downloader.js"></script>
</body>
</html>

View File

@@ -0,0 +1,206 @@
// MIT License:
//
// Copyright (c) 2016-2017, Alexander I. Chebykin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
/**
* CAI CP v.1
*
* @module : Downloader app
* @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
* @copyright : Copyright (c) 2016-2017 Alexander I. Chebykin
* @version : 1.0
* @build date : 2017-06-05
* @license : MIT
* @link : https://github.com/CAI79/CAI-CP
******************************************************************/
(function () {
'use strict';
/**
* Return GET parameter from parent page
*
* @param {string} key Key name
*
* returns {string}
*/
function $_PARENT_GET(key) {
// var s = window.location.search;
var s = (window.location !== window.parent.location)
? document.referrer
: document.location.href;
s = s.match(new RegExp(key + '=([^&=]+)'));
return s ? s[1] : false;
}
/**
* Return GET parameter
*
* @param {string} key Key name
*
* returns {string}
*/
function $_GET(key) {
// var s = window.location.search;
var s = document.referrer;
s = s.match(new RegExp(key + '=([^&=]+)'));
return s ? s[1] : false;
}
/**
* Download system constructor
*
* @returns {undefined}
*/
function DownloadSystem() {
this.locales = 'en ru';
this.lang = {};
}
/**
* Download system initialization
*
* @param {string} lang Language code. Ex: en, ru etc.
*
* @returns {undefined}
*/
DownloadSystem.prototype.init = function (lang) {
var dl_instance = this,
json_file = 'locale/',
request = new XMLHttpRequest();
if (this.check_locale(lang)) {
json_file += lang + '.json';
} else {
json_file += 'en.json';
}
if (document.getElementById('lang') !== null) {
document.getElementById('lang').value = lang;
}
if ($_GET('overwrite') && (document.getElementById('overwrite') !== null)) {
document.getElementById('overwrite').checked = true;
}
request.open('GET', json_file);
request.send();
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
dl_instance.lang = JSON.parse(this.responseText);
document.getElementById('lbl_uri').textContent = dl_instance.lang.uri + ': ';
document.getElementById('lbl_dir').textContent = dl_instance.lang.dir + ': ';
document.getElementById('lbl_overwrite').textContent = dl_instance.lang.overwrite;
document.getElementById('lgn_log').textContent = dl_instance.lang.log;
document.getElementById('in_submit').value = dl_instance.lang.go;
document.getElementById('div_download').classList.toggle('hidden');
document.getElementById('div_log').classList.toggle('hidden');
}
}
};
};
/**
* Check locale support
*
* @param {string} locale Locale code to check. Ex: en, ru etc.
*
* @returns {Boolean}
*/
DownloadSystem.prototype.check_locale = function (locale) {
return this.locales.indexOf(locale.toLowerCase()) !== -1;
};
document.addEventListener('DOMContentLoaded', function () {
/**
* Initialize download object
*/
var download = new DownloadSystem();
if ($_GET('lang')) {
download.init($_GET('lang'));
} else if ($_PARENT_GET('lang')) {
download.init($_PARENT_GET('lang'));
} else {
download.init('en');
}
document.getElementById('frm_submit').onsubmit = function () {
var xhr = new XMLHttpRequest(),
msg,
cur_date = new Date();
xhr.onload = function () {
var log_rec = document.createElement('div'),
log_span = document.createElement('span'),
img_del = document.createElement('img'),
hr = document.createElement('hr');
log_rec.classList.add('div_log_rec');
log_rec.classList.add('hidden');
img_del.classList.add('del_rec');
img_del.src = '../../../gfx/buttons/delete.png';
img_del.title = download.lang.del_log_rec;
img_del.addEventListener('click', function () {
this.parentNode.parentNode.removeChild(this.parentNode);
});
log_rec.appendChild(log_span);
log_rec.appendChild(img_del);
log_rec.appendChild(hr);
// document.getElementById('div_log_recs').appendChild(log_rec);
document.getElementById('div_log_recs').insertBefore(log_rec,
document.getElementById('div_log_recs').childNodes[0]);
if (xhr.responseText === '[langDownloadStarted]') {
msg = download.lang.download_started;
} else {
msg = xhr.responseText;
}
log_span.appendChild(document.createTextNode(
cur_date.toLocaleString() + ': ' +
document.getElementById('dir').value + ' (' +
document.getElementById('uri').value + '): ' +
msg
)
);
log_rec.classList.toggle('hidden');
};
xhr.open(this.method, this.action, true);
xhr.send(new FormData(this));
return false;
};
});
}());

View File

@@ -0,0 +1,9 @@
{
"uri" : "URI",
"dir" : "Directory",
"overwrite" : "Overwrite",
"go" : "Go!",
"log" : "Log",
"del_log_rec" : "Delete log record",
"download_started" : "Download started"
}

View File

@@ -0,0 +1,9 @@
{
"uri" : "URI",
"dir" : "Директория",
"overwrite" : "Перезаписать",
"go" : "Поехали!",
"log" : "Журнал",
"del_log_rec" : "Удалить запись журнала",
"download_started" : "Загрузка начата"
}

View File

@@ -0,0 +1,4 @@
Settings
========
Set $DataDir variable value to download dir in exec/index.php file.
Grant write access for this directory to web server.

View File

@@ -0,0 +1,4 @@
Настройка
=========
В файле exec/index.php задайте каталог для загрузки файлов в переменной $DataDir.
Права на каталог должны позволять запись веб-серверу.

16
system/apps/index.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
require_once('../settings.php');
$action = filter_input(INPUT_GET, 'do', FILTER_SANITIZE_STRING);
if ($action === 'get_apps') {
$apps = new \CAI\CAICP\Applications(CP_ROOT_REL);
echo $apps->get_avail_json();
} elseif ($action === 'get_enabled_apps') {
$apps = new \CAI\CAICP\Applications(CP_ROOT_REL);
echo $apps->get_enabled_json();
}

View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_nextcloud",
"caption" : "NextCloud",
"http_uri" : "",
"use_http" : false,
"https_uri" : "https://[server_name]/",
"use_https" : true,
"frame_support" : false,
"require" : [
{"data" : "php"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_openfire",
"caption" : "OpenFire",
"http_uri" : "http://[server_name]:9090/",
"use_http" : true,
"https_uri" : "https://[server_name]:9091/",
"use_https" : true,
"frame_support" : false,
"require" : [
{"data" : "openfire"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_owncloud",
"caption" : "OwnCloud",
"http_uri" : "http://[server_name]/owncloud/",
"use_http" : true,
"https_uri" : "https://[server_name]/owncloud/",
"use_https" : true,
"frame_support" : true,
"require" : [
{"data" : "php"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_phpmyadmin",
"caption" : "phpMyAdmin",
"http_uri" : "",
"use_http" : true,
"https_uri" : "https://[server_name]/phpMyAdmin/",
"use_https" : true,
"frame_support" : false,
"require" : [
{"data" : "php"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_phppgadmin",
"caption" : "phpPgAdmin",
"http_uri" : "",
"use_http" : true,
"https_uri" : "https://[server_name]/phpPgAdmin/",
"use_https" : true,
"frame_support" : true,
"require" : [
{"data" : "php"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

12
system/apps/plex/app.json Normal file
View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_plex",
"caption" : "Plex",
"http_uri" : "http://[server_name]:32400/web/index.html",
"use_http" : false,
"https_uri" : "https://[server_name]:32400/web/index.html",
"use_https" : true,
"frame_support" : false,
"require" : [
{"data" : "plexmediaserver"}
]
}

BIN
system/apps/plex/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_rslsync",
"caption" : "Resilio sync",
"http_uri" : "http://[server_name]:8888/",
"use_http" : true,
"https_uri" : "",
"use_https" : true,
"frame_support" : false,
"require" : [
{"data" : "rslsync"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -0,0 +1,12 @@
{
"app_name" : "app_transmission",
"caption" : "Transmission",
"http_uri" : "http://[server_name]:9091/",
"use_http" : true,
"https_uri" : "",
"use_https" : false,
"frame_support" : true,
"require" : [
{"data" : "transmission"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,154 @@
<?php
/**
* CAI CP v.0.9
* Applications class
*
* build date 2017-07-05
*
* @package : System
* @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
* @copyright : Copyright (c) 2017 Alexander I. Chebykin
* @version : 0.9
* @license : MIT
* @link : https://github.com/CAI79/CAI-CP
******************************************************************/
namespace CAI\CAICP;
class Applications
{
protected $apps_avail = array();
protected $apps_enabled = array();
protected $cp_root = '';
/**
* Constructor
*
* @param string $root_dir Control panel's root directory
*/
function __construct($root_dir)
{
$this->cp_root = filter_input(INPUT_SERVER, 'DOCUMENT_ROOT') . $root_dir;
$this->enum_enabled_apps();
$this->enum_avail_apps();
}
/**
* Read available applications info
*/
private function enum_avail_apps()
{
$dir = opendir($this->cp_root . '/system/apps');
while($file = readdir($dir)) {
if (is_dir($this->cp_root . '/system/apps/' . $file)
&& $file != '.' && $file != '..'
&& file_exists($this->cp_root . '/system/apps/' . $file . '/app.json')) {
$app_info = json_decode(file_get_contents($this->cp_root .
'/system/apps/' .
$file .
'/app.json'),
true);
if (!array_key_exists('version', $app_info)) {
$app_info['version'] = '';
}
if (!array_key_exists('author', $app_info)) {
$app_info['author'] = '';
}
$this->apps_avail[$file] = array('caption' => $app_info['caption'],
'version' => $app_info['version'],
'author' => $app_info['author'],
'enabled' => array_key_exists($app_info['caption'],
$this->apps_enabled));
}
}
}
/**
* Returns enabled applications list
*
* @return array enabled applications list
*/
public function enum_enabled_apps() {
$this->apps_enabled = json_decode(file_get_contents($this->cp_root .
'/system/apps/apps.json'),
true);
}
/**
* Returns available applications list
*
* @return array available applications list
*/
public function get_avail() {
return $this->apps_avail;
}
/**
* Returns available applications list in json format
*
* @return string available applications list in json format
*/
public function get_avail_json() {
return html_entity_decode(json_encode($this->get_avail()));
}
/**
* Returns enabled applications list
*
* @return array enabled applications list
*/
public function get_enabled() {
return $this->apps_enabled;
}
/**
* Returns enabled applications list in json format
*
* @return string enabled applications list
*/
public function get_enabled_json() {
return html_entity_decode(json_encode($this->get_enabled()));
}
/**
* Enable apps
*
* @param array $values Array with apps
*/
public function enable($values)
{
$this->apps_enabled = $values;
}
/**
* Enable apps
*
* @param string $json Apps in JSON format
*/
public function enable_json($json)
{
$this->enable(json_decode($json, true));
}
/**
* Set list of enabled applications
*
* @param array $values array with enabled applications
*/
public function set($values)
{
$this->apps_enabled = $values;
}
/**
* Saves enabled applications list
*
* @return bool
*/
public function save()
{
return file_put_contents($this->cp_root . '/system/apps/apps.json',
html_entity_decode(json_encode($this->apps_enabled)));
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* CAI CP v.0.9
* Localization class
*
* build date : 2017-07-23
*
* @package : System
* @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
* @copyright : Copyright (c) 2017 Alexander I. Chebykin
* @version : 1.0
* @license : MIT
* @link : https://github.com/CAI79/CAI-CP
******************************************************************/
namespace CAI\CAICP;
class Localization
{
protected $cp_root;
protected $lang;
protected $locale;
/**
* Constructor
*
* @param string $root_dir Control panel's root directory
* @param string $settings Control panel settings
*/
function __construct($root_dir, $settings)
{
$this->cp_root = filter_input(INPUT_SERVER, 'DOCUMENT_ROOT') . $root_dir;
$this->lang = filter_input(INPUT_GET, 'lang', FILTER_SANITIZE_STRING);
if (!array_key_exists($this->lang, $settings['langs'])) {
$this->lang = $settings['lang'];
}
if ($this->lang == '') {
$this->lang = 'en';
}
$this->locale = json_decode(file_get_contents($this->cp_root .
'/system/json/locale/' .
$this->lang . '.json'),
true);
}
public function translate($id)
{
return $this->locale[$id];
}
}

View File

@@ -0,0 +1,192 @@
<?php
namespace CAI\CAICP;
/**
* @package PSR-4 autoloader
* @copyright (c) PHP Framework Interop Group
* @link http://www.php-fig.org/psr/psr-4/examples/ Source code
*
* An example of a general-purpose implementation that includes the optional
* functionality of allowing multiple base directories for a single namespace
* prefix.
*
* Given a foo-bar package of classes in the file system at the following
* paths ...
*
* /path/to/packages/foo-bar/
* src/
* Baz.php # Foo\Bar\Baz
* Qux/
* Quux.php # Foo\Bar\Qux\Quux
* tests/
* BazTest.php # Foo\Bar\BazTest
* Qux/
* QuuxTest.php # Foo\Bar\Qux\QuuxTest
*
* ... add the path to the class files for the \Foo\Bar\ namespace prefix
* as follows:
*
* <?php
* // instantiate the loader
* $loader = new \Example\Psr4AutoloaderClass;
*
* // register the autoloader
* $loader->register();
*
* // register the base directories for the namespace prefix
* $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
* $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests');
*
* The following line would cause the autoloader to attempt to load the
* \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php:
*
* <?php
* new \Foo\Bar\Qux\Quux;
*
* The following line would cause the autoloader to attempt to load the
* \Foo\Bar\Qux\QuuxTest class from /path/to/packages/foo-bar/tests/Qux/QuuxTest.php:
*
* <?php
* new \Foo\Bar\Qux\QuuxTest;
*/
class PSR4Autoloader
{
/**
* An associative array where the key is a namespace prefix and the value
* is an array of base directories for classes in that namespace.
*
* @var array
*/
protected $prefixes = array();
/**
* Register loader with SPL autoloader stack.
*
* @return void
*/
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
}
/**
* Adds a base directory for a namespace prefix.
*
* @param string $prefix The namespace prefix.
* @param string $base_dir A base directory for class files in the
* namespace.
* @param bool $prepend If true, prepend the base directory to the stack
* instead of appending it; this causes it to be searched first rather
* than last.
* @return void
*/
public function addNamespace($prefix, $base_dir, $prepend = false)
{
// normalize namespace prefix
$prefix = trim($prefix, '\\') . '\\';
// normalize the base directory with a trailing separator
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
// initialize the namespace prefix array
if (isset($this->prefixes[$prefix]) === false) {
$this->prefixes[$prefix] = array();
}
// retain the base directory for the namespace prefix
if ($prepend) {
array_unshift($this->prefixes[$prefix], $base_dir);
} else {
array_push($this->prefixes[$prefix], $base_dir);
}
}
/**
* Loads the class file for a given class name.
*
* @param string $class The fully-qualified class name.
* @return mixed The mapped file name on success, or boolean false on
* failure.
*/
public function loadClass($class)
{
// the current namespace prefix
$prefix = $class;
// work backwards through the namespace names of the fully-qualified
// class name to find a mapped file name
while (false !== $pos = strrpos($prefix, '\\')) {
// retain the trailing namespace separator in the prefix
$prefix = substr($class, 0, $pos + 1);
// the rest is the relative class name
$relative_class = substr($class, $pos + 1);
// try to load a mapped file for the prefix and relative class
$mapped_file = $this->loadMappedFile($prefix, $relative_class);
if ($mapped_file) {
return $mapped_file;
}
// remove the trailing namespace separator for the next iteration
// of strrpos()
$prefix = rtrim($prefix, '\\');
}
// never found a mapped file
return false;
}
/**
* Load the mapped file for a namespace prefix and relative class.
*
* @param string $prefix The namespace prefix.
* @param string $relative_class The relative class name.
* @return mixed Boolean false if no mapped file can be loaded, or the
* name of the mapped file that was loaded.
*/
protected function loadMappedFile($prefix, $relative_class)
{
// are there any base directories for this namespace prefix?
if (isset($this->prefixes[$prefix]) === false) {
return false;
}
// look through base directories for this namespace prefix
foreach ($this->prefixes[$prefix] as $base_dir) {
// replace the namespace prefix with the base directory,
// replace namespace separators with directory separators
// in the relative class name, append with .php
$file = $base_dir
. str_replace('\\', '/', $relative_class)
. '.php';
// if the mapped file exists, require it
if ($this->requireFile($file)) {
// yes, we're done
return $file;
}
}
// never found it
return false;
}
/**
* If a file exists, require it from the file system.
*
* @param string $file The file to require.
* @return bool True if the file exists, false if not.
*/
protected function requireFile($file)
{
if (file_exists($file)) {
require $file;
return true;
}
return false;
}
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* CAI CP v.0.9
* Core class
*
* build date 2017-06-17
*
* @package : System
* @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
* @copyright : Copyright (c) 2017 Alexander I. Chebykin
* @version : 0.9
* @license : MIT
* @link : https://github.com/CAI79/CAI-CP
******************************************************************/
namespace CAI\CAICP;
class Settings
{
protected $user_settings = array();
protected $cp_root = '';
/**
* Constructor
*
* @param string $root_dir Control panel's root directory
*/
function __construct($root_dir)
{
$this->cp_root = filter_input(INPUT_SERVER, 'DOCUMENT_ROOT') . $root_dir;
$this->load();
}
/**
* Read settings from disk
*/
private function load()
{
$this->user_settings = json_decode(
file_get_contents($this->cp_root . '/system/json/settings.json'),
true);
}
/**
* Save settings to disk
*
* @return false|written bytes count
*/
public function save()
{
return file_put_contents($this->cp_root . '/system/json/settings.json',
html_entity_decode(json_encode($this->user_settings)));
}
/**
* Return array with settings
*
* @return array
*/
public function get()
{
return $this->user_settings;
}
/**
* Return string with settings in JSON format
*
* @return string
*/
public function get_json()
{
return html_entity_decode(json_encode($this->get()));
}
/**
* Return option value
*
* @param string $option_name Option name
*
* @return variant|boolean
*/
public function get_value($option_name)
{
if (trim($option_name) !== '') {
return $this::user_settings[$option_name];
} else {
return false;
}
}
/**
* Set all settings
*
* @param array $values Array with settings
*/
public function set($values)
{
$this->user_settings = $values;
}
/**
* Set all settings
*
* @param string $json Settings in JSON format
*/
public function set_json($json)
{
$this->set(json_decode($json, true));
}
/**
* Set option value
*
* @param string $option_name Option name
* @param variant $value New value
*/
public function set_value($option_name, $value)
{
if (trim($option_name) !== '') {
$this->user_settings[$option_name] = $value;
}
}
}

32
system/help/css/about.css Normal file
View File

@@ -0,0 +1,32 @@
.hidden {display: none;}
.centered {text-align: center;}
.help_title {font-weight: bold;}
.help_ver, .span_ver,
.span_ver_date {font-style: italic;}
.span_author,
.span_author_ru {}
html,
body {
height: 100%;
margin: 0;
}
hr {
margin: 5px 0;
padding: 0;
border: 0;
height: 1px;
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background: linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0, 0));
}
article {
margin: 10px;
}

89
system/help/css/help.css Normal file
View File

@@ -0,0 +1,89 @@
.hidden {display: none;}
.centered {text-align: center;}
.help_title {font-weight: bold;}
.help_ver, .span_ver,
.span_ver_date {font-style: italic;}
.tbl_wide {
width: 100%;
border: solid 1px #ccc;
}
.tbl_wide .tbl_header {
font-weight: bold;
text-align: center;
background-color: #ccc;
}
.tbl_wide td {
padding: 5px;
border: solid 1px #ccc;
}
.mnu_selected {
background-color: #000;
color: #fff;
}
.scrollable {overflow: auto;}
html,
body {
height: 100%;
margin: 0;
}
hr {
margin: 5px 0;
padding: 0;
border: 0;
height: 1px;
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0,0));
background: linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.25),rgba(0,0,0, 0));
}
nav {
width: 200px;
box-shadow: 5px 5px 5px #ccc;
position: fixed;
padding: 2px;
margin-left: 10px;
border: solid 1px #ccc;
}
nav ul {
padding: 0;
margin: 2px;
list-style: none;
transition: all 0.5s ease-out 0.1s;
}
nav ul li {
cursor: pointer;
}
nav ul li ul {
padding: 0 0 0 2px;
}
nav ul li div {
padding: 2px 2px 2px 4px;
}
nav ul li div:hover {
background-color: #ddd;
color: #000;
}
article {
margin: 2px 2px 2px 225px;
transition: all 0.5s ease-out 0.1s;
}
a, a:visited, a:hover {
color: #555;
text-decoration: none;
}
a:hover {text-decoration: underline;}
#div_license {
height: 150px;
}

13
system/help/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>CAI CP: Help</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/help.css" type="text/css" />
</head>
<body>
Loading...
<script src="js/help.js"></script>
</body>
</html>

201
system/help/js/help.js Normal file
View File

@@ -0,0 +1,201 @@
// MIT License:
//
// Copyright (c) 2016-2017, Alexander I. Chebykin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
/**
* CAI CP v.1
*
* @module : Help subsystem
* @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
* @copyright : Copyright (c) 2016-2017 Alexander I. Chebykin
* @version : 0.9
* @build date : 2017-06-16
* @license : MIT
* @link : https://github.com/CAI79/CAI-CP
******************************************************************/
(function () {
'use strict';
/**
* Return GET parameter
*
* @param {string} key Key name
*
* returns {string}
*/
function $_GET(key) {
var s = window.location.search;
s = s.match(new RegExp(key + '=([^&=]+)'));
return s ? s[1] : false;
}
/**
* HelpSystem constructor
*
* @returns {undefined}
*/
function HelpSystem() {
this.locale = 'en';
}
/**
*
* @param {int} init_level Initialization level: 1 - select locale
* 2 - redirect to localized resource
* 3 - load version info
* 4 - set event handlers
*
* @returns {undefined}
*/
HelpSystem.prototype.init = function (init_level) {
var help_instance = this;
switch (init_level) {
case 1:
if ($_GET('lang') !== '') {
this.locale = $_GET('lang');
} else {
var request = new XMLHttpRequest(),
res_data;
if (!~location.href.indexOf('locale')) {
request.open('GET', '../json/settings.json');
} else {
request.open('GET', '../../../json/settings.json');
}
request.send();
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
res_data = JSON.parse(this.responseText);
help_instance.locale = res_data.lang;
}
}
};
}
this.init(2);
break;
case 2:
if (!~location.href.indexOf('locale')) {
location.href = 'locale/' + this.locale + location.hash;
return;
} else {
this.init(3);
}
break;
case 3:
var request = new XMLHttpRequest(),
res_data;
if (!~location.href.indexOf('locale')) {
request.open('GET', '../json/version.json');
} else {
request.open('GET', '../../../json/version.json');
}
request.send();
request.onreadystatechange = function (e) {
if (this.readyState === 4) {
if (this.status === 200) {
res_data = JSON.parse(this.responseText);
var vers = document.getElementsByClassName('span_ver'),
ver_dates = document.getElementsByClassName('span_ver_date');
for (var i = 0; i < vers.length; i++) {
vers[i].textContent = res_data.version;
}
for (var i = 0; i < ver_dates.length; i++) {
ver_dates[i].textContent = new Date(res_data.build_date).toLocaleDateString();
}
}
}
};
this.init(4);
break;
case 4:
var nav_list = document.getElementsByTagName('nav'),
toc_lis = document.getElementById('menu_toc').getElementsByTagName('li');
// Show menu
for (var i = 0; i < nav_list.length; i++) {
nav_list[i].classList.remove('hidden');
}
// Add event listeners
for (var i = 0; i < toc_lis.length; i++) {
toc_lis[i].getElementsByTagName('div')[0].addEventListener('click', function (event) {
help_instance.select_topic(this.parentElement.id.substr(4));
});
}
if (location.hash !== '') {
help_instance.select_topic(location.hash.substr(1));
} else {
help_instance.select_topic('start');
}
}
};
/**
*
* @param {string} topic_id Topic identifier
*
* @returns {undefined}
*/
HelpSystem.prototype.select_topic = function (topic_id) {
var articles = document.getElementsByTagName('article'),
toc_divs = document.getElementsByClassName('div_toc');
for (var j = 0; j < toc_divs.length; j++) {
toc_divs[j].classList.remove('mnu_selected');
}
document.getElementById('mnu_' + topic_id).getElementsByTagName('div')[0].classList.add('mnu_selected');
for (var j = 0; j < articles.length; j++) {
if (articles[j].id === 'art_' + topic_id) {
articles[j].classList.remove('hidden');
} else {
articles[j].classList.add('hidden');
}
}
location.hash = topic_id;
};
document.addEventListener('DOMContentLoaded', function () {
'use strict';
/**
* Initialize help object
*/
var help = new HelpSystem();
help.init(1);
});
}());

View File

@@ -0,0 +1,230 @@
<!DOCTYPE html>
<html>
<head>
<title>CAI CP: Help</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../css/help.css" type="text/css" />
</head>
<body>
<nav class="hidden">
<ul id="menu_toc">
<li id="mnu_start"><div class="div_toc mnu_selected">Tips and ticks</div><hr></li>
<li id="mnu_sys_req"><div class="div_toc mnu_selected">System requirements</div><hr></li>
<li id="mnu_setup"><div class="div_toc">Setting up</div><hr>
<ul>
<li id="mnu_security"><div class="div_toc">Security</div><hr></li>
</ul>
</li>
<li id="mnu_about"><div class="div_toc">About</div></li>
</ul>
</nav>
<article id="art_start" class="hidden">
<h1>Tips and ticks</h1>
<ul>
<li>Table witgets can be maximized by double click on header.</li>
<li>You can switch between information widgets blocks with
following hotkeys:
<ul>
<li><i>Ctrl + 1</i>: System</li>
<li><i>Ctrl + 2</i>: System pulse</li>
<li><i>Ctrl + 3</i>: Storage</li>
<li><i>Ctrl + 4</i>: Network</li>
<li><i>Ctrl + 5</i>: SMB</li>
<li><i>Ctrl + Left arrow</i>: Previous block</li>
<li><i>Ctrl + Right arrow</i>: Next block</li>
</ul>
Also You can use left or right swipe on header on devices
with touchscreen.
<hr>
<ul>
<li><i>Ctrl + F1</i>: This help</li>
</ul>
</li>
</ul>
</article>
<article id="art_sys_req" class="hidden">
<h1>System requirements</h1>
<p>Control panel core uses following commands and utilities:</p>
<ul>
<li>gawk (GNU awk)</li>
<li>grep</li>
<li>hddtemp</li>
<li>lsb-release</li>
<li>sed</li>
<li>smartmontools (smartctl)</li>
<li>sysstat (iostat)</li>
<li>php7</li>
</ul>
<p>
Applications may have other dependencies.
</p>
</article>
<article id="art_setup" class="hidden">
<h1>Setting up</h1>
<p>S.M.A.R.T. and HDD temperature monitoring widgets requires super
user priviledges. You need to add webserver account to sudoers.
Just run visudo command and add to User privilege specification
section next lines:
<pre>
wwwrun ALL=NOPASSWD: /usr/sbin/smartctl
wwwrun ALL=NOPASSWD: /usr/sbin/hddtemp
</pre>
</p>
<p>SMB monitoring widgets requires super user priveledges. You need
to add webserver account to sudoers. Just run visudo command and
add to User privilege specification section next lines:
<pre>
wwwrun ALL=NOPASSWD: /usr/bin/smbstatus
</pre>
</p>
<p>
Control panel configuration file is /system/json/settings.json.<br>
Available options:
<table class="tbl_wide">
<tr class="tbl_header">
<td>Option</td>
<td>Possible values</td>
<td>Description</td>
</tr>
<tr>
<td>lang</td>
<td>ru<br>en<br>...</td>
<td>Default languag. You can specify one of installed
languages.
</td>
</tr>
<tr>
<td>langs</td>
<td>"en" : "English"<br>
"ru" : "Русский"<br>
...
</td>
<td>Available languages.</td>
</tr>
<tr>
<td>dim_on_create</td>
<td>true<br>false</td>
<td>Widgets runs semi-transparent until data is loaded.</td>
</tr>
<tr>
<td>check_files_rights</td>
<td>true<br>false</td>
<td>Check files and directories rights on startup.</td>
</tr>
<tr>
<td>check_hdd_temp_interval</td>
<td>0 .. 86400</td>
<td>HDD temperature checking interval (in seconds).</td>
</tr>
<tr>
<td>check_smart_interval</td>
<td>0 .. 86400</td>
<td>HDD S.M.A.R.T checking interval (in seconds).</td>
</tr>
</table>
</p>
<p>
You can find applications list in /system/apps/apps.json.
Control panel checks dependencies and run applications if they
are ok. You can manually disable application by removing string
with it from this file.
</p>
</article>
<article id="art_security" class="hidden">
<h1>Security</h1>
<ol>
<li><p>You need to set owner to control panel files to wwwrun:www,
all directories and .sh files must have 550 mask, other
directories - 440 mask.</p>
<p>You need to set 640 mask to /system/json/settings.json if
You want to change some settings from WebUI.</p>
<p>You can set rights by executing following commands:<br>
<code>
$ chown -R wwwrun:www /path/to/base/dir<br>
$ chmod 440 $(find /path/to/base/dir -type f)<br>
$ chmod 550 $(find /path/to/base/dir -type d)<br>
$ chmod 550 $(find /path/to/base/dir -type f | grep .sh$)<br>
$ chmod 640 /path/to/base/dir/system/json/settings.json<br>
$ chmod 640 /path/to/base/dir/system/apps/apps.json
</code>
</p>
</li>
<li>Deny accss to .sh files by adding next options to
<pre><span><</span>Directory><span><</span>/Directory></pre>
block of Apache settings:
<pre>
<span><</span>FilesMatch "\.(sh)$">
Require all denied
<span><</span>/FilesMatch>
</pre>
</li>
<li>Set password to restrict access. Basic autorization example:
run Apache's utility htpasswd to generate password file
.htpasswd. Add next lines to Apache's config file into
<pre><span><</span>Directory><span><</span>/Directory></pre>
section:
<pre>
AuthName "Restricted zone"
AuthType Basic
AuthUserFile [Путь к файлу .htpasswd]
Require valid-user
</pre>
<p>Restart Apache.</p>
<p>
Attention! Basic authorization uses plain text to send
passwords. Consider to use HTTPS to avoid password leak.
</p>
</li>
<li><p>You need to add wwwrun user to sudoers if to enable
shutdown or reboot server functions. Be carefully with this
option!</p>
<p>Run <code># visudo</code> and add following line to
"User privilege specification":
<code>wwwrun ALL=NOPASSWD: /sbin/shutdown</code>
</p>
</li>
</ol>
</article>
<article id="art_about" class="hidden">
<h1>About</h1>
<div class="help_title">CAI CP</div>
<div class="help_ver">Version <span class="span_ver">_._</span>. Build date <span class="span_ver_date">__.__.____</span></div>
<div>Author: <span class="span_author_ru">Alexander Chebykin</span></div>
<div>License: MIT
<div id="div_license" class="scrollable">
<pre>
MIT License
-----------
Copyright (c) 2016-2017, Alexander I. Chebykin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</pre>
</div>
</div>
<p>This product partially based on
<a href="https://github.com/afaqurk/linux-dash" target="_blank">
Linux Dash
</a> project.
</p>
</article>
<script src="../../js/help.js"></script>
</body>
</html>

View File

@@ -0,0 +1,268 @@
<!DOCTYPE html>
<html>
<head>
<title>CAI CP: Help</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../css/help.css" type="text/css" />
</head>
<body>
<nav class="hidden">
<ul id="menu_toc">
<li id="mnu_start"><div class="div_toc mnu_selected">Советы по использованию</div><hr></li>
<li id="mnu_sys_req"><div class="div_toc">Системные требования</div><hr></li>
<li id="mnu_setup"><div class="div_toc">Настройка</div><hr>
<ul>
<li id="mnu_security"><div class="div_toc">Безопасность</div><hr></li>
</ul>
</li>
<li id="mnu_about"><div class="div_toc">О панели управления</div></li>
</ul>
</nav>
<article id="art_start" class="hidden">
<h1>Советы по использованию</h1>
<ul>
<li>Табличные виджеты можно распахнуть на весь экран двойным
щелчком по заголовку.</li>
<li>Для переключения по информационным блокам используйте
следующие комбинации клавиш:
<ul>
<li><i>Ctrl + 1</i>: Система</li>
<li><i>Ctrl + 2</i>: Пульс системы</li>
<li><i>Ctrl + 3</i>: Файловое хранилище</li>
<li><i>Ctrl + 4</i>: Сеть</li>
<li><i>Ctrl + 5</i>: SMB</li>
<li><i>Ctrl + Влево</i>: Предыдущий блок</li>
<li><i>Ctrl + Вправо</i>: Следующий блок</li>
</ul>
Также вы можете переключаться между блоками, проведя влево
или вправо по заголовку на устройствах с сенсорным экраном.
<hr>
<ul>
<li><i>Ctrl + F1</i>: Справка</li>
</ul>
</li>
</ul>
</article>
<article id="art_sys_req" class="hidden">
<h1>Системные требования</h1>
<p>Ядро системы использует следующие команды и утилиты:</p>
<ul>
<li>gawk (GNU awk)</li>
<li>grep</li>
<li>hddtemp</li>
<li>lsb-release</li>
<li>sed</li>
<li>smartmontools (smartctl)</li>
<li>sysstat (iostat)</li>
<li>php7</li>
</ul>
<p>
Различные приложения могут требовать наличие других программ и утилит.
</p>
</article>
<article id="art_setup" class="hidden">
<h1>Настройка</h1>
<p>Для мониторинга S.M.A.R.T. и температуры дисков требуется
разрешить выполнение smartctl и hddtemp веб-сервером. Для этого
запустите редактор sudo командой visudo и добавьте в раздел User
privilege specification следующие строки:
<pre>
wwwrun ALL=NOPASSWD: /usr/sbin/smartctl
wwwrun ALL=NOPASSWD: /usr/sbin/hddtemp
</pre>
</p>
<p>Для мониторинга ресурсов SMB требуется разрешить выполнение
smbstatus веб-сервером. Для этого запустите редактор sudo
командой visudo и добавьте в раздел User privilege specification
следующие строки:
<pre>
wwwrun ALL=NOPASSWD: /usr/bin/smbstatus
</pre>
</p>
<p>
Конфигурация панели управления задаётся в файле /system/json/settings.json.<br>
Параметры:
<table class="tbl_wide">
<tr class="tbl_header">
<td>Параметр</td>
<td>Возможные значения</td>
<td>Описание</td>
</tr>
<tr>
<td>lang</td>
<td>ru<br>en<br>...</td>
<td>Язык по умолчанию. Может быть указан один из
доступных языков.
</td>
</tr>
<tr>
<td>langs</td>
<td>"en" : "English"<br>
"ru" : "Русский"<br>
...
</td>
<td>Доступные языки.</td>
</tr>
<tr>
<td>dim_on_create</td>
<td>true<br>false</td>
<td>Виджеты отображаются полупрозрачными пока не
загрузятся данные.</td>
</tr>
<tr>
<td>check_files_rights</td>
<td>true<br>false</td>
<td>При запуске проводится проверка правильности
установленных прав на файлы и каталоги.</td>
</tr>
<tr>
<td>check_hdd_temp_interval</td>
<td>0 .. 86400</td>
<td>Интервал (в секундах) проверки температуры жёстких
дисков.</td>
</tr>
<tr>
<td>check_smart_interval</td>
<td>0 .. 86400</td>
<td>Интервал (в секундах) проверки состояния S.M.A.R.T.
жёстких дисков.</td>
</tr>
</table>
</p>
<p>
Список загружаемых приложений находится в файле /system/apps/apps.json.
Панель управления проверяет зависимости приложений и отключает
те, что не могут быть запущены на данном сервере. Если вы хотите
принудительно отключить какое-либо приложение, удалите строку
с его названием из данного файла.
</p>
</article>
<article id="art_security" class="hidden">
<h1>Безопасность</h1>
<ol>
<li><p>Назначьте владельцем файлов и каталогов wwwrun:www, всем
каталогам и файлам .sh назначьте права по маске 550,
остальным файлам - 440.</p>
<p>Если хотите иметь возможность управлять некоторыми
параметрами из веб-интерфейса, установите маску 640 файлу
/system/json/settings.json.</p>
<p>Для этого выполните следующие команды:<br>
<code>
$ chown -R wwwrun:www /path/to/base/dir<br>
$ chmod 440 $(find /path/to/base/dir -type f)<br>
$ chmod 550 $(find /path/to/base/dir -type d)<br>
$ chmod 550 $(find /path/to/base/dir -type f | grep .sh$)<br>
$ chmod 640 /path/to/base/dir/system/json/settings.json<br>
$ chmod 640 /path/to/base/dir/system/apps/apps.json
</code>
</p>
</li>
<li>Запретите доступ через веб к файлам с расширением .sh, для
этого в конфигурационный файл Apache в блок
<pre><span><</span>Directory><span><</span>/Directory></pre>
добавьте следующие строки:
<pre>
<span><</span>FilesMatch "\.(sh)$">
Require all denied
<span><</span>/FilesMatch>
</pre>
</li>
<li>Установите пароль на доступ к панели управления. Пример для
настройки базовой аутентификации: с помощью утилиты htpasswd
(входит в комплект сервера Apache) создайте содержащий пароль
файл .htpasswd. В конфигурационный файл Apache добавьте в блок
<pre><span><</span>Directory><span><</span>/Directory></pre> следующие строки:
<pre>
AuthName "Restricted zone"
AuthType Basic
AuthUserFile [Путь к файлу .htpasswd]
Require valid-user
</pre>
<p>После этого перезагрузите сервер Apache.</p>
<p>
Обратите внимание, что в рассмотренном случае используется
базовая аутентификация, при её использовании пароль
передаётся в открытом виде, для защиты передаваемой
информации настройте доступ по протоколу HTTPS.
</p>
</li>
<li><p>Если хотите включить возможность перезагрузки и отключения
сервера, следует добавить пользователя wwwrun в sudoers.
Будьте осторожны с данной возможностью!</p>
<p>Запустите <code># visudo</code> и добавьте следующую
строку в блок "User privilege specification":
<code>wwwrun ALL=NOPASSWD: /sbin/shutdown</code>
</p>
</li>
</ol>
</article>
<article id="art_about" class="hidden">
<h1>О панели управления</h1>
<div class="help_title">CAI CP</div>
<div class="help_ver">Версия <span class="span_ver">_._</span> от <span class="span_ver_date">__.__.____</span></div>
<div>Автор: <span class="span_author_ru">Александр Чебыкин</span></div>
<div>Лицензия: MIT
<div id="div_license" class="scrollable">
<pre>
Лицензия MIT
------------
Copyright (c) 2016-2017, Александр Чебыкин
Данная лицензия разрешает лицам, получившим копию данного программного
обеспечения и сопутствующей документации (в дальнейшем именуемыми
«Программное Обеспечение»), безвозмездно использовать Программное Обеспечение
без ограничений, включая неограниченное право на использование, копирование,
изменение, слияние, публикацию, распространение, сублицензирование и/или
продажу копий Программного Обеспечения, а также лицам, которым предоставляется
данное Программное Обеспечение, при соблюдении следующих условий:
Указанное выше уведомление об авторском праве и данные условия должны быть
включены во все копии или значимые части данного Программного Обеспечения.
ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО
ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ
ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ,
НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ
ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ
ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ, ВОЗНИКШИМ ИЗ-ЗА
ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ
ОБЕСПЕЧЕНИЕМ.
-------------------------------------------------------------------------------
MIT License
-----------
Copyright (c) 2016-2017, Alexander I. Chebykin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</pre>
</div>
</div>
<p>Данный продукт частично основан на
<a href="https://github.com/afaqurk/linux-dash" target="_blank">
Linux Dash
</a>.
</p>
</article>
<script src="../../js/help.js"></script>
</body>
</html>

View File

@@ -0,0 +1,9 @@
<?php
header('Content-Type: application/json');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
require_once('../../settings.php');
echo html_entity_decode(json_encode($settings));

30
system/json/index.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
header('Content-Type: application/json');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
$filtered_widget = filter_input(INPUT_GET, 'widget', FILTER_SANITIZE_STRING);
$filtered_param = preg_replace('/[^a-zA-Z0-9]+/',
'',
filter_input(INPUT_GET,
'param',
FILTER_SANITIZE_STRING)
);
if ($filtered_widget !== '') {
if ($filtered_param !== '') {
echo shell_exec(sprintf('../scripts/json_api_nix.sh %s %s',
$filtered_widget,
$filtered_param
)
);
} else {
echo shell_exec(sprintf('../scripts/json_api_nix.sh %s',
$filtered_widget
)
);
}
} else {
echo '{}';
}

View File

@@ -0,0 +1,70 @@
{
"_lang" : "English",
"about" : "About",
"application" : "Application",
"applications" : "Applications",
"attention" : "Attention!",
"author" : "Author",
"check_files_rights" : "Check files rights",
"check_hdd_temp_int" : "HDD temperature check interval",
"check_smart_int" : "HDD S.M.A.R.T. check interval",
"check_users_online_int" : "Online users check interval",
"control_panel" : "Control panel",
"ctrl_click_hint" : "Ctrl + mouse click to open in new window...",
"cpu_info" : "CPU",
"default_language" : "Default language",
"dim_on_create" : "Dim widgets while creating",
"drv_smart_info" : "S.M.A.R.T.",
"drv_temp_info" : "Drives temperature",
"enbld" : "Enbl",
"error" : "Error occured",
"fs_check" : "File structure check",
"fs_errors" : "Attention! Files structure misconfiguration detected. Click this record to view details.",
"fs_info" : "File system",
"general_info" : "OS version and uptime",
"general_settings" : "General settings",
"hdd_overheat" : "HDD overheat detected:",
"hdd_smart_error" : "S.M.A.R.T.: HDD error detected",
"help" : "Help",
"information" : "Information",
"iostat_info" : "I/O statistics",
"max_hdd_temp" : "Max HDD temperature",
"memory_info" : "Memory",
"monitoring" : "Monitoring",
"net_arp_cache_info" : "ARP cache table",
"net_band_info" : "Network bandwidth",
"net_conn_info" : "Network connections",
"net_down_info" : "Download transfer rate",
"net_ip_addr_info" : "Host's IP-addresses",
"net_ip_route_info" : "IP routing table",
"net_lstn_socks_info" : "Listening server sockets",
"net_mcast_info" : "Multicast group membership",
"net_unix_socks_info" : "Active unix domain sockets",
"net_up_info" : "Upload transfer rate",
"network" : "Network",
"new_user_connected" : "New user login detected",
"proc_info" : "Processes",
"reboot" : "Reboot",
"reboot_confirm" : "Do You really want to reboot server?",
"reboot_in_progress" : "Reboot in progress",
"reboot_prohibited" : "Reboot prohibited!",
"save" : "Save",
"secs" : "seconds",
"settings" : "Settings",
"settings_saved" : "Настройки сохранены",
"shutdown" : "Shutdown",
"shutdown_confirm" : "Do You really want to shutdown server?",
"shutdown_in_progress" : "Shutdown in progress",
"shutdown_prohibited" : "Shutdown prohibited!",
"smb" : "SMB",
"smb_locks_info" : "SMB locks",
"smb_proc_info" : "SMB processes",
"smb_shares_info" : "SMB shares",
"storage" : "Storage",
"swap_info" : "Swap",
"system" : "System",
"system_pulse" : "System pulse",
"transmission_info" : "Transmission",
"users_online_info" : "Users online",
"version" : "Version"
}

View File

@@ -0,0 +1,70 @@
{
"_lang" : "Русский",
"about" : "О панели управления",
"application" : "Приложение",
"applications" : "Приложения",
"attention" : "Внимание!",
"author" : "Автор",
"check_files_rights" : "Проверять права доступа к файлам",
"check_hdd_temp_int" : "Интервал проверки температуры дисков",
"check_smart_int" : "Интервал проверки S.M.A.R.T.",
"check_users_online_int" : "Интервал проверки подключений пользователей",
"control_panel" : "Панель управления",
"ctrl_click_hint" : "Ctrl + щелчок мыши для открытия в новом окне...",
"cpu_info" : "ЦПУ",
"default_language" : "Язык по умолчанию",
"dim_on_create" : "Затемнять виджеты пока они создаются",
"drv_smart_info" : "S.M.A.R.T.",
"drv_temp_info" : "Температура дисков",
"enbld" : "Вкл",
"error" : "Возникла ошибка",
"fs_check" : "Проверка файловой структуры",
"fs_errors" : "Внимание! Обнаружены связанные с файловой структурой ошибки, щёлкните по данному сообщению для просмотра отчёта.",
"fs_info" : "Файловая система",
"general_info" : "Версия ОС и время работы",
"general_settings" : "Основные настройки",
"hdd_overheat" : "Обнаружен перегрев диска",
"hdd_smart_error" : "S.M.A.R.T.: Обнаружена ошибка диска",
"help" : "Справка",
"information" : "Информация",
"iostat_info" : "Статистика ввода/вывода",
"max_hdd_temp" : "Максимально допустимая температура дисков",
"memory_info" : "Память",
"monitoring" : "Мониторинг",
"net_arp_cache_info" : "Таблица ARP-кэша",
"net_band_info" : "Пропускная способность",
"net_conn_info" : "Сетевые соединения",
"net_down_info" : "Скорость загрузки",
"net_ip_addr_info" : "IP-адреса хоста",
"net_ip_route_info" : "Таблица маршрутизации",
"net_lstn_socks_info" : "Прослушиваемые серверные сокеты",
"net_mcast_info" : "Мультикаст-группы",
"net_unix_socks_info" : "Активные сокеты unix",
"net_up_info" : "Скорость отдачи",
"network" : "Сеть",
"new_user_connected" : "Подключился новый пользователь",
"proc_info" : "Процессы",
"reboot" : "Перезагрузка",
"reboot_in_progress" : "Сервер перезагружается",
"reboot_confirm" : "Вы действительно хотите перезагрузить сервер?",
"reboot_prohibited" : "Перезагрузка сервера запрещена!",
"save" : "Сохранить",
"secs" : "секунд",
"settings" : "Настройки",
"settings_saved" : "Настройки сохранены",
"shutdown" : "Завершение работы",
"shutdown_confirm" : "Вы действительно хотите выключить сервер?",
"shutdown_in_progress" : "Сервер завершает работу",
"shutdown_prohibited" : "Завершение работы сервера запрещено!",
"smb" : "SMB",
"smb_locks_info" : "Блокировки SMB",
"smb_proc_info" : "Процессы SMB",
"smb_shares_info" : "Ресурсы SMB",
"storage" : "Файловое хранилище",
"swap_info" : "Подкачка",
"system" : "Система",
"system_pulse" : "Пульс системы",
"transmission_info" : "Transmission",
"users_online_info" : "Подключенные пользователи",
"version" : "Версия"
}

13
system/json/settings.json Normal file
View File

@@ -0,0 +1,13 @@
{
"dim_on_create" : true,
"check_files_rights" : true,
"check_users_online_interval" : 60,
"check_hdd_temp_interval" : 300,
"check_smart_interval" : 3600,
"max_hdd_temp" : 45,
"lang" : "ru",
"langs" : {
"en" : "English",
"ru" : "Русский"
}
}

4
system/json/version.json Normal file
View File

@@ -0,0 +1,4 @@
{
"version" : "0.9 beta",
"build_date" : "2018-08-25"
}

View File

@@ -0,0 +1,171 @@
<?php
header('Content-Type: application/json');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
require_once('../settings.php');
$files = array( 'index.html' => 440,
'LICENSE' => 440,
'css' => 550,
'css/core.css' => 440,
'css/core.min.css' => 440,
'gfx' => 550,
'gfx/bg.jpg' => 440,
'gfx/menu.png' => 440,
'gfx/buttons' => 550,
'gfx/buttons/delete.png' => 440,
'gfx/distros' => 550,
'gfx/distros/apple.png' => 440,
'gfx/distros/arch.png' => 440,
'gfx/distros/bsd.png' => 440,
'gfx/distros/debian.png' => 440,
'gfx/distros/fedora.png' => 440,
'gfx/distros/linux.png' => 440,
'gfx/distros/opensuse.png' => 440,
'gfx/distros/ubuntu.png' => 440,
'gfx/distros/unknown.png' => 440,
'gfx/flags' => 550,
'gfx/flags/russian-16x16.png' => 440,
'gfx/flags/uk-16x16.png' => 440,
'gfx/icons' => 550,
'gfx/icons/about.png' => 440,
'gfx/icons/help.png' => 440,
'gfx/icons/loading.gif' => 440,
'gfx/icons/network.png' => 440,
'gfx/icons/server.png' => 440,
'gfx/icons/settings.png' => 440,
'gfx/icons/samba.png' => 440,
'gfx/icons/storage.png' => 440,
'gfx/icons/sysinfo.png' => 440,
'js' => 550,
'js/core.js' => 440,
'js/smoothie.js' => 440,
'system' => 550,
'system/settings.php' => 440,
'system/action' => 550,
'system/action/index.php' => 440,
'system/apps' => 550,
'system/apps/apps.json' => 640,
'system/apps/cai_downloader' => 550,
'system/apps/cai_downloader/app.json' => 440,
'system/apps/cai_downloader/icon.png' => 440,
'system/apps/cai_downloader/index.html' => 440,
'system/apps/cai_downloader/css' => 550,
'system/apps/cai_downloader/css/downloader.css' => 440,
'system/apps/cai_downloader/exec' => 550,
'system/apps/cai_downloader/exec/index.php' => 440,
'system/apps/cai_downloader/exec/scripts' => 550,
'system/apps/cai_downloader/exec/scripts/app.sh' => 550,
'system/apps/cai_downloader/js' => 550,
'system/apps/cai_downloader/js/downloader.js' => 440,
'system/apps/cai_downloader/locale' => 550,
'system/apps/cai_downloader/locale/en.json' => 440,
'system/apps/cai_downloader/locale/ru.json' => 440,
'system/apps/nextcloud' => 550,
'system/apps/nextcloud/app.json' => 440,
'system/apps/nextcloud/icon.png' => 440,
'system/apps/openfire' => 550,
'system/apps/openfire/app.json' => 440,
'system/apps/openfire/icon.png' => 440,
'system/apps/owncloud' => 550,
'system/apps/owncloud/app.json' => 440,
'system/apps/owncloud/icon.png' => 440,
'system/apps/phpmyadmin' => 550,
'system/apps/phpmyadmin/app.json' => 440,
'system/apps/phpmyadmin/icon.png' => 440,
'system/apps/phppgadmin' => 550,
'system/apps/phppgadmin/app.json' => 440,
'system/apps/phppgadmin/icon.png' => 440,
'system/apps/plex' => 550,
'system/apps/plex/app.json' => 440,
'system/apps/plex/icon.png' => 440,
'system/apps/rslsync' => 550,
'system/apps/rslsync/app.json' => 440,
'system/apps/rslsync/icon.png' => 440,
'system/apps/transmission' => 550,
'system/apps/transmission/app.json' => 440,
'system/apps/transmission/icon.png' => 440,
'system/classes' => 550,
'system/classes/CAI' => 550,
'system/classes/CAI/CAICP' => 550,
'system/classes/CAI/CAICP/src' => 550,
'system/classes/CAI/CAICP/src/Applications.php' => 440,
'system/classes/CAI/CAICP/src/Localization.php' => 440,
'system/classes/CAI/CAICP/src/PSR4Autoloader.php' => 440,
'system/classes/CAI/CAICP/src/Settings.php' => 440,
'system/help' => 550,
'system/help/index.html' => 440,
'system/help/css' => 550,
'system/help/css/help.css' => 440,
'system/help/js' => 550,
'system/help/js/help.js' => 440,
'system/help/locale' => 550,
'system/help/locale/en' => 550,
'system/help/locale/en/index.html' => 440,
'system/help/locale/ru' => 550,
'system/help/locale/ru/index.html' => 440,
'system/json' => 550,
'system/json/index.php' => 440,
'system/json/settings.json' => 640,
'system/json/version.json' => 440,
'system/json/general_settings' => 550,
'system/json/general_settings/index.php' => 440,
'system/json/locale' => 550,
'system/json/locale/en.json' => 440,
'system/json/locale/ru.json' => 440,
'system/scripts' => 550,
'system/scripts/check_files.php' => 440,
'system/scripts/index.php' => 440,
'system/scripts/json_api_nix.sh' => 550,
'system/scripts/json_transmission.php' => 440,
'system/scripts/json_transmission.sh' => 550,
'system/scripts/smart_temp.sh' => 550,
'system/scripts/trim.awk' => 440,
'system/ui' => 550,
'system/ui/forms' => 550,
'system/ui/forms/settings' => 550,
'system/ui/forms/settings/index.html' => 440,
'system/ui/forms/settings/css' => 550,
'system/ui/forms/settings/css/styles.css' => 440,
'system/ui/forms/settings/js' => 550,
'system/ui/forms/settings/js/settings.js' => 440
);
$script_response = array();
$err_count = 0;
foreach ($files as $key => $value) {
if (!file_exists($cp_root . '/' . $key)) {
$err_count += 1;
$script_response[] = array( 'file' => $key,
'exists' => 0,
'mask_required' => 0,
'mask_actual' => 0);
} else {
$file_owner = posix_getpwuid(fileowner($cp_root . '/' . $key))['name'];
$file_group = posix_getgrgid(filegroup($cp_root . '/' . $key))['name'];
$file_mask = (int)substr(sprintf('%o',
fileperms($cp_root . '/' . $key)
),
-3);
if (($value != $file_mask) ||
($file_group != FILE_GROUP) ||
$file_owner != FILE_OWNER) {
$err_count += 1;
$script_response[] = array( 'file' => $key,
'exists' => 1,
'mask_required' => $value,
'mask_actual' => $file_mask,
'owner_required' => FILE_OWNER,
'owner_actual' => $file_owner,
'group_required' => FILE_GROUP,
'group_actual' => $file_group);
}
}
}
echo html_entity_decode(json_encode($script_response));

30
system/scripts/index.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
header('Content-Type: application/json');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
$filtered_widget = filter_input(INPUT_GET, 'widget', FILTER_SANITIZE_STRING);
$filtered_param = preg_replace('/[^a-zA-Z0-9]+/',
'',
filter_input(INPUT_GET,
'param',
FILTER_SANITIZE_STRING)
);
if ($filtered_widget !== '') {
if ($filtered_param !== '') {
echo shell_exec(sprintf('./json_api_nix.sh %s %s',
$filtered_widget,
$filtered_param
)
);
} else {
echo shell_exec(sprintf('./json_api_nix.sh %s',
$filtered_widget
)
);
}
} else {
echo '{}';
}

View File

@@ -0,0 +1,938 @@
#!/bin/bash
# MIT License:
#
# Copyright (c) 2016-2018, Alexander I. Chebykin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#################################################################
# CAI CP v.0.9.1
#
# @module : Bash script module
# @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
# @copyright : Copyright (c) 2016-2018 Alexander I. Chebykin
# @version : 0.9.1
# @build date : 2018-08-23
# @license : MIT
# @link : https://github.com/CAI79/CAI-CP
#################################################################
skeleton() {
cmd_arp=`which arp`
cmd_awk=`which awk`
cmd_cat=`which cat`
cmd_date=`which date`
cmd_df=`which df`
cmd_free=`which free`
cmd_grep=`which grep`
cmd_hostname=`which hostname`
cmd_iostat=`which iostat`
cmd_ip=`which ip`
cmd_lsb_release=`which lsb_release`
cmd_lscpu=`which lscpu`
cmd_netstat=`which netstat`
cmd_ps=`which ps`
cmd_sed=`which sed`
cmd_smartctl=`which smartctl`
cmd_smbstatus=`which smbstatus`
cmd_sort=`which sort`
cmd_ss=`which ss`
cmd_uname=`which uname`
cmd_w=`which w`
result=$()
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
_print_parsed() {
while read data; do
# echo -n "$data" | sed -r "s/\"/\\\\\"/g" | tr -d "\n";
echo -n "$data" | tr -d "\n";
done;
}
#########################
# Common info functions #
#########################
cpu() {
cmd_awk=`which awk`
cmd_cat=`which cat`
result=$({ $cmd_cat /proc/stat; sleep "1"; $cmd_cat /proc/stat; } \
| $cmd_awk '/^cpu* / {usr=$2-usr; sys=$4-sys; idle=$5-idle; iow=$6-iow} END \
{total=usr+sys+idle+iow; printf "%.2f\n", (total-idle)*100/total}' \
| $cmd_awk -F " " '{print "{\n \"cpu\": " $1 "\n}"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# CPU(s) count
cpu_count() {
cmd_awk=`which awk`
cmd_grep=`which grep`
cmd_lscpu=`which lscpu`
result=$($cmd_lscpu \
| $cmd_grep '^CPU(s):' \
| $cmd_awk '{ print "{\n\t\"cpu(s)\": " $2 "\n}" }')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# CPU(s) load information
cpu_load() {
cmd_awk=`which awk`
cmd_cat=`which cat`
cmd_grep=`which grep`
cmd_lscpu=`which lscpu`
cpus=$($cmd_lscpu \
| $cmd_grep '^CPU(s):' \
| $cmd_awk '{ print $2 }')
i=0
while [ $i -lt $cpus ]
do
if [ "$i" -ne 0 ]; then
result="$result,"
fi
result+=$(
{ $cmd_cat /proc/stat; sleep "1"; $cmd_cat /proc/stat; } \
| $cmd_awk '/^cpu'$i' / {usr=$2-usr; sys=$4-sys; idle=$5-idle; iow=$6-iow} END \
{total=usr+sys+idle+iow; printf "%.2f\n", (total-idle)*100/total}' \
| $cmd_awk -F " " '{print "\n \"cpu'$i'\": " int($1) "\n"}'
)
(( i++ ))
done
echo "{$result}" | _print_parsed
}
# CPU information
cpu_info() {
cmd_awk=`which awk`
cmd_lscpu=`which lscpu`
result=$($cmd_lscpu \
| $cmd_awk -F: '{print "\""$1"\": \""$2"\"," }'\
)
echo "[{" ${result%?} "}]" | _print_parsed
}
# General OS information
general_info() {
cmd_awk=`which awk`
cmd_cat=`which cat`
cmd_date=`which date`
cmd_hostname=`which hostname`
cmd_lsb_release=`which lsb_release`
cmd_sed=`which sed`
cmd_uname=`which uname`
function displaytime {
local T=$1
local D=$((T/60/60/24))
local H=$((T/60/60%24))
local M=$((T/60%60))
local S=$((T%60))
[[ $D > 0 ]] && printf '%d days ' $D
[[ $H > 0 ]] && printf '%d hours ' $H
[[ $M > 0 ]] && printf '%d minutes ' $M
[[ $D > 0 || $H > 0 || $M > 0 ]] && printf 'and '
printf '%d seconds\n' $S
}
lsbRelease=$($cmd_lsb_release -ds | $cmd_sed -e 's/^"//' -e 's/"$//')
uname=$($cmd_uname -r | $cmd_sed -e 's/^"//' -e 's/"$//')
os=`echo $lsbRelease $uname`
hostname=$($cmd_hostname)
uptime_seconds=$($cmd_cat /proc/uptime | $cmd_awk '{print $1}')
server_time=$($cmd_date)
echo "[{ \"OS\": \"$os\", \
\"Hostname\": \"$hostname\", \
\"Uptime\": \" $(displaytime ${uptime_seconds%.*}) \", \
\"Server Time\": \"$server_time\" }]" \
| _print_parsed
}
# OS distriboutive info
os_distr() {
cmd_lsb_release=`which lsb_release`
cmd_sed=`which sed`
cmd_uname=`which uname`
lsbRelease=$($cmd_lsb_release -ds | $cmd_sed -e 's/^"//' -e 's/"$//')
osFamily=$($cmd_uname)
echo "{ \"Distr\": \"$lsbRelease\", \
\"Family\": \"$osFamily\" }" \
| _print_parsed
}
# Running processes list
processes() {
cmd_awk=`which awk`
cmd_ps=`which ps`
cmd_sed=`which sed`
cmd_sort=`which sort`
result=$($cmd_ps -eafw \
| $cmd_sed -e '1d' \
| $cmd_sort -k1 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"uid\": \"%s\", \
\n\t\t\"pid\": %s, \
\n\t\t\"ppid\": %s, \
\n\t\t\"c\": %s, \
\n\t\t\"stime\": \"%s\", \
\n\t\t\"tty\": \"%s\", \
\n\t\t\"time\": \"%s\", \
\n\t\t\"cmd\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7, $8)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Server name
srv_name() {
cmd_awk=`which awk`
cmd_uname=`which uname`
result=$($cmd_uname -n | $cmd_awk '{ print "{\n\t\"server_name\": \"" $1 "\"\n}" }')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
##############################
# File system info functions #
##############################
# File system info
fs() {
cmd_awk=`which awk`
cmd_df=`which df`
cmd_sed=`which sed`
cmd_sort=`which sort`
result=$($cmd_df -h -T \
| $cmd_sed -e '1d' \
| $cmd_sort -k1,1 -k7,7 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"fs\": \"%s\", \
\n\t\t\"type\": \"%s\", \
\n\t\t\"size\": \"%s\", \
\n\t\t\"used\": \"%s\", \
\n\t\t\"free\": \"%s\", \
\n\t\t\"percent\": \"%s\", \
\n\t\t\"mount\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7)} \
END{print "\n]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# HDD S.M.A.R.T. status
hdd_smart() {
cmd_awk=`which awk`
cmd_sed=`which sed`
cmd_smartctl=`which smartctl`
result=$(sudo $cmd_smartctl --scan \
| $cmd_awk '{printf("%s ", $1)} {system("sudo smartctl -H \"" $1 "\" \
| sed -n '5p'")}' \
| $cmd_sed -e '/^$/d' \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"drive\": \"%s\",\n\t\t\"status\": \"%s\"\n\t}", $1, $NF)} \
END \
{print "\n]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# HDD temperature info
hdd_temp() {
cmd_awk=`which awk`
cmd_smartctl=`which smartctl`
path=`pwd`
result=$($cmd_smartctl --scan \
| $cmd_awk '{system("./smart_temp.sh \"" $1 "\"")}' \
| $cmd_awk -F: 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{FS=": "} \
{printf("\t\t\"drive\": \"%s\", \
\n\t\t\"model\": \"%s\", \
\n\t\t\"temperature\": \"%s\"\n\t}", $1, $2, $3)} \
END\
{print "\n]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# IO statistics
io_stat() {
cmd_awk=`which awk`
cmd_iostat=`which iostat`
cmd_sed=`which sed`
cmd_sort=`which sort`
result=$($cmd_iostat \
| $cmd_sed -e '1,6d;/^$/d' \
| $cmd_sort -k1 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"device\": \"%s\", \
\n\t\t\"tps\": %s, \
\n\t\t\"kB_read/s\": %s, \
\n\t\t\"kB_wrtn/s\": %s, \
\n\t\t\"kB_read\": %s, \
\n\t\t\"kB_wrtn\": %s\n\t}", $1, $2, $3, $4, $5, $6)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
#########################
# Memory info functions #
#########################
# General memory information
mem_info() {
cmd_awk=`which awk`
cmd_cat=`which cat`
cmd_sed=`which sed`
result=$($cmd_cat /proc/meminfo \
| $cmd_awk -F: 'BEGIN {print "{"} {print "\"" $1 "\": \"" $2 "\"," } END {print "}"}' \
| $cmd_sed 'N;$s/,\n/\n/;P;D')
echo "[" ${result%?} "}]" | _print_parsed
}
# Memory usage information
#
# Based on Linux Dash codebase: https://github.com/afaqurk/linux-dash
#
# References:
# Calculations: http://zcentric.com/2012/05/29/mapping-procmeminfo-to-output-of-free-command/
# Fields: https://www.kernel.org/doc/Documentation/filesystems/proc.txt
mem() {
cmd_awk=`which awk`
cmd_cat=`which cat`
cmd_grep=`which grep`
memInfoFile="/proc/meminfo"
memInfo=`$cmd_cat $memInfoFile | $cmd_grep 'MemTotal\|MemFree\|Buffers\|Cached'`
echo $memInfo \
| $cmd_awk '{print "{ \"total\": " ($2/1024) ", \"used\": " ( ($2-($5+$8+$11))/1024 ) " }" }' \
| _print_parsed
}
# Swap memory info
swap() {
cmd_awk=`which awk`
cmd_free=`which free`
cmd_sed=`which sed`
# result=$($cmd_free -m \
# | $cmd_sed -e '1d' -e '2d' -e '3d' \
# | $cmd_awk 'BEGIN \
# {print "{"} \
# {if (NR > 1) print ","} \
# {printf("\n\t\"total\": %s, \n\t\"used\": %s", $2, $3)} \
# END{print "\n}"}')
result=$($cmd_free -m \
| $cmd_sed '/Swap:/!d' \
| $cmd_awk 'BEGIN \
{print "{"} \
{if (NR > 1) print ","} \
{printf("\n\t\"total\": %s, \n\t\"used\": %s", $2, $3)} \
END{print "\n}"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
##########################
# Network info functions #
##########################
# ARP cache table
#
# Based on Linux Dash codebase: https://github.com/afaqurk/linux-dash
arp_cache() {
cmd_awk=`which awk`
cmd_sed=`which sed`
if hash arp 2>/dev/null; then cmd_arp=`which arp`
else cmd_arp="ip neigh"
fi
result=$($cmd_arp | \
$cmd_awk 'BEGIN {print "["} NR>1 \
{if ( NF==6 ) {print "{ \"addr\": \"" $1 "\", " \
"\"hw_type\": \"" $2 "\", " \
"\"hw_addr\": \"" $3 "\", " \
"\"flags\": \"" $4 "\", " \
"\"mask\": \"" $5 "\" , " \
"\"iface\": \"" $6 "\" }, "} \
if ( NF==5 ) {print "{ \"addr\": \"" $1 "\", " \
"\"hw_type\": \"" $2 "\", " \
"\"hw_addr\": \"" $3 "\", " \
"\"flags\": \"" $4 "\", " \
"\"mask\": \"\", " \
"\"iface\": \"" $5 "\" }, "} \
if ( NF==4 ) {print "{ \"addr\": \"" $1 "\", " \
"\"hw_type\": \"" $2 "\", " \
"\"hw_addr\": \"" $3 "\", " \
"\"flags\": \"\", " \
"\"mask\": \"\", " \
"\"iface\": \"" $4 "\" }, "} \
if ( NF==3 ) {print "{ \"addr\": \"" $1 "\", " \
"\"hw_type\": \"\", " \
"\"hw_addr\": \"" $2 "\", " \
"\"flags\": \"\", " \
"\"mask\": \"\", " \
"\"iface\": \"" $3 "\" }, "} \
} \
END {print "]"}' \
| $cmd_sed 'N;$s/},/}/;P;D')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# IP addresses
#
# Based on Linux Dash codebase: https://github.com/afaqurk/linux-dash
ip_addr() {
cmd_awk=`which awk`
cmd_grep=`which grep`
cmd_ifconfig=`which ifconfig`
cmd_tr=`which tr`
cmd_dig=`which dig`
externalIp=`$cmd_dig +short myip.opendns.com @resolver1.opendns.com`
$cmd_ifconfig \
| $cmd_grep -B1 "inet addr" \
| $cmd_awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' \
| $cmd_awk -v exIp="$externalIp" -F: 'BEGIN {print "["} { print "{ \"interface\": \"" $1 "\", \"ip\": \"" $3 "\" },"} END {print "{ \"interface\": \"external\", \"ip\": \""exIp"\" } ]"}' \
| $cmd_tr -d '\r\n'
}
# Network bandwith
net_band() {
cmd_awk=`which awk`
cmd_cat=`which cat`
cmd_sed=`which sed`
result=$($cmd_cat /proc/net/dev \
| $cmd_awk 'BEGIN\
{print "["} NR>2 \
{print "{ \"interface\": \"" $1 "\"," " \"tx\": " $2 "," " \"rx\": " $10 " }," } \
END\
{print "]"}' \
| $cmd_sed 'N;$s/,\n/\n/;P;D')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Network connections
net_conn() {
cmd_awk=`which awk`
cmd_sed=`which sed`
cmd_sort=`which sort`
cmd_ss=`which ss`
result=$($cmd_ss \
| $cmd_sed -e '1d;/u_str/d' \
| $cmd_sort -k1 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"netid\": \"%s\", \
\n\t\t\"state\": \"%s\", \
\n\t\t\"rcvq\": %s, \
\n\t\t\"sendq\": %s, \
\n\t\t\"local\": \"%s\", \
\n\t\t\"peer\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6)} \
END{print "\n]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Download transfer rate
#
# Based on Linux Dash codebase: https://github.com/afaqurk/linux-dash
net_download_transfer_rate() {
files=(/sys/class/net/*)
pos=$(( ${#files[*]} - 1 ))
last=${files[$pos]}
json_output="{"
for interface in "${files[@]}"
do
basename=$(basename "$interface")
# find the number of bytes transfered for this interface
in1=$(cat /sys/class/net/"$basename"/statistics/rx_bytes)
# wait a second
sleep 1
# check same interface again
in2=$(cat /sys/class/net/"$basename"/statistics/rx_bytes)
# get the difference (transfer rate)
in_bytes=$((in2 - in1))
# convert transfer rate to KB
in_kbytes=$((in_bytes / 1024))
# convert transfer rate to KB
json_output="$json_output \"$basename\": $in_kbytes"
# if it is not the last line
if [[ ! $interface == $last ]]
then
# add a comma to the line (JSON formatting)
json_output="$json_output,"
fi
done
# close the JSON object & print to screen
echo "$json_output}" | _print_parsed
}
# Upload transfer rate
#
# Based on Linux Dash codebase: https://github.com/afaqurk/linux-dash
net_upload_transfer_rate() {
files=(/sys/class/net/*)
pos=$(( ${#files[*]} - 1 ))
last=${files[$pos]}
json_output="{"
for interface in "${files[@]}"
do
basename=$(basename "$interface")
# find the number of bytes transfered for this interface
out1=$(cat /sys/class/net/"$basename"/statistics/tx_bytes)
# wait a second
sleep 1
# check same interface again
out2=$(cat /sys/class/net/"$basename"/statistics/tx_bytes)
# get the difference (transfer rate)
out_bytes=$((out2 - out1))
# convert transfer rate to KB
out_kbytes=$((out_bytes / 1024))
# convert transfer rate to KB
json_output="$json_output \"$basename\": $out_kbytes"
# if it is not the last line
if [[ ! $interface == $last ]]
then
# add a comma to the line (JSON formatting)
json_output="$json_output,"
fi
done
# close the JSON object & print to screen
echo "$json_output}" | _print_parsed
}
# Online users info
users_online() {
cmd_awk=`which awk`
cmd_netstat=`which netstat`
cmd_sed=`which sed`
cmd_smbstatus=`which smbstatus`
cmd_sort=`which sort`
cmd_w=`which w`
result=$($cmd_w \
| $cmd_sed -e '1,2d' \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"user\": \"%s\", \
\n\t\t\"tty\": \"%s\", \
\n\t\t\"from\": \"%s\", \
\n\t\t\"login\": \"%s\", \
\n\t\t\"idle\": \"%s\", \
\n\t\t\"jcpu\": \"%s\", \
\n\t\t\"pcpu\": \"%s\", \
\n\t\t\"what\": \"%s %s %s\"\n\t}", \
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)} \
END \
{print "\n]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# IP routing table
ip_route() {
if hash netstat 2>/dev/null; then ip_route_netstat
else ip_route_ip
fi
}
# IP routing table (ip)
ip_route_ip() {
cmd_awk=`which awk`
cmd_ip=`which ip`
cmd_sed=`which sed`
result=$($cmd_ip r \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{\"route\": \""} \
{print } \
{print "\"\n\t}"} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# IP routing table (netstat)
ip_route_netstat() {
cmd_awk=`which awk`
cmd_netstat=`which netstat`
cmd_sed=`which sed`
result=$($cmd_netstat -r \
| $cmd_sed -e '1,2d' \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"destination\": \"%s\", \
\n\t\t\"gateway\": \"%s\", \
\n\t\t\"genmask\": \"%s\", \
\n\t\t\"flags\": \"%s\", \
\n\t\t\"mss\": %s, \
\n\t\t\"window\": %s, \
\n\t\t\"irtt\": %s, \
\n\t\t\"iface\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7, $8)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Multicast groups
net_multicast() {
cmd_awk=`which awk`
cmd_netstat=`which netstat`
cmd_sed=`which sed`
cmd_sort=`which sort`
result=$($cmd_netstat -g \
| $cmd_sed -e '1,3d' \
| $cmd_sort -k1 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"interface\": \"%s\", \
\n\t\t\"refcnt\": %s, \
\n\t\t\"group\": \"%s\"\n\t}", $1, $2, $3)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Listening sockets
listen_socks() {
if hash netstat 2>/dev/null; then listen_socks_netstat
else listen_socks_ss
fi
}
# Listening sockets (ss)
listen_socks_ss() {
cmd_awk=`which awk`
cmd_ss=`which ss`
cmd_sed=`which sed`
result=$($cmd_ss -ltn \
| $cmd_sed -e '1d' \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"state\": \"%s\", \
\n\t\t\"recv-q\": %s, \
\n\t\t\"send-q\": %s, \
\n\t\t\"local address:port\": \"%s\", \
\n\t\t\"peer addr:port\": \"%s\"\n\t}", $1, $2, $3, $4, $5)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Listening sockets (netstat)
listen_socks_netstat() {
cmd_awk=`which awk`
cmd_netstat=`which netstat`
cmd_sed=`which sed`
result=$($cmd_netstat -l \
| $cmd_sed -n '/tcp/p;/udp/p;/raw/p' \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"proto\": \"%s\", \
\n\t\t\"recv-q\": %s, \
\n\t\t\"send-q\": %s, \
\n\t\t\"localaddr\": \"%s\", \
\n\t\t\"foreignaddr\": \"%s\", \
\n\t\t\"state\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Active unix domain sockets
active_unix_socks() {
if hash netstat 2>/dev/null; then active_unix_socks_netstat
else active_unix_socks_ss
fi
}
# Active unix domain sockets (ss)
active_unix_socks_ss() {
cmd_awk=`which awk`
cmd_ss=`which ss`
cmd_sed=`which sed`
cmd_sort=`which sort`
result=$($cmd_ss -x \
| $cmd_sed -e '1d' \
| $cmd_sort -k6 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"netid\": \"%s\", \
\n\t\t\"state\": \"%s\", \
\n\t\t\"recv-q\": %s, \
\n\t\t\"send-q\": %s, \
\n\t\t\"local address:port\": \"%s:%s\", \
\n\t\t\"peer address:port\": \"%s:%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7, $8)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Active unix domain sockets (netstat)
active_unix_socks_netstat() {
cmd_awk=`which awk`
cmd_netstat=`which netstat`
cmd_sed=`which sed`
cmd_sort=`which sort`
result=$($cmd_netstat -l \
| $cmd_sed -n '/unix/p' \
| $cmd_sort -k6 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"proto\": \"%s\", \
\n\t\t\"refcnt\": %s, \
\n\t\t\"flags\": \"%s%s%s\", \
\n\t\t\"type\": \"%s\", \
\n\t\t\"state\": \"%s\", \
\n\t\t\"i-node\": \"%s\", \
\n\t\t\"path\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7, $8, $9)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# Check is application installed or not
check_app() {
cmd_awk=`which awk`
result=$(whereis -S /opt -f $1 \
| $cmd_awk -F: '{if(length($2)==0) { installed="false"; } else { installed="true"; } \
print \
"{ \
\"binary\": \""$1"\", \
\"location\": \""$2"\", \
\"installed\": "installed" \
}"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# SMB processes
smb_proc() {
cmd_awk=`which awk`
cmd_sed=`which sed`
cmd_smbstatus=`which smbstatus`
cmd_sort=`which sort`
result=$(sudo $cmd_smbstatus -pf \
| $cmd_sed -e '1,4d' \
| $cmd_sort -k1 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"pid\": %s, \
\n\t\t\"username\": \"%s\", \
\n\t\t\"group\": \"%s\", \
\n\t\t\"machine\": \"%s\", \
\n\t\t\"protocol ver\": \"%s\", \
\n\t\t\"encryption\": \"%s\", \
\n\t\t\"signing\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# SMB shares
smb_shares() {
cmd_awk=`which awk`
cmd_sed=`which sed`
cmd_smbstatus=`which smbstatus`
cmd_sort=`which sort`
result=$(sudo $cmd_smbstatus -Sf \
| $cmd_sed -e '1,3d;/^\s*$/d' \
| $cmd_sort -k1 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{print "\t{"} \
{printf("\t\t\"service\": \"%s\", \
\n\t\t\"pid\": %s, \
\n\t\t\"machine\": \"%s\", \
\n\t\t\"connected at\": \"%s %s %s %s %s %s\", \
\n\t\t\"encryption\": \"%s\", \
\n\t\t\"signing\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
# SMB locked files
smb_locks() {
cmd_awk=`which awk`
cmd_sed=`which sed`
cmd_smbstatus=`which smbstatus`
cmd_sort=`which sort`
result=$(sudo $cmd_smbstatus -Lf \
| $cmd_sed -e '1,3d;/^\s*$/d' \
| $cmd_sort -k1 \
| $cmd_awk 'BEGIN \
{print "["} \
{if (NR > 1) print ","} \
{fname = ""} \
{ftime = ""} \
{for (i = 8; i < NF - 4; i++) fname = fname" "$i} \
{for (i = NF - 4; i < NF; i++) ftime = ftime" "$i} \
{print "\t{"} \
{printf("\t\t\"pid\": %s, \
\n\t\t\"uid\": %s, \
\n\t\t\"deny mode\": \"%s\", \
\n\t\t\"access\": \"%s\", \
\n\t\t\"r/w\": \"%s\", \
\n\t\t\"oplock\": \"%s\", \
\n\t\t\"share path\": \"%s\", \
\n\t\t\"name\": \"%s\", \
\n\t\t\"time\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7, fname, ftime)} \
END \
{print "\n\t]"}')
if [ -z "$result" ]; then echo {}
else echo $result | _print_parsed
fi
}
function_name="$1"
parameter="$2"
${function_name} ${parameter}

View File

@@ -0,0 +1,15 @@
<?php
header('Content-Type: application/json');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
require_once('../settings.php');
if (W_TRANSMISSION_ENABLED) {
echo shell_exec('./json_transmission.sh ' . W_TRANSMISSION_HOST . ' '
. W_TRANSMISSION_NAME . ' '
. W_TRANSMISSION_PASS);
} else {
echo '[]';
}

View File

@@ -0,0 +1,2 @@
#! /bin/bash
transmission-remote $1 -n $2:$3 -l | sed '$d' | sed -e '1d' | awk '@include "trim.awk";{{printf("%s;%s;%s;%s;%s;%s;%s;%s;%s;", $1, $2, $3, $4, $5, $6, $7, $8, $9)} {$1=$2=$3=$4=$5=$6=$7=$8=$9=""; print trim($0)}}' | awk -F ";" 'BEGIN{print "["}{if (NR > 1) print ","}{print "\t{"}{printf("\t\t\"ID\": \"%s\",\n\t\t\"Done\": \"%s\",\n\t\t\"Have\": \"%s %s\",\n\t\t\"ETA\": \"%s\",\n\t\t\"Up\": \"%s\",\n\t\t\"Down\": \"%s\",\n\t\t\"Ratio\": \"%s\",\n\t\t\"Status\": \"%s\",\n\t\t\"Name\": \"%s\"\n\t}", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)}END{print "\n]"}'

View File

@@ -0,0 +1,18 @@
#!/bin/bash
cmd_awk=`which awk`
cmd_grep=`which grep`
cmd_hddtemp=`which hddtemp`
cmd_smartctl=`which smartctl`
drvtemp=$(sudo $cmd_hddtemp $1)
hdd=$(echo "$drvtemp" | $cmd_awk -F: '{print $1}')
model=$(echo "$drvtemp" | $cmd_awk -F: '{print $2}')
result=$(sudo $cmd_smartctl -a $1 | $cmd_grep "Current Drive Temperature" | $cmd_awk '{print $4"°"$5}')
if [ -z "$result" ];
then
result=$(echo "$drvtemp" | $cmd_awk -F: '{print $3}')
fi
echo $hdd: $model: $result

3
system/scripts/trim.awk Normal file
View File

@@ -0,0 +1,3 @@
function ltrim(s) { sub(/^[ \t\r\n]+/, "", s); return s }
function rtrim(s) { sub(/[ \t\r\n]+$/, "", s); return s }
function trim(s) { return rtrim(ltrim(s)); }

43
system/settings.php Normal file
View File

@@ -0,0 +1,43 @@
<?php
/* ----- Begin of settings block ----- */
/* Security check constants */
const FILE_OWNER = 'wwwrun';
const FILE_GROUP = 'www';
/* Shutdown and reboot options */
const SHUTDOWN_ENABLED = false;
const REBOOT_ENABLED = false;
/* Control panel directory relative to server root */
const CP_ROOT_REL = '';
/* Wrere downloadable file must be stored */
const FILE_DOWNLOAD_DIR = '';
/* Transmission widget */
const W_TRANSMISSION_ENABLED = false;
const W_TRANSMISSION_HOST = '127.0.0.1';
const W_TRANSMISSION_NAME = 'transmission';
const W_TRANSMISSION_PASS = 'transmission';
/* ----- End of settings block ----- */
/* Don't change lines below */
$cp_root = filter_input(INPUT_SERVER, 'DOCUMENT_ROOT') . CP_ROOT_REL;
$settings = array('shutdown_enabled' => SHUTDOWN_ENABLED,
'reboot_enabled' => REBOOT_ENABLED,
'w_transmisson_enabled' => W_TRANSMISSION_ENABLED);
/* Configure autoloader */
require_once($cp_root . '/system/classes/CAI/CAICP/src/PSR4Autoloader.php');
$autoloader = new \CAI\CAICP\PSR4Autoloader;
$autoloader->register();
$autoloader->addNamespace('CAI\CAICP', $cp_root . '/system/classes/CAI/CAICP/src');
//$Autoloader->addNamespace('CAI\CAICP', $cp_root . '/system/classes/CAI/CAICP/tests');
/* Create system objects */
$user_cfg = new \CAI\CAICP\Settings(CP_ROOT_REL);
$lang = new \CAI\CAICP\Localization(CP_ROOT_REL, $user_cfg->get());

View File

@@ -0,0 +1,79 @@
/* Common classes block */
.hidden {
/* visibility: hidden; */
display: none;
}
.full_width {
width: 100%;
}
.bold {
font-weight: bold;
}
/* Elements block */
html, body {
margin: 0;
padding: 0;
min-width: 600px;
height: 100%;
width: 100%;
/* background: url(../gfx/bg.jpg) repeat fixed; */
font-family: Arial, sans-serif;
}
hr {
margin: 0;
padding: 0;
border: 0;
height: 1px;
background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.25), rgba(0,0,0,0));
background-image: -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.25), rgba(0,0,0,0));
background-image: -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.25), rgba(0,0,0,0));
background-image: -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.25), rgba(0,0,0,0));
background: linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.25), rgba(0,0,0,0));
}
fieldset {
border: solid 1px #ccc;
margin: 5px 0;
}
form {
margin: 5px;
transition: all 0.5s ease-out 0.1s;
}
/* Language selector */
input, select {border: solid 1px #999;}
.select_lang {
border : 0;
background-color : transparent;
}
.select_lang option {
color: #000;
background-color: rgba(255, 255, 255, 0.85);
}
/*
select#gender option[value="male"] { background-image:url(male.png); }
select#gender option[value="female"] { background-image:url(female.png); }
select#gender option[value="others"] { background-image:url(others.png); }
*/
.input_ru {
background-image: url('../gfx/flags/russian-16x16.png');
background-repeat: no-repeat;
background-attachment: scroll;
background-position: 2px center;
padding-left: 21px;
margin-left: 1px;
}
.input_en {
background-image: url('../gfx/flags/uk-16x16.png');
background-repeat: no-repeat;
background-attachment: scroll;
background-position: 2px center;
padding-left: 21px;
margin-left: 1px;
}
#in_submit {margin-top: 5px};

View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html>
<head>
<title>CAI CP Settings</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/styles.css" type="text/css">
</head>
<body>
<div>
<form id="frm_submit" method="get" action="../../../action/" class="hidden">
<input type="hidden" name="do" value="setup">
<fieldset id="fs_general">
<legend id="fsl_general"></legend>
<table>
<tr>
<td>
<span id="lbl_default_language">[lang_default_language]: </span>
</td>
<td>
<select id="default_language" name="default_language" class="select_lang"></select>
</td>
</tr>
<tr>
<td>
<label for="dim_on_create" id="lbl_dim_on_create">[lang_dim_on_create]: </label>
</td>
<td>
<input type="checkbox" value="1" name="dim_on_create" id="dim_on_create">
</td>
</tr>
<tr>
<td>
<label for="check_files_rights" id="lbl_check_files_rights">[lang_check_files_rights]: </label>
</td>
<td>
<input type="checkbox" value="1" name="chk_files_rights" id="chk_files_rights">
</td>
</tr>
</table>
</fieldset>
<fieldset id="fs_monitoring">
<legend id="fsl_monitoring"></legend>
<table>
<tr>
<td>
<span id="lbl_max_hdd_temp">[lang_max_hdd_temp]: </span>
</td>
<td>
<input type="number" id="max_hdd_temp" name="max_hdd_temp" min="30" max="100">
</td>
</tr>
<tr>
<td>
<span id="lbl_check_hdd_temp_interval">[lang_check_temp_int]: </span>
</td>
<td>
<input type="number" id="chk_temp_interval" name="chk_temp_interval" min="0" max="86400"> <span id="lbl_temp_secs">[lang_secs]</span>
</td>
</tr>
<tr>
<td>
<span id="lbl_check_smart_interval">[lang_check_smart_int]: </span>
</td>
<td>
<input type="number" id="chk_smart_interval" name="chk_smart_interval" min="0" max="86400"> <span id="lbl_smart_secs">[lang_secs]</span>
</td>
</tr>
<tr>
<td>
<span id="lbl_check_users_online_interval">[lang_check_users_online_int]: </span>
</td>
<td>
<input type="number" id="chk_users_online_interval" name="chk_users_online_interval" min="0" max="86400"> <span id="lbl_users_online_secs">[lang_secs]</span>
</td>
</tr>
</table>
</fieldset>
<fieldset id="fs_apps">
<legend id="fsl_apps"></legend>
<table id="tbl_apps" class="full_width">
<tr class="bold">
<td>
<span id="lbl_enabled">[lang_enabled]</span>
</td>
<td>
<span id="lbl_app_name">[lang_app_name]</span>
</td>
<td>
<span id="lbl_app_ver">[lang_app_ver]</span>
</td>
<td>
<span id="lbl_app_author">[lang_app_author]: </span>
</td>
</tr>
</table>
</fieldset>
<input id="in_submit" type="submit" value="[lang_save]">
</form>
</div>
<script src="js/settings.js"></script>
</body>
</html>

View File

@@ -0,0 +1,278 @@
// MIT License:
//
// Copyright (c) 2016-2017, Alexander I. Chebykin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
/**
* CAI CP v.0.9
*
* @module : Configuration subsystem
* @author : Alexander I. Chebykin <alex.chebykin@gmail.com>
* @copyright : Copyright (c) 2016-2017 Alexander I. Chebykin
* @version : 0.9
* @build date : 2017-07-23
* @license : MIT
* @link : https://github.com/CAI79/CAI-CP
******************************************************************/
(function () {
'use strict';
/**
* Return GET parameter
*
* @param {string} key Key name
*
* returns {string}
*/
function $_GET(key) {
var s = window.location.search;
s = s.match(new RegExp(key + '=([^&=]+)'));
return s ? s[1] : false;
}
/**
* SetupSystem constructor
*
* @returns {undefined}
*/
function SetupSystem() {
this.locale = 'en';
this.langs = [];
this.tranlation = [];
}
/**
*
* @param {int} init_level Initialization level: 1 - configure language
* 2 - do localization
* 3 - load languages list
*
* @returns {undefined}
*/
SetupSystem.prototype.init = function (init_level) {
var setup_instance = this,
request = new XMLHttpRequest(),
res_data;
switch (init_level) {
case 1: // Configure language
if ($_GET('lang') !== '') {
this.locale = $_GET('lang');
} else {
request.open('GET', '../../../json/settings.json');
request.send();
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
res_data = JSON.parse(this.responseText);
setup_instance.locale = res_data.lang;
}
}
};
}
this.init(2);
break;
case 2: // Do localization
request.open('GET', '../../../json/locale/' + this.locale + '.json');
request.send();
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
res_data = JSON.parse(this.responseText);
setup_instance.tranlation = res_data;
document.getElementById('lbl_dim_on_create').textContent = res_data.dim_on_create;
document.getElementById('lbl_default_language').textContent = res_data.default_language;
document.getElementById('lbl_check_files_rights').textContent = res_data.check_files_rights;
document.getElementById('lbl_check_hdd_temp_interval').textContent = res_data.check_hdd_temp_int;
document.getElementById('lbl_check_users_online_interval').textContent = res_data.check_users_online_int;
document.getElementById('lbl_max_hdd_temp').textContent = res_data.max_hdd_temp;
document.getElementById('lbl_check_smart_interval').textContent = res_data.check_smart_int;
document.getElementById('lbl_temp_secs').textContent = res_data.secs;
document.getElementById('lbl_smart_secs').textContent = res_data.secs;
document.getElementById('lbl_users_online_secs').textContent = res_data.secs;
document.getElementById('fsl_general').textContent = res_data.general_settings;
document.getElementById('fsl_monitoring').textContent = res_data.monitoring;
document.getElementById('fsl_apps').textContent = res_data.applications;
document.getElementById('lbl_enabled').textContent = res_data.enbld;
document.getElementById('lbl_app_name').textContent = res_data.application;
document.getElementById('lbl_app_ver').textContent = res_data.version;
document.getElementById('lbl_app_author').textContent = res_data.author;
document.getElementById('in_submit').value = res_data.save;
document.getElementById("frm_submit").classList.remove('hidden');
}
}
};
this.init(3);
break;
case 3: // Load languages list
request.open('GET', '../../../json/settings.json');
request.send();
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
var select_lang = document.getElementById('default_language');
res_data = JSON.parse(this.responseText);
document.getElementById('dim_on_create').checked = res_data.dim_on_create;
document.getElementById('chk_files_rights').checked = res_data.check_files_rights;
document.getElementById('chk_temp_interval').value = res_data.check_hdd_temp_interval;
document.getElementById('chk_smart_interval').value = res_data.check_smart_interval;
document.getElementById('chk_users_online_interval').value = res_data.check_users_online_interval;
document.getElementById('max_hdd_temp').value = res_data.max_hdd_temp;
setup_instance.langs = res_data.langs;
for (var language in res_data.langs) {
var opt_lang = document.createElement('option');
opt_lang.value = language;
opt_lang.appendChild(document.createTextNode(res_data.langs[language]));
if (res_data.lang === language) {
opt_lang.selected = true;
} else if (!$_GET('lang') && setup_instance.locale === language){
opt_lang.selected = true;
}
select_lang.appendChild(opt_lang);
}
}
}
};
this.init(4);
break;
case 4: // Load apps list
request.open('GET', '../../../apps/?do=get_apps');
request.send();
request.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
var apps_table = document.getElementById('tbl_apps'),
apps_tr,
apps_td,
apps_name,
apps_caption,
apps_check,
i = 0;
res_data = JSON.parse(this.responseText);
for (var app_info in res_data) {
apps_tr = document.createElement('tr');
apps_td = document.createElement('td');
apps_caption = document.createElement('input');
apps_caption.type = 'hidden';
apps_caption.name = 'app_caption[' + i + ']';
apps_caption.value = res_data[app_info].caption;
apps_td.appendChild(apps_caption);
apps_name = document.createElement('input');
apps_name.type = 'hidden';
apps_name.name = 'app_name[' + i + ']';
apps_name.value = app_info;
apps_td.appendChild(apps_name);
apps_check = document.createElement('input');
apps_check.type = 'checkbox';
apps_check.name = 'app_enabled[' + i + ']';
apps_check.value = '1';
apps_check.checked = res_data[app_info].enabled;
apps_td.appendChild(apps_check);
apps_tr.appendChild(apps_td);
apps_td = document.createElement('td');
apps_td.appendChild(document.createTextNode(res_data[app_info].caption));
apps_tr.appendChild(apps_td);
apps_td = document.createElement('td');
apps_td.appendChild(document.createTextNode(res_data[app_info].version));
apps_tr.appendChild(apps_td);
apps_td = document.createElement('td');
apps_td.appendChild(document.createTextNode(res_data[app_info].author));
apps_tr.appendChild(apps_td);
apps_table.appendChild(apps_tr);
i++;
}
}
}
};
}
};
document.addEventListener('DOMContentLoaded', function () {
'use strict';
/**
* Initialize setup object
*/
var setup = new SetupSystem();
setup.init(1);
document.getElementById('frm_submit').onsubmit = function () {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.responseText === 'true') {
alert(setup.tranlation.settings_saved);
window.top.location.reload(true);
} else {
alert(setup.tranlation.error);
}
};
if (this.method.toLowerCase() === 'post') {
xhr.open (this.method, this.action, true);
xhr.send (new FormData (this));
} else {
var element,
el_type,
file,
search = '';
for (var i = 0; i < this.elements.length; i++) {
element = this.elements[i];
if (!element.hasAttribute('name')) { continue; }
el_type = element.nodeName.toLowerCase() === 'input' ?
element.getAttribute('type').toLowerCase() : 'text';
if (el_type === 'file') {
for (file = 0; file < element.files.length;
search += '&' + escape(element.name) + '=' + escape(element.files[file++].name));
} else if ((el_type !== 'radio' && el_type !== 'checkbox') || element.checked) {
search += '&' + escape(element.name) + '=' + escape(element.value);
}
}
xhr.open('get', this.action.replace(/(?:\?.*)?$/, search.replace(/^&/, '?')), true);
xhr.send(null);
}
return false;
};
});
}());