initial code comit

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

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
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.

1
_config.yml Normal file
View File

@ -0,0 +1 @@
theme: jekyll-theme-slate

430
css/core.css Normal file
View File

@ -0,0 +1,430 @@
/* Common classes block */
.wide {width: 100%;}
.hidden {
/* visibility: hidden; */
display: none;
}
.div_clear {
clear: both;
height: 1px;
margin: 5px 0;
}
.div_maximized {
width: calc(100% - 10px) !important;
height: calc(100% - 90px) !important;
}
.div_maximized_content {
max-height: calc(100% - 30px) !important;
}
.loading_div {
background: url(../gfx/ico_loading.gif) no-repeat center center;
}
.slightly_visible {
opacity: 0.25;
}
th,
.table_header {
font-weight: bold;
}
.top_right_hint {
text-align: right;
font-weight: normal;
font-style: italic
}
.distro_logo {
max-height: 140px;
max-width: 380px;
}
/* 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;
}
header {
display: block;
position: fixed;
top: 0;
width: 100%;
color: #fff;
background-color: rgba(0, 0, 0, 0.85);
box-shadow: 0 0 10px rgba(0,0,0,0.5);
padding: 4px;
font-size: 14px;
font-weight: bold;
}
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));
}
/* Page block */
#app_header {min-width: 600px;}
#s_header {
position: absolute;
margin: 14px auto 0 55px;
top: 0;
font-family: Courier;
font-size: 24px;
font-weight: bold;
font-style: italic;
}
#page_content {
margin: 70px 10px 0 10px;
height: inherit;
text-align: center;
}
/* Attention block */
#div_attention {
position: absolute;
right: 100px;
top: 4px;
}
#div_attention img {width: 30px;}
#div_attention_content {
right: 0;
width: 400px;
}
#ul_attention {
display: inline-block;
margin: 2px;
padding: 0;
border-color: #fff;
}
#ul_attention li{
margin: 1px;
float: left;
position: relative;
list-style: none;
}
#ul_attention a {
font-weight: bold;
color: #fff;
text-decoration: none;
display: block;
padding: 8px 8px 6px 8px;
border: solid 1px transparent;
border-radius: 25px;
transition: all 0.5s ease-out 0.1s;
}
#ul_attention a:hover {
box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
}
#ul_attention .current a,
#ul_attention li:hover a {
background-color: #fff;
border: solid 1px #000;
}
#ul_attention li:hover > #div_attention_content {
visibility: visible;
opacity: 0.95;
}
#ul_attention #div_attention_content {
visibility: hidden;
opacity: 0;
position: absolute;
width: 400px;
min-height: 40px;
max-height: calc(100vh - 80px);
max-width: calc(100vw - 80px);
overflow: auto;
padding: 5px;
border: 1px solid #000;
background: #fff;
color: #000;
z-index: 1000;
margin-top: -1px;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
transition: all 0.5s ease-out 0.1s;
}
/* Navigation block */
#ul_menu {
display: inline-block;
margin: 2px;
padding: 0;
border-color: #fff;
}
#ul_menu li {
margin: 1px;
float: left;
position: relative;
list-style: none;
}
#ul_menu a {
font-weight: bold;
color: #fff;
text-decoration: none;
display: block;
padding: 8px 8px 6px 8px;
border: solid 1px transparent;
transition: all 0.5s ease-out 0.1s;
}
#ul_menu a:hover {
box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
}
#ul_menu .current a,
#ul_menu li:hover > a {
background-color: #fff;
border: solid 1px #000;
}
#ul_menu li:hover > #div_menu {
visibility: visible;
opacity: 0.95;
}
#ul_menu li img {
width: 25px;
-webkit-filter: invert(1);
filter: invert(1);
}
#ul_menu li:hover > a img {
-webkit-filter: invert(0) !important;
filter: invert(0) !important;
}
#ul_menu #div_menu {
visibility: hidden;
opacity: 0;
position: absolute;
min-width: 700px;
min-height: 100px;
max-height: calc(100vh - 80px);
max-width: calc(100vw - 80px);
overflow: auto;
padding: 5px;
border: 1px solid #000;
background: #fff;
color: #000;
z-index: 1000;
margin-top: -1px;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
transition: all 0.5s ease-out 0.1s;
}
#ul_menu #div_menu a {
color: #000;
text-decoration: none;
padding: 0;
}
.div_menu_block {
padding: 0;
overflow: hidden;
position: relative;
}
.div_menu_block_caption {
margin: 5px;
}
/* Menu item */
.div_m_item {
float: left;
min-height: 120px;
width: 100px;
margin: 5px;
padding: 5px;
text-align: center;
cursor: pointer;
}
.div_m_item:hover {
background-color: rgba(0, 0, 0, 0.25);
transition: all 0.5s ease-out 0.1s;
}
.div_m_item_footer {
text-align: center;
vertical-align: bottom;
}
.menu_icon {
height: 64px !important;
width: 64px !important;
border-width: 0;
-webkit-filter: invert(0) !important;
filter: invert(0) !important;
}
/* Widget div block */
.div_widget {
border: solid #888 1px;
border-radius: 5px 5px 0 0;
display: inline-block;
padding: 0;
margin: 5px;
vertical-align: top;
/* float: left; */
/* min-width: 900px; */
min-height: 100px;
width: 600px;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
background: rgba(255, 255, 255, 0.85);
transition: all 0.5s linear;
}
.div_widget_type_a {
border: solid #888 1px;
border-radius: 5px 5px 0 0;
display: inline-block;
padding: 0;
margin: 5px;
vertical-align: top;
/* float: left; */
/* min-width: 900px; */
min-height: 328px;
width: 400px;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
background: rgba(255, 255, 255, 0.85);
transition: all 0.5s linear;
}
.div_widget_type_b {
border: solid #888 1px;
border-radius: 5px 5px 0 0;
display: inline-block;
padding: 0;
margin: 5px;
vertical-align: top;
/* float: left; */
/* min-width: 900px; */
min-height: 330px;
width: 600px;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
background: rgba(255, 255, 255, 0.85);
transition: all 0.5s linear;
}
.div_widget_full_width {
border: solid #888 1px;
border-radius: 5px 5px 0 0;
display: inline-block;
padding: 0;
margin: 5px;
vertical-align: top;
/* float: left; */
/* min-width: 900px; */
min-height: 330px;
width: calc(100% - 10px);
box-shadow: 0 0 10px rgba(0,0,0,0.5);
background: rgba(255, 255, 255, 0.85);
transition: all 0.5s linear;
}
.div_w_head {
margin: 0;
padding: 5px;
font-weight: bold;
border-radius: 4px 4px 0 0;
color: #fff;
/* background-color: rgba(10, 110, 180, 0.5); */
background-color: rgba(0, 0, 0, 0.85);
box-shadow: inset 0 0 4px rgba(0,0,0,0.5);
}
.div_w_content_container {
overflow: auto;
max-height: 300px; /* 500 */
}
/* Info table block */
/*.tbl_info {float: left !important;} */
.tbl_info table {
border-spacing: 1px;
width: 100%;
}
.tbl_info th {
color: #fff;
background-color: #555;
font-weight: bold;
padding: 5px;
}
.tbl_info td {padding: 2px 5px;}
.tbl_info .even_line {background-color: #ccc;}
/* Canvas block */
.canvas_info {
width: 400px;
min-height: 209px;
background-color: #000;
}
.canvas_legend {
float: left;
font-size: 12px;
margin: 0 5px 5px 5px;
}
.app_widget {
display: inherit !important;
/* float: inherit !important; */
height: calc(100% - 100px);
width: calc(100% - 10px) !important;
}
.app_widget .div_w_content,
.app_widget .div_w_content_container {
height: calc(100% - 18px);
overflow: hidden !important;
max-height: inherit !important;
}
.app_widget iframe {
width: 100%;
height: 100%;
border: 0;
}
/* Language selector */
input, select {border: solid 1px #999;}
.select_lang {
/* margin-left: 0 !important;
border: solid 1px #999;
float: right; */
position : absolute;
top : 22px;
right : 20px;
padding : 0 5px 0 20px;
border : 0;
color : #fff;
background-color : transparent;
-webkit-appearance : none;
-moz-appearance : none;
appearance : none;
}
.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;
}

2
css/core.min.css vendored Normal file

File diff suppressed because one or more lines are too long

BIN
gfx/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
gfx/buttons/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
gfx/distros/apple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

BIN
gfx/distros/arch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
gfx/distros/bsd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
gfx/distros/debian.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
gfx/distros/fedora.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
gfx/distros/hires/apple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
gfx/distros/hires/arch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
gfx/distros/hires/bsd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
gfx/distros/linux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
gfx/distros/opensuse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
gfx/distros/ubuntu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
gfx/distros/unknown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

BIN
gfx/flags/russian-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

BIN
gfx/flags/uk-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

BIN
gfx/hires/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

BIN
gfx/icons/about.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
gfx/icons/attention.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
gfx/icons/help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
gfx/icons/hires/samba.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
gfx/icons/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
gfx/icons/network.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
gfx/icons/reboot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
gfx/icons/samba.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
gfx/icons/server.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
gfx/icons/settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
gfx/icons/shutdown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
gfx/icons/storage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
gfx/icons/sysinfo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
gfx/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

38
index.dev.html Normal file
View File

@ -0,0 +1,38 @@
<!doctype html>
<html>
<head>
<title>Control panel</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.8, user-scalable=yes, maximum-scale=1.0"/>
<link rel="stylesheet" href="css/core.css" type="text/css" />
</head>
<body>
<header id="app_header">
<nav>
<ul id="ul_menu">
<li><a href="#"><img alt="Menu" src="gfx/menu.png"></a>
<div id="div_menu">
</div>
</li>
</ul>
</nav>
<div id="s_header">Loading...</div>
<div id="div_attention" class="hidden">
<ul id="ul_attention">
<li><a href="#"><img alt="Attention" src="gfx/icons/attention.png"></a>
<div id="div_attention_content"></div>
</li>
</ul>
</div>
</header>
<div id="page_content">
<noscript class="no_script_message">
<img src="gfx/flags/russian-16x16.png" alt="Русский"> Панель управления не работает с отключенным JavaScript.
<hr>
<img src="gfx/flags/uk-16x16.png" alt="English"> Control panel can't operate with disabled JavaScript.
</noscript>
</div>
<script src="js/smoothie.js"></script>
<script src="js/core.js"></script>
</body>
</html>

2
index.html Normal file
View File

@ -0,0 +1,2 @@
<!doctype html><html><head><title>Control panel</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.8, user-scalable=yes, maximum-scale=1.0"/><link rel="stylesheet" href="css/core.css" type="text/css"/></head><body><header id="app_header"><nav><ul id="ul_menu"><li><a href="#"><img alt="Menu" src="gfx/menu.png"></a><div id="div_menu"></div></li></ul></nav><div id="s_header">Loading...</div><div id="div_attention" class="hidden"><ul id="ul_attention"><li><a href="#"><img alt="Attention" src="gfx/icons/attention.png"></a><div id="div_attention_content"></div></li></ul></div></header><div id="page_content"><noscript class="no_script_message"><img src="gfx/flags/russian-16x16.png" alt="Русский"> Панель управления не работает с отключенным JavaScript. <hr><img src="gfx/flags/uk-16x16.png" alt="English"> Control panel can't operate with disabled JavaScript. </noscript></div><script src="js/smoothie.js"></script><script src="js/core.js"></script></body></html>

2276
js/core.js Normal file

File diff suppressed because it is too large Load Diff

1047
js/smoothie.js Normal file

File diff suppressed because it is too large Load Diff

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>

Some files were not shown because too many files have changed in this diff Show More