diff --git a/css/index.css b/css/index.css index 9019721..87ed970 100644 --- a/css/index.css +++ b/css/index.css @@ -17,3 +17,54 @@ body { .signed { margin-top: 20px; } + +/* +https://bootsnipp.com/snippets/jvP6z +*/ +.mini-led-green, .mini-led-green-blink { + background-color: #80FF00; + box-shadow: #7D7B80 0 -1px 6px 1px, inset #460 0 -1px 8px, #80FF00 0 3px 11px; +} +.mini-led-red, .mini-led-red-blink { + background-color: #F00; + box-shadow: #7D7B80 0 -1px 6px 1px, inset #600 0 -1px 8px, #F00 0 3px 11px; +} +.mini-led-gray, +.mini-led-gray-blink, +.mini-led-red, +.mini-led-red-blink, +.mini-led-orange, +.mini-led-orange-blink, +.mini-led-green, +.mini-led-green-blink, +.mini-led-yellow, +.mini-led-yellow-blink, +.mini-led-blue, +.mini-led-blue-blink { + margin: 0 auto; + margin-top: 5px; + width: 12px; + height: 12px; + border-radius: 50%; +} + +#config-cards textarea { + font-family: Courier; +} + +#message-stage { + position: fixed; + bottom: 0; +} +#message-stage i.stauts-icon { + margin-right: 10px; +} + +#save-config-btn.get-attention a { + background-color: #f0ad4e; /* orange */ + color: white; +} +#save-config-btn.saved-success a { + background-color: #5cb85c; /* green */ + color: white; +} \ No newline at end of file diff --git a/include/grids.php b/include/grids.php index 68a1138..abd658d 100644 --- a/include/grids.php +++ b/include/grids.php @@ -45,9 +45,27 @@ // Creation of the LIMIT for build different pages $page = "LIMIT $offset, $limit"; + // ... filtering by the bootstrap table plugin + $filter = isset($_GET['filter']) ? json_decode($_GET['filter'],true) : []; // this is passed by the bootstrap table filter plugin (if a filter was chosen by the user): these are the concrete set filters with their value + $where = !empty($filter)?'WHERE TRUE':''; + $allowed_query_filters = ['user_id', 'log_trusted_ip','log_trusted_port','log_remote_ip','log_remote_port']; // these are valid filters that could be used (defined here for sql security reason) + $query_filters_existing = []; + foreach($filter as $unsanitized_filter_key => $unsanitized_filter_val) { + if(in_array($unsanitized_filter_key, $allowed_query_filters)) { // if this condition does not match: ignore it, because this parameter should not be passed + // if $unsanitized_filter_key is in array $allowed_query_filters its a valid key and can not be harmful, so it can be considered sanitized + $where .= " AND $unsanitized_filter_key = ?"; + $query_filters_existing[] = $unsanitized_filter_key; + } + } + // Select the logs - $req_string = "SELECT *, (SELECT COUNT(*) FROM log) AS nb FROM log ORDER BY log_id DESC $page"; + $req_string = "SELECT *, (SELECT COUNT(*) FROM log $where) AS nb FROM log $where ORDER BY log_id DESC $page"; $req = $bdd->prepare($req_string); + + // dynamically bind the params + foreach(array_merge($query_filters_existing,$query_filters_existing) as $i => $query_filter) // array_merge -> duplicated the array contents; this is needed because our where clause is bound two times (in subquery + the outer query) + $req->bindValue($i+1, $filter[$query_filter]); + $req->execute(); $list = array(); @@ -75,7 +93,6 @@ "log_received" => $received, "log_send" => $sent)); - } while ($data = $req->fetch()); } else { @@ -203,4 +220,36 @@ $req->execute(array($_POST['del_admin_id'])); } + // ---------------- UPDATE CONFIG ---------------- + else if(isset($_POST['update_config'])){ + + $pathinfo = pathinfo($_POST['config_file']); + + $config_full_uri = $_POST['config_file']; // the complete path to the file, including the file (name) its self and the fully qualified path + $config_full_path = $pathinfo['dirname']; // path to file (without filename its self) + $config_name = basename($_POST['config_file']); // config file name only (without path) + $config_parent_dir = basename($config_full_path); // name of the dir that contains the config file (without path) + + /* + * create backup for history + */ + if (!file_exists($dir="../$config_full_path/history")) + mkdir($dir, 0777, true); + $ts = time(); + copy("../$config_full_uri", "../$config_full_path/history/${ts}_${config_name}"); + + /* + * write config + */ + $conf_success = file_put_contents('../'.$_POST['config_file'], $_POST['config_content']); + + echo json_encode([ + 'debug' => [ + 'config_file' => $_POST['config_file'], + 'config_content' => $_POST['config_content'] + ], + 'config_success' => $conf_success !== false, + ]); + } + ?> diff --git a/include/html/grids.php b/include/html/grids.php index 5c4845f..ff3dd6e 100644 --- a/include/html/grids.php +++ b/include/html/grids.php @@ -1,9 +1,40 @@ + +

History

+
+ $file): ?> +
+
+

+ + + +

+
+
+
+
+
+ +
+
+ @@ -82,15 +114,70 @@ + + + + + + + diff --git a/index.php b/index.php index 8266dd8..457b46e 100644 --- a/index.php +++ b/index.php @@ -30,7 +30,7 @@ } $rootPath = realpath("./client-conf/$conf_dir"); - // Initialize archive object + // Initialize archive object ;;;; why doing this every time the user logs in, when the cert is static? $archive_base_name = "openvpn-$conf_dir"; $archive_name = "$archive_base_name.zip"; $archive_path = "./client-conf/$archive_name"; @@ -99,6 +99,7 @@ + @@ -193,7 +194,7 @@
- +

@@ -204,5 +205,8 @@ require(dirname(__FILE__) . '/include/html/grids.php'); } ?> +
+ +
diff --git a/js/grids.js b/js/grids.js index 637800e..217d162 100644 --- a/js/grids.js +++ b/js/grids.js @@ -1,6 +1,18 @@ $(function () { "use strict"; + // ------------------------- GENERIC STUFF ------------------------------ + window.printStatus = function(msg, alert_type='warning', bootstrap_icon='') { + $('#message-stage').empty() + .append( + $(document.createElement('div')) + .addClass('alert alert-'+alert_type) + .html(bootstrap_icon?'':'') + .append(msg) + .hide().fadeIn().delay(2000).fadeOut() + ); + } + // ------------------------- GLOBAL definitions ------------------------- var gridsUrl = 'include/grids.php'; @@ -21,6 +33,10 @@ $(function () { return ''; } + function LEDIndicatorFormatter(value, row, index) { + return '
'; + } + // ------------------------- USERS definitions ------------------------- var $userTable = $('#table-users'); var $modalUserAdd = $('#modal-user-add'); @@ -86,6 +102,27 @@ $(function () { } } + function updateConfig(config_file, config_content) { + $.ajax({ + url: gridsUrl, + data: { + update_config : true, + config_file: config_file, + config_content: config_content + }, + success : function(res){ + printStatus( + res.config_success?'Config Successfully updated!':'An error occured while trying to save the updated config.', + res.config_success?'success':'danger', + res.config_success?'ok':'warning-sign' + ); + }, + dataType : 'json', + method: 'POST', + error: onAjaxError + }); + } + // ES 2015 so be prudent if (typeof Object.assign == 'function') { var userDateEditable = Object.assign({ type: 'date', placement: 'bottom' }, userEditable); @@ -164,7 +201,11 @@ $(function () { { title: "Pass", field: "user_pass", editable: userEditable }, { title: "Mail", field: "user_mail", editable: userEditable }, { title: "Phone", field: "user_phone", editable: userEditable }, - { title: "Online", field: "user_online" }, + { + title: "Online", + field: "user_online", + formatter : LEDIndicatorFormatter + }, { title: "Enabled", field: "user_enable", @@ -253,18 +294,27 @@ $(function () { }, columns: [ { title: "Log ID", field: "log_id" }, - { title: "User ID", field: "user_id" }, - { title: "Trusted IP", field: "log_trusted_ip" }, - { title: "Trusted Port", field: "log_trusted_port" }, - { title: "Remote IP", field: "log_remote_ip" }, - { title: "Remote Port", field: "log_remote_port" }, + { title: "User ID", field: "user_id", filterControl : 'select' }, + { title: "Trusted IP", field: "log_trusted_ip", filterControl : 'select' }, + { title: "Trusted Port", field: "log_trusted_port", filterControl : 'select' }, + { title: "Remote IP", field: "log_remote_ip", filterControl : 'select' }, + { title: "Remote Port", field: "log_remote_port", filterControl : 'select' }, { title: "Start Time", field: "log_start_time" }, { title: "End Time", field: "log_end_time" }, { title: "Receveid", field: "log_received" }, { title: "Sent", field: "log_send" } ] }); -}); + + // watch the config textareas for changes an persist them if a change was made + $('textarea').keyup(function(){ + $('#save-config-btn').removeClass('saved-success hidden').addClass('get-attention'); + }).change(function(){ + updateConfig($(this).data('config-file'), $(this).val()); + $('#save-config-btn').removeClass('get-attention').addClass('saved-success'); + }); + +}); // doc ready end // -------------------- HACKS --------------------