Refactor and enforce Content-Security-Policy

This commit is contained in:
Skylar Ittner 2017-11-13 16:17:14 -07:00
parent 6d17b400de
commit 79cb1a8f25
14 changed files with 232 additions and 55 deletions

View File

@ -74,7 +74,7 @@ if (!is_empty($_GET['page'])) {
}
?>
<a class="navbar-brand" href="app.php">
<img style="height: 35px; padding-bottom: 12px; padding-left: 5px;" src="<?php echo $src; ?>" />
<img src="<?php echo $src; ?>" />
</a>
<?php
}
@ -122,7 +122,7 @@ if (!is_empty($_GET['page'])) {
<?php
if (MENU_BAR_STYLE == "fixed") {
?>
<div style="height: 75px;"></div>
<div class="pad-75px"></div>
<?php
}
?>

View File

@ -54,11 +54,11 @@ if (count($messages) > 0) {
<div class="col-xs-12 col-sm-6 col-md-6">
<i class="fa fa-user fa-fw"></i> <span data-toggle="tooltip" title="<?php lang2("from user", ["user" => $usercache[$msg['from']]['username']]) ?>"><?php echo $usercache[$msg['from']]['name']; ?></span> &nbsp;<i class="fa fa-caret-right fa-fw"></i> <span data-toggle="tooltip" title="<?php lang2("to user", ["user" => $to['username']]) ?>"><?php echo $to['name']; ?></span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6" style="text-align: right;">
<div class="col-xs-12 col-sm-6 col-md-6 text-right">
<i class='fa fa-clock-o'></i> <?php echo date("F j, Y, g:i a", strtotime($msg['date'])) ?>
<form style="display: inline-block; margin-left: 5px;"
action="action.php" method="GET"
onsubmit="$('#delmsgbtn<?php echo $msg['id']; ?>').prop('disabled', true);setTimeout(refreshMsgs, 100);">
<form class="msgdelform"
data-msgid="<?php echo $msg['id']; ?>"
action="action.php" method="GET">
<input type="hidden" name="msgid" value="<?php echo $msg['id']; ?>" />
<input type="hidden" name="action" value="delmsg" />
<button type="submit" id="delmsgbtn<?php echo $msg['id']; ?>" class="btn btn-sm btn-danger" data-toggle="tooltip" data-placement="auto left" title="<?php lang("delete message") ?>"><i class="fa fa-trash"></i></button>

View File

@ -115,12 +115,16 @@ if (count($tasks) > 0) {
</div>
<div class='col-xs-12 col-sm-4 col-md-4'>
<div class='pull-right'>
<form action='app.php?page=edittask' method='GET' class='form-inline' style='display: inline-block;'>
<form action='app.php?page=edittask' method='GET' class='form-inline inblock'>
<input type='hidden' name='page' value='edittask' />
<input type='hidden' name='taskid' value='<?php echo $task['taskid'] ?>' />
<button type='submit' class='btn btn-sm btn-primary' data-toggle="tooltip" data-placement="auto left" title="<?php lang("edit task") ?>"><i class='fa fa-pencil'></i></button>
</form>
<form action='action.php' onsubmit='$("#deltaskbtn<?php echo $task['taskid'] ?>").prop("disabled", true);' method='POST' class='form-inline' style='display: inline-block; padding-left: 5px;'>
<form
action='action.php'
method='POST'
data-taskid="<?php echo $task['taskid'] ?>"
class='form-inline inblock padleft-5px deltaskform'>
<input type='hidden' name='taskid' value='<?php echo $task['taskid'] ?>' />
<input type='hidden' name='action' value='deltask' />
<?php
@ -146,7 +150,7 @@ if (count($tasks) > 0) {
if (isset($_GET['alone']) || (isset($pageid) && $pageid != "home")) {
echo "<div class=\"col-xs-12 col-sm-6 col-md-4 col-sm-offset-3 col-md-offset-4\">";
} else {
echo "<div style=\"height: 52px;\"></div>";
echo "<div class=\"height-52px></div>";
}
echo "<div class='alert alert-info'><i class='fa fa-info-circle'></i> " . lang("no tasks", false) . "</div>";
if (isset($_GET['alone']) || (isset($pageid) && $pageid != "home")) {

View File

@ -73,7 +73,12 @@ if (count($tasks) > 0) {
<?php
if ($task['statusid'] == 0) {
?>
<form action='action.php' method='POST' onsubmit='$("#starttaskbtn<?php echo $task['taskid'] ?>").prop("disabled", true); refreshTasksSoon();' class='form-inline' style='display: inline-block;'>
<form
action='action.php'
method='POST'
data-taskid="<?php echo $task['taskid'] ?>"
data-action="start"
class='form-inline inblock task-btn'>
<input type='hidden' name='taskid' value='<?php echo $task['taskid'] ?>' />
<input type='hidden' name='action' value='start' />
<button type='submit' id='starttaskbtn<?php echo $task['taskid'] ?>' class='btn btn-primary'><i class='fa fa-fw fa-play'></i> <?php lang("start") ?></button>
@ -81,17 +86,32 @@ if (count($tasks) > 0) {
<?php
} else if ($task['statusid'] == 1) {
?>
<form action='action.php' method='POST' onsubmit='$("#finishtaskbtn<?php echo $task['taskid'] ?>").prop("disabled", true); refreshTasksSoon();' class='form-inline' style='display: inline-block; padding-left: 5px;'>
<form
action='action.php'
method='POST'
data-taskid="<?php echo $task['taskid'] ?>"
data-action="finish"
class='form-inline inblock task-btn padleft-5px'>
<input type='hidden' name='taskid' value='<?php echo $task['taskid'] ?>' />
<input type='hidden' name='action' value='finish' />
<button type='submit' id='finishtaskbtn<?php echo $task['taskid'] ?>' class='btn btn-success'><i class='fa fa-stop'></i> <?php lang("finish") ?></button>
</form>
<form action='action.php' method='POST' onsubmit='$("#pausetaskbtn<?php echo $task['taskid'] ?>").prop("disabled", true); refreshTasksSoon();' class='form-inline' style='display: inline-block; padding-left: 5px;'>
<form
action='action.php'
method='POST'
data-taskid="<?php echo $task['taskid'] ?>"
data-action="pause"
class='form-inline inblock task-btn padleft-5px'>
<input type='hidden' name='taskid' value='<?php echo $task['taskid'] ?>' />
<input type='hidden' name='action' value='pause' />
<button type='submit' id='pausetaskbtn<?php echo $task['taskid'] ?>' class='btn btn-warning'><i class='fa fa-pause'></i> <?php lang("pause") ?></button>
</form>
<form action='action.php' method='POST' onsubmit='$("#problemtaskbtn<?php echo $task['taskid'] ?>").prop("disabled", true); refreshTasksSoon();' class='form-inline' style='display: inline-block; padding-left: 5px;'>
<form
action='action.php'
method='POST'
data-taskid="<?php echo $task['taskid'] ?>"
data-action="problem"
class='form-inline inblock task-btn padleft-5px'>
<input type='hidden' name='taskid' value='<?php echo $task['taskid'] ?>' />
<input type='hidden' name='action' value='problem' />
<button type='submit' id='problemtaskbtn<?php echo $task['taskid'] ?>' class='btn btn-danger'><i class='fa fa-exclamation'></i> <?php lang("problem") ?></button>
@ -99,7 +119,12 @@ if (count($tasks) > 0) {
<?php
} else if ($task['statusid'] == 3 || $task['statusid'] == 4) {
?>
<form action='action.php' method='POST' onsubmit='$("#resumetaskbtn<?php echo $task['taskid'] ?>").prop("disabled", true); refreshTasksSoon();' class='form-inline' style='display: inline-block;'>
<form
action='action.php'
method='POST'
data-taskid="<?php echo $task['taskid'] ?>"
data-action="resume"
class='form-inline inblock task-btn'>
<input type='hidden' name='taskid' value='<?php echo $task['taskid'] ?>' />
<input type='hidden' name='action' value='resume' />
<button type='submit' id='resumetaskbtn<?php echo $task['taskid'] ?>' class='btn btn-primary'><i class='fa fa-play'></i> <?php lang("resume") ?></button>

View File

@ -90,6 +90,7 @@ switch ($VARS['action']) {
if (authenticate_user($VARS['username'], $VARS['password'], $autherror)) {
if (account_has_permission($VARS['username'], "TASKFLOOR")) {
doLoginUser($VARS['username'], $VARS['password']);
$_SESSION['mobile'] = true;
exit(json_encode(["status" => "OK"]));
} else {
exit(json_encode(["status" => "ERROR", "msg" => lang("no permission", false)]));

View File

@ -11,18 +11,25 @@ define("PAGES", [
],
"scripts" => [
"static/js/jquery.easy-autocomplete.min.js",
"static/js/messages.js"
"static/js/messages.js",
"static/js/tasks.js"
]
],
"mytasks" => [
"title" => "my tasks",
"navbar" => true,
"icon" => "th-list"
"icon" => "th-list",
"scripts" => [
"static/js/tasks.js"
]
],
"taskman" => [
"title" => "task manager",
"navbar" => true,
"icon" => "tasks"
"icon" => "tasks",
"scripts" => [
"static/js/taskman.js"
]
],
"messages" => [
"title" => "messages",

View File

@ -6,41 +6,26 @@ redirectifnotloggedin();
<h2 class="page-header">
<?php lang("messages") ?>
</h2>
<form action="action.php" method="POST" onsubmit="setTimeout(function () {
$('#msgsendbox').val('');
$('#msgtobox').val('');
refreshMsgs();
}, 100);" class="form-horizontal">
<form action="action.php" method="POST" class="form-horizontal" id="msgsendform">
<input type="hidden" name="action" value="sendmsg" />
<div class="form-group">
<div class="col-xs-12 col-sm-6" style="margin-bottom: 5px;">
<div class="col-xs-12 col-sm-6 mgn-btm-5px">
<input type="text" id="msgsendbox" name="msg" class="form-control" placeholder="<?php lang("send message") ?>" autocomplete="off" />
</div>
<div class="col-xs-9 col-sm-4" style="padding-right: 0px;">
<div class="col-xs-9 col-sm-4 padright-0px">
<input type="text" id="msgtobox" name="to" class="form-control" placeholder="<?php lang("to") ?>" autocomplete="off" />
</div>
<button id="msgsendbtn" style="border-top-left-radius: 0px; border-bottom-left-radius: 0px; margin-left: 0px;" class="btn btn-primary col-xs-3 col-sm-2" type="submit"><i class="fa fa-paper-plane"></i> <?php lang("send") ?></button>
<button id="msgsendbtn" class="btn btn-primary col-xs-3 col-sm-2" type="submit"><i class="fa fa-paper-plane"></i> <?php lang("send") ?></button>
</div>
</form>
<div style="<?php
<div<?php
if ($pageid != "messages") {
echo "max-height: 600px; overflow-y: auto; padding: 5px;";
echo ' class="home-list-container"';
}
?>">
?>>
<div id="messagedispdiv">
<?php
include __DIR__ . '/../lib/getmsgs.php';
?>
</div>
<script>
function refreshMsgs() {
$.get('lib/getmsgs.php', function (data) {
$('#messagedispdiv').html(data);
setupTooltips();
});
}
setInterval(function () {
refreshMsgs();
}, 10 * 1000);
</script>
</div>

View File

@ -4,15 +4,17 @@ require_once __DIR__ . '/../required.php';
redirectifnotloggedin();
?>
<h2 class="page-header"><?php lang("my tasks") ?></h2>
<div id="tasksdispdiv" style="<?php if ($pageid != "mytasks") {
echo "max-height: 600px; overflow-y: auto; padding: 5px;";
} ?>" class="row">
<div id="tasksdispdiv" class="row<?php
if ($pageid != "mytasks") {
echo ' home-list-container"';
}
?>">
<?php
include __DIR__ . '/../lib/gettasks.php';
?>
</div>
<br />
<script>
<script nonce="<?php echo $SECURE_NONCE; ?>">
function refreshTasks() {
$.get('lib/gettasks.php<?php if ($pageid == "mytasks") {
echo "?alone=1";

View File

@ -7,17 +7,17 @@ redirectifnotloggedin();
<div class="well well-sm">
<a href="app.php?page=edittask" class="btn btn-primary"><i class="fa fa-plus"></i> <?php lang("new task") ?></a>
</div>
<div id="tasksdispdiv" style="<?php
<div id="tasksdispdiv" class="row<?php
if ($pageid != "taskman") {
echo "max-height: 600px; overflow-y: auto; padding: 5px;";
echo ' home-list-container"';
}
?>" class="row">
?>">
<?php
include __DIR__ . '/../lib/gettaskman.php';
?>
</div>
<br />
<script>
<script nonce="<?php echo $SECURE_NONCE; ?>">
function refreshTasks() {
$.get('lib/gettaskman.php<?php
if ($pageid == "taskman") {

View File

@ -10,6 +10,11 @@ header('Content-Type: text/html; charset=utf-8');
// l33t $ecurity h4x
header('X-Content-Type-Options: nosniff');
header('X-XSS-Protection: 1; mode=block');
header('X-Powered-By: PHP'); // no versions makes it harder to find vulns
header('X-Frame-Options: "DENY"');
header('Referrer-Policy: "no-referrer, strict-origin-when-cross-origin"');
$SECURE_NONCE = base64_encode(random_bytes(8));
$session_length = 60 * 60; // 1 hour
session_set_cookie_params($session_length, "/", null, false, false);
@ -17,6 +22,30 @@ session_start(); // stick some cookies in it
// renew session cookie
setcookie(session_name(), session_id(), time() + $session_length);
if ($_SESSION['mobile'] === TRUE) {
header("Content-Security-Policy: "
. "default-src 'self';"
. "object-src 'none'; "
. "img-src * data:; "
. "media-src 'self'; "
. "frame-src 'none'; "
. "font-src 'self'; "
. "connect-src *; "
. "style-src 'self' 'unsafe-inline'; "
. "script-src 'self' 'unsafe-inline'");
} else {
header("Content-Security-Policy: "
. "default-src 'self';"
. "object-src 'none'; "
. "img-src * data:; "
. "media-src 'self'; "
. "frame-src 'none'; "
. "font-src 'self'; "
. "connect-src *; "
. "style-src 'self' 'nonce-$SECURE_NONCE'; "
. "script-src 'self' 'nonce-$SECURE_NONCE'");
}
// Composer
require __DIR__ . '/vendor/autoload.php';
@ -32,7 +61,21 @@ require __DIR__ . '/lang/' . LANGUAGE . ".php";
* @param string $error error message
*/
function sendError($error) {
die("<!DOCTYPE html><html><head><title>Error</title></head><body><h1 style='color: red; font-family: sans-serif; font-size:100%;'>" . htmlspecialchars($error) . "</h1></body></html>");
global $SECURE_NONCE;
die("<!DOCTYPE html>"
. "<meta charset=\"UTF-8\">"
. "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
. "<title>Error</title>"
. "<style nonce=\"" . $SECURE_NONCE . "\">"
. "h1 {color: red; font-family: sans-serif; font-size: 20px; margin-bottom: 0px;} "
. "h2 {font-family: sans-serif; font-size: 16px;} "
. "p {font-family: monospace; font-size: 14px; width: 100%; wrap-style: break-word;} "
. "i {font-size: 12px;}"
. "</style>"
. "<h1>A fatal application error has occurred.</h1>"
. "<i>(This isn't your fault.)</i>"
. "<h2>Details:</h2>"
. "<p>". htmlspecialchars($error) . "</p>");
}
date_default_timezone_set(TIMEZONE);

View File

@ -9,6 +9,65 @@
font-size: 110%;
}
.navbar-brand img {
height: 35px;
padding-bottom: 12px;
padding-left: 5px;
}
.pad-75px {
height: 75px;
}
.mgn-btm-10px {
margin-bottom: 10px;
}
.mgn-top-8px {
margin-top: 8px;
}
.black-text {
color: black;
}
.msgdelform {
display: inline-block;
margin-left: 5px;
}
.inblock {
display: inline-block;
}
.padleft-5px {
padding-left: 5px;
}
.height-52px {
height: 52px;
}
.mgn-btm-5px {
margin-bottom: 5px;
}
.padright-0px {
padding-right: 0px;
}
#msgsendbtn {
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
margin-left: 0px;
}
.home-list-container {
max-height: 600px;
overflow-y: auto;
padding: 5px;
}
.footer {
margin-top: 10em;
text-align: center;

View File

@ -23,3 +23,30 @@ var options = {
};
$("#msgtobox").easyAutocomplete(options);
function refreshMsgs() {
$.get('lib/getmsgs.php', function (data) {
$('#messagedispdiv').html(data);
setupTooltips();
});
}
setInterval(function () {
refreshMsgs();
}, 10 * 1000);
$(".msgdelform").on("submit", function () {
var msgid = $(this).data("msgid");
$('#delmsgbtn' + msgid).prop('disabled', true);
setTimeout(function () {
refreshMsgs();
}, 100);
});
$("#msgsendform").on("submit", function () {
setTimeout(function () {
$('#msgsendbox').val('');
$('#msgtobox').val('');
refreshMsgs();
}, 100);
});

3
static/js/taskman.js Normal file
View File

@ -0,0 +1,3 @@
$('.deltaskform').on("submit", function () {
$("#deltaskbtn" + $(this).data("taskid")).prop("disabled", true);
});

21
static/js/tasks.js Normal file
View File

@ -0,0 +1,21 @@
$("#tasksdispdiv").on("click", ".task-btn", function () {
var taskid = $(this).data("taskid");
var action = $(this).data("action");
switch (action) {
case "start":
break;
case "finish":
break;
case "pause":
break;
case "problem":
break;
case "resume":
break;
default:
// Not a valid action code
return;
}
$("#" + action + "taskbtn" + taskid).prop("disabled", true);
refreshTasksSoon();
});