Skip to content

Commit

Permalink
feat: Implement computer approval using webpanel.
Browse files Browse the repository at this point in the history
Now it is possible to approve computers without manually touching the config DB.

Github issue #12
  • Loading branch information
Maxwell175 committed Aug 16, 2018
1 parent 87ead89 commit 58026b1
Show file tree
Hide file tree
Showing 11 changed files with 412 additions and 55 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
path = SSNFSd/webpanel/crypto-js
url = https://github.com/MDTech-us-MAN/crypto-js.git
branch = master
[submodule "SSNFSd/webpanel/SpeechBubbleJS"]
path = SSNFSd/webpanel/SpeechBubbleJS
url = https://github.com/MDTech-us-MAN/SpeechBubble.js.git
branch = master
2 changes: 1 addition & 1 deletion SSNFSd/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ int main(int argc, char *argv[])

server.listen(QHostAddress::Any, dbPort);

app.exec();
return app.exec();
}

QSqlDatabase getConfDB() {
Expand Down
188 changes: 186 additions & 2 deletions SSNFSd/ssnfswebworker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ static int PH7CheckAuthCookie(ph7_context *pCtx,int argc,ph7_value **argv) {
LEFT JOIN `User_Roles` ur
ON `Token` = ? AND ((julianday('now') - julianday(LastAccess_TmStmp)) * 24 * 60) < 30 AND t.`User_Key` = ur.`User_Key`
LEFT JOIN `Server_Role_Perms` rp
ON ur.`Role_Key` = rp.`Role_Key;)");
ON ur.`Role_Key` = rp.`Role_Key`;)");
getUserKey.addBindValue(cookie);
if (getUserKey.exec()) {
if (getUserKey.next()) {
Expand Down Expand Up @@ -211,6 +211,171 @@ static int PH7GetConnected(ph7_context *pCtx,int argc,ph7_value **argv) {
return PH7_OK;
}

static int PH7GetPending(ph7_context *pCtx,int argc,ph7_value **argv) {
(void) argc;
(void) argv;

SSNFSWorker *worker = (SSNFSWorker*)ph7_context_user_data(pCtx);

ph7_value *pending = ph7_context_new_array(pCtx);
QSqlQuery getPending(worker->configDB);
if (worker->userPerms.contains("computers")) {
getPending.prepare(R"(
SELECT `Pending_Client_Key`,
u.`FullName`,
`Client_Name`,
CAST(strftime('%s',`Submit_TmStmp`) AS INTEGER),
`Submit_Host`
FROM `Pending_Clients` c
JOIN `Users` u
ON c.`User_Key` = u.`User_Key`;)");
} else {
getPending.prepare(R"(
SELECT `Pending_Client_Key`,
u.`FullName`,
`Client_Name`,
CAST(strftime('%s',`Submit_TmStmp`) AS INTEGER),
`Submit_Host`
FROM `Pending_Clients` c
JOIN `Users` u
ON c.`User_Key` = ? AND c.`User_Key` = u.`User_Key`;)");
getPending.addBindValue(worker->userKey);
}
if (getPending.exec()) {
while (getPending.next()) {
ph7_value *clientInfo = ph7_context_new_array(pCtx);
ph7_value *pendingClientKeyVal = ph7_context_new_scalar(pCtx);
ph7_value_int64(pendingClientKeyVal, getPending.value(0).toLongLong());
ph7_array_add_strkey_elem(clientInfo, "pendingClientKey", pendingClientKeyVal);
ph7_value *userNameVal = ph7_context_new_scalar(pCtx);
ph7_value_string(userNameVal, ToChr(getPending.value(1).toString()), -1);
ph7_array_add_strkey_elem(clientInfo, "userName", userNameVal);
ph7_value *clientNameVal = ph7_context_new_scalar(pCtx);
ph7_value_string(clientNameVal, ToChr(getPending.value(2).toString()), -1);
ph7_array_add_strkey_elem(clientInfo, "clientName", clientNameVal);
ph7_value *submitTmStmpVal = ph7_context_new_scalar(pCtx);
ph7_value_int64(submitTmStmpVal, getPending.value(3).toLongLong());
ph7_array_add_strkey_elem(clientInfo, "submitTmStmp", submitTmStmpVal);
ph7_value *submitHostVal = ph7_context_new_scalar(pCtx);
ph7_value_string(submitHostVal, ToChr(getPending.value(4).toString()), -1);
ph7_array_add_strkey_elem(clientInfo, "submitHost", submitHostVal);
ph7_array_add_elem(pending, NULL, clientInfo);
}
} else {
Log::error(Log::Categories["Web Server"], "Error while getting pending computers: {0}", ToChr(getPending.lastError().text()));
ph7_context_throw_error(pCtx, PH7_CTX_ERR, "Internal error while getting pending computers.");
}

ph7_result_value(pCtx, pending);

return PH7_OK;
}

static int PH7ApprovePending(ph7_context *pCtx,int argc,ph7_value **argv) {
SSNFSWorker *worker = (SSNFSWorker*)ph7_context_user_data(pCtx);

if (argc < 1 || argc > 2 || ph7_value_is_numeric(argv[0]) == false || (argc == 2 && ph7_value_is_string(argv[1]) == false)) {
ph7_context_throw_error(pCtx, PH7_CTX_ERR, "An invalid number of argument(s) was specified.");
} else {
qint64 pendingClientKey = ph7_value_to_int64(argv[0]);
QSqlQuery approvePend(worker->configDB);
if (argc == 1) {
if (worker->userPerms.contains("computers")) {
approvePend.prepare(R"(
INSERT OR REPLACE INTO Clients
(`User_Key`
,`Client_Name`
,`Client_Cert`
,`Client_Info`
,`Updt_User`)
SELECT c.`User_Key`
,`Client_Name`
,`Client_Cert`
,`Client_Info`
,u.`FullName`
FROM `Pending_Clients` c
JOIN `Users` u
ON c.`Pending_Client_Key` = ? AND u.`User_Key` = ?)");
} else {
approvePend.prepare(R"(
INSERT OR REPLACE INTO Clients
(`User_Key`
,`Client_Name`
,`Client_Cert`
,`Client_Info`
,`Updt_User`)
SELECT c.`User_Key`
,`Client_Name`
,`Client_Cert`
,`Client_Info`
,u.`FullName`
FROM `Pending_Clients` c
JOIN `Users` u
ON c.`Pending_Client_Key` = ? AND c.`User_Key` = ? AND u.`User_Key` = c.`User_Key`)");
}
approvePend.addBindValue(pendingClientKey);
approvePend.addBindValue(worker->userKey);
} else {
if (worker->userPerms.contains("computers")) {
approvePend.prepare(R"(
INSERT OR REPLACE INTO Clients
(`User_Key`
,`Client_Name`
,`Client_Cert`
,`Client_Info`
,`Updt_User`)
SELECT c.`User_Key`
,? as Client_Name
,`Client_Cert`
,`Client_Info`
,u.`FullName`
FROM `Pending_Clients` c
JOIN `Users` u
ON c.`Pending_Client_Key` = ? AND u.`User_Key` = ?)");
} else {
approvePend.prepare(R"(
INSERT OR REPLACE INTO Clients
(`User_Key`
,`Client_Name`
,`Client_Cert`
,`Client_Info`
,`Updt_User`)
SELECT c.`User_Key`
,? as Client_Name
,`Client_Cert`
,`Client_Info`
,u.`FullName`
FROM `Pending_Clients` c
JOIN `Users` u
ON c.`Pending_Client_Key` = ? AND c.`User_Key` = ? AND u.`User_Key` = c.`User_Key`)");
}
approvePend.addBindValue(QString(ph7_value_to_string(argv[1], NULL)));
approvePend.addBindValue(pendingClientKey);
approvePend.addBindValue(worker->userKey);
}
if (approvePend.exec()) {
if (approvePend.numRowsAffected() == 0) {
ph7_result_string(pCtx, "The computer was not approved. The computer may already be approved or you may not have permissions to approve such computers.", -1);
} else {
QSqlQuery delApproved(worker->configDB);
delApproved.prepare("DELETE FROM `Pending_Clients` WHERE `Pending_Client_Key` = ?");
delApproved.addBindValue(pendingClientKey);
if (delApproved.exec()) {
ph7_result_string(pCtx, "OK", -1);
} else {
Log::error(Log::Categories["Web Server"], "Error while deleting an approved pending computer: {0}", ToChr(approvePend.lastError().text()));
ph7_context_throw_error(pCtx, PH7_CTX_ERR, "Internal error while deleting an approved pending computer.");
}
}
} else {
Log::error(Log::Categories["Web Server"], "Error while approving a pending computer: {0}", ToChr(approvePend.lastError().text()));
ph7_context_throw_error(pCtx, PH7_CTX_ERR, "Internal error while approving a pending computer.");
}
}

return PH7_OK;
}

// TODO: Read this from file?
#define HTTP_500_RESPONSE "HTTP/1.1 500 Internal Server Error\r\n" \
"Connection: close\r\n\r\n" \
Expand Down Expand Up @@ -321,7 +486,6 @@ void SSNFSWorker::processHttpRequest(char firstChar)
socket->write(HTTP_500_RESPONSE);
return;
}
/* Compile the PHP test program defined above */
rc = ph7_compile_file(
pEngine,
ToChr(FinalPath),
Expand Down Expand Up @@ -445,6 +609,26 @@ void SSNFSWorker::processHttpRequest(char firstChar)
Log::error(Log::Categories["Web Server"], "Error while setting up get_connected() function in PH7.");
return;
}
rc = ph7_create_function(
pVm,
"get_pending",
PH7GetPending,
this);
if( rc != PH7_OK ) {
socket->write(HTTP_500_RESPONSE);
Log::error(Log::Categories["Web Server"], "Error while setting up get_pending() function in PH7.");
return;
}
rc = ph7_create_function(
pVm,
"approve_pending",
PH7ApprovePending,
this);
if( rc != PH7_OK ) {
socket->write(HTTP_500_RESPONSE);
Log::error(Log::Categories["Web Server"], "Error while setting up approve_pending() function in PH7.");
return;
}

/*
* And finally, execute our program.
Expand Down
137 changes: 137 additions & 0 deletions SSNFSd/webpanel/approve.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<!--
* SSNFS WebPanel v0.1
*
* Available under the license(s) specified at https://github.com/MDTech-us-MAN/SSNFS.
*
* Copyright 2018 Maxwell Dreytser
*
-->
<?php include_once("check-cookie.php"); ?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SSNFS - Approve Computer</title>

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<style>
table, td {
text-align: right;
vertical-align: middle;
padding: 5px;
font-size: 0.97em
}
table {
width: 100%;
}
.heading {
font-weight: bold;
font-size: 1em;
}
.fa-edit {
color: #337ab7;
}
.btn-primary {
font-weight: bold;
padding: 10px 0;
margin: 5px 0;
}
</style>
</head>
<body>
<script type="text/javascript">
try {
if (window.self === window.top) {
alert("This page will not work if accessed directly. Please properly access it using the dashboard.")
}
} catch (e) {
alert("It looks like this page was loaded in an iframe outside of the current domain.");
}
</script>
<?php
if (isset($_POST['key']) && isset($_POST['CompName'])) {
$approveResult = approve_pending($_POST['key'], $_POST['CompName']);
if ($approveResult != 'OK'): ?>
<h3 style="color:darkred"><?php echo $approveResult; ?></h3>
<?php else: ?>
<h3 style="color:darkgreen">This computer has been approved.</h3>
<script type="text/javascript">
window.top.setTimeout(function () {
window.top.location.reload(true);
}, 5000)
</script>
<?php endif; ?>
</body>
</html>
<?php
exit();
}
?>
<div id="container">
<form action="approve.php" method="post" onsubmit="Approve.disabled = true; return true;">
<input type="hidden" value="" name="key" id="Key"/>
<table>
<tr>
<td class="heading">User Name:</td>
<td id="UserName"></td>
</tr>
<tr>
<td class="heading">Computer Name:</td>
<td>
<input type="text" value="" name="CompName" id="txtCompName" size="11" style="display: none;"/>
<span id="CompName">TST</span> <a href="javascript:void(0)"id="CompNameEdit"><i class="fas fa-edit"></i></a>
</td>
</tr>
<tr>
<td class="heading">Submitted On:</td>
<td id="SubmitTmStmp"></td>
</tr>
<tr>
<td class="heading">Submitted By:</td>
<td id="SubmitBy"></td>
</tr>
</table>
<button id="btnApprove" type="submit" class="btn btn-primary btn-block" name="Approve"> Approve </button>
</form>
</div>

<script type="text/javascript">
var editCompName = document.getElementById('CompNameEdit');
var lblCompName = document.getElementById('CompName');
var txtCompName = document.getElementById('txtCompName');

var txtKey = document.getElementById('Key');
var lblUserName = document.getElementById('UserName');
var lblSubmitTmStmp = document.getElementById('SubmitTmStmp');
var lblSubmitBy = document.getElementById('SubmitBy');
txtKey.value = window.parent.currApprovalInfo.pendingClientKey;
lblUserName.innerHTML = window.parent.currApprovalInfo.userName;
lblSubmitTmStmp.innerHTML = window.parent.currApprovalInfo.submitTmStmp.toLocaleString();
lblSubmitBy.innerHTML = window.parent.currApprovalInfo.submitHost;
lblCompName.innerHTML = window.parent.currApprovalInfo.clientName;
txtCompName.value = window.parent.currApprovalInfo.clientName;

var containerDiv = document.getElementById('container');

function resizeFrame() {
var bounds = containerDiv.getBoundingClientRect();

if (window.parent.currApprovalInfo.iframe.height != bounds.height + 5)
window.parent.currApprovalInfo.iframe.height = bounds.height + 5;
}
resizeFrame();
setInterval(resizeFrame, 500);

editCompName.onclick = function() {
lblCompName.style.display = 'none';
editCompName.style.display = 'none';
txtCompName.style.display = '';
resizeFrame();
};
</script>
</body>
1 change: 1 addition & 0 deletions SSNFSd/webpanel/computers.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login - SSNFS</title>

Expand Down
1 change: 1 addition & 0 deletions SSNFSd/webpanel/connected.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login - SSNFS</title>

Expand Down
Loading

0 comments on commit 58026b1

Please sign in to comment.