Add modules to repository
559
Papers/api/module.php
Executable file
@@ -0,0 +1,559 @@
|
||||
<?php
|
||||
|
||||
namespace pineapple;
|
||||
define('__INCLUDES__', "/pineapple/modules/Papers/includes/");
|
||||
define('__SCRIPTS__', __INCLUDES__ . "scripts/");
|
||||
define('__SSLSTORE__', __INCLUDES__ . "ssl/");
|
||||
define('__SSHSTORE__', __INCLUDES__ . "ssh/");
|
||||
define('__LOGS__', __INCLUDES__ . "logs/");
|
||||
define('__CHANGELOGS__', __INCLUDES__ . "changelog/");
|
||||
define('__HELPFILES__', __INCLUDES__ . "help/");
|
||||
define('__DOWNLOAD__', __INCLUDES__ . "download/");
|
||||
define('__UPLOAD__', __INCLUDES__ . "upload/");
|
||||
|
||||
/*
|
||||
Determine the type of file that has been uploaded and move it to the appropriate
|
||||
directory. If it's a .zip it is an injection set and will be unpacked. If it is
|
||||
an .exe it will be moved to __WINDL__, etc.
|
||||
*/
|
||||
if (!empty($_FILES)) {
|
||||
$response = [];
|
||||
foreach ($_FILES as $file) {
|
||||
$tempPath = $file[ 'tmp_name' ];
|
||||
$name = $file['name'];
|
||||
$type = pathinfo($file['name'], PATHINFO_EXTENSION);
|
||||
|
||||
// Do not accept any file other than .zip
|
||||
if ($type != "zip") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure the upload directory exists
|
||||
if (!file_exists(__UPLOAD__)) {
|
||||
if (!mkdir(__UPLOAD__, 0755, true)) {
|
||||
Papers::logError("Failed Upload", "Failed to upload " . $file['name'] . " because the directory structure could not be created");
|
||||
}
|
||||
}
|
||||
|
||||
$uploadPath = __UPLOAD__ . $name;
|
||||
$res = move_uploaded_file( $tempPath, $uploadPath );
|
||||
|
||||
if ($res) {
|
||||
// Unpack the key archive and move the keys to their appropriate directories
|
||||
exec(__SCRIPTS__ . "/unpackKeyArchive.sh -f " . explode(".", $name)[0]);
|
||||
$response[$name] = "Success";
|
||||
} else {
|
||||
$response[$name] = "Failed";
|
||||
}
|
||||
}
|
||||
echo json_encode($response);
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class Papers extends Module
|
||||
{
|
||||
public function route() {
|
||||
switch ($this->request->action) {
|
||||
case 'checkDepends':
|
||||
$this->checkDepends();
|
||||
break;
|
||||
case 'installDepends':
|
||||
$this->installDepends();
|
||||
break;
|
||||
case 'removeDepends':
|
||||
$this->removeDepends();
|
||||
break;
|
||||
case 'buildCert':
|
||||
$this->buildCert($this->request->parameters);
|
||||
break;
|
||||
case 'genSSHKeys':
|
||||
$this->genSSHKeys($this->request->parameters);
|
||||
break;
|
||||
case 'loadCertificates':
|
||||
$this->loadCertificates();
|
||||
break;
|
||||
case 'downloadKeys':
|
||||
$this->downloadKeys($this->request->parameters->name, $this->request->parameters->type);
|
||||
break;
|
||||
case 'clearDownloadArchive':
|
||||
$this->clearDownloadArchive();
|
||||
break;
|
||||
case 'removeCertificate':
|
||||
$this->removeCertificate($this->request->params->cert, $this->request->params->type);
|
||||
break;
|
||||
case 'securePineapple':
|
||||
$this->securePineapple($this->request->params->cert, $this->request->params->type);
|
||||
break;
|
||||
case 'getNginxSSLCerts':
|
||||
$this->getNginxSSLCerts();
|
||||
break;
|
||||
case 'unSSLPineapple':
|
||||
$this->unSSLPineapple();
|
||||
break;
|
||||
case 'revokeSSHKey':
|
||||
$this->revokeSSHKey($this->request->key);
|
||||
break;
|
||||
case 'getLogs':
|
||||
$this->getLogs($this->request->type);
|
||||
break;
|
||||
case 'readLog':
|
||||
$this->retrieveLog($this->request->parameters, $this->request->type);
|
||||
break;
|
||||
case 'deleteLog':
|
||||
$this->deleteLog($this->request->parameters);
|
||||
break;
|
||||
}
|
||||
}
|
||||
private function checkDepends() {
|
||||
$retData = array();
|
||||
exec(__SCRIPTS__ . "checkDepends.sh", $retData);
|
||||
if (implode(" ", $retData) == "Installed") {
|
||||
$this->respond(true);
|
||||
} else {
|
||||
$this->respond(false);
|
||||
}
|
||||
}
|
||||
private function installDepends() {
|
||||
$retData = array();
|
||||
exec(__SCRIPTS__ . "installDepends.sh", $retData);
|
||||
if (implode(" ", $retData) == "Complete") {
|
||||
$this->respond(true);
|
||||
} else {
|
||||
$this->respond(false);
|
||||
}
|
||||
}
|
||||
private function removeDepends() {
|
||||
// removeDepends.sh doesn't return anything whether successful or not
|
||||
exec(__SCRIPTS__ . "removeDepends.sh");
|
||||
$this->respond(true);
|
||||
}
|
||||
private function genSSHKeys($paramsObj) {
|
||||
$keyInfo = array();
|
||||
$params = (array)$paramsObj;
|
||||
|
||||
$keyInfo['-k'] = $params['keyName'];
|
||||
$keyInfo['-b'] = $params['bitSize'];
|
||||
if (array_key_exists('pass', $params)) {
|
||||
$keyInfo['-p'] = $params['pass'];
|
||||
}
|
||||
if (array_key_exists('comment', $params)) {
|
||||
$keyInfo['-c'] = $params['comment'];
|
||||
}
|
||||
|
||||
// Build the argument string to pass to buildCert.sh
|
||||
foreach ($keyInfo as $k => $v) {
|
||||
$argString .= $k . " \"" . $v . "\" ";
|
||||
}
|
||||
$argString = rtrim($argString);
|
||||
|
||||
$retData = array();
|
||||
exec(__SCRIPTS__ . "genSSHKeys.sh " . $argString, $retData);
|
||||
$res = implode("\n", $retData);
|
||||
if ($res != "") {
|
||||
$this->logError("Build SSH Key Error", "Failed to build SSH keys. The following data was returned:\n" . $res);
|
||||
$this->respond(false);
|
||||
return;
|
||||
}
|
||||
$this->respond(true);
|
||||
}
|
||||
private function buildCert($paramsObj) {
|
||||
$certInfo = array();
|
||||
$params = (array)$paramsObj;
|
||||
|
||||
$keyName = (array_key_exists('keyName', $params)) ? $params['keyName'] : "newCert";
|
||||
$certInfo['-k'] = $keyName;
|
||||
|
||||
if (array_key_exists('days', $params)) {
|
||||
$numberofdays = intval($params['days']);
|
||||
$certInfo['-d'] = $numberofdays;
|
||||
}
|
||||
if (array_key_exists('sigalgo', $params)) {
|
||||
$certInfo['-sa'] = $params['sigalgo'];
|
||||
}
|
||||
if (array_key_exists('bitSize', $params)) {
|
||||
$certInfo['-b'] = $params['bitSize'];
|
||||
}
|
||||
if (array_key_exists('country', $params)) {
|
||||
$certInfo['-c'] = $params['country'];
|
||||
}
|
||||
if (array_key_exists('state', $params)) {
|
||||
$certInfo['-st'] = $params['state'];
|
||||
}
|
||||
if (array_key_exists('city', $params)) {
|
||||
$certInfo['-l'] = $params['city'];
|
||||
}
|
||||
if (array_key_exists('organization', $params)) {
|
||||
$certInfo['-o'] = $params['organization'];
|
||||
}
|
||||
if (array_key_exists('section', $params)) {
|
||||
$certInfo['-ou'] = $params['section'];
|
||||
}
|
||||
if (array_key_exists('commonName', $params)) {
|
||||
$certInfo['-cn'] = $params['commonName'];
|
||||
}
|
||||
if (array_key_exists('email', $params)) {
|
||||
$certInfo['-email'] = $params['email'];
|
||||
}
|
||||
|
||||
// Build the argument string to pass to buildCert.sh
|
||||
foreach ($certInfo as $k => $v) {
|
||||
$argString .= $k . " \"" . $v . "\" ";
|
||||
}
|
||||
$argString = rtrim($argString);
|
||||
|
||||
$retData = array();
|
||||
exec(__SCRIPTS__ . "buildCert.sh " . $argString, $retData);
|
||||
$res = implode("\n", $retData);
|
||||
if ($res != "Complete") {
|
||||
$this->logError("Build Certificate Error", "The key pair failed with the following error from the console:\n\n" . $res);
|
||||
$this->respond(false, "Failed to build key pair. Check the logs for details.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (array_key_exists('container', $params) || array_key_exists('encrypt', $params)) {
|
||||
$cryptInfo = array();
|
||||
$argString = "";
|
||||
|
||||
$cryptInfo['-k'] = $keyName;
|
||||
|
||||
// Check if the certificate should be encrypted
|
||||
if (array_key_exists('encrypt', $params)) {
|
||||
$argString = "--encrypt ";
|
||||
|
||||
$cryptInfo['-a'] = (array_key_exists('algo', $params)) ? $params['algo'] : False;
|
||||
$cryptInfo['-p'] = (array_key_exists('pkey_pass', $params)) ? $params['pkey_pass'] : False;
|
||||
|
||||
if (!$cryptInfo['-a'] || !$cryptInfo['-p']) {
|
||||
$this->logError("Build Certificate Error", "The public and private keys were generated successfully but an algorithm or password were not supplied for encryption. The certs can still be found in your SSL store.");
|
||||
$this->respond(false, "Build finished with errors. Check the logs for details.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Check if the certificates should be placed into an encrypted container
|
||||
if (array_key_exists('container', $params)) {
|
||||
$cryptInfo['-c'] = (array_key_exists('container', $params)) ? $params['container'] : False;
|
||||
$cryptInfo['-calgo'] = (array_key_exists('c_algo', $params)) ? $params['c_algo'] : False;
|
||||
$cryptInfo['-cpass'] = (array_key_exists('c_pass', $params)) ? $params['c_pass'] : False;
|
||||
}
|
||||
|
||||
// Build an argument string with all available arguments
|
||||
foreach ($cryptInfo as $k => $v) {
|
||||
if (!$v) {continue;}
|
||||
$argString .= $k . " \"" . $v . "\" ";
|
||||
}
|
||||
$argString = rtrim($argString);
|
||||
|
||||
// Execute encryptKeys.sh with the parameters and check for errors
|
||||
$retData = array();
|
||||
exec(__SCRIPTS__ . "encryptKeys.sh " . $argString, $retData);
|
||||
$res = implode("\n", $retData);
|
||||
if ($res != "Complete") {
|
||||
$this->logError("Certificate Encryption Error", "The public and private keys were generated successfully but encryption failed with the following error:\n\n" . $res);
|
||||
$this->respond(false, "Build finished with errors. Check the logs for details.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->respond(true, "Keys created successfully!");
|
||||
}
|
||||
|
||||
private function loadCertificates() {
|
||||
$certs = $this->getKeys(__SSLSTORE__);
|
||||
$certs = array_merge($certs, $this->getKeys(__SSHSTORE__));
|
||||
$this->respond(true,null,$certs);
|
||||
}
|
||||
|
||||
private function getKeys($dir) {
|
||||
$keyType = ($dir == __SSLSTORE__) ? "TLS/SSL" : "SSH";
|
||||
$keys = scandir($dir);
|
||||
$certs = array();
|
||||
foreach ($keys as $key) {
|
||||
if ($key == "." || $key == "..") {continue;}
|
||||
|
||||
$parts = explode(".", $key);
|
||||
$fname = $parts[0];
|
||||
$type = "." . $parts[1];
|
||||
|
||||
// Check if the object name already exists in the array
|
||||
if ($this->objNameExistsInArray($fname, $certs)) {
|
||||
foreach ($certs as &$obj) {
|
||||
if ($obj->Name == $fname) {
|
||||
$obj->Type .= ", " . $type;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add a new object to the array
|
||||
$enc = ($this->keyIsEncrypted($fname, $keyType)) ? "Yes" : "No";
|
||||
array_push($certs, (object)array('Name' => $fname, 'Type' => $type, 'Encrypted' => $enc, 'KeyType' => $keyType, 'Authorized' => $this->checkSSHKeyAuth($fname, $keyType)));
|
||||
}
|
||||
}
|
||||
return $certs;
|
||||
}
|
||||
|
||||
private function checkSSHKeyAuth($keyName, $keyType) {
|
||||
if ($keyType != "SSH") {return false;}
|
||||
$res = exec(__SCRIPTS__ . "checkSSHKey.sh -k " . $keyName);
|
||||
if ($res == "TRUE") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function revokeSSHKey($keyName) {
|
||||
exec(__SCRIPTS__ . "revokeSSHKey.sh -k " . $keyName);
|
||||
$this->respond(true);
|
||||
}
|
||||
|
||||
private function keyIsEncrypted($keyName, $keyType) {
|
||||
$data = array();
|
||||
$keyDir = ($keyType == "SSH") ? __SSHSTORE__ : __SSLSTORE__;
|
||||
exec(__SCRIPTS__ . "testEncrypt.sh -k " . $keyName . " -d " . $keyDir . " 2>&1", $data);
|
||||
if ($data[0] == "writing RSA key") {
|
||||
return false;
|
||||
} else if ($data[0] == "unable to load Private Key") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private function downloadKeys($keyName, $keyType) {
|
||||
$argString = "-o " . $keyName . ".zip -f \"";
|
||||
|
||||
// Grab all of the keys, certs, and containers
|
||||
$keyDir = ($keyType == "SSH") ? __SSHSTORE__ : __SSLSTORE__;
|
||||
$contents = scandir($keyDir);
|
||||
$certs = array();
|
||||
foreach ($contents as $cert) {
|
||||
if ($cert == "." || $cert == "..") {continue;}
|
||||
$parts = explode(".", $cert);
|
||||
$fname = $parts[0];
|
||||
$type = "." . $parts[1];
|
||||
|
||||
if ($fname == $keyName) {
|
||||
$argString .= $cert ." ";
|
||||
}
|
||||
}
|
||||
$argString = rtrim($argString);
|
||||
$argString .= "\"";
|
||||
|
||||
// Pack them into an archive
|
||||
exec(__SCRIPTS__ . "packKeys.sh " . $keyDir . " " . $argString);
|
||||
|
||||
// Check if the files were archived properly
|
||||
$archiveExists = False;
|
||||
foreach (scandir(__DOWNLOAD__) as $file) {
|
||||
if ($file == $keyName . ".zip") {
|
||||
$archiveExists = True;
|
||||
}
|
||||
}
|
||||
|
||||
// Begin downloading the archive
|
||||
if ($archiveExists) {
|
||||
$this->respond(true, null, $this->downloadFile(__DOWNLOAD__ . $keyName . ".zip"));
|
||||
} else {
|
||||
$this->respond(false, "Failed to create archive.");
|
||||
}
|
||||
}
|
||||
|
||||
private function clearDownloadArchive() {
|
||||
foreach (scandir(__DOWNLOAD__) as $file) {
|
||||
if ($file == "." || $file == "..") {continue;}
|
||||
unlink(__DOWNLOAD__ . $file);
|
||||
}
|
||||
$files = glob(__DOWNLOAD__ . "*");
|
||||
if (count($files) > 0) {
|
||||
$this->respond(false, "Failed to clear archive.");
|
||||
}
|
||||
$this->respond(true);
|
||||
}
|
||||
|
||||
private function objNameExistsInArray($name, $arr) {
|
||||
foreach ($arr as $x) {
|
||||
if ($x->Name == $name) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
private function removeCertificate($delCert, $keyType) {
|
||||
$res = True;
|
||||
$msg = "Failed to delete the following files:";
|
||||
$keyDir = ($keyType == "SSH") ? __SSHSTORE__ : __SSLSTORE__;
|
||||
foreach (scandir($keyDir) as $cert) {
|
||||
if ($cert == "." || $cert == "..") {continue;}
|
||||
if (explode(".",$cert)[0] == $delCert) {
|
||||
if (!unlink($keyDir . $cert)) {
|
||||
$res = False;
|
||||
$msg .= " " . $cert;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->respond($res, $msg);
|
||||
}
|
||||
|
||||
private function respond($success, $msg = null, $data = null, $error = null) {
|
||||
$this->response = array("success" => $success,"message" => $msg, "data" => $data, "error" => $error);
|
||||
}
|
||||
|
||||
private function getNginxSSLCerts() {
|
||||
$res = $this->checkSSLConfig();
|
||||
if ($res == "") {
|
||||
$this->respond(false, array("[!] SSL keys not configured in nginx.conf"));
|
||||
} else {
|
||||
$this->respond(true, null, explode(" ", $res));
|
||||
}
|
||||
}
|
||||
|
||||
private function checkSSLConfig() {
|
||||
$retData = array();
|
||||
exec(__SCRIPTS__ . "readKeys.sh", $retData);
|
||||
return implode(" ", $retData);
|
||||
}
|
||||
|
||||
private function unSSLPineapple() {
|
||||
// First check if SSL is configured
|
||||
if ($this->checkSSLConfig() == "") {
|
||||
$this->respond(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the keys from /etc/nginx/ssl/ and delete the directory
|
||||
$status = True;
|
||||
if (!$this->removeKeysFromNginx()) {
|
||||
$status = False;
|
||||
$this->logError("UnSSLPineapple", "Failed to remove keys from /etc/nginx/ssl/.");
|
||||
}
|
||||
|
||||
// Remove the configurations from /etc/nginx/nginx.conf
|
||||
$retData = array();
|
||||
exec("python " . __SCRIPTS__ . "cfgNginx.py --remove", $retData);
|
||||
if (implode("", $retData) != "Complete") {
|
||||
$status = False;
|
||||
$this->logError("UnSSLPineapple", "Failed to remove SSL configurations from /etc/nginx/nginx.conf");
|
||||
}
|
||||
$this->respond($status);
|
||||
}
|
||||
|
||||
private function securePineapple($certName, $keyType) {
|
||||
// Check the key type to determine whether we are adding an SSH key or SSL keys
|
||||
if ($keyType == "SSH") {
|
||||
// Modify authorized_keys file
|
||||
exec(__SCRIPTS__ . "addSSHKey.sh -k " . $certName);
|
||||
$this->respond(true);
|
||||
} else {
|
||||
// Update SSL configs
|
||||
$this->SSLPineapple($certName);
|
||||
}
|
||||
}
|
||||
|
||||
private function SSLPineapple($certName) {
|
||||
// Check if nginx SSL directory exists
|
||||
$nginx_ssl_dir = "/etc/nginx/ssl/";
|
||||
if (!file_exists($nginx_ssl_dir)) {
|
||||
if (!mkdir($nginx_ssl_dir)) {
|
||||
$this->logError("SSL Config Failure", "nginx SSL directory does not exist and it could not be created.");
|
||||
$this->respond(false, "An error occurred. Check the logs for details.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if SSL is already configured, if so simply replace the keys
|
||||
// and skip the rest of this function
|
||||
if ($this->checkSSLConfig() != "") {
|
||||
$this->replaceSSLCerts($certName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy selected key pair to the SSL directory
|
||||
if (!$this->copyKeysToNginx($certName)) {
|
||||
$this->respond(false, "An error occurred. Check the logs for details.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the nginx configuration script cfgNginx.py
|
||||
$retData = array();
|
||||
exec("python " . __SCRIPTS__ . "cfgNginx.py --add -k " . $certName, $retData);
|
||||
if (implode("", $retData) == "Complete") {
|
||||
$this->respond(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Log whatever message came from cfgNginx.py and return False
|
||||
$this->logError("SSL Config Failure", implode("", $retData));
|
||||
$this->respond(false, "An error occurred. Check the logs for details.");
|
||||
}
|
||||
|
||||
private function replaceSSLCerts($certName) {
|
||||
// Remove the old keys from the SSL store
|
||||
$this->removeKeysFromNginx();
|
||||
|
||||
// Copy selected key pair to the SSL directory
|
||||
if (!$this->copyKeysToNginx($certName)) {
|
||||
$this->respond(false, "An error occurred. Check the logs for details.");
|
||||
return;
|
||||
}
|
||||
|
||||
$retData = array();
|
||||
exec("python " . __SCRIPTS__ . "cfgNginx.py --replace -k " . $certName, $retData);
|
||||
if (implode("", $retData) == "Complete") {
|
||||
$this->respond(true);
|
||||
return;
|
||||
}
|
||||
$this->logError("Replace SSL Cert Failure", $retData);
|
||||
$this->respond(false);
|
||||
return;
|
||||
}
|
||||
private function copyKeysToNginx($certName) {
|
||||
// Copy selected key pair to the SSL directory
|
||||
$retData = array();
|
||||
$res = exec(__SCRIPTS__ . "copyKeys.sh " . __SSLSTORE__ . $certName, $retData);
|
||||
if ($res) {
|
||||
$this->logError("Replace SSL Cert Failure", $retData);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
private function removeKeysFromNginx() {
|
||||
$keys = $this->checkSSLConfig();
|
||||
$retData = array();
|
||||
$res = exec(__SCRIPTS__ . "removeKeys.sh {$keys}", $retData);
|
||||
if ($res) {
|
||||
$this->logError("Key Removal Failed", "Old keys may still exist in /etc/nginx/ssl/. Continuing process anyway...");
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
private function getLogs($type) {
|
||||
$dir = ($type == "error") ? __LOGS__ : __CHANGELOGS__;
|
||||
$contents = array();
|
||||
foreach (scandir($dir) as $log) {
|
||||
if ($log == "." || $log == "..") {continue;}
|
||||
array_push($contents, $log);
|
||||
}
|
||||
$this->respond(true, null, $contents);
|
||||
}
|
||||
private function logError($filename, $data) {
|
||||
$time = exec("date +'%H_%M_%S'");
|
||||
$fh = fopen(__LOGS__ . str_replace(" ","_",$filename) . "_" . $time . ".txt", "w+");
|
||||
fwrite($fh, $data);
|
||||
fclose($fh);
|
||||
}
|
||||
private function retrieveLog($logname, $type) {
|
||||
$dir = ($type == "error") ? __LOGS__ : ($type == "help") ? __HELPFILES__ : __CHANGELOGS__;
|
||||
$data = file_get_contents($dir . $logname);
|
||||
if (!$data) {
|
||||
$this->respond(false);
|
||||
return;
|
||||
}
|
||||
$this->respond(true, null, $data);
|
||||
}
|
||||
private function deleteLog($logname) {
|
||||
$data = unlink(__LOGS__ . $logname);
|
||||
if (!$data) {
|
||||
$this->respond(false, "Failed to delete log.");
|
||||
return;
|
||||
}
|
||||
$this->respond(true);
|
||||
}
|
||||
}
|
||||
?>
|
||||
2
Papers/includes/changelog/Version 1.0
Executable file
@@ -0,0 +1,2 @@
|
||||
January 24, 2016<br /><br />
|
||||
- Module released.
|
||||
7
Papers/includes/changelog/Version 1.2
Executable file
@@ -0,0 +1,7 @@
|
||||
April 6, 2016<br /><br />
|
||||
- Revamped cfgNginx.py to include support for adding, replacing, getting, and removing SSL keys.<br /><br />
|
||||
- cfgNginx.py now only selects the SSL keys associated with port 1471 instead of pulling all keys from the configuration file.<br /><br />
|
||||
- Removal of SSL keys is also targeted now. In the previous version the whole /etc/nginx/ssl/ directory would be deleted but now only the keys you've selected for port 1471 will be removed.<br /><br />
|
||||
- Upon adding/replacing/removing SSL keys to Nginx the browser will now automatically redirect to the new protocol.<br /><br />
|
||||
- Updated the user interface<br /><br />
|
||||
- Fixed module.info to reflect current version of module.<br />
|
||||
3
Papers/includes/changelog/Version 1.3
Executable file
@@ -0,0 +1,3 @@
|
||||
July 30, 2016<br /><br />
|
||||
- Fixed bug where browser would refresh when approving/revoking SSH keys
|
||||
|
||||
4
Papers/includes/changelog/Version 1.4
Executable file
@@ -0,0 +1,4 @@
|
||||
September 12, 2016<br /></br >
|
||||
- Added functionality to upload certificate archives</br >
|
||||
- Updated UI<br />
|
||||
- Added dependency unzip</br >
|
||||
36
Papers/includes/help/build.help
Executable file
@@ -0,0 +1,36 @@
|
||||
<h4 style="color:red">WARNING!</h4>
|
||||
<strong>Do not encrypt the private key in the set you will use for SSL on the Pineapple! If you do nginx will require a password upon boot which you will not have the chance to enter thus forcing you to factory reset your Pineapple!</strong>
|
||||
<hr />
|
||||
|
||||
<strong>Key Type</strong><br />
|
||||
Select the type of keys you want to build.
|
||||
<br /><br />
|
||||
|
||||
<strong>Bit Size</strong><br />
|
||||
This is the key length. The higher the value the harder it is to crack the key. Higher values will take longer to build and longer to check when used in applications. 2048 is the recommended value for web applications.
|
||||
<br /><br />
|
||||
|
||||
<strong>Key Pair Name</strong><br />
|
||||
This is the name of your keys when they are generated. Single word names are best.
|
||||
<br /><br />
|
||||
|
||||
<strong>Days Valid</strong><br />
|
||||
This value indicates how long the certificate will be valid. A default value of 365 days is set for convenience.
|
||||
<br /></br >
|
||||
|
||||
|
||||
<strong>Signature Algorithm</strong><br />
|
||||
SHA-1 is considered to be too weak these days, or it will be soon enough, so SHA-256 is selected by default.
|
||||
<br /><br />
|
||||
|
||||
|
||||
<strong>Certificate Info (click to expand)</strong><br />
|
||||
These fields are self explanatory and provide information that gets embedded in the public key. This can be left blank but if so the default settings will be used by OpenSSL.
|
||||
<br /><br />
|
||||
|
||||
<strong>Encrypt Private Key</strong><br />
|
||||
Check this box if you want to require a password to view the private key. You will have to select an algorithm (SHA-256 by default) and enter a password.
|
||||
<br /><br />
|
||||
|
||||
<strong>Export keys to PKCS#12 container</strong><br />
|
||||
Check this box if you want to export both the private and public keys into an encrypted container. This option will generate three files (.cer, .pem, .pfx).
|
||||
10
Papers/includes/help/status.help
Executable file
@@ -0,0 +1,10 @@
|
||||
<strong>SSL Certificate and Private Key</strong><br />
|
||||
Displays the keys currently being used by nginx on your Pineapple. These values are pulled directly from /etc/nginx/nginx.conf so they are always current.
|
||||
<br /><br />
|
||||
|
||||
<strong>Dependencies</strong><br />
|
||||
The only dependencies for Papers are zip and unzip which are downloaded via opkg. They are used to pack, and unpack, certificate archives for download/upload.
|
||||
<br /><br />
|
||||
|
||||
<strong>Remove SSL</strong><br />
|
||||
This reverts the Pineapple back to its original web configuration and removes all traces of SSL from the nginx config. This does not affect the certificate store or any configuration in the Papers module.
|
||||
21
Papers/includes/help/store.help
Executable file
@@ -0,0 +1,21 @@
|
||||
<strong>Encrypted</strong><br />
|
||||
Displays if the private key (.pem) is encrypted. Does not include encryption on .pfx containers.
|
||||
<br /><br />
|
||||
|
||||
<strong>PineSSL / PineSSH</strong><br />
|
||||
For TLS/SSL keys this button configures SSL on the Pineapple or swaps the current SSL keys with those selected.
|
||||
<br />
|
||||
For SSH key pairs this button has two modes (the state does not change for TLS/SSL keys):
|
||||
<br /><br />
|
||||
<ul>
|
||||
<li><img src="/modules/Papers/includes/icons/glyphicons-204-lock.png"/>  Add key to /root/.ssh/authorized_keys to allow connections to users who hold the private key.<br /><br />
|
||||
<li><img src="/modules/Papers/includes/icons/glyphicons-205-unlock.png"/> Revoke key from /root/.ssh/authorized_keys to deny connections from those who use the private key.
|
||||
</ul>
|
||||
<br />
|
||||
|
||||
<strong>Download</strong><br />
|
||||
Packages the keys in the selected row into a zip archive and downloads it.
|
||||
<br /><br />
|
||||
|
||||
<strong>Delete</strong><br />
|
||||
Removes the selected keys from the SSL store. This can't be undone.
|
||||
BIN
Papers/includes/icons/glyphicons-17-bin.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Papers/includes/icons/glyphicons-182-download-alt.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Papers/includes/icons/glyphicons-198-remove-circle.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Papers/includes/icons/glyphicons-201-download.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Papers/includes/icons/glyphicons-202-upload.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Papers/includes/icons/glyphicons-204-lock.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Papers/includes/icons/glyphicons-205-unlock.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Papers/includes/icons/glyphicons-45-keys.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
95
Papers/includes/nginx.conf
Executable file
@@ -0,0 +1,95 @@
|
||||
user root root;
|
||||
worker_processes 1;
|
||||
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
index index.php index.html index.htm;
|
||||
default_type text/html;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
gzip on;
|
||||
|
||||
gzip_min_length 1k;
|
||||
gzip_buffers 4 16k;
|
||||
gzip_http_version 1.0;
|
||||
gzip_comp_level 2;
|
||||
gzip_types text/plain application/x-javascript text/css application/xml;
|
||||
gzip_vary on;
|
||||
server {
|
||||
listen 80; # Port, make sure it is not in conflict with another http daemon.
|
||||
server_name www; # Change this, reference -> http://nginx.org/en/docs/http/server_names.html
|
||||
error_page 404 =200 /index.php;
|
||||
error_log /dev/null;
|
||||
access_log /dev/null;
|
||||
fastcgi_connect_timeout 300;
|
||||
fastcgi_send_timeout 300;
|
||||
fastcgi_read_timeout 300;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 4 32k;
|
||||
fastcgi_busy_buffers_size 32k;
|
||||
fastcgi_temp_file_write_size 32k;
|
||||
client_body_timeout 10;
|
||||
client_header_timeout 10;
|
||||
send_timeout 60; # 60 sec should be enough, if experiencing alof of timeouts, increase this.
|
||||
output_buffers 1 32k;
|
||||
postpone_output 1460;
|
||||
|
||||
root /www/; # Your document root, where all public material is.
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
|
||||
if (-f $request_filename) {
|
||||
# Only throw it at PHP-FPM if the file exists (prevents some PHP exploits)
|
||||
fastcgi_pass unix:/var/run/php5-fpm.sock; # The upstream determined above
|
||||
}
|
||||
}
|
||||
error_page 404 =200 /index.php;
|
||||
}
|
||||
|
||||
|
||||
server {
|
||||
listen 1471;
|
||||
server_name pineapple; # Change this, reference -> http://nginx.org/en/docs/http/server_names.html
|
||||
error_page 404 =200 /index.php;
|
||||
error_log /dev/null;
|
||||
access_log /dev/null;
|
||||
fastcgi_connect_timeout 300;
|
||||
fastcgi_send_timeout 300;
|
||||
fastcgi_read_timeout 300;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 4 32k;
|
||||
fastcgi_busy_buffers_size 32k;
|
||||
fastcgi_temp_file_write_size 32k;
|
||||
client_body_timeout 10;
|
||||
client_header_timeout 10;
|
||||
send_timeout 60; # 60 sec should be enough, if experiencing alof of timeouts, increase this.
|
||||
output_buffers 1 32k;
|
||||
postpone_output 1460;
|
||||
|
||||
root /pineapple/; # Your document root, where all public material is.
|
||||
add_header 'Cache-Control' 'no-cache, no-store, must-revalidate';
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
|
||||
if (-f $request_filename) {
|
||||
# Only throw it at PHP-FPM if the file exists (prevents some PHP exploits)
|
||||
fastcgi_pass unix:/var/run/php5-fpm.sock; # The upstream determined above
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
Papers/includes/scripts/addSSHKey.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Feb 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: ./addAuthKey.sh <keydir> <opts>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-k:\tName of key to be used';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
SSH_STORE='/pineapple/modules/Papers/includes/ssh/';
|
||||
KEY='';
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-k" ]]; then
|
||||
KEY="$2";
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
cat $SSH_STORE$KEY.pub >> /root/.ssh/authorized_keys
|
||||
117
Papers/includes/scripts/buildCert.sh
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: ./buildCert.sh <opts>";
|
||||
echo '';
|
||||
echo 'Required Parameters:';
|
||||
echo -e '\t-k,--keyName:\tName of exported key files';
|
||||
echo '';
|
||||
echo 'Optional Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-b,--bitSize:\tBitsize of keys (Default: 2048)';
|
||||
echo -e '\t-d,--days:\tNumber days keys will be valid (Default: 365)';
|
||||
echo -e '\t-sa,--sigAlgo:\tSignature algorithm (Default: SHA-256)';
|
||||
echo '';
|
||||
echo 'Distinguished Name Options:';
|
||||
echo '';
|
||||
echo -e '\t-c,--country:\t\t\tCountry Code';
|
||||
echo -e '\t-st,--state:\t\t\tState or Province';
|
||||
echo -e '\t-l,--locality:\t\t\tCity or Locality';
|
||||
echo -e '\t-o,--orgnaization:\t\tOrganization';
|
||||
echo -e '\t-ou,--organizationalUnit:\tOrganizational Unit';
|
||||
echo -e '\t-cn,--commonName:\t\tCommon Name';
|
||||
echo -e '\t-email,--emailAddress:\t\tEmail Address';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
# Defaults
|
||||
SIGALGO="sha256";
|
||||
BITSIZE=2048;
|
||||
DAYS=365;
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-d" || "$1" == "--days" ]]; then
|
||||
DAYS="$2";
|
||||
fi
|
||||
if [[ "$1" == "-b" || "$1" == "--bitSize" ]]; then
|
||||
BITSIZE="$2";
|
||||
fi
|
||||
if [[ "$1" == "-k" || "$1" == "--keyName" ]]; then
|
||||
KEYNAME="$2";
|
||||
fi
|
||||
if [[ "$1" == "-sa" || "$1" == "--sigAlgo" ]]; then
|
||||
SIGALGO="$2";
|
||||
fi
|
||||
if [[ "$1" == "-c" || "$1" == "--country" ]]; then
|
||||
COUNTRY="$2"
|
||||
fi
|
||||
if [[ "$1" == "-st" || "$1" == "--state" ]]; then
|
||||
STATE="$2"
|
||||
fi
|
||||
if [[ "$1" == "-l" || "$1" == "--locality" ]]; then
|
||||
LOCALITY="$2"
|
||||
fi
|
||||
if [[ "$1" == "-o" || "$1" == "--organization" ]]; then
|
||||
ORGANIZATION="$2"
|
||||
fi
|
||||
if [[ "$1" == "-ou" || "$1" == "--organizationalUnit" ]]; then
|
||||
OU="$2"
|
||||
fi
|
||||
if [[ "$1" == "-cn" || "$1" == "--commonName" ]]; then
|
||||
CN="$2"
|
||||
fi
|
||||
if [[ "$1" == "-email" || "$1" == "--emailAddress" ]]; then
|
||||
EMAIL="$2"
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$DAYS" ] || [ -z "$BITSIZE" ] || [ -z "$KEYNAME" ]; then
|
||||
echo "[-] You must enter at least key name, bitsize, and days valid parameters.";
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
subj="";
|
||||
ssl_store="/pineapple/modules/Papers/includes/ssl/";
|
||||
|
||||
if [ -n "$COUNTRY" ]; then
|
||||
subj="$subj/C=$COUNTRY";
|
||||
fi
|
||||
if [ -n "$STATE" ]; then
|
||||
subj="$subj/ST=$STATE";
|
||||
fi
|
||||
if [ -n "$LOCALITY" ]; then
|
||||
subj="$subj/L=$LOCALITY";
|
||||
fi
|
||||
if [ -n "$ORGANIZATION" ]; then
|
||||
subj=$subj"/O=$ORGANIZATION";
|
||||
fi
|
||||
if [ -n "$OU" ]; then
|
||||
subj="$subj/OU=$OU";
|
||||
fi
|
||||
if [ -n "$CN" ]; then
|
||||
subj="$subj/CN=$CN";
|
||||
fi
|
||||
if [ -n "$EMAIL" ]; then
|
||||
subj="$subj/emailAddress=$EMAIL";
|
||||
fi
|
||||
|
||||
if [ -n "$subj" ]; then
|
||||
openssl req -x509 -nodes -batch -days $DAYS -newkey rsa:$BITSIZE -$SIGALGO -keyout $ssl_store$KEYNAME.pem -out $ssl_store$KEYNAME.cer -subj "$subj";
|
||||
else
|
||||
openssl req -x509 -nodes -batch -days $DAYS -newkey rsa:$BITSIZE -$SIGALGO -keyout $ssl_store$KEYNAME.pem -out $ssl_store$KEYNAME.cer;
|
||||
fi
|
||||
|
||||
echo "Complete";
|
||||
121
Papers/includes/scripts/cfgHelper.py
Executable file
@@ -0,0 +1,121 @@
|
||||
# Author: sud0nick
|
||||
# Date: Apr 2016
|
||||
|
||||
from subprocess import call
|
||||
import os
|
||||
|
||||
class ConfigHelper:
|
||||
|
||||
def __init__(self, sslDir = "/etc/nginx/ssl/"):
|
||||
self.nginxConf = "/etc/nginx/nginx.conf"
|
||||
self.lines = [f for f in open(self.nginxConf)]
|
||||
self.ssl_dir = sslDir
|
||||
self.serverBlockIndex = self.getServerBlockIndex()
|
||||
self.currentSSLCerts = self.getCurrentSSLCerts()
|
||||
|
||||
|
||||
def checkSSLCertsExist(self):
|
||||
flags = [".pem", ".cer"]
|
||||
if os.path.isdir(self.ssl_dir):
|
||||
for file in os.listdir(self.ssl_dir):
|
||||
for flag in flags:
|
||||
if flag in file:
|
||||
flags.remove(flag)
|
||||
if flags:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def getCurrentSSLCerts(self):
|
||||
certs = []
|
||||
index = self.serverBlockIndex
|
||||
for line in self.lines[index:]:
|
||||
if "ssl_certificate" in line:
|
||||
i = line.rfind("/")
|
||||
certs.append(line[i+1:].strip(";\n"))
|
||||
|
||||
return certs
|
||||
|
||||
|
||||
def getServerBlockIndex(self):
|
||||
index = 0
|
||||
for line in self.lines:
|
||||
if ("listen" in line) and not ("80" in line or "443" in line):
|
||||
return index
|
||||
index = index + 1
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def checkSSLConfigStatus(self):
|
||||
index = self.serverBlockIndex
|
||||
for line in self.lines[index:]:
|
||||
if "1471 ssl;" in line:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def addSSLConfig(self, keyName):
|
||||
|
||||
# Check if SSL has already been configured for port 1471
|
||||
if self.checkSSLConfigStatus():
|
||||
return True
|
||||
|
||||
index = 0
|
||||
cert = keyName + ".cer"
|
||||
key = keyName + ".pem"
|
||||
|
||||
with open(self.nginxConf, "w") as out:
|
||||
for line in self.lines:
|
||||
if index == self.serverBlockIndex:
|
||||
line = "\t\tlisten\t1471 ssl;\n"
|
||||
|
||||
if index > self.serverBlockIndex:
|
||||
if "root /pineapple/;" in line:
|
||||
self.lines.insert(index + 1, "\t\tssl_certificate /etc/nginx/ssl/" + cert + ";\n"
|
||||
"\t\tssl_certificate_key /etc/nginx/ssl/" + key + ";\n"
|
||||
"\t\tssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n")
|
||||
index = index + 1
|
||||
out.write(line)
|
||||
call(["/etc/init.d/nginx", "reload"])
|
||||
|
||||
return True
|
||||
|
||||
def replaceSSLConfig(self, newKey):
|
||||
cert = newKey + ".cer"
|
||||
key = newKey + ".pem"
|
||||
currentKey = self.currentSSLCerts[0].rsplit(".")[0]
|
||||
index = 0
|
||||
|
||||
with open(self.nginxConf, "w") as out:
|
||||
for line in self.lines:
|
||||
if index > self.serverBlockIndex:
|
||||
if (currentKey + ".cer") in line:
|
||||
line = "\t\tssl_certificate /etc/nginx/ssl/" + cert + ";\n"
|
||||
|
||||
if (currentKey + ".pem") in line:
|
||||
line = "\t\tssl_certificate_key /etc/nginx/ssl/" + key + ";\n"
|
||||
|
||||
index = index + 1
|
||||
out.write(line)
|
||||
|
||||
call(["/etc/init.d/nginx", "reload"])
|
||||
|
||||
|
||||
def removeSSLConfig(self):
|
||||
index = 0
|
||||
with open(self.nginxConf, "w") as out:
|
||||
for line in self.lines:
|
||||
if index == self.serverBlockIndex:
|
||||
line = "\t\tlisten\t1471;\n"
|
||||
|
||||
if index > self.serverBlockIndex:
|
||||
if "ssl_certificate" in line or "ssl_protocols" in line:
|
||||
continue
|
||||
|
||||
index = index + 1
|
||||
out.write(line)
|
||||
|
||||
call(["/etc/init.d/nginx", "reload"])
|
||||
|
||||
47
Papers/includes/scripts/cfgNginx.py
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
from cfgHelper import ConfigHelper
|
||||
|
||||
parser = argparse.ArgumentParser(description='Nginx Configuration Tool')
|
||||
parser.add_argument('-k', action='store', dest='keyName', help='Name of the keys to use for SSL configuration')
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('--add', action='store_true', dest='addSSL', help='Configure Nginx to use SSL. Requires -k to be set.')
|
||||
group.add_argument('--replace', action='store_true', dest='replaceSSL', help='Replace current SSL certificates. Requires -k to be set.')
|
||||
group.add_argument('--remove', action='store_true', dest='removeSSL', help='Remove SSL configuration from Nginx.')
|
||||
group.add_argument('--getSSLCerts', action='store_true', dest='getSSLCerts', help="Get the current certs being used for SSL in Nginx.")
|
||||
args = parser.parse_args()
|
||||
|
||||
if (args.addSSL and not args.keyName) or (args.replaceSSL and not args.keyName):
|
||||
parser.error("The option selected requires the -k option be provided as well.")
|
||||
|
||||
# Create a new instance of ConfigHelper that points to the
|
||||
# nginx SSL store (default is /etc/nginx/ssl/)
|
||||
helper = ConfigHelper()
|
||||
|
||||
# Add the configuration to the nginx config file
|
||||
if args.addSSL:
|
||||
if not helper.checkSSLCertsExist():
|
||||
print "SSL certs must first be generated"
|
||||
quit()
|
||||
|
||||
if not helper.addSSLConfig(args.keyName):
|
||||
print "An error has occurred while attempting to configure SSL"
|
||||
else:
|
||||
print "Complete"
|
||||
|
||||
elif args.replaceSSL:
|
||||
helper.replaceSSLConfig(args.keyName)
|
||||
print "Complete"
|
||||
|
||||
elif args.removeSSL:
|
||||
helper.removeSSLConfig()
|
||||
print "Complete"
|
||||
|
||||
elif args.getSSLCerts:
|
||||
if len(helper.currentSSLCerts) > 0:
|
||||
print "\n".join(helper.currentSSLCerts)
|
||||
14
Papers/includes/scripts/checkDepends.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
testZip=$(opkg list-installed | grep -w 'zip')
|
||||
testUnzip=$(opkg list-installed | grep -w 'unzip')
|
||||
|
||||
if [ -z "$testZip" ]; then
|
||||
echo "Not Installed";
|
||||
else
|
||||
if [ -z "$testUnzip" ]; then
|
||||
echo "Not Installed";
|
||||
else
|
||||
echo "Installed";
|
||||
fi
|
||||
fi
|
||||
42
Papers/includes/scripts/checkSSHKey.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Feb 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: ./checkSSHKey.sh <keydir> <opts>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-k:\tName of key to be checked';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
SSH_STORE='/pineapple/modules/Papers/includes/ssh/';
|
||||
KEY='';
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-k" ]]; then
|
||||
if [ -e "$SSH_STORE$2.pub" ]; then
|
||||
KEY=$(cat "$SSH_STORE$2.pub");
|
||||
else
|
||||
exit;
|
||||
fi
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
RES=$(cat /root/.ssh/authorized_keys | grep "$KEY")
|
||||
if [[ -z "$RES" ]]; then
|
||||
echo "FALSE";
|
||||
else
|
||||
echo "TRUE";
|
||||
fi
|
||||
12
Papers/includes/scripts/copyKeys.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
if ! cp $1.pem /etc/nginx/ssl/; then
|
||||
echo "Failed to copy $1.pem to /etc/nginx/ssl/";
|
||||
fi
|
||||
|
||||
if ! cp $1.cer /etc/nginx/ssl/; then
|
||||
echo "Failed to copy $1.cer to /etc/nginx/ssl/";
|
||||
fi
|
||||
110
Papers/includes/scripts/encryptKeys.sh
Executable file
@@ -0,0 +1,110 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
# Location of SSL keys
|
||||
ssl_store="/pineapple/modules/Papers/includes/ssl/";
|
||||
|
||||
help() {
|
||||
echo "Encryption/Export script for OpenSSL certificates";
|
||||
echo "Usage: ./encryptKeys.sh <opts>";
|
||||
echo "Use './encryptKeys.sh --examples' to see example commands";
|
||||
echo '';
|
||||
echo 'NOTE:';
|
||||
echo "Current SSL store is at $ssl_store";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-k:\tName of key to be encrypted';
|
||||
echo '';
|
||||
echo 'Encryption Options:';
|
||||
echo '';
|
||||
echo -e '\t--encrypt:\tMust be supplied to encrypt keys';
|
||||
echo -e '\t-a:\t\tAlgorithm to use for key encryption (aes256, 3des, camellia256, etc)';
|
||||
echo -e '\t-p:\t\tPassword to use for encryption';
|
||||
echo '';
|
||||
echo 'Container Options:';
|
||||
echo '';
|
||||
echo -e '\t-c:\tContainer type (pkcs12, pkcs8)';
|
||||
echo -e '\t-calgo:\tEncyrption algorithm for container. (Default is the value supplied for -a)';
|
||||
echo -e '\t-cpass:\tPassword for container. (Default is the password supplied for -p)';
|
||||
echo '';
|
||||
}
|
||||
|
||||
examples() {
|
||||
echo '';
|
||||
echo 'Examples:';
|
||||
echo 'Encrypt private key:';
|
||||
echo './encryptKeys.sh -k keyName --encrypt -a aes256 -p password';
|
||||
echo '';
|
||||
echo 'Export keys to PKCS#12 container:';
|
||||
echo './encryptKeys.sh -k keyName -c pkcs12 -calgo aes256 -cpass password';
|
||||
echo '';
|
||||
echo 'Encrypt private key and export to PKCS#12 container using same algo and pass:';
|
||||
echo './encryptKeys.sh -k keyName --encrypt -a aes256 -p password -c pkcs12';
|
||||
echo '';
|
||||
echo 'Encrypt private key and export to PKCS#12 container using different algo and pass:';
|
||||
echo './encryptKeys.sh -k keyName --encrypt -a aes256 -p password -c pkcs12 -calgo camellia256 -cpass diffpass';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
ENCRYPT_KEYS=false;
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "--examples" ]]; then
|
||||
examples;
|
||||
exit;
|
||||
fi
|
||||
if [[ "$1" == "--encrypt" ]]; then
|
||||
ENCRYPT_KEYS=true;
|
||||
fi
|
||||
if [[ "$1" == "-a" ]]; then
|
||||
ALGO="$2";
|
||||
fi
|
||||
if [[ "$1" == "-k" ]]; then
|
||||
KEY="$2";
|
||||
fi
|
||||
if [[ "$1" == "-p" ]]; then
|
||||
PASS="$2";
|
||||
fi
|
||||
if [[ "$1" == "-c" ]]; then
|
||||
CONTAINER="$2";
|
||||
fi
|
||||
if [[ "$1" == "-calgo" ]]; then
|
||||
CALGO="$2";
|
||||
fi
|
||||
if [[ "$1" == "-cpass" ]]; then
|
||||
CPASS="$2";
|
||||
fi
|
||||
|
||||
shift
|
||||
done;
|
||||
|
||||
# Generate a password on the private key
|
||||
if [ $ENCRYPT_KEYS = true ]; then
|
||||
openssl rsa -$ALGO -in $ssl_store$KEY.pem -out $ssl_store$KEY.pem -passout pass:"$PASS";
|
||||
fi
|
||||
|
||||
# If a container type is present but not an algo or pass then use
|
||||
# the same algo and pass from the private key
|
||||
if [ -n "$CONTAINER" ]; then
|
||||
if [ -z "$CALGO" ]; then
|
||||
CALGO="$ALGO";
|
||||
fi
|
||||
if [ -z "$CPASS" ]; then
|
||||
CPASS="$PASS";
|
||||
fi
|
||||
|
||||
# Generate a container for the public and private keys
|
||||
openssl $CONTAINER -$CALGO -export -nodes -out $ssl_store$KEY.pfx -inkey $ssl_store$KEY.pem -in $ssl_store$KEY.cer -passin pass:"$PASS" -passout pass:"$CPASS";
|
||||
fi
|
||||
|
||||
echo "Complete"
|
||||
59
Papers/includes/scripts/genSSHKeys.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: ./genSSHKeys.sh <opts>";
|
||||
echo '';
|
||||
echo 'Required Parameters:';
|
||||
echo -e '\t-k,--keyName:\tName of exported key files';
|
||||
echo '';
|
||||
echo 'Optional Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-b,--bitSize:\tBitsize of keys (Default: 2048)';
|
||||
echo -e '\t-p,--pass:\tPassword for private key';
|
||||
echo -e '\t-c,--comment:\tInclude a comment in the public key (Default: root@Pineapple)';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
# Defaults
|
||||
BITSIZE=2048;
|
||||
PASSWORD='';
|
||||
SSH_STORE="/pineapple/modules/Papers/includes/ssh/";
|
||||
COMMENT='root@Pineapple';
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-k" || "$1" == "--keyName" ]]; then
|
||||
KEYNAME="$2";
|
||||
fi
|
||||
|
||||
if [[ "$1" == "-b" || "$1" == "--bitSize" ]]; then
|
||||
BITSIZE="$2";
|
||||
fi
|
||||
|
||||
if [[ "$1" == "-p" || "$1" == "--pass" ]]; then
|
||||
PASSWORD="$2";
|
||||
fi
|
||||
|
||||
if [[ "$1" == "-c" || "$1" == "--comment" ]]; then
|
||||
COMMENT="$2"
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ -z $KEYNAME ]]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
ssh-keygen -q -b $BITSIZE -t rsa -N "$PASSWORD" -f $SSH_STORE$KEYNAME.pem -C $COMMENT
|
||||
mv $SSH_STORE$KEYNAME.pem.pub $SSH_STORE$KEYNAME.pub
|
||||
8
Papers/includes/scripts/installDepends.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
opkg update > /dev/null;
|
||||
opkg install zip unzip > /dev/null;
|
||||
echo "Complete"
|
||||
49
Papers/includes/scripts/packKeys.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: ./packKeys.sh <keydir> <opts>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\tkeydir:\tDirectory where the key resides';
|
||||
echo -e '\t-f:\tFile names as string value';
|
||||
echo -e '\t-o:\tName of output file';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
# Define and clear out the download directory
|
||||
DL_DIR="/pineapple/modules/Papers/includes/download/";
|
||||
rm -rf $DL_DIR*
|
||||
|
||||
# Get the key directory and shift it out of the argument vectors
|
||||
KEY_DIR="$1";
|
||||
shift;
|
||||
|
||||
FILES='';
|
||||
OUTPUT='';
|
||||
export IFS=" ";
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-f" ]]; then
|
||||
for word in $2; do
|
||||
FILES="$FILES $KEY_DIR$word";
|
||||
done
|
||||
fi
|
||||
if [[ "$1" == "-o" ]]; then
|
||||
OUTPUT="$2";
|
||||
fi
|
||||
|
||||
shift
|
||||
done;
|
||||
|
||||
zip -j $DL_DIR$OUTPUT $FILES > /dev/null;
|
||||
18
Papers/includes/scripts/readKeys.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: April 6, 2016
|
||||
|
||||
IN_SERVER_BLOCK=false;
|
||||
|
||||
while read p; do
|
||||
if [[ $IN_SERVER_BLOCK == false ]]; then
|
||||
if [[ $p == *"listen"* && $p == *"1471"* ]]; then
|
||||
IN_SERVER_BLOCK=true;
|
||||
fi
|
||||
else
|
||||
if [[ $p == *".cer;" || $p == *".pem;" ]]; then
|
||||
echo $p | cut -d '/' -f 5 | tr -d ';';
|
||||
fi
|
||||
fi
|
||||
done < /etc/nginx/nginx.conf
|
||||
6
Papers/includes/scripts/removeDepends.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
opkg remove zip unzip > /dev/null;
|
||||
11
Papers/includes/scripts/removeKeys.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
SSL_DIR="/etc/nginx/ssl/";
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
rm -rf $SSL_DIR$1;
|
||||
shift;
|
||||
done
|
||||
34
Papers/includes/scripts/revokeSSHKey.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Feb 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: ./revokeSSHKey.sh <keydir> <opts>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-k:\tName of key to be revoked';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
SSH_STORE='/pineapple/modules/Papers/includes/ssh/';
|
||||
KEY='';
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-k" ]]; then
|
||||
KEY=$(cat "$SSH_STORE$2.pub");
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
# Revoke the key from /root/.ssh/authorized_keys
|
||||
grep -v "$KEY" /root/.ssh/authorized_keys > /root/.ssh/authorized_keys.new; mv /root/.ssh/authorized_keys.new /root/.ssh/authorized_keys
|
||||
35
Papers/includes/scripts/testEncrypt.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
|
||||
help() {
|
||||
echo "Usage: ./testEncrypt.sh <opts>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-d:\tDirectory where key resides';
|
||||
echo -e '\t-k:\tName of key to test';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
KEY=''
|
||||
KEYDIR=''
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-k" ]]; then
|
||||
KEY="$2.pem"
|
||||
fi
|
||||
if [[ "$1" == "-d" ]]; then
|
||||
KEYDIR="$2"
|
||||
fi
|
||||
|
||||
shift
|
||||
done;
|
||||
|
||||
openssl rsa -in $KEYDIR$KEY -passin pass: | awk 'NR==0;'
|
||||
53
Papers/includes/scripts/unpackKeyArchive.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Sept 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: ./unpackKeyArchive.sh -f <fileName>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-f:\tFile name without extension';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
# Define and clear out the download directory
|
||||
DL_DIR="/pineapple/modules/Papers/includes/upload/";
|
||||
|
||||
FILE='';
|
||||
export IFS=" ";
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-f" ]]; then
|
||||
FILE="$DL_DIR$2"
|
||||
fi
|
||||
|
||||
shift
|
||||
done;
|
||||
|
||||
output=$(unzip $FILE.zip -d $DL_DIR);
|
||||
|
||||
# If the archive contained a .pub these
|
||||
# keys are destined for the SSH directory
|
||||
if [[ $output == *".pub"* ]]; then
|
||||
mv $FILE.pub /pineapple/modules/Papers/includes/ssh/
|
||||
mv $FILE.pem /pineapple/modules/Papers/includes/ssh/
|
||||
fi
|
||||
|
||||
# If the archive contained a .cer these
|
||||
# keys are destined for the SSL directory
|
||||
if [[ $output == *".cer"* ]]; then
|
||||
mv $FILE.cer /pineapple/modules/Papers/includes/ssl/
|
||||
mv $FILE.pem /pineapple/modules/Papers/includes/ssl/
|
||||
fi
|
||||
|
||||
# Clear the download directory
|
||||
rm -rf $DL_DIR*
|
||||
419
Papers/js/module.js
Executable file
@@ -0,0 +1,419 @@
|
||||
registerController('PapersController', ['$api', '$scope', '$sce', '$http', function($api, $scope, $sce, $http) {
|
||||
|
||||
$scope.certKeyType = "tls_ssl";
|
||||
$scope.certKeyComment = "";
|
||||
$scope.certBitSize = "2048";
|
||||
$scope.certDaysValid = "365";
|
||||
$scope.certSigAlgo = "sha256";
|
||||
$scope.certKeyName = "";
|
||||
$scope.modifyCertInfo = false;
|
||||
$scope.certInfoCountry = "";
|
||||
$scope.certInfoState = "";
|
||||
$scope.certInfoLocality = "";
|
||||
$scope.certInfoOrganization = "";
|
||||
$scope.certInfoSection = "";
|
||||
$scope.certInfoCN = "";
|
||||
$scope.certEncryptKeysBool = false;
|
||||
$scope.certEncryptAlgo = "aes256";
|
||||
$scope.certEncryptPassword = "";
|
||||
$scope.certExportPKCS12 = false;
|
||||
$scope.certEncryptPKCS12Algo = "aes256";
|
||||
$scope.certContainerPassword = "";
|
||||
$scope.certificates = "";
|
||||
$scope.SSLStatus = ['Loading...'];
|
||||
$scope.showCertThrobber = false;
|
||||
$scope.showBuildThrobber = false;
|
||||
$scope.showRemoveSSLButton = true;
|
||||
$scope.showUnSSLThrobber = false;
|
||||
$scope.logs = "";
|
||||
$scope.changelogs = "";
|
||||
$scope.currentLogTitle = "";
|
||||
$scope.currentLogData = "";
|
||||
$scope.dependsInstalled = true;
|
||||
$scope.dependsProcessing = false;
|
||||
$scope.selectedFiles = [];
|
||||
$scope.uploading = false;
|
||||
|
||||
$scope.checkDepends = (function(){
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'checkDepends'
|
||||
},function(response){
|
||||
if (response.success === true) {
|
||||
$scope.dependsInstalled = true;
|
||||
} else {
|
||||
$scope.dependsInstalled = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.installDepends = (function(){
|
||||
$scope.dependsProcessing = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'installDepends'
|
||||
},function(response){
|
||||
$scope.checkDepends();
|
||||
if (response.success === false) {
|
||||
alert("Failed to install dependencies. Make sure you are connected to the internet.");
|
||||
}
|
||||
$scope.dependsProcessing = false;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.removeDepends = (function(){
|
||||
$scope.dependsProcessing = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'removeDepends'
|
||||
},function(response){
|
||||
$scope.checkDepends();
|
||||
$scope.dependsProcessing = false;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.buildCertificate = (function() {
|
||||
var params = {};
|
||||
|
||||
if ($scope.certKeyName != ''){
|
||||
params['keyName'] = $scope.certKeyName;
|
||||
} else {
|
||||
alert("You must enter a name for the keys!");
|
||||
return;
|
||||
}
|
||||
|
||||
params['bitSize'] = $scope.certBitSize;
|
||||
|
||||
if ($scope.certKeyType == "ssh") {
|
||||
if ($scope.certEncryptKeysBool) {
|
||||
if (!$scope.certEncryptPassword) {
|
||||
alert("You must enter a password for the private key");
|
||||
return;
|
||||
}
|
||||
params['pass'] = $scope.certEncryptPassword;
|
||||
}
|
||||
if ($scope.certKeyComment != "") {
|
||||
params['comment'] = $scope.certKeyComment;
|
||||
}
|
||||
$scope.showBuildThrobber = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'genSSHKeys',
|
||||
parameters: params
|
||||
},function(response){
|
||||
$scope.getLogs();
|
||||
$scope.showBuildThrobber = false;
|
||||
$scope.loadCertificates();
|
||||
$api.reloadNavbar();
|
||||
});
|
||||
} else if ($scope.certKeyType == "tls_ssl") {
|
||||
params['sigalgo'] = $scope.certSigAlgo;
|
||||
|
||||
if ($scope.certInfoCountry != ''){
|
||||
params['country'] = $scope.certInfoCountry;
|
||||
}
|
||||
if ($scope.certInfoState != '') {
|
||||
params['state'] = $scope.certInfoState;
|
||||
}
|
||||
if ($scope.certInfoLocality != ''){
|
||||
params['city'] = $scope.certInfoLocality;
|
||||
}
|
||||
if ($scope.certInfoOrganization != ''){
|
||||
params['organization'] = $scope.certInfoOrganization;
|
||||
}
|
||||
if ($scope.certInfoSection != ''){
|
||||
params['section'] = $scope.certInfoSection;
|
||||
}
|
||||
if ($scope.certInfoCN != ''){
|
||||
params['commonName'] = $scope.certInfoCN;
|
||||
}
|
||||
if ($scope.certDaysValid != ''){
|
||||
params['days'] = $scope.certDaysValid;
|
||||
}
|
||||
if ($scope.certEncryptKeysBool === true) {
|
||||
params['encrypt'] = "";
|
||||
params['algo'] = $scope.certEncryptAlgo;
|
||||
if (!$scope.certEncryptPassword) {
|
||||
alert("You must set a password for the private key!");
|
||||
return;
|
||||
}
|
||||
params['pkey_pass'] = $scope.certEncryptPassword;
|
||||
}
|
||||
if ($scope.certExportPKCS12 === true) {
|
||||
params['container'] = "pkcs12";
|
||||
params['c_algo'] = $scope.certEncryptPKCS12Algo;
|
||||
if (!$scope.certContainerPassword) {
|
||||
alert("You must enter a password for the exported container!");
|
||||
return;
|
||||
}
|
||||
params['c_pass'] = $scope.certContainerPassword;
|
||||
}
|
||||
|
||||
$scope.showBuildThrobber = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'buildCert',
|
||||
parameters: params
|
||||
},function(response) {
|
||||
$scope.getLogs();
|
||||
$scope.showBuildThrobber = false;
|
||||
$scope.loadCertificates();
|
||||
$api.reloadNavbar();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$scope.clearForm = (function() {
|
||||
$scope.certKeyType = "tls_ssl";
|
||||
$scope.certDaysValid = "365";
|
||||
$scope.certBitSize = "2048";
|
||||
$scope.certSigAlgo = "sha256";
|
||||
$scope.certKeyName = "";
|
||||
$scope.certInfoCountry = "";
|
||||
$scope.certInfoState = "";
|
||||
$scope.certInfoLocality = "";
|
||||
$scope.certInfoOrganization = "";
|
||||
$scope.certInfoSection = "";
|
||||
$scope.certInfoCN = "";
|
||||
$scope.certEncryptKeysBool = false;
|
||||
$scope.certEncryptAlgo = "aes256";
|
||||
$scope.certEncryptPassword = "";
|
||||
$scope.certExportPKCS12 = false;
|
||||
$scope.certEncryptPKCS12Algo = "aes256";
|
||||
$scope.certContainerPassword = "";
|
||||
});
|
||||
|
||||
$scope.loadCertificates = (function() {
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'loadCertificates'
|
||||
},function(response){
|
||||
if (response.success === true) {
|
||||
// Display certificate information
|
||||
$scope.certificates = response.data;
|
||||
} else {
|
||||
// Display error
|
||||
console.log("Failed to load certificates.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.downloadKeys = (function(name,type) {
|
||||
$scope.showCertThrobber = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'downloadKeys',
|
||||
parameters: {name,type}
|
||||
},function(response){
|
||||
$scope.showCertThrobber = false;
|
||||
if (response.success === true) {
|
||||
window.location = '/api/?download=' + response.data;
|
||||
} else {
|
||||
console.log(response.message);
|
||||
}
|
||||
// Clear the download archive to keep things clean
|
||||
//$scope.clearDownloadArchive();
|
||||
});
|
||||
});
|
||||
|
||||
$scope.clearDownloadArchive = (function(){
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'clearDownloadArchive'
|
||||
},function(response) {
|
||||
if (response.success === false) {
|
||||
console.log(response.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.deleteKeys = (function(cert,type) {
|
||||
if (confirm("Confirm key deletion by pressing OK") == false) {return;}
|
||||
$scope.showCertThrobber = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'removeCertificate',
|
||||
params: {cert,type}
|
||||
},function(response){
|
||||
$scope.showCertThrobber = false;
|
||||
$scope.getLogs();
|
||||
if (response.success === true) {
|
||||
$scope.loadCertificates();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.securePineapple = (function(cert,type) {
|
||||
$scope.showCertThrobber = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'securePineapple',
|
||||
params: {cert,type}
|
||||
},function(response) {
|
||||
$scope.showCertThrobber = false;
|
||||
if (response.success === true) {
|
||||
// Redirect if key type is TLS/SSL
|
||||
if (type == "TLS/SSL") {
|
||||
$scope.redirect("https");
|
||||
}
|
||||
} else {
|
||||
// Alert error
|
||||
alert(response.message);
|
||||
}
|
||||
$scope.loadCertificates();
|
||||
});
|
||||
});
|
||||
|
||||
$scope.revokeSSHKey = (function(name){
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'revokeSSHKey',
|
||||
key: name
|
||||
},function(response) {
|
||||
$scope.loadCertificates();
|
||||
});
|
||||
});
|
||||
|
||||
$scope.redirect = (function(proto){
|
||||
loc = window.location.href.split(":");
|
||||
if (loc[0] == proto) {
|
||||
alert("Success! Refreshing your browser now!");
|
||||
window.location.reload();
|
||||
} else {
|
||||
loc[0] = proto;
|
||||
alert("Success! Redirecting to " + loc.join(":") + "!");
|
||||
window.location = loc.join(":");
|
||||
}
|
||||
});
|
||||
|
||||
$scope.unSSLPineapple = (function(){
|
||||
$scope.showRemoveSSLButton = false;
|
||||
$scope.showUnSSLThrobber = true;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'unSSLPineapple'
|
||||
},function(response){
|
||||
$scope.showUnSSLThrobber = false;
|
||||
$scope.showRemoveSSLButton = true;
|
||||
$scope.refresh();
|
||||
|
||||
if (response.success === true) {
|
||||
$scope.redirect("http");
|
||||
} else {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.getNginxSSLCerts = (function(){
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'getNginxSSLCerts'
|
||||
},function(response){
|
||||
if (response.success === true) {
|
||||
$scope.SSLStatus = response.data;
|
||||
} else {
|
||||
$scope.SSLStatus = response.message;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.getLogs = (function(){
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'getLogs',
|
||||
type: 'error'
|
||||
},function(response){
|
||||
$scope.logs = response.data;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.getChangeLogs = (function(){
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'getLogs',
|
||||
type: 'changelog'
|
||||
},function(response){
|
||||
$scope.changelogs = response.data;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.readLog = (function(log,type){
|
||||
$scope.currentLogTitle = log;
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'readLog',
|
||||
parameters: log,
|
||||
type: type
|
||||
},function(response){
|
||||
if (response.success === true) {
|
||||
$scope.currentLogData = $sce.trustAsHtml(response.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.deleteLog = (function(log){
|
||||
$api.request({
|
||||
module: 'Papers',
|
||||
action: 'deleteLog',
|
||||
parameters: log
|
||||
},function(response){
|
||||
$scope.getLogs();
|
||||
if (response === false) {
|
||||
alert(response.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.refresh = (function(){
|
||||
$scope.getLogs();
|
||||
$scope.getChangeLogs();
|
||||
$scope.clearDownloadArchive();
|
||||
$scope.getNginxSSLCerts();
|
||||
$scope.loadCertificates();
|
||||
});
|
||||
|
||||
// Upload functions
|
||||
$scope.setSelectedFiles = (function(){
|
||||
files = document.getElementById("selectedFiles").files;
|
||||
for (var x = 0; x < files.length; x++) {
|
||||
$scope.selectedFiles.push(files[x]);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.removeSelectedFile = (function(file){
|
||||
var x = $scope.selectedFiles.length;
|
||||
while (x--) {
|
||||
if ($scope.selectedFiles[x] === file) {
|
||||
$scope.selectedFiles.splice(x,1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.uploadFile = (function(){
|
||||
$scope.uploading = true;
|
||||
|
||||
var fd = new FormData();
|
||||
for (x = 0; x < $scope.selectedFiles.length; x++) {
|
||||
fd.append($scope.selectedFiles[x].name, $scope.selectedFiles[x]);
|
||||
}
|
||||
$http.post("/modules/Papers/api/module.php", fd, {
|
||||
transformRequest: angular.identity,
|
||||
headers: {'Content-Type': undefined}
|
||||
}).success(function(response) {
|
||||
for (var key in response) {
|
||||
if (response.hasOwnProperty(key)) {
|
||||
if (response.key == "Failed") {
|
||||
alert("Failed to upload " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
$scope.selectedFiles = [];
|
||||
$scope.refresh();
|
||||
$scope.uploading = false;
|
||||
});
|
||||
});
|
||||
|
||||
// Init
|
||||
$scope.checkDepends();
|
||||
$scope.refresh();
|
||||
}])
|
||||
419
Papers/module.html
Executable file
@@ -0,0 +1,419 @@
|
||||
<!-- Papers by sud0nick (C) 2016 -->
|
||||
<style>
|
||||
.form-horizontal .control-label {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
$(document).on('mouseenter', '.papers_hoverSuccess', function() {
|
||||
$(this).addClass("btn-success");
|
||||
}).on('mouseleave', '.papers_hoverSuccess', function(){
|
||||
$(this).removeClass("btn-success");
|
||||
});
|
||||
|
||||
$(document).on('mouseenter', '.papers_hoverPrimary', function() {
|
||||
$(this).addClass("btn-primary");
|
||||
}).on('mouseleave', '.papers_hoverPrimary', function(){
|
||||
$(this).removeClass("btn-primary");
|
||||
});
|
||||
|
||||
$(document).on('mouseenter', '.papers_hoverInfo', function() {
|
||||
$(this).addClass("btn-info");
|
||||
}).on('mouseleave', '.papers_hoverInfo', function(){
|
||||
$(this).removeClass("btn-info");
|
||||
});
|
||||
|
||||
$(document).on('mouseenter', '.papers_hoverDanger', function() {
|
||||
$(this).addClass("btn-danger");
|
||||
}).on('mouseleave', '.papers_hoverDanger', function(){
|
||||
$(this).removeClass("btn-danger");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div class="row" ng-controller="PapersController">
|
||||
<div class="col-md-12">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<table style="width: 100%">
|
||||
<tr><td align="left">
|
||||
<h3 class="panel-title">Papers Status</h3>
|
||||
</td><td align="right">
|
||||
<span class="panel-title">
|
||||
<button type="button" class="btn btn-success" ng-show="showRemoveSSLButton" ng-hide="!showRemoveSSLButton" ng-click="unSSLPineapple();">Remove SSL</button>
|
||||
<img ng-show="showUnSSLThrobber" ng-hide="!showUnSSLThrobber" src='/img/throbber.gif'/>
|
||||
</span>
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
<table style="width: 100%">
|
||||
<tr><td>
|
||||
<strong>SSL Certificate and Private Key</strong>
|
||||
</td><td align="right">
|
||||
<button type="button" class="btn" data-toggle="modal" data-target="#viewLogInfo" ng-click="readLog('status.help','help');">?</button>
|
||||
</td></tr>
|
||||
</table>
|
||||
<div ng-repeat="cert in SSLStatus">
|
||||
{{ cert }}
|
||||
</div>
|
||||
</div><br />
|
||||
<div>
|
||||
<strong>Dependencies</strong><br />
|
||||
<button type="button" class="btn btn-success" ng-show="!dependsInstalled" ng-disabled="dependsProcessing" ng-hide="dependsInstalled" ng-click="installDepends();"><img src="/modules/Papers/includes/icons/glyphicons-182-download-alt.png"/> Install</button>
|
||||
<button type="button" class="btn papers_hoverDanger" ng-show="dependsInstalled" ng-disabled="dependsProcessing" ng-hide="!dependsInstalled" ng-click="removeDepends();"><img src="/modules/Papers/includes/icons/glyphicons-198-remove-circle.png"/> Uninstall</button>
|
||||
<img ng-show="dependsProcessing" ng-hide="!dependsProcessing" src='/img/throbber.gif'/>
|
||||
</div><br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<table style="width: 100%">
|
||||
<tr><td align="left">
|
||||
<h3 class="panel-title">Certificate Store</h3>
|
||||
</td><td align="right">
|
||||
<img ng-show="showCertThrobber" ng-hide="!showCertThrobber" src='/img/throbber.gif'/>
|
||||
<button type="button" class="btn" ng-show="!showCertThrobber" ng-hide="showCertThrobber" data-toggle="modal" data-target="#viewLogInfo" ng-click="readLog('store.help','help');">?</button>
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px; margin-left: 10px">
|
||||
<button type="button" class="btn papers_hoverInfo" data-toggle="modal" data-target="#papers_uploaderView"><img src="/modules/Papers/includes/icons/glyphicons-202-upload.png"/> Upload Keys</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive table-dropdown">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Files</th>
|
||||
<th>Encrypted</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="(index,data) in certificates">
|
||||
<td>{{ data.Name }}</td>
|
||||
<td>{{ data.KeyType }}</td>
|
||||
<td>{{ data.Type }}</td>
|
||||
<td>{{ data.Encrypted }}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm papers_hoverDanger" ng-show="data.Authorized==true" ng-click="revokeSSHKey(data.Name);"><img src="/modules/Papers/includes/icons/glyphicons-205-unlock.png"/></button>
|
||||
<button type="button" class="btn btn-sm papers_hoverSuccess" ng-disabled="data.Encrypted == 'Yes' && data.KeyType == 'TLS/SSL'" ng-show="data.Authorized==false" ng-click="securePineapple(data.Name, data.KeyType);"><img src="/modules/Papers/includes/icons/glyphicons-204-lock.png"/></button>
|
||||
<button type="button" class="btn btn-sm papers_hoverInfo" ng-click="downloadKeys(data.Name, data.KeyType);"><img src="/modules/Papers/includes/icons/glyphicons-201-download.png"/></button>
|
||||
<button type="button" class="btn btn-sm papers_hoverDanger" ng-click="deleteKeys(data.Name, data.KeyType);"><img src="/modules/Papers/includes/icons/glyphicons-17-bin.png"/></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default" style="border-radius: 7px;">
|
||||
<div class="panel-heading pointer" data-toggle="collapse" data-target="#papers_certBuilder">
|
||||
<table style="width: 100%">
|
||||
<tr><td align="left">
|
||||
<h3 class="panel-title">Build Certificates</h3>
|
||||
</td><td align="right">
|
||||
<span class="panel-title">
|
||||
<img ng-show="showBuildThrobber" ng-hide="!showBuildThrobber" src='/img/throbber.gif'/>
|
||||
</span>
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-body panel-collapse collapse" id="papers_certBuilder">
|
||||
<form class="form-horizontal">
|
||||
<div style="width: 100%;">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td align="left">
|
||||
<button type="button" class="btn papers_hoverSuccess" ng-disabled="showBuildThrobber || certKeyName == ''" ng-click="buildCertificate();"><img src="/modules/Papers/includes/icons/glyphicons-45-keys.png"/> Build Keys</button>
|
||||
</td>
|
||||
<td align="right">
|
||||
<button type="button" class="btn" data-toggle="modal" data-target="#viewLogInfo" ng-click="readLog('build.help','help');">?</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Key Type</label>
|
||||
<div class="col-md-9">
|
||||
<div class="col-md-2">
|
||||
<label><input type="radio" ng-model="certKeyType" value="tls_ssl" name="certKeyType"> TLS/SSL</label>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label><input type="radio" ng-model="certKeyType" value="ssh" name="certKeyType"> SSH</label><br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Bit Size</label>
|
||||
<div class="col-md-9">
|
||||
<div class="col-md-2">
|
||||
<label><input type="radio" ng-model="certBitSize" value="2048" name="bitSize"> 2048</label>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label><input type="radio" ng-model="certBitSize" value="4096" name="bitSize"> 4096</label><br />
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label><input type="radio" ng-model="certBitSize" value="8192" name="bitSize"> 8192</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Key Pair Name</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certKeyName" placeholder="Name of exported keys">
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="form-group" ng-show="certKeyType=='ssh'" ng-hide="certKeyType=='tls_ssl'">
|
||||
<label class="col-md-2 control-label">Comment</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certKeyComment" placeholder="root@Pineapple">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
|
||||
<label class="col-md-2 control-label">Days Valid</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certDaysValid" placeholder="365">
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
|
||||
<label class="col-md-2 control-label">Signature Algorithm</label>
|
||||
<div class="col-md-8">
|
||||
<select name="sigalgo" ng-model="certSigAlgo" required>
|
||||
<option value="sha1">SHA-1</option>
|
||||
<option value="sha256">SHA-256</option>
|
||||
<option value="sha512">SHA-512</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<hr ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'" />
|
||||
<div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
|
||||
<div class="col-md-8">
|
||||
<label>Modify Certificate Info <input type="checkbox" ng-model="modifyCertInfo"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body" ng-show="modifyCertInfo" ng-hide="!modifyCertInfo">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Country</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certInfoCountry">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">State/Province</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certInfoState">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Locality</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certInfoLocality">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Organization</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certInfoOrganization">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Section</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certInfoSection">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Common Name</label>
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" ng-model="certInfoCN">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'" />
|
||||
<div class="form-group">
|
||||
<div class="col-md-8">
|
||||
<label>Encrypt Private Key? <input type="checkbox" ng-model="certEncryptKeysBool"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body" ng-show="certEncryptKeysBool" ng-hide="!certEncryptKeysBool">
|
||||
<div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
|
||||
<label class="col-md-2 control-label">Algorithm</label>
|
||||
<div class="col-md-8">
|
||||
<select name="algo" ng-model="certEncryptAlgo">
|
||||
<option value="aes128">AES 128</option>
|
||||
<option value="aes192">AES 192</option>
|
||||
<option value="aes256">AES 256</option>
|
||||
<option value="des">DES</option>
|
||||
<option value="des3">3DES</option>
|
||||
<option value="camellia128">Camellia 128</option>
|
||||
<option value="camellia192">Camellia 192</option>
|
||||
<option value="camellia256">Camellia 256</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Private Key Password</label>
|
||||
<div class="col-md-6">
|
||||
<input type="password" class="form-control" ng-model="certEncryptPassword">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
|
||||
<div class="col-md-8">
|
||||
<label>Export keys to PKCS#12 container? <input type="checkbox" ng-model="certExportPKCS12"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body" ng-show="certExportPKCS12" ng-hide="!certExportPKCS12">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Container Algorithm</label>
|
||||
<div class="col-md-8">
|
||||
<select name="containerAlgo" ng-model="certEncryptPKCS12Algo">
|
||||
<option value="aes128">AES 128</option>
|
||||
<option value="aes192">AES 192</option>
|
||||
<option value="aes256">AES 256</option>
|
||||
<option value="des">DES</option>
|
||||
<option value="des3">3DES</option>
|
||||
<option value="camellia128">Camellia 128</option>
|
||||
<option value="camellia192">Camellia 192</option>
|
||||
<option value="camellia256">Camellia 256</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Container Password</label>
|
||||
<div class="col-md-6">
|
||||
<input type="password" class="form-control" ng-model="certContainerPassword">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button type="button" class="btn papers_hoverInfo" ng-click="clearForm();"><img src="/modules/Papers/includes/icons/glyphicons-198-remove-circle.png"/> Clear Form</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="viewLogInfo" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h3>{{ currentLogTitle }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p ng-bind-html="currentLogData"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading pointer" data-toggle="collapse" data-target="#papers_errorLogs">
|
||||
<h3 class="panel-title">Error Logs</h3>
|
||||
</div>
|
||||
<div class="panel-body panel-collapse collapse" id="papers_errorLogs">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Log Name</th>
|
||||
<th>Actions</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="log in logs">
|
||||
<td>{{ log }}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-info" data-toggle="modal" data-target="#viewLogInfo" ng-click="readLog(log, 'error');">View</button>
|
||||
<button type="button" class="btn btn-sm btn-danger" ng-click="deleteLog(log);">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading pointer" data-toggle="collapse" data-target="#papers_changelog">
|
||||
<h3 class="panel-title">Change Log</h3>
|
||||
</div>
|
||||
<div id="papers_changelog" class="panel-body panel-collapse collapse">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th>Actions</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="version in changelogs">
|
||||
<td>{{ version }}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm papers_hoverInfo" data-toggle="modal" data-target="#viewLogInfo" ng-click="readLog(version, 'changelog');">View</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="papers_uploaderView" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<div class="btn btn-primary">
|
||||
<label for="selectedFiles" style="cursor: pointer">Add files</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>File</th>
|
||||
<th>Actions</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="file in selectedFiles">
|
||||
<td>{{ file.name }}</td>
|
||||
<td><button class="btn papers_hoverDanger" ng-click="removeSelectedFile(file);"><img src="/modules/Papers/includes/icons/glyphicons-17-bin.png"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div style="text-align:center">
|
||||
<input type="file" accept=".zip" id="selectedFiles" onchange="angular.element(this).scope().setSelectedFiles()" style="visibility: hidden;" multiple>
|
||||
<img ng-show="uploading" ng-hide="!uploading" src='/img/throbber.gif'/>
|
||||
<button class="btn" ng-show="!uploading" ng-hide="uploading" ng-class="{'papers_hoverInfo' : selectedFiles.length > 0}" ng-disabled="selectedFiles.length == 0" ng-click="uploadFile();"><img src="/modules/Papers/includes/icons/glyphicons-202-upload.png"/> Upload</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
10
Papers/module.info
Executable file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"author": "sud0nick",
|
||||
"description": "A TLS/SSL and SSH certificate generator/manager.",
|
||||
"devices": [
|
||||
"nano",
|
||||
"tetra"
|
||||
],
|
||||
"title": "Papers",
|
||||
"version": "1.4"
|
||||
}
|
||||