mirror of
https://github.com/hak5/nano-tetra-modules.git
synced 2025-10-29 16:58:09 +00:00
New Module: Themes
This commit is contained in:
565
Themes/api/module.php
Normal file
565
Themes/api/module.php
Normal file
@@ -0,0 +1,565 @@
|
||||
<?php namespace pineapple;
|
||||
|
||||
class Themes extends Module
|
||||
{
|
||||
// CONSTANTS
|
||||
private $MODULE_DIR = '/pineapple/modules/Themes/';
|
||||
private $CSS_DIR = '/pineapple/modules/Themes/css/';
|
||||
private $SKELETON_CSS = '/pineapple/modules/Themes/css/main.css';
|
||||
private $CURRENT_CSS = '/pineapple/modules/Themes/css/CURRENT_CSS';
|
||||
private $CURRENT_LOGO = '/pineapple/modules/Themes/img/CURRENT_LOGO';
|
||||
private $CURRENT_THROBBER = '/pineapple/modules/Themes/img/CURRENT_THROBBER';
|
||||
private $CURRENT_FAVICON = '/pineapple/modules/Themes/img/CURRENT_FAVICON';
|
||||
private $CURRENT_DASHBOARD = '/pineapple/modules/Themes/img/CURRENT_DASHBOARD';
|
||||
private $BACKUP_MAIN_CSS = '/pineapple/css/.backup.main.css';
|
||||
private $BACKUP_FAVICON = '/pineapple/img/.backup.favicon.ico';
|
||||
private $BACKUP_THROBBER = '/pineapple/img/.backup.throbber.gif';
|
||||
private $BACKUP_LOGO = '/pineapple/img/.backup.logo.png';
|
||||
private $BACKUP_DASHBOARD = '/pineapple/modules/Dashboard/.backup.module_icon.svg';
|
||||
|
||||
private $current_theme = "";
|
||||
|
||||
/*
|
||||
* Static list of all module names
|
||||
* from here we can grab the CURRENT file, and the module directory
|
||||
*/
|
||||
private $ALL_MODULES = array(
|
||||
"Dashboard",
|
||||
"Recon",
|
||||
"Profiling",
|
||||
"Clients",
|
||||
"ModuleManager",
|
||||
"Filters",
|
||||
"PineAP",
|
||||
"Tracking",
|
||||
"Logging",
|
||||
"Reporting",
|
||||
"Networking",
|
||||
"Configuration",
|
||||
"Advanced",
|
||||
"Help",
|
||||
);
|
||||
/*
|
||||
* Faster to map Hex values then to calculate on the fly
|
||||
*/
|
||||
private $WHITE_HEX = 'ffffff';
|
||||
private $RESTORE_HEX = '808080';
|
||||
private $NORMAL_COLOR_HEX_MAP = array(
|
||||
"red" => "FF0000",
|
||||
"green" => "00FF00",
|
||||
"blue" => "0000FF",
|
||||
"purple" => "800080",
|
||||
"orange" => "cc3300",
|
||||
"yellow" => "ffff00",
|
||||
"pink" => "ff0066",
|
||||
);
|
||||
private $LIGHT_COLOR_HEX_MAP = array(
|
||||
"red" => "ff4d4d",
|
||||
"green" => "80ff80",
|
||||
"blue" => "8080ff",
|
||||
"purple" => "ff66ff",
|
||||
"orange" => "ff9f80",
|
||||
"yellow" => "ffff66",
|
||||
"pink" => "ff99c2",
|
||||
);
|
||||
private $DARK_COLOR_HEX_MAP = array(
|
||||
"red" => "990000",
|
||||
"green" => "004d00",
|
||||
"blue" => "000077",
|
||||
"purple" => "4d004d",
|
||||
"orange" => "992600",
|
||||
"yellow" => "cccc00",
|
||||
"pink" => "99003d",
|
||||
);
|
||||
|
||||
public function route()
|
||||
{
|
||||
switch ($this->request->action) {
|
||||
case 'getThemeList':
|
||||
$this->handleGetThemeList();
|
||||
break;
|
||||
case 'themeFields':
|
||||
$this->getThemeFields();
|
||||
break;
|
||||
case 'deleteTheme':
|
||||
$this->handleDeleteTheme();
|
||||
break;
|
||||
case 'activateTheme':
|
||||
$this->activateTheme();
|
||||
break;
|
||||
case 'getThemeCode':
|
||||
$this->getThemeCode();
|
||||
break;
|
||||
case 'submitThemeCode':
|
||||
$this->submitThemeCode();
|
||||
break;
|
||||
case 'getCurrentTheme':
|
||||
$this->getCurrentTheme();
|
||||
break;
|
||||
case 'createNewTheme':
|
||||
$this->handleCreateNewTheme();
|
||||
break;
|
||||
case 'restoreDefault':
|
||||
$this->restoreDefault();
|
||||
break;
|
||||
case 'backupFiles':
|
||||
$this->backupFiles();
|
||||
break;
|
||||
case 'replaceImage':
|
||||
$this->replaceImage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Get the CURRENT_<MODULE_ICON> file, which is 1 line with the current color of the icon
|
||||
public function currentFile($name)
|
||||
{
|
||||
$upper = strtoupper($name);
|
||||
return "/pineapple/modules/Themes/img/CURRENT_{$upper}";
|
||||
}
|
||||
// Move an image from light->dark or vice versa
|
||||
public function replaceImage()
|
||||
{
|
||||
$img = $this->request->img;
|
||||
switch ($img)
|
||||
{
|
||||
// Pineapple Logo
|
||||
case 'Logo':
|
||||
$this->response = array("message" => "Logo Changed");
|
||||
if ($this->request->light) {
|
||||
exec("cp $this->BACKUP_LOGO /pineapple/img/logo.png");
|
||||
exec("echo light > $this->CURRENT_LOGO");
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("echo dark > $this->CURRENT_LOGO");
|
||||
exec('cp /pineapple/modules/Themes/img/logo-dark.png /pineapple/img/logo.png');
|
||||
}
|
||||
$this->response = array("message" => "Logo Changed");
|
||||
break;
|
||||
|
||||
// Pineapple favicon.ico Image
|
||||
case 'Icon':
|
||||
if ($this->request->light) {
|
||||
exec("echo light > $this->CURRENT_FAVICON");
|
||||
exec("cp $this->BACKUP_FAVICON /pineapple/img/favicon.ico");
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("echo dark > $this->CURRENT_FAVICON");
|
||||
exec('cp /pineapple/modules/Themes/img/favicon-dark.ico /pineapple/img/favicon.ico');
|
||||
}
|
||||
$this->response = array("message" => "Icon Changed");
|
||||
break;
|
||||
|
||||
// Pineapple Throbber gif
|
||||
case 'Throbber':
|
||||
if ($this->request->light) {
|
||||
exec("echo light > $this->CURRENT_THROBBER");
|
||||
exec("cp $this->BACKUP_THROBBER /pineapple/img/throbber.gif");
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("echo dark > $this->CURRENT_THROBBER");
|
||||
exec('cp /pineapple/modules/Themes/img/throbber-dark.gif /pineapple/img/throbber.gif');
|
||||
}
|
||||
$this->response = array("message" => "Throbber Changed");
|
||||
break;
|
||||
|
||||
// Modify all of the module Icons
|
||||
case 'All':
|
||||
foreach ($this->ALL_MODULES as $module)
|
||||
{
|
||||
$current = $this->currentFile($module);
|
||||
$success = $this->replaceModuleImage(
|
||||
$module,
|
||||
$this->request->color,
|
||||
$this->request->brightness
|
||||
);
|
||||
}
|
||||
$this->response = array(
|
||||
"success" => true,
|
||||
"message" => "All module icons changed to {$this->request->color}-{$this->request->brightness}"
|
||||
);
|
||||
break;
|
||||
// Assume module Icon
|
||||
default:
|
||||
$success = $this->replaceModuleImage(
|
||||
$this->request->img,
|
||||
$this->request->color,
|
||||
$this->request->brightness
|
||||
);
|
||||
$this->response = array(
|
||||
"success" => $success,
|
||||
"message" => "{$this->request->img} icon changed to {$this->request->color}-{$this->request->brightness}"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* replaceModuleImage
|
||||
* $moduleName -> String name of module, can be any format (nEtWoRkIng) because it gets formatted
|
||||
* $color -> string name of the color, used for index of mapping
|
||||
* $brightness -> string name of brightness, used for map selection
|
||||
*/
|
||||
public function replaceModuleImage($moduleName, $color, $brightness)
|
||||
{
|
||||
$current = $this->currentFile($moduleName);
|
||||
$replace = "/pineapple/modules/{$moduleName}/module_icon.svg";
|
||||
switch($color)
|
||||
{
|
||||
case 'light':
|
||||
return $this->restoreModuleIcon (
|
||||
$moduleName
|
||||
);
|
||||
break;
|
||||
case 'dark':
|
||||
if (exec("echo dark > $current") != 0 ||
|
||||
exec("echo $brightness >> $current") != 0 ||
|
||||
!$this->searchAndReplaceFile($replace, "FFFFFF"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$hex = "";
|
||||
switch($brightness)
|
||||
{
|
||||
case 'light':
|
||||
$hex = $this->LIGHT_COLOR_HEX_MAP[$color];
|
||||
break;
|
||||
case 'dark':
|
||||
$hex = $this->DARK_COLOR_HEX_MAP[$color];
|
||||
break;
|
||||
default:
|
||||
$hex = $this->NORMAL_COLOR_HEX_MAP[$color];
|
||||
break;
|
||||
}
|
||||
// Replace the modules icon image
|
||||
if (exec("echo $color > $current") != 0 ||
|
||||
exec("echo $brightness >> $current") != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!$this->searchAndReplaceFile($replace, $hex)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* searchAndReplaceFile
|
||||
* $s -> substring to find
|
||||
* return: true or false showing succcessful string replacement
|
||||
*/
|
||||
public function searchAndReplaceFile($f, $s)
|
||||
{
|
||||
// Use a stream editor so we dont have to load the entire file into RAM
|
||||
return (exec("sed -i 's/fill:\(.*\);/fill:#{$s};/g' $f") == 0);
|
||||
}
|
||||
/*
|
||||
* setCurrentTheme
|
||||
* $theme -> modify CURRENT_CSS file with new theme
|
||||
*/
|
||||
public function setCurrentTheme($theme)
|
||||
{
|
||||
$this->current_theme = $theme;
|
||||
exec('echo '.$theme.' > /pineapple/modules/Themes/css/CURRENT_CSS');
|
||||
}
|
||||
/*
|
||||
* getCurrentTheme
|
||||
* return current theme, and all parameters for icon colors/brightness
|
||||
*/
|
||||
public function getCurrentTheme()
|
||||
{
|
||||
$line = file('/pineapple/modules/Themes/css/CURRENT_CSS')[0];
|
||||
$line = trim(preg_replace('/\s+/', ' ', $line));
|
||||
|
||||
$logo = file('/pineapple/modules/Themes/img/CURRENT_LOGO')[0];
|
||||
$logo = trim(preg_replace('/\s+/', ' ', $logo));
|
||||
|
||||
$icon = file('/pineapple/modules/Themes/img/CURRENT_FAVICON')[0];
|
||||
$icon = trim(preg_replace('/\s+/', ' ', $icon));
|
||||
|
||||
$throbber = file('/pineapple/modules/Themes/img/CURRENT_THROBBER')[0];
|
||||
$throbber = trim(preg_replace('/\s+/', ' ', $throbber));
|
||||
$this->response = array(
|
||||
"current" => $line,
|
||||
"logo" => $logo,
|
||||
"icon" => $icon,
|
||||
"throbber" => $throbber,
|
||||
);
|
||||
foreach ($this->ALL_MODULES as $module)
|
||||
{
|
||||
$current = $this->currentFile($module);
|
||||
$lower = strtolower($module);
|
||||
$color = file($current)[0];
|
||||
$color = trim(preg_replace('/\s+/', ' ', $color));
|
||||
$brightness = file($current)[1];
|
||||
$brightness = trim(preg_replace('/\s+/', ' ', $brightness));
|
||||
$this->response[$lower] = $color;
|
||||
$this->response[$lower.'brightness'] = $brightness;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* isCurrentThemeEnv
|
||||
* $theme string name of theme to check if its current
|
||||
* check if global current_them var is set, compare against that
|
||||
* this way we dont open,read,close a file every for every check
|
||||
*/
|
||||
public function isCurrentThemeEnv($theme)
|
||||
{
|
||||
if ($this->current_theme != "") {
|
||||
return ($this->current_theme == $theme);
|
||||
}
|
||||
if (!file_exists($this->CURRENT_CSS)) {
|
||||
return false;
|
||||
}
|
||||
$line = file($this->CURRENT_CSS)[0];
|
||||
$line = trim(preg_replace('/\s+/', ' ', $line));
|
||||
return ($line === $theme);
|
||||
}
|
||||
/*
|
||||
* restoreImages
|
||||
* Undo any changes made by this Module
|
||||
* This includes: original icons, gifs, svg's
|
||||
*/
|
||||
public function restoreImages()
|
||||
{
|
||||
$success = true;
|
||||
exec("cp {$this->BACKUP_FAVICON} /pineapple/img/favicon.ico");
|
||||
exec("cp {$this->BACKUP_LOGO} /pineapple/img/logo.png");
|
||||
exec("cp {$this->BACKUP_THROBBER} /pineapple/img/throbber.gif");
|
||||
exec('echo light > /pineapple/modules/Themes/img/CURRENT_LOGO');
|
||||
exec('echo light > /pineapple/modules/Themes/img/CURRENT_FAVICON');
|
||||
exec('echo light > /pineapple/modules/Themes/img/CURRENT_THROBBER');
|
||||
|
||||
foreach ($this->ALL_MODULES as $module)
|
||||
{
|
||||
$current = $this->currentFile($module);
|
||||
$success = $this->restoreModuleIcon (
|
||||
$module
|
||||
);
|
||||
}
|
||||
$this->response = array(
|
||||
"success" => $success,
|
||||
"message" => "Restored all files"
|
||||
);
|
||||
}
|
||||
/*
|
||||
* restoreModuleIcon
|
||||
* Generic helper function to put a modules icon back to normal
|
||||
* using only the name of the module (in any format).
|
||||
*/
|
||||
public function restoreModuleIcon($moduleName)
|
||||
{
|
||||
$current = $this->currentFile($moduleName);
|
||||
$replace = "/pineapple/modules/{$moduleName}/module_icon.svg";
|
||||
if (!$this->searchAndReplaceFile($replace, $this->RESTORE_HEX))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (exec("echo light > $current") != 0 ||
|
||||
exec("echo normal >> $current") != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* restoreDefault
|
||||
* backup all files if not done yet
|
||||
* put the original css file back
|
||||
* restore all of the images
|
||||
*/
|
||||
public function restoreDefault()
|
||||
{
|
||||
$this->backupFiles();
|
||||
exec("cp {$this->BACKUP_MAIN_CSS} /pineapple/css/main.css");
|
||||
$this->setCurrentTheme('main.css');
|
||||
$this->restoreImages();
|
||||
}
|
||||
/*
|
||||
* getThemeCode
|
||||
* retrieve the css styling code from a theme file
|
||||
*/
|
||||
public function getThemeCode()
|
||||
{
|
||||
$code = file_get_contents($this->CSS_DIR . $this->request->name);
|
||||
$this->response = array("code" => $code, "file" => $this->CSS_DIR . $this->request->name);
|
||||
}
|
||||
/*
|
||||
* getThemeFields
|
||||
* more or less only returns the code for now
|
||||
*/
|
||||
public function getThemeFields()
|
||||
{
|
||||
$allFields = array();
|
||||
$code = file_get_contents($this->CSS_DIR . $this->request->name);
|
||||
$this->response = array("code" => $code);
|
||||
}
|
||||
/*
|
||||
* activateTheme
|
||||
* mv the users selected theme to main.css file
|
||||
*/
|
||||
public function activateTheme()
|
||||
{
|
||||
$themeName = $this->request->name;
|
||||
$cmd = exec("cp {$this->CSS_DIR}{$themeName} /pineapple/css/main.css");
|
||||
if ($cmd == 0) {
|
||||
$this->setCurrentTheme($themeName);
|
||||
$message = $themeName . " is now active.";
|
||||
$this->response = array("return" => true, "message" => $message);
|
||||
}
|
||||
else
|
||||
{
|
||||
$message = "Could not move theme" . $themeName . "(Something is wrong..)";
|
||||
$this->response = array("return" => false,"message" => $message);
|
||||
}
|
||||
}
|
||||
/* Credits to SteveRusin at http://php.net/manual/en/ref.strings.php */
|
||||
private function endsWith($str, $sub)
|
||||
{
|
||||
return (substr($str, strlen($str) - strlen($sub)) === $sub);
|
||||
}
|
||||
/*
|
||||
* handleDeleteTheme
|
||||
* delete a users theme file from the local css directory
|
||||
*/
|
||||
public function handleDeleteTheme()
|
||||
{
|
||||
$themeName = $this->request->name;
|
||||
exec("rm {$this->CSS_DIR}{$themeName}");
|
||||
if (!file_exists("/pineapple/modules/Themes/css/" . $themeName)) {
|
||||
$message = "Deleted " . $themeName;
|
||||
} else {
|
||||
$message = "Error deleting " . $themeName;
|
||||
}
|
||||
$this->response = array("message" => $message);
|
||||
}
|
||||
/*
|
||||
* submitThemeCode
|
||||
* save a users theme file in the local css directory
|
||||
*/
|
||||
public function submitThemeCode()
|
||||
{
|
||||
$code = $this->request->themeCode;
|
||||
$themeName = $this->request->name;
|
||||
$fileName = $this->request->fileName;
|
||||
file_put_contents($this->CSS_DIR . $themeName, $code);
|
||||
$message = (!file_exists($this->CSS_DIR . $themeName)) ? "Created " . $themeName : "Updated " . $themeName;
|
||||
|
||||
$this->response = array(
|
||||
"message" => $message,
|
||||
"filename" => $fileName
|
||||
);
|
||||
}
|
||||
/*
|
||||
* handleGetThemeList
|
||||
* get the list of .css files in the local css directory
|
||||
* avoid sending back the main.css file so it cannot be modified
|
||||
*/
|
||||
public function handleGetThemeList()
|
||||
{
|
||||
$all_themes = array();
|
||||
$root_themes = preg_grep('/^([^.])/', scandir("{$this->CSS_DIR}"));
|
||||
foreach ($root_themes as $theme) {
|
||||
if (!is_file($theme) && $this->endsWith($theme, '.css') && $theme != "main.css") {
|
||||
$active = $this->isCurrentThemeEnv($theme);
|
||||
$obj = array("title" => $theme, "location" => "../Themes/css/", "active" => $active);
|
||||
array_push($all_themes, $obj);
|
||||
}
|
||||
}
|
||||
$this->response = $all_themes;
|
||||
}
|
||||
/*
|
||||
* handleCreateNewTheme
|
||||
* create a new .css theme file in the local css directory
|
||||
*/
|
||||
public function handleCreateNewTheme()
|
||||
{
|
||||
$themePath = $this->CSS_DIR;
|
||||
$themeName = str_replace(' ', '_', $this->request->themeName);
|
||||
if (!$this->endswith($themeName, '.css')) {
|
||||
$themeName = $themeName . ".css";
|
||||
}
|
||||
if (file_exists($themePath . $themeName)) {
|
||||
$this->response = array("create_success" => false, "create_message" => "A theme named {$themeName} already exists.");
|
||||
return;
|
||||
}
|
||||
exec("cp {$this->SKELETON_CSS} {$themePath}{$themeName}");
|
||||
$this->response = array("create_success" => true, "create_message" => "Created {$themeName}");
|
||||
}
|
||||
/*
|
||||
* backupFiles
|
||||
* Backup all of the .css/IMG files used so the module can properly restore defaults
|
||||
*/
|
||||
public function backupFiles()
|
||||
{
|
||||
$success = true;
|
||||
$modules = array();
|
||||
if (!file_exists($this->BACKUP_MAIN_CSS)) {
|
||||
exec("cp /pineapple/css/main.css {$this->BACKUP_MAIN_CSS}");
|
||||
array_push($modules, "Backed up main.css.");
|
||||
}
|
||||
if (!file_exists($this->SKELETON_CSS)) {
|
||||
mkdir($this->CSS_DIR);
|
||||
exec("cp {$this->BACKUP_MAIN_CSS} {$this->SKELETON_CSS}");
|
||||
array_push($modules, "Backed up skeleton.css.");
|
||||
}
|
||||
if (!file_exists($this->BACKUP_THROBBER)) {
|
||||
exec("cp /pineapple/img/throbber.gif {$this->BACKUP_THROBBER}");
|
||||
array_push($modules, "Backed up favicon.ico");
|
||||
}
|
||||
if (!file_exists($this->CURRENT_THROBBER)) {
|
||||
exec("echo light > $this->CURRENT_THROBBER");
|
||||
array_push($modules, "Wrote to {$this->CURRENT_THROBBER}");
|
||||
}
|
||||
if (!file_exists($this->BACKUP_FAVICON)) {
|
||||
exec("cp /pineapple/img/favicon.ico {$this->BACKUP_FAVICON}");
|
||||
array_push($modules, "Backed up favicon.ico");
|
||||
}
|
||||
if (!file_exists($this->CURRENT_FAVICON)) {
|
||||
exec("echo light > $this->CURRENT_FAVICON");
|
||||
array_push($modules, "Wrote to /pineapple/modules/Themes/img/CURRENT_FAVICON");
|
||||
}
|
||||
if (!file_exists($this->BACKUP_LOGO)) {
|
||||
exec("cp /pineapple/img/logo.png $this->BACKUP_LOGO");
|
||||
array_push($modules, "Wrote to {$this->BACKUP_LOGO}");
|
||||
}
|
||||
if (!file_exists($this->CURRENT_LOGO)) {
|
||||
exec("echo light > $this->CURRENT_LOGO");
|
||||
array_push($modules, "Wrote to {$this->CURRENT_LOGO}");
|
||||
}
|
||||
foreach ($this->ALL_MODULES as $module)
|
||||
{
|
||||
$current = $this->currentFile($module);
|
||||
if (!$this->backupModuleIcon($current))
|
||||
{
|
||||
array_push($modules, "Did not write to {$current}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
array_push($modules, "Wrote to {$current}.");
|
||||
}
|
||||
}
|
||||
$this->response = array(
|
||||
"success" => $success,
|
||||
"message" => $success ?
|
||||
"Created a backup file for all files" :
|
||||
"Failed to backup files! Tread lightly",
|
||||
"modules" => $modules
|
||||
);
|
||||
}
|
||||
public function backupModuleIcon($currentFile) {
|
||||
if (!file_exists($currentFile)) {
|
||||
if (exec("echo light > $currentFile") != 0 ||
|
||||
exec("echo normal >> $currentFile") != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user