mirror of
https://github.com/hak5/nano-tetra-modules.git
synced 2025-10-29 16:58:09 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
4d96f79d78
11
CONTRIBUTING.md
Normal file
11
CONTRIBUTING.md
Normal file
@ -0,0 +1,11 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
To ease code reviews please follow the [PSR-1](https://www.php-fig.org/psr/psr-1/) and
|
||||
[PSR-2](https://www.php-fig.org/psr/psr-2/). Take a few minutes to actually read them,
|
||||
they're not all that bad. To jump right in use the [PHP-CS-Fixer
|
||||
tool](http://cs.sensiolabs.org/). Or install PHP_CodeSniffer and use it like so:
|
||||
|
||||
`apt install php-codesniffer`
|
||||
|
||||
`phpcs --standard=PSR2 your_file.php`
|
||||
@ -20,6 +20,7 @@ import errno
|
||||
|
||||
class Commander(object):
|
||||
print "[*] WiFi Pineapple Commander Module"
|
||||
print "[*] peace to: sebkinne & tesla"
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
@ -118,4 +119,4 @@ if __name__ == '__main__':
|
||||
commander.parseConfig()
|
||||
commander.printConfig()
|
||||
commander.connect()
|
||||
commander.run()
|
||||
commander.run()
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "Commander",
|
||||
"version": "2.0"
|
||||
}
|
||||
"version": "2.1"
|
||||
}
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "Deauth",
|
||||
"version": "1.4"
|
||||
}
|
||||
"version": "1.5"
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ TMPBLACKLIST=${MYPATH}lists/blacklist.tmp
|
||||
|
||||
if [ "$1" = "start" ]; then
|
||||
|
||||
killall -9 mkd3
|
||||
killall -9 mdk3
|
||||
rm ${TMPBLACKLIST}
|
||||
rm ${TMPWHITELIST}
|
||||
rm ${LOG}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
188
EvilPortal/executable/executable
Normal file → Executable file
188
EvilPortal/executable/executable
Normal file → Executable file
@ -1,133 +1,99 @@
|
||||
#!/usr/bin/python
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Evil Portal
|
||||
# Newbi3
|
||||
# This is the python control script to handle all iptables things for creating and managing a Captive Portal
|
||||
#
|
||||
#Modified by oXis for the Wifi Pineapple (OpenWRT)
|
||||
|
||||
import sys
|
||||
import os
|
||||
# Written by Sitwon and The Doctor.
|
||||
# Copyright (C) 2013 Project Byzantium
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
|
||||
|
||||
arp () { cat /proc/net/arp; } # arp function
|
||||
|
||||
CLIENTS_FILE = "/tmp/EVILPORTAL_CLIENTS.txt"
|
||||
WHITE_LIST = ["172.16.42.42"]
|
||||
IPTABLES=/usr/sbin/iptables
|
||||
ARP=arp
|
||||
IP=172.16.42.1
|
||||
|
||||
case "$1" in
|
||||
'init')
|
||||
|
||||
def revoke_client(ip_address=None):
|
||||
global CLIENTS_FILE
|
||||
# Convert the IP address of the client interface into a netblock.
|
||||
CLIENTNET=`echo $IP | sed 's/1$/0\/24/'`
|
||||
|
||||
if not ip_address:
|
||||
print "An ipaddress is expected."
|
||||
return
|
||||
# Exempt traffic which does not originate from the client network.
|
||||
$IPTABLES -t mangle -I PREROUTING -p all ! -s $CLIENTNET -j RETURN
|
||||
|
||||
f = open(CLIENTS_FILE, 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
# Traffic not coming from an accepted user gets marked 99.
|
||||
$IPTABLES -t mangle -A fwmark -j MARK --set-mark 99
|
||||
|
||||
f = open(CLIENTS_FILE, 'w')
|
||||
for line in lines:
|
||||
if line == ip_address + "\n":
|
||||
os.system("iptables -t nat -D PREROUTING -s " + line.rstrip('\n') + " -j ACCEPT")
|
||||
else:
|
||||
f.write(line)
|
||||
f.close()
|
||||
# Traffic which has been marked 99 and is headed for 80/TCP or 443/TCP
|
||||
# should be redirected to the captive portal web server.
|
||||
$IPTABLES -t nat -A prerouting_rule -m mark --mark 99 -p tcp --dport 80 -j DNAT --to-destination $IP:80
|
||||
# Need to activate HTTPS on the nginx server of the PineAP, so for now HTTPS traffic is dropped.
|
||||
#$IPTABLES -t nat -A prerouting_rule -m mark --mark 99 -p tcp --dport 443 -j DNAT --to-destination $IP:443
|
||||
|
||||
# for use with dns spoff
|
||||
$IPTABLES -t filter -A forwarding_rule -p udp --dport 53 -j ACCEPT
|
||||
$IPTABLES -t nat -A prerouting_rule -m mark --mark 99 -p udp --dport 53 -j DNAT --to-destination $IP:53
|
||||
|
||||
def authorize_client(ip_address=None):
|
||||
global CLIENTS_FILE
|
||||
$IPTABLES -t filter -A input_rule -p tcp --dport 80 -j ACCEPT #Webserver
|
||||
#$IPTABLES -t filter -A input_rule -p tcp --dport 443 -j ACCEPT #Webserver
|
||||
$IPTABLES -t filter -A input_rule -p tcp --dport 1471 -j ACCEPT #PineAP admin page
|
||||
$IPTABLES -t filter -A input_rule -p tcp --dport 22 -j ACCEPT #SSH
|
||||
|
||||
if not ip_address:
|
||||
print "An ipaddress is expected."
|
||||
return
|
||||
# All other traffic which is marked 99 is just dropped
|
||||
$IPTABLES -t filter -A forwarding_rule -m mark --mark 99 -j DROP
|
||||
# Even on INPUT rule
|
||||
$IPTABLES -t filter -A input_rule -m mark --mark 99 -j DROP
|
||||
|
||||
f = open(CLIENTS_FILE, 'a+')
|
||||
lines = f.readlines()
|
||||
if ip_address + "\n" not in lines:
|
||||
os.system("iptables -t nat -I PREROUTING -s " + ip_address + " -j ACCEPT")
|
||||
f.write(ip_address + "\n")
|
||||
f.close()
|
||||
exit 0
|
||||
;;
|
||||
'add')
|
||||
# $2: IP address of client.
|
||||
CLIENT=$2
|
||||
|
||||
# Isolate the MAC address of the client in question.
|
||||
CLIENTMAC=`$ARP -n | grep ':' | grep $CLIENT | awk '{print $4}'`
|
||||
|
||||
def stop_evilportal():
|
||||
"""
|
||||
stop_evilportal
|
||||
Stop EvilPortals
|
||||
"""
|
||||
global CLIENTS_FILE, WHITE_LIST
|
||||
# Add the MAC address of the client to the whitelist, so it'll be able
|
||||
# to access the mesh even if its IP address changes.
|
||||
$IPTABLES -t mangle -I fwmark -m mac --mac-source $CLIENTMAC -j RETURN
|
||||
$IPTABLES -A INPUT -m mac --mac-source 74:da:38:5a:03:66 -p udp --dport 53 -j ACCEPT
|
||||
|
||||
if os.path.isfile(CLIENTS_FILE):
|
||||
# Remove rule for each accepted client
|
||||
[os.system("iptables -t nat -D PREROUTING -s " + line.rstrip('\n') + " -j ACCEPT") for line in open(CLIENTS_FILE, 'r')]
|
||||
exit 0
|
||||
;;
|
||||
'remove')
|
||||
# $2: IP address of client.
|
||||
CLIENT=$2
|
||||
|
||||
# Delete the clients file
|
||||
os.remove(CLIENTS_FILE)
|
||||
# Isolate the MAC address of the client in question.
|
||||
CLIENTMAC=`$ARP -n | grep ':' | grep $CLIENT | awk '{print $4}'`
|
||||
|
||||
# Stop HTTP Redirection
|
||||
os.system("iptables -t nat -D PREROUTING -s 172.16.42.0/24 -p tcp --dport 80 -j DNAT --to-destination 172.16.42.1:80")
|
||||
# Delete the MAC address of the client from the whitelist.
|
||||
$IPTABLES -t mangle -D fwmark -m mac --mac-source $CLIENTMAC -j RETURN
|
||||
|
||||
# Remove DNS Policy
|
||||
os.system("iptables -D INPUT -p tcp --dport 53 -j ACCEPT")
|
||||
exit 0
|
||||
;;
|
||||
'purge')
|
||||
CLIENTNET=`echo $IP | sed 's/1$/0\/24/'`
|
||||
# Purge the user defined chains
|
||||
$IPTABLES -t mangle -F fwmark
|
||||
$IPTABLES -t nat -F prerouting_rule
|
||||
$IPTABLES -t filter -F input_rule
|
||||
$IPTABLES -t filter -F forwarding_rule
|
||||
$IPTABLES -t mangle -D PREROUTING -p all ! -s $CLIENTNET -j RETURN
|
||||
|
||||
$IPTABLES -t nat -D prerouting_rule -m mark --mark 99 -p udp --dport 53 -j DNAT --to-destination $IP:53
|
||||
|
||||
def start_evilportal():
|
||||
"""
|
||||
start_evilportal
|
||||
Start EvilPortals IP table based captive portal
|
||||
"""
|
||||
global CLIENTS_FILE, WHITE_LIST
|
||||
exit 0
|
||||
;;
|
||||
'list')
|
||||
# Display the currently running IP tables ruleset.
|
||||
$IPTABLES --list -t nat -n
|
||||
$IPTABLES --list -t mangle -n
|
||||
$IPTABLES --list -t filter -n
|
||||
|
||||
if os.path.isfile(CLIENTS_FILE):
|
||||
os.remove(CLIENTS_FILE)
|
||||
|
||||
# Make sure forwarding is enabled which it should be but just to be sure do it here
|
||||
os.system("echo 1 > /proc/sys/net/ipv4/ip_forward")
|
||||
|
||||
# Setup the iptables
|
||||
# Set white listed clients
|
||||
f = open(CLIENTS_FILE, "w")
|
||||
for client in WHITE_LIST:
|
||||
os.system("iptables -A INPUT -s " + client + " -j ACCEPT")
|
||||
f.write(client + "\n")
|
||||
f.close()
|
||||
|
||||
# Redirect all web traffic to port 80 on the pineapple
|
||||
os.system("iptables -t nat -A PREROUTING -s 172.16.42.0/24 -p tcp --dport 80 -j DNAT --to-destination 172.16.42.1:80")
|
||||
|
||||
# Accept dns
|
||||
os.system("iptables -A INPUT -p tcp --dport 53 -j ACCEPT")
|
||||
|
||||
|
||||
def handler(args=None):
|
||||
cmd = None
|
||||
param = None
|
||||
if args is not None:
|
||||
try:
|
||||
cmd = args[1].lower()
|
||||
except IndexError as e:
|
||||
cmd = "help"
|
||||
try:
|
||||
param = args[2].lower()
|
||||
except IndexError as e:
|
||||
pass
|
||||
else:
|
||||
cmd = "start"
|
||||
|
||||
commands = {"start": "Start EvilPortal", "stop": "Stop EvilPortal", "help": "What you are reading"}
|
||||
|
||||
if cmd == "start":
|
||||
start_evilportal()
|
||||
elif cmd == "stop":
|
||||
stop_evilportal()
|
||||
elif cmd == "authorize":
|
||||
authorize_client(param)
|
||||
elif cmd == "help":
|
||||
print "-"*20
|
||||
print "Evil Portal"
|
||||
print "-"*20
|
||||
for command, description in commands.iteritems():
|
||||
print command + ":\t" + description
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
handler(sys.argv)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "USAGE: $0 {initialize|add <IP>|remove <IP>|purge|list}"
|
||||
exit 0
|
||||
esac
|
||||
@ -7,6 +7,7 @@ abstract class Portal
|
||||
protected $error;
|
||||
|
||||
protected $AUTHORIZED_CLIENTS_FILE = "/tmp/EVILPORTAL_CLIENTS.txt";
|
||||
private $BASE_EP_COMMAND = 'module EvilPortal';
|
||||
|
||||
public function __construct($request)
|
||||
{
|
||||
@ -24,44 +25,80 @@ abstract class Portal
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a command in the background and don't wait for it to finish.
|
||||
* @param $command: The command to run
|
||||
*/
|
||||
protected function execBackground($command)
|
||||
{
|
||||
exec("echo \"{$command}\" | at now");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an iptables rule allowing the client to access the internet and writes them to the authorized clients.
|
||||
* Override this method to add other authorization steps validation.
|
||||
* @param $clientIP: The IP address of the client to authorize
|
||||
* @return bool: True if the client was successfully authorized otherwise false.
|
||||
*/
|
||||
protected function authorizeClient($clientIP)
|
||||
{
|
||||
if (!$this->isClientAuthorized($clientIP)) {
|
||||
exec("iptables -t nat -I PREROUTING -s {$clientIP} -j ACCEPT");
|
||||
// exec("{$this->BASE_EP_COMMAND} add {$clientIP}");
|
||||
file_put_contents($this->AUTHORIZED_CLIENTS_FILE, "{$clientIP}\n", FILE_APPEND);
|
||||
$this->redirect();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle client authorization here.
|
||||
* By default it just checks that the redirection target is in the request.
|
||||
* Override this to perform your own validation.
|
||||
*/
|
||||
protected function handleAuthorization()
|
||||
{
|
||||
if (isset($this->request->target)) {
|
||||
$this->authorizeClient($_SERVER['REMOTE_ADDR']);
|
||||
$this->showSuccess();
|
||||
$this->onSuccess();
|
||||
$this->redirect();
|
||||
} elseif ($this->isClientAuthorized($_SERVER['REMOTE_ADDR'])) {
|
||||
$this->showSuccess();
|
||||
$this->redirect();
|
||||
} else {
|
||||
$this->showError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Where to redirect to on successful authorization.
|
||||
*/
|
||||
protected function redirect()
|
||||
{
|
||||
header("Location: {$this->request->target}", true, 302);
|
||||
}
|
||||
|
||||
protected function showSuccess()
|
||||
/**
|
||||
* Override this to do something when the client is successfully authorized.
|
||||
* By default it just notifies the Web UI.
|
||||
*/
|
||||
protected function onSuccess()
|
||||
{
|
||||
echo "You have been authorized successfully.";
|
||||
$this->execBackground("notify New client authorized through EvilPortal!");
|
||||
}
|
||||
|
||||
/**
|
||||
* If an error occurs then do something here.
|
||||
* Override to provide your own functionality.
|
||||
*/
|
||||
protected function showError()
|
||||
{
|
||||
echo "You have not been authorized.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the client has been authorized.
|
||||
* @param $clientIP: The IP of the client to check.
|
||||
* @return bool|int: True if the client is authorized else false.
|
||||
*/
|
||||
protected function isClientAuthorized($clientIP)
|
||||
{
|
||||
$authorizeClients = file_get_contents($this->AUTHORIZED_CLIENTS_FILE);
|
||||
|
||||
4
EvilPortal/includes/skeleton/.disable
Normal file
4
EvilPortal/includes/skeleton/.disable
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Commands in this file are ran when a portal is de-activated.
|
||||
# You can use any interpreter you want to, the default is bash.
|
||||
4
EvilPortal/includes/skeleton/.enable
Normal file
4
EvilPortal/includes/skeleton/.enable
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Commands in this file are ran when a portal is activated and when Evil Portal startsup on boot.
|
||||
# You can use any interpreter you want to, the default is bash.
|
||||
@ -5,18 +5,27 @@ class MyPortal extends Portal
|
||||
|
||||
public function handleAuthorization()
|
||||
{
|
||||
// handle form input or other extra things there
|
||||
|
||||
// Call parent to handle basic authorization first
|
||||
parent::handleAuthorization();
|
||||
|
||||
// Check for other form data here
|
||||
}
|
||||
|
||||
public function showSuccess()
|
||||
/**
|
||||
* Override this to do something when the client is successfully authorized.
|
||||
* By default it just notifies the Web UI.
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
// Calls default success message
|
||||
parent::showSuccess();
|
||||
parent::onSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* If an error occurs then do something here.
|
||||
* Override to provide your own functionality.
|
||||
*/
|
||||
public function showError()
|
||||
{
|
||||
// Calls default error message
|
||||
|
||||
45
EvilPortal/includes/skeleton/helper.php
Normal file
45
EvilPortal/includes/skeleton/helper.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* getClientMac
|
||||
* Gets the mac address of a client by the IP address
|
||||
* Returns the mac address as a string
|
||||
* @param $clientIP : The clients IP address
|
||||
* @return string
|
||||
*/
|
||||
function getClientMac($clientIP)
|
||||
{
|
||||
return trim(exec("grep " . escapeshellarg($clientIP) . " /tmp/dhcp.leases | awk '{print $2}'"));
|
||||
}
|
||||
|
||||
/**
|
||||
* getClientSSID
|
||||
* Gets the SSID a client is associated by the IP address
|
||||
* Returns the SSID as a string
|
||||
* @param $clientIP : The clients IP address
|
||||
* @return string
|
||||
*/
|
||||
function getClientSSID($clientIP)
|
||||
{
|
||||
// Get the clients mac address. We need this to get the SSID
|
||||
$mac = getClientMac($clientIP);
|
||||
|
||||
// get the path to the log file
|
||||
$pineAPLogPath = trim(file_get_contents('/etc/pineapple/pineap_log_location'));
|
||||
|
||||
// get the ssid
|
||||
return trim(exec("grep " . $mac . " " . $pineAPLogPath . "pineap.log | grep 'Association' | awk -F ',' '{print $4}'"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* getClientHostName
|
||||
* Gets the host name of the connected client by the IP address
|
||||
* Returns the host name as a string
|
||||
* @param $clientIP : The clients IP address
|
||||
* @return string
|
||||
*/
|
||||
function getClientHostName($clientIP)
|
||||
{
|
||||
return trim(exec("grep " . escapeshellarg($clientIP) . " /tmp/dhcp.leases | awk '{print $4}'"));
|
||||
}
|
||||
@ -1,27 +1,33 @@
|
||||
<?php
|
||||
$destination = "http://". $_SERVER['HTTP_HOST'] . $_SERVER['HTTP_URI'] . "";
|
||||
$destination = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['HTTP_URI'] . "";
|
||||
require_once('helper.php');
|
||||
?>
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<title>Evil Portal</title>
|
||||
<script type="text/javascript">
|
||||
function redirect() { setTimeout(function(){window.location = "/captiveportal/index.php";},100);}
|
||||
</script>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
<center>
|
||||
<div style="text-align: center;">
|
||||
<h1>Evil Portal</h1>
|
||||
<p>This is the default Evil Portal page</p>
|
||||
<p>This is the default Evil Portal page.</p>
|
||||
<p>The SSID you are connected to is <?=getClientSSID($_SERVER['REMOTE_ADDR']);?></p>
|
||||
<p>Your host name is <?=getClientHostName($_SERVER['REMOTE_ADDR']);?></p>
|
||||
<p>Your MAC Address is <?=getClientMac($_SERVER['REMOTE_ADDR']);?></p>
|
||||
<p>Your internal IP address is <?=$_SERVER['REMOTE_ADDR'];?></p>
|
||||
|
||||
<form method="POST" action="/captiveportal/index.php" onsubmit="redirect()">
|
||||
<form method="POST" action="/captiveportal/index.php">
|
||||
<input type="hidden" name="target" value="<?=$destination?>">
|
||||
<button type="submit">Authorize</button>
|
||||
</form>
|
||||
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
</HTML>
|
||||
|
||||
4
EvilPortal/includes/skeleton/portalinfo.json
Normal file
4
EvilPortal/includes/skeleton/portalinfo.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": null,
|
||||
"type": "basic"
|
||||
}
|
||||
4
EvilPortal/includes/targeted_skeleton/.disable
Normal file
4
EvilPortal/includes/targeted_skeleton/.disable
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Commands in this file are ran when a portal is de-activated.
|
||||
# You can use any interpreter you want to, the default is bash.
|
||||
4
EvilPortal/includes/targeted_skeleton/.enable
Normal file
4
EvilPortal/includes/targeted_skeleton/.enable
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Commands in this file are ran when a portal is activated and when Evil Portal startsup on boot.
|
||||
# You can use any interpreter you want to, the default is bash.
|
||||
33
EvilPortal/includes/targeted_skeleton/MyPortal.php
Normal file
33
EvilPortal/includes/targeted_skeleton/MyPortal.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php namespace evilportal;
|
||||
|
||||
class MyPortal extends Portal
|
||||
{
|
||||
|
||||
public function handleAuthorization()
|
||||
{
|
||||
// handle form input or other extra things there
|
||||
|
||||
// Call parent to handle basic authorization first
|
||||
parent::handleAuthorization();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to do something when the client is successfully authorized.
|
||||
* By default it just notifies the Web UI.
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
// Calls default success message
|
||||
parent::onSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* If an error occurs then do something here.
|
||||
* Override to provide your own functionality.
|
||||
*/
|
||||
public function showError()
|
||||
{
|
||||
// Calls default error message
|
||||
parent::showError();
|
||||
}
|
||||
}
|
||||
35
EvilPortal/includes/targeted_skeleton/default.php
Normal file
35
EvilPortal/includes/targeted_skeleton/default.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
$destination = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['HTTP_URI'] . "";
|
||||
require_once('helper.php');
|
||||
?>
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<title>Evil Portal</title>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<script type="text/javascript">
|
||||
function redirect() { setTimeout(function(){window.location = "/captiveportal/index.php";},100);}
|
||||
</script>
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
<div style="text-align: center;">
|
||||
<h1>Evil Portal</h1>
|
||||
<p>This is the default Evil Portal page.</p>
|
||||
<p>The SSID you are connected to is <?=getClientSSID($_SERVER['REMOTE_ADDR']);?></p>
|
||||
<p>Your host name is <?=getClientHostName($_SERVER['REMOTE_ADDR']);?></p>
|
||||
<p>Your MAC Address is <?=getClientMac($_SERVER['REMOTE_ADDR']);?></p>
|
||||
<p>Your internal IP address is <?=$_SERVER['REMOTE_ADDR'];?></p>
|
||||
|
||||
<form method="POST" action="/captiveportal/index.php" onsubmit="redirect()">
|
||||
<input type="hidden" name="target" value="<?=$destination?>">
|
||||
<button type="submit">Authorize</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
45
EvilPortal/includes/targeted_skeleton/helper.php
Normal file
45
EvilPortal/includes/targeted_skeleton/helper.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* getClientMac
|
||||
* Gets the mac address of a client by the IP address
|
||||
* Returns the mac address as a string
|
||||
* @param $clientIP : The clients IP address
|
||||
* @return string
|
||||
*/
|
||||
function getClientMac($clientIP)
|
||||
{
|
||||
return trim(exec("grep " . escapeshellarg($clientIP) . " /tmp/dhcp.leases | awk '{print $2}'"));
|
||||
}
|
||||
|
||||
/**
|
||||
* getClientSSID
|
||||
* Gets the SSID a client is associated by the IP address
|
||||
* Returns the SSID as a string
|
||||
* @param $clientIP : The clients IP address
|
||||
* @return string
|
||||
*/
|
||||
function getClientSSID($clientIP)
|
||||
{
|
||||
// Get the clients mac address. We need this to get the SSID
|
||||
$mac = getClientMac($clientIP);
|
||||
|
||||
// get the path to the log file
|
||||
$pineAPLogPath = trim(file_get_contents('/etc/pineapple/pineap_log_location'));
|
||||
|
||||
// get the ssid
|
||||
return trim(exec("grep " . $mac . " " . $pineAPLogPath . "pineap.log | grep 'Association' | awk -F ',' '{print $4}'"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* getClientHostName
|
||||
* Gets the host name of the connected client by the IP address
|
||||
* Returns the host name as a string
|
||||
* @param $clientIP : The clients IP address
|
||||
* @return string
|
||||
*/
|
||||
function getClientHostName($clientIP)
|
||||
{
|
||||
return trim(exec("grep " . escapeshellarg($clientIP) . " /tmp/dhcp.leases | awk '{print $4}'"));
|
||||
}
|
||||
81
EvilPortal/includes/targeted_skeleton/index.php
Normal file
81
EvilPortal/includes/targeted_skeleton/index.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
require_once('helper.php');
|
||||
|
||||
/**
|
||||
*
|
||||
* DO NOT MODIFY THIS FILE
|
||||
* I highly recommend against modifying this file unless you know what you are doing!
|
||||
*
|
||||
* This file handles determining the destination file a client should see based on the conditions set in the json.
|
||||
*
|
||||
*/
|
||||
|
||||
// The value for this variable needs to be set when an new instance of a portal is created
|
||||
// EvilPortal does this automatically when a targeted portal is created by running:
|
||||
// sed -i 's/"portal_name_here"/"{portalName}"/g' index.php
|
||||
$PORTAL_NAME = "portal_name_here";
|
||||
|
||||
// Get the information about the client and map
|
||||
// it to the rule key specified in the {$PORTAL_NAME}.ep file
|
||||
$MAPPED_RULES = [
|
||||
"mac" => getClientMac($_SERVER['REMOTE_ADDR']),
|
||||
"ssid" => getClientSSID($_SERVER['REMOTE_ADDR']),
|
||||
"hostname" => getClientHostName($_SERVER['REMOTE_ADDR']),
|
||||
"useragent" => $_SERVER['HTTP_USER_AGENT']
|
||||
];
|
||||
|
||||
// Read the json
|
||||
$jsonData = json_decode(file_get_contents("{$PORTAL_NAME}.ep"), true);
|
||||
$routeData = $jsonData['targeted_rules'];
|
||||
|
||||
// This variable represents the page to include
|
||||
$includePage = null;
|
||||
|
||||
// Check rules to find the page
|
||||
foreach ($routeData['rule_order'] as $key) {
|
||||
$includePage = handle_rule($routeData['rules'][$key], $MAPPED_RULES[$key]);
|
||||
if ($includePage != null) {
|
||||
include $includePage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to display something.
|
||||
// If the includePage variable is still null after checking the rules
|
||||
// then include the default page.
|
||||
if ($includePage == null) {
|
||||
include $routeData['default'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given rule matches a given value
|
||||
* @param $rules: The rules to check the client data against
|
||||
* @param $client_data: The data to check if the rules match
|
||||
* @return string: If a rule matches it returns the page to include, null otherwise
|
||||
*/
|
||||
function handle_rule($rules, $client_data) {
|
||||
$return_value = null;
|
||||
foreach ($rules as $key => $val) {
|
||||
switch($key) {
|
||||
case "exact": // exact matches
|
||||
if (isset($val[$client_data])) {
|
||||
$return_value = $val[$client_data];
|
||||
break 2; // break out of the loop
|
||||
}
|
||||
break 1;
|
||||
|
||||
case "regex": // regex matches
|
||||
foreach($val as $expression => $destination) {
|
||||
if (preg_match($expression, $client_data)) {
|
||||
$return_value = $destination;
|
||||
break 1; // match was found. Exit this loop
|
||||
}
|
||||
|
||||
if ($return_value != null)
|
||||
break 2; // break out of the main loop
|
||||
}
|
||||
break 1;
|
||||
}
|
||||
}
|
||||
return $return_value;
|
||||
}
|
||||
4
EvilPortal/includes/targeted_skeleton/jquery-2.2.1.min.js
vendored
Normal file
4
EvilPortal/includes/targeted_skeleton/jquery-2.2.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
34
EvilPortal/includes/targeted_skeleton/portalinfo.json
Normal file
34
EvilPortal/includes/targeted_skeleton/portalinfo.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": null,
|
||||
"type": "targeted",
|
||||
"targeted_rules": {
|
||||
"default": "default.php",
|
||||
"rule_order": ["mac", "ssid", "hostname", "useragent"],
|
||||
"rules": {
|
||||
"mac": {
|
||||
"exact": {
|
||||
},
|
||||
"regex": {
|
||||
}
|
||||
},
|
||||
"ssid": {
|
||||
"exact": {
|
||||
},
|
||||
"regex": {
|
||||
}
|
||||
},
|
||||
"hostname": {
|
||||
"exact": {
|
||||
},
|
||||
"regex": {
|
||||
}
|
||||
},
|
||||
"useragent": {
|
||||
"exact": {
|
||||
},
|
||||
"regex": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,322 +1,671 @@
|
||||
registerController("EvilPortalController", ['$api', '$scope', function ($api, $scope) {
|
||||
|
||||
getControls();
|
||||
getPortals();
|
||||
|
||||
$scope.portals = [];
|
||||
$scope.portalToDelete = null;
|
||||
$scope.portalDeleteValidation = '';
|
||||
$scope.messages = [];
|
||||
$scope.newPortalName = '';
|
||||
$scope.throbber = true;
|
||||
$scope.running = false;
|
||||
$scope.library = true;
|
||||
$scope.whiteList = '';
|
||||
$scope.whiteListInput = '';
|
||||
$scope.accessList = '';
|
||||
$scope.accessListInput = '';
|
||||
$scope.workshopPortal = {name: "", files: [], storage: "internal"};
|
||||
$scope.editPortalFile = {portalName: "", storage: "", file: "", code: ""};
|
||||
|
||||
$scope.handleControl = function (control) {
|
||||
control.throbber = true;
|
||||
switch (control.title) {
|
||||
|
||||
case "CaptivePortal":
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "startStop"
|
||||
}, function (response) {
|
||||
getControls();
|
||||
control.throbber = false;
|
||||
if (!response.control_success) {
|
||||
$scope.sendMessage(control.title, response.control_message);
|
||||
}
|
||||
$scope.refreshLivePreview()
|
||||
});
|
||||
break;
|
||||
|
||||
case "Auto Start":
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "enableDisable"
|
||||
}, function (response) {
|
||||
getControls();
|
||||
control.throbber = false;
|
||||
if (!response.control_success) {
|
||||
$scope.sendMessage(control.title, response.control_message);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
// status information about the module
|
||||
$scope.evilPortal = {
|
||||
"throbber": false,
|
||||
"sdAvailable": false,
|
||||
"running": false,
|
||||
"startOnBoot": false,
|
||||
"library": true
|
||||
};
|
||||
|
||||
// controls that belong in the Controls pane
|
||||
$scope.controls = [
|
||||
{ "title": "Captive Portal", "visible": true, "throbber": false, "status": "Start"},
|
||||
{"title": "Start On Boot", "visible": true, "throbber": false, "status": "Enable"}
|
||||
];
|
||||
|
||||
// messages to be displayed in the Messages pane
|
||||
$scope.messages = [];
|
||||
|
||||
$scope.whiteList = {"clients": "", "toManipulate": null};
|
||||
|
||||
$scope.accessList = {"clients": "", "toManipulate": null};
|
||||
|
||||
// all of the portals that could be found
|
||||
$scope.portals = [];
|
||||
|
||||
// a model of a new portal to create
|
||||
$scope.newPortal = {"type": "basic", "name": ""};
|
||||
|
||||
// deleting portal stuff
|
||||
$scope.portalToDelete = null;
|
||||
$scope.portalDeleteValidation = null;
|
||||
|
||||
// the portal workshop
|
||||
$scope.workshop = {"portal": {}, "dirContents": null, "inRoot": true, "rootDirectory": null, "editFile": {"path": null, "isNewFile": true},
|
||||
"onEnable": null, "onDisable": null, "concreteTargetedRules": null, "workingTargetedRules": null, "deleteFile": null
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the workshop object to a blank slate with initial values.
|
||||
*/
|
||||
$scope.resetWorkshop = function () {
|
||||
$scope.workshop = {"portal": {}, "dirContents": null, "inRoot": true, "rootDirectory": null, "editFile": {"path": null, "isNewFile": true},
|
||||
"onEnable": null, "onDisable": null, "concreteTargetedRules": null, "workingTargetedRules": null, "deleteFile": null
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Push a message to the Evil Portal Messages Pane
|
||||
* @param t: The Title of the message
|
||||
* @param m: The message body
|
||||
*/
|
||||
$scope.sendMessage = function (t, m) {
|
||||
// Add a new message to the top of the list
|
||||
$scope.messages.unshift({title: t, msg: m});
|
||||
|
||||
// if there are 4 items in the list remove the 4th item
|
||||
if ($scope.messages.length == 4) {
|
||||
if ($scope.messages.length === 4) {
|
||||
$scope.dismissMessage(3);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a message from the Evil Portal Messages pane
|
||||
* @param $index: The index of the message in the list to remove
|
||||
*/
|
||||
$scope.dismissMessage = function ($index) {
|
||||
//var index = $scope.messages.indexOf(message);
|
||||
$scope.messages.splice($index, 1);
|
||||
};
|
||||
|
||||
function getControls() {
|
||||
$scope.throbber = true;
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "getControlValues"
|
||||
}, function (response) {
|
||||
updateControls(response);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Preform an action for a given control
|
||||
* This can be starting the captive portal or toggle on boot.
|
||||
* @param control: The control to handle
|
||||
*/
|
||||
$scope.handleControl = function(control) {
|
||||
control.throbber = true;
|
||||
var actionToPreform = null;
|
||||
switch(control.title) {
|
||||
case "Captive Portal":
|
||||
actionToPreform = "toggleCaptivePortal";
|
||||
break;
|
||||
|
||||
function updateControls(response) {
|
||||
var running;
|
||||
var autostart;
|
||||
if (response.running == false) {
|
||||
running = "Start";
|
||||
$scope.running = false;
|
||||
} else {
|
||||
running = "Stop";
|
||||
$scope.running = true;
|
||||
case "Start On Boot":
|
||||
actionToPreform = "toggleOnBoot";
|
||||
break;
|
||||
}
|
||||
if (response.autostart == false) {
|
||||
autostart = "Enable";
|
||||
} else {
|
||||
autostart = "Disable";
|
||||
}
|
||||
$scope.controls = [
|
||||
{
|
||||
title: "CaptivePortal",
|
||||
status: running,
|
||||
visible: true,
|
||||
throbber: false
|
||||
},
|
||||
{
|
||||
title: "Auto Start",
|
||||
status: autostart,
|
||||
visible: true,
|
||||
throbber: false
|
||||
}];
|
||||
$scope.throbber = false;
|
||||
}
|
||||
|
||||
$scope.createNewPortal = function () {
|
||||
if (actionToPreform !== null) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: actionToPreform
|
||||
}, function(response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage(control.title, response.message);
|
||||
}
|
||||
getStatus();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates the information in the newPortal model and then makes an API request to create a new portal.
|
||||
* @param storage: The storage medium to create the portal on (internal or sd)
|
||||
*/
|
||||
$scope.createNewPortal = function(storage) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "createNewPortal",
|
||||
portalName: $scope.newPortalName
|
||||
}, function (response) {
|
||||
if (response.create_success) {
|
||||
getPortals();
|
||||
$scope.newPortalName = '';
|
||||
} else {
|
||||
$scope.sendMessage("Error Creating Portal", response.create_message);
|
||||
name: $scope.newPortal.name,
|
||||
type: $scope.newPortal.type,
|
||||
storage: storage
|
||||
}, function(response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage('Error Creating Portal', response.message);
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deletePortalRequest = function(portal) {
|
||||
$scope.portalToDelete = portal;
|
||||
console.log(portal);
|
||||
};
|
||||
|
||||
$scope.deletePortal = function (portal) {
|
||||
console.log(portal.storage);
|
||||
console.log(portal.title);
|
||||
$scope.portalToDelete = null;
|
||||
$scope.portalDeleteValidation = null
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "deletePortal",
|
||||
storage: portal.storage,
|
||||
name: portal.title
|
||||
}, function (response) {
|
||||
$scope.sendMessage("Delete Portal", response.message);
|
||||
$scope.newPortal = {"type": "basic", "name": ""};
|
||||
getPortals();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.activatePortal = function (portal) {
|
||||
/**
|
||||
* Move a given portal between storage mediums if an SD card is present.
|
||||
* @param portal: The portal to move
|
||||
*/
|
||||
$scope.movePortal = function(portal) {
|
||||
if (!$scope.evilPortal.sdAvailable) {
|
||||
$scope.sendMessage("No SD Card.", "An SD card must be present to preform this action.");
|
||||
return;
|
||||
}
|
||||
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "movePortal",
|
||||
name: portal.title,
|
||||
storage: portal.storage
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
getPortals();
|
||||
$scope.sendMessage("Moved Portal", response.message);
|
||||
} else {
|
||||
$scope.sendMessage("Error Moving " + portal.title, response.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a portal from the wifi pineapple
|
||||
* @param verified: Has the delete request been verified? If so then make the API request otherwise setup
|
||||
* @param portal: The portal to delete
|
||||
*/
|
||||
$scope.deletePortal = function(verified, portal) {
|
||||
if (!verified) { // if the request has not been verified then setup the shits
|
||||
$scope.portalToDelete = portal;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.portalToDelete === null || $scope.portalToDelete.fullPath === null) {
|
||||
$scope.sendMessage("Unable To Delete Portal", "No portal was set for deletion.");
|
||||
return;
|
||||
}
|
||||
deleteFileOrDirectory($scope.portalToDelete.fullPath, function (response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage("Error Deleting Portal", response.message); // push an error if deletion failed
|
||||
} else {
|
||||
$scope.sendMessage("Deleted Portal", "Successfully deleted " + $scope.portalToDelete.title + ".");
|
||||
$scope.portalToDelete = null;
|
||||
$scope.portalDeleteValidation = null;
|
||||
getPortals(); // refresh the library
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Activate a portal
|
||||
* @param portal: The portal to activate
|
||||
*/
|
||||
$scope.activatePortal = function(portal) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "activatePortal",
|
||||
storage: portal.storage,
|
||||
name: portal.title
|
||||
}, function (response) {
|
||||
//$scope.sendMessage("Activate Portal", response.message);
|
||||
getPortals();
|
||||
name: portal.title,
|
||||
storage: portal.storage
|
||||
}, function(response) {
|
||||
console.log(response);
|
||||
if (response.success) {
|
||||
getPortals();
|
||||
$scope.sendMessage("Activated Portal", portal.title + " has been activated successfully.");
|
||||
} else {
|
||||
$scope.sendMessage("Error Activating " + portal.title, response.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deactivatePortal = function (portal) {
|
||||
/**
|
||||
* Deactivate a given portal if its active
|
||||
* @param portal: The portal to deactivate
|
||||
*/
|
||||
$scope.deactivatePortal = function(portal) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "deactivatePortal",
|
||||
storage: portal.storage,
|
||||
name: portal.title
|
||||
}, function (response) {
|
||||
//$scope.sendMessage("Deactivate Portal", response.message);
|
||||
getPortals();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.editPortal = function (portal, file) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "getPortalCode",
|
||||
storage: portal.storage,
|
||||
name: portal.name,
|
||||
portalFile: file
|
||||
}, function (response) {
|
||||
//$scope.sendMessage("Edit Portal", response.message);
|
||||
$scope.editPortalFile.code = response.code;
|
||||
$scope.editPortalFile.file = file;
|
||||
$scope.editPortalFile.portalName = portal.name;
|
||||
$scope.editPortalFile.storage = portal.storage;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.savePortalCode = function (editFile) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "submitPortalCode",
|
||||
storage: editFile.storage,
|
||||
portalCode: editFile.code,
|
||||
name: editFile.portalName,
|
||||
fileName: editFile.file
|
||||
}, function (response) {
|
||||
$scope.sendMessage("Edit File", response.message);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.getPortalFiles = function (portal) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "portalFiles",
|
||||
storage: portal.storage,
|
||||
name: portal.title
|
||||
}, function (response) {
|
||||
$scope.workshopPortal.name = portal.title;
|
||||
$scope.workshopPortal.storage = portal.storage;
|
||||
$scope.workshopPortal.files = response.portalFiles;
|
||||
$scope.library = false;
|
||||
});
|
||||
};
|
||||
|
||||
function getPortals() {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "portalList"
|
||||
}, function (response) {
|
||||
$scope.portals = [];
|
||||
for (var i = 0; i < response.length; i++) {
|
||||
$scope.portals.unshift({
|
||||
title: response[i].title,
|
||||
storage: response[i].location,
|
||||
active: response[i].active
|
||||
});
|
||||
//console.log({title: response[i].title, storage: response[i].location, active: response[i].active});
|
||||
name: portal.title,
|
||||
storage: portal.storage
|
||||
}, function(response) {
|
||||
console.log(response);
|
||||
if (response.success) {
|
||||
getPortals();
|
||||
$scope.sendMessage("Deactivated Portal", portal.title + " has been deactivated successfully.");
|
||||
} else {
|
||||
$scope.sendMessage("Error Deactivating " + portal.title, response.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.refreshLivePreview = function () {
|
||||
window.frames['livePreviewIframe'].src = "http://172.16.42.1";
|
||||
};
|
||||
|
||||
$scope.getList = function (listToGet) {
|
||||
/**
|
||||
* Load portal contents and open it up in the work bench
|
||||
* @param portal: The portal to get the contents of
|
||||
*/
|
||||
$scope.loadPortal = function (portal) {
|
||||
getFileOrDirectoryContent(portal.fullPath, function(response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage("Error Getting Contents", response.message);
|
||||
return;
|
||||
}
|
||||
$scope.workshop.inRoot = true;
|
||||
$scope.workshop.portal = portal;
|
||||
$scope.workshop.dirContents = response.content;
|
||||
$scope.workshop.rootDirectory = portal.fullPath;
|
||||
$scope.evilPortal.library = false;
|
||||
console.log(response.content);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Load toggle commands for the current portal in the work bench.
|
||||
* These are the commands that are executed when a portal is enabled/disabled.
|
||||
*/
|
||||
$scope.loadToggleCommands = function() {
|
||||
[".enable", ".disable"].forEach(getScript);
|
||||
function getScript(scriptName) {
|
||||
getFileOrDirectoryContent($scope.workshop.rootDirectory + "/" + scriptName, function (response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage("Error Getting Contents", response.message);
|
||||
return;
|
||||
}
|
||||
if (scriptName === ".enable")
|
||||
$scope.workshop.onEnable = response.content.fileContent;
|
||||
else
|
||||
$scope.workshop.onDisable = response.content.fileContent;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Save toggle commands.
|
||||
* @param cmdFile: The commands to save (enable, disable)
|
||||
*/
|
||||
$scope.saveToggleCommands = function(cmdFile) {
|
||||
function sendData(f, content) {
|
||||
writeToFile($scope.workshop.rootDirectory + "/" + f, content, false, function (response) {
|
||||
if (!response.success)
|
||||
$scope.sendMessage("Error write to file " + f, response.message);
|
||||
});
|
||||
}
|
||||
|
||||
switch(cmdFile) {
|
||||
case "disable":
|
||||
sendData(".disable", $scope.workshop.onDisable);
|
||||
break;
|
||||
|
||||
case "enable":
|
||||
sendData(".enable", $scope.workshop.onEnable);
|
||||
break;
|
||||
|
||||
default:
|
||||
sendData(".enable", $scope.workshop.onEnable);
|
||||
sendData(".disable", $scope.workshop.onDisable);
|
||||
break;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the rules for targeted portals
|
||||
*/
|
||||
$scope.loadTargetedRules = function() {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "getList",
|
||||
listName: listToGet
|
||||
}, function (response) {
|
||||
if (response.list_success) {
|
||||
if (listToGet == "whiteList") {
|
||||
$scope.whiteList = response.list_contents;
|
||||
} else if (listToGet == "accessList") {
|
||||
$scope.accessList = response.list_contents;
|
||||
action: "getRules",
|
||||
name: $scope.workshop.portal.title,
|
||||
storage: $scope.workshop.portal.storage
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
$scope.workshop.concreteTargetedRules = response.data;
|
||||
$scope.workshop.workingTargetedRules = {"rules": {}};
|
||||
|
||||
// welcome to the realm of loops. I will be your guide
|
||||
// We have to turn each rule into a keyed set of rules with a rule index represented by var index
|
||||
// this is because we need a constant key for each rule when editing on the web interface
|
||||
// the index must be removed later before saving the results to the routes.json file
|
||||
// if you have a better way to do this you are my hero. Email me n3rdcav3@gmail.com or fork the repo :)
|
||||
|
||||
// This first loop loops over each rule categories such as "mac", "ssid" and so on
|
||||
for (var key in response.data['rules']) {
|
||||
|
||||
// we then create the a object with that key name in our workingData object
|
||||
$scope.workshop.workingTargetedRules['rules'][key] = {};
|
||||
|
||||
// Now its time to loop over each category specifier such as "exact" and "regex"
|
||||
for (var specifier in response.data['rules'][key]) {
|
||||
var index = 0;
|
||||
|
||||
// We then create that specifier in our workingData
|
||||
$scope.workshop.workingTargetedRules['rules'][key][specifier] = {};
|
||||
|
||||
// finally we loop over the specific rules defined in the specifier
|
||||
for (var r in response.data['rules'][key][specifier]) {
|
||||
var obj = {};
|
||||
obj['key'] = r;
|
||||
obj['destination'] = response.data['rules'][key][specifier][r];
|
||||
$scope.workshop.workingTargetedRules['rules'][key][specifier][index] = obj;
|
||||
}
|
||||
// increment index
|
||||
index++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$scope.sendMessage("List Data Error", response.list_message);
|
||||
console.log(response);
|
||||
$scope.sendMessage("Error", "There was an issue getting the portal rules.");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addWhiteListClient = function () {
|
||||
/**
|
||||
* Remove a targeted rule
|
||||
* @param rule
|
||||
* @param specifier
|
||||
* @param index
|
||||
*/
|
||||
$scope.removeTargetedRule = function(rule, specifier, index) {
|
||||
delete $scope.workshop.workingTargetedRules['rules'][rule][specifier][index];
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new targeted rule
|
||||
* @param rule
|
||||
* @param specifier
|
||||
*/
|
||||
$scope.newTargetedRule = function(rule, specifier) {
|
||||
// make sure the specifier is set
|
||||
if ($scope.workshop.workingTargetedRules['rules'][rule][specifier] == undefined) {
|
||||
$scope.workshop.workingTargetedRules['rules'][rule][specifier] = {};
|
||||
}
|
||||
|
||||
var highest = 0;
|
||||
|
||||
// get the highest index
|
||||
for (var i in $scope.workshop.workingTargetedRules['rules'][rule][specifier]) {
|
||||
if (parseInt(i) >= highest) {
|
||||
highest = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.workshop.workingTargetedRules['rules'][rule][specifier][highest] = {"": ""};
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the targeted rules and sned them to the API for saving
|
||||
*/
|
||||
$scope.saveTargetedRules = function() {
|
||||
// build the rules
|
||||
for (var key in $scope.workshop.concreteTargetedRules.rules) {
|
||||
for (var specifier in $scope.workshop.concreteTargetedRules.rules[key]) {
|
||||
var obj = {};
|
||||
for (var i in $scope.workshop.workingTargetedRules['rules'][key][specifier]) {
|
||||
obj[$scope.workshop.workingTargetedRules['rules'][key][specifier][i]['key']] = $scope.workshop.workingTargetedRules['rules'][key][specifier][i]['destination'];
|
||||
}
|
||||
$scope.workshop.concreteTargetedRules['rules'][key][specifier] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify($scope.workshop.concreteTargetedRules));
|
||||
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "addToList",
|
||||
listName: "whiteList",
|
||||
clientIP: $scope.whiteListInput
|
||||
}, function (response) {
|
||||
if (response.add_success) {
|
||||
$scope.whiteListInput = '';
|
||||
$scope.getList("whiteList");
|
||||
} else {
|
||||
$scope.sendMessage("White List", response.add_message);
|
||||
console.log(response);
|
||||
action: "saveRules",
|
||||
name: $scope.workshop.portal.title,
|
||||
storage: $scope.workshop.portal.storage,
|
||||
rules: JSON.stringify($scope.workshop.concreteTargetedRules)
|
||||
}, function(response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage("Error", response.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeWhiteListClient = function () {
|
||||
/**
|
||||
* check if a given object is empty.
|
||||
* @param obj: The object to check
|
||||
* @returns {boolean}: true if empty false if not empty
|
||||
*/
|
||||
$scope.isObjectEmpty = function(obj) {
|
||||
return (Object.keys(obj).length === 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the contents of a given file.
|
||||
* @param filePath: The path to the file to load
|
||||
*/
|
||||
$scope.loadFileContent = function(filePath) {
|
||||
getFileOrDirectoryContent(filePath, function(response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage("Error Getting Contents", response.message);
|
||||
return;
|
||||
}
|
||||
$scope.workshop.editFile = {
|
||||
"name": response.content.name,
|
||||
"path": response.content.path,
|
||||
"size": response.content.size,
|
||||
"content": response.content.fileContent
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup the workshop to create a new empty file.
|
||||
*/
|
||||
$scope.setupNewFile = function() {
|
||||
var basePath = ($scope.workshop.portal.storage === "sd") ? "/sd/portals/" : "/root/portals/";
|
||||
$scope.workshop.editFile.path = basePath + $scope.workshop.portal.title + "/";
|
||||
$scope.workshop.editFile.isNewFile = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write file content to the file system.
|
||||
* @param editFile: A portal.editFile object
|
||||
*/
|
||||
$scope.saveFileContent = function(editFile) {
|
||||
// new files wont have the filename in the path so make sure to set it here if needed.
|
||||
if (!editFile.path.includes(editFile.name))
|
||||
editFile.path = editFile.path + editFile.name;
|
||||
|
||||
console.log(editFile.path);
|
||||
writeToFile(editFile.path, editFile.content, false, function(response) {
|
||||
if (!response.success)
|
||||
$scope.sendMessage("Error write to file " + editFile.name, response.message);
|
||||
|
||||
$scope.loadPortal($scope.workshop.portal); // refresh the portal
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a requested file.
|
||||
*/
|
||||
$scope.deleteFile = function() {
|
||||
deleteFileOrDirectory($scope.workshop.deleteFile.path, function(response){
|
||||
if (!response.success)
|
||||
$scope.sendMessage("Error deleting file " + $scope.workshop.deleteFile.name, response.message);
|
||||
|
||||
$scope.loadPortal($scope.workshop.portal); // refresh the portal
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Load either the white list or the authorized clients (access) list
|
||||
* @param listName: The name of the list: whiteList or accessList (authorized clients)
|
||||
*/
|
||||
$scope.getList = function (listName) {
|
||||
var whiteList = '/pineapple/modules/EvilPortal/data/allowed.txt';
|
||||
var authorized = '/tmp/EVILPORTAL_CLIENTS.txt';
|
||||
|
||||
getFileOrDirectoryContent((listName === "whiteList") ? whiteList : authorized, function (response) {
|
||||
switch (listName) {
|
||||
case 'whiteList':
|
||||
$scope.whiteList.clients = response.content.fileContent;
|
||||
break;
|
||||
case 'accessList':
|
||||
$scope.accessList.clients = response.content.fileContent;
|
||||
break;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a client from either the white list (whiteList) the authorized clients list (accessList)
|
||||
* @param listName: whiteList or accessList
|
||||
*/
|
||||
$scope.removeClientFromList = function(listName) {
|
||||
var clientToRemove = (listName === 'whiteList') ? $scope.whiteList.toManipulate : $scope.accessList.toManipulate;
|
||||
console.log(clientToRemove);
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "removeFromList",
|
||||
listName: "whiteList",
|
||||
clientIP: $scope.whiteListInput
|
||||
}, function (response) {
|
||||
if (response.remove_success) {
|
||||
$scope.whiteListInput = '';
|
||||
$scope.getList("whiteList");
|
||||
} else {
|
||||
$scope.sendMessage("White List", response.remove_message);
|
||||
console.log(response);
|
||||
action: "removeClientFromList",
|
||||
clientIP: clientToRemove,
|
||||
listName: listName
|
||||
}, function(response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage("Error", response.message);
|
||||
return;
|
||||
}
|
||||
$scope.getList(listName);
|
||||
switch (listName) {
|
||||
case 'whiteList':
|
||||
$scope.whiteList.toManipulate = null;
|
||||
break;
|
||||
case 'accessList':
|
||||
$scope.accessList.toManipulate = null;
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a new client to the white list
|
||||
*/
|
||||
$scope.addWhiteListClient = function() {
|
||||
writeToFile('/pineapple/modules/EvilPortal/data/allowed.txt', $scope.whiteList.toManipulate + "\n", true, function(response) {
|
||||
$scope.getList('whiteList');
|
||||
});
|
||||
$scope.whiteList.toManipulate = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Authorize a new client
|
||||
*/
|
||||
$scope.authorizeClient = function () {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "addToList",
|
||||
listName: "accessList",
|
||||
clientIP: $scope.accessListInput
|
||||
action: "authorizeClient",
|
||||
clientIP: $scope.accessList.toManipulate
|
||||
}, function (response) {
|
||||
if (response.add_success) {
|
||||
$scope.accessListInput = '';
|
||||
$scope.getList("accessList");
|
||||
} else {
|
||||
$scope.sendMessage("Access List", response.add_message);
|
||||
console.log(response);
|
||||
}
|
||||
$scope.getList('accessList');
|
||||
$scope.accessList.toManipulate = null;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.revokeClient = function () {
|
||||
/**
|
||||
* Get a line clicked in a text area and set that line as the text for a text input
|
||||
* @param textareaId: The id of the text area to grab from
|
||||
* @param inputname: The name of the input field to write to
|
||||
*/
|
||||
$scope.getClickedClient = function(textareaId, inputname) {
|
||||
var textarea = $('#' + textareaId);
|
||||
var lineNumber = textarea.val().substr(0, textarea[0].selectionStart).split('\n').length;
|
||||
var ssid = textarea.val().split('\n')[lineNumber-1].trim();
|
||||
$("input[name='" + inputname + "']").val(ssid).trigger('input');
|
||||
};
|
||||
|
||||
/**
|
||||
* Write given content to a given file on the file system.
|
||||
* @param filePath: The path to the file to write content to
|
||||
* @param fileContent: The content to write to the file
|
||||
* @param appendFile: Should the content be append to the file (true) or overwrite the file (false)
|
||||
* @param callback: A callback function to handle the API response
|
||||
*/
|
||||
function writeToFile(filePath, fileContent, appendFile, callback) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "removeFromList",
|
||||
listName: "accessList",
|
||||
clientIP: $scope.accessListInput
|
||||
}, function (response) {
|
||||
if (response.remove_success) {
|
||||
$scope.accessListInput = '';
|
||||
$scope.getList("accessList");
|
||||
} else {
|
||||
$scope.sendMessage("Access List", response.remove_message);
|
||||
console.log(response);
|
||||
}
|
||||
action: "writeFileContent",
|
||||
filePath: filePath,
|
||||
content: fileContent,
|
||||
append: appendFile
|
||||
}, function(response) {
|
||||
callback(response);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a directory
|
||||
* @param pathToObject: The full path to the file or directory to get the contents of
|
||||
* @param callback: A function that handles the response from the API.
|
||||
*/
|
||||
function getFileOrDirectoryContent(pathToObject, callback) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "getFileContent",
|
||||
filePath: pathToObject
|
||||
}, function(response) {
|
||||
callback(response);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file or directory from the pineapples filesystem.
|
||||
* This is intended to be used for only deleting portals and portal related files but anything can be delete.
|
||||
* @param fileOrDirectory: The path to the file to delete
|
||||
* @param callback: The callback function to handle the API response
|
||||
*/
|
||||
function deleteFileOrDirectory(fileOrDirectory, callback) {
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "deleteFile",
|
||||
filePath: fileOrDirectory
|
||||
}, function(response) {
|
||||
callback(response);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the control models so they reflect the proper information
|
||||
*/
|
||||
function updateControls() {
|
||||
$scope.controls = [
|
||||
{
|
||||
"title": "Captive Portal",
|
||||
"status": ($scope.evilPortal.running) ? "Stop" : "Start",
|
||||
"visible": true,
|
||||
"throbber": false
|
||||
},
|
||||
{
|
||||
"title": "Start On Boot",
|
||||
"status": ($scope.evilPortal.startOnBoot) ? "Disable": "Enable",
|
||||
"visible": true,
|
||||
"throbber": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status's for the controls in the Controls pane and other various information
|
||||
*/
|
||||
function getStatus() {
|
||||
$scope.evilPortal.throbber = true;
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "status"
|
||||
}, function (response) {
|
||||
for (var key in response) {
|
||||
if (response.hasOwnProperty(key) && $scope.evilPortal.hasOwnProperty(key)) {
|
||||
$scope.evilPortal[key] = response[key];
|
||||
}
|
||||
}
|
||||
$scope.evilPortal.throbber = false;
|
||||
updateControls();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the portals on the Pineapple
|
||||
*/
|
||||
function getPortals() {
|
||||
$scope.evilPortal.throbber = true;
|
||||
$api.request({
|
||||
module: "EvilPortal",
|
||||
action: "listAvailablePortals"
|
||||
}, function(response) {
|
||||
if (!response.success) {
|
||||
$scope.sendMessage("Error Listing Portals", "An error occurred while trying to get list of portals.");
|
||||
return;
|
||||
}
|
||||
$scope.portals = [];
|
||||
response.portals.forEach(function(item, index) {
|
||||
$scope.portals.unshift({
|
||||
title: item.title,
|
||||
storage: item.storage,
|
||||
active: item.active,
|
||||
type: item.portalType,
|
||||
fullPath: item.location
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// The status for the Evil Portal module as well as current portals should be retrieved when the controller loads.
|
||||
getStatus();
|
||||
getPortals();
|
||||
|
||||
|
||||
}]);
|
||||
@ -1,6 +1,7 @@
|
||||
<div class="row" ng-controller="EvilPortalController">
|
||||
|
||||
<div class="col-md-3">
|
||||
<!-- Controls Panel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="javascript:;" data-toggle="collapse" data-target="#collapseControls" class="text-muted"><h4
|
||||
@ -24,6 +25,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages Panel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="javascript:;" data-toggle="collapse" data-target="#collapseMessages" class="text-muted"><h4
|
||||
@ -37,10 +40,11 @@
|
||||
<table style="width:100%" ng-hide="(messages.length == 0)">
|
||||
<tr ng-repeat="message in messages">
|
||||
<td>
|
||||
<hr/>
|
||||
<h5><b>{{ message.title }}</b> <a ng-click="dismissMessage($index)" href="javascript:;"
|
||||
class="pull-right">Dismiss</a></h5>
|
||||
<fieldset>
|
||||
<legend><h5><b>{{ message.title }}</b> <a ng-click="dismissMessage($index)" href="javascript:;"
|
||||
class="pull-right">Dismiss</a></h5></legend>
|
||||
<p class="text-muted"><i>{{ message.msg }}</i></p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -49,49 +53,65 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<div ng-show="dependencies">-->
|
||||
<div class="panel-group" id="accordion">
|
||||
<div class="col-md-9">
|
||||
<!-- Library panel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
|
||||
data-target="#collapseLibrary" class="text-muted">Work Bench</a></h5>
|
||||
data-target="#collapseLibrary" class="text-muted">Work Bench <b style="text-transform: capitalize"><i>{{ workshop.portal.title }}</i></b></a></h5>
|
||||
</div>
|
||||
<div id="collapseLibrary" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<div class="input-group" ng-show="library">
|
||||
<input type="text" class="form-control" placeholder="PortalName" name="portalName"
|
||||
ng-model="newPortalName">
|
||||
<span class="input-group-btn">
|
||||
<button ng-disabled="newPortalName == ''" class="btn btn-default" type="button" ng-click="createNewPortal()">Create New Portal</button>
|
||||
</span>
|
||||
<div class="input-group" ng-show="evilPortal.library">
|
||||
|
||||
<span class="input-group-btn">
|
||||
<select class="form-control ng-pristine ng-valid ng-touched" style="width:80px" ng-model="newPortal.type">
|
||||
<option value="basic">Basic</option>
|
||||
<option value="targeted">Targeted</option>
|
||||
</select>
|
||||
</span>
|
||||
|
||||
<input type="text" class="form-control" placeholder="Portal Name" name="portalName" ng-model="newPortal.name">
|
||||
|
||||
<span class="input-group-btn">
|
||||
<button ng-disabled="newPortal.name == ''" class="btn btn-default" type="button" ng-click="createNewPortal('internal')">Create New Portal</button>
|
||||
<button ng-disabled="newPortal.name == ''" class="btn btn-default" type="button" ng-click="createNewPortal('sd')" ng-show="evilPortal.sdAvailable">Create On SD Card</button>
|
||||
</span>
|
||||
</div>
|
||||
<hr ng-show="library"/>
|
||||
<div ng-show="portals.length > 0 && library == true">
|
||||
<hr ng-show="evilPortal.library"/>
|
||||
<div ng-show="portals.length > 0 && evilPortal.library">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" align="center">
|
||||
<thead>
|
||||
<th>Portal Name</th>
|
||||
<th>Portal Type</th>
|
||||
<th>Location</th>
|
||||
<th ng-show="evilPortal.sdAvailable">Move</th>
|
||||
<th>Activate</th>
|
||||
<th>Delete</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="portal in portals">
|
||||
<td><a href="javascript:;" ng-click="getPortalFiles(portal)"><b>{{ portal.title
|
||||
}}</b></a></td>
|
||||
<td class="text-muted"><i>{{ portal.storage }}</i></td>
|
||||
<td ng-hide="portal.active"><a href="javascript:;"
|
||||
ng-click="activatePortal(portal)">Activate</a>
|
||||
<!-- Open portal work shop -->
|
||||
<td><a href="javascript:;" ng-click="loadPortal(portal)" style="text-transform: capitalize"><b>{{ portal.title }}</b></a></td>
|
||||
<!-- Portal type -->
|
||||
<td class="text-muted" style="text-transform: capitalize"><i>{{ portal.type }}</i></td>
|
||||
<!-- What storage device the portal is on -->
|
||||
<td class="text-muted" style="text-transform: capitalize"><i>{{ portal.storage }}</i></td>
|
||||
<!-- change storage -->
|
||||
<td ng-show="evilPortal.sdAvailable">
|
||||
<a ng-show="(portal.storage == 'internal') && !portal.active" href="javascript:;" ng-click="movePortal(portal, 'sd');">Move to SD</a>
|
||||
<a ng-show="(portal.storage == 'sd') && !portal.active" href="javascript:;" ng-click="movePortal(portal, 'internal');">Move to Internal</a>
|
||||
</td>
|
||||
<td ng-show="portal.active"><a href="javascript:;"
|
||||
ng-click="deactivatePortal(portal)">Deactivate</a>
|
||||
<!-- activate/deactivate -->
|
||||
<td>
|
||||
<a ng-hide="portal.active" href="javascript:;" ng-click="activatePortal(portal)">Activate</a>
|
||||
<a ng-show="portal.active" href="javascript:;" ng-click="deactivatePortal(portal)">Deactivate</a>
|
||||
</td>
|
||||
<td ng-hide="portal.active"><a href="javascript:;" data-toggle="modal"
|
||||
data-target="#deleteModal"
|
||||
ng-click="deletePortalRequest(portal)"
|
||||
ng-hide="portal.storage == 'active'">Delete</a>
|
||||
<!-- delete portal button -->
|
||||
<td>
|
||||
<a ng-hide="portal.active" data-toggle="modal" data-target="#deleteModal" ng-click="deletePortal(false, portal)">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -99,28 +119,43 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-hide="portals.length > 0 || library == false">
|
||||
<div ng-hide="portals.length > 0 || !evilPortal.library">
|
||||
<p class="text-muted text-center"><i>No Portals in Library to Display.</i></p>
|
||||
</div>
|
||||
|
||||
<div ng-show="library == false">
|
||||
<button type="submit" class="btn btn-default btn-sm" ng-click="library = true">Back To
|
||||
Library
|
||||
</button>
|
||||
<hr />
|
||||
<h3>Contents of {{ workshopPortal.name }}</h3>
|
||||
<!-- Portal Editor -->
|
||||
<div ng-hide="evilPortal.library">
|
||||
|
||||
<!-- Editor Buttons -->
|
||||
<div class="row-fluid">
|
||||
<span class="pull-left">
|
||||
<button type="submit" class="btn btn-default btn-sm" ng-click="evilPortal.library = true; resetWorkshop()">Back To Library</button>
|
||||
</span>
|
||||
<span class="pull-right">
|
||||
<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#fileModal" ng-click="setupNewFile()">New File</button>
|
||||
<!-- Holding off on toggle commands until a future release. Still need to think through how they should work. -->
|
||||
<!--<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#commandEditorModal" ng-click="loadToggleCommands()">Toggle Commands</button>-->
|
||||
<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#ruleEditorModal" ng-show="workshop.portal.type == 'targeted'" ng-click="loadTargetedRules();">Target Rule Editor</button>
|
||||
<button type="submit" class="btn btn-default btn-sm" ng-click="loadPortal(workshop.portal)">Refresh</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<hr />
|
||||
|
||||
<!-- Portal Files -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" align="center">
|
||||
<thead>
|
||||
<th>File Name</th>
|
||||
<th>Edit</th>
|
||||
<th>Delete</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="file in workshopPortal.files">
|
||||
<td>{{ file }}</td>
|
||||
<td><a href="javascript:;" ng-click="editPortal(workshopPortal, file)"
|
||||
data-toggle="modal" data-target="#fileModal">Edit</a></td>
|
||||
<tr ng-repeat="file in workshop.dirContents">
|
||||
<td>{{ file.name }}</td>
|
||||
<td><a href="javascript:;" ng-click="loadFileContent(file.path)" data-toggle="modal" data-target="#fileModal">Edit</a></td>
|
||||
<td><a href="javascript:;" ng-click="workshop.deleteFile = file" data-toggle="modal" data-target="#deleteFileModal" ng-show="file.deletable">Delete</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -144,18 +179,18 @@
|
||||
<i>This is a list of clients who are allowed to connect to the internet without ever viewing the captive portal.</i>
|
||||
</p>
|
||||
<p>
|
||||
<textarea class="form-control" rows="15" ng-model="whiteList" readonly></textarea>
|
||||
<textarea id="whiteListPool" class="form-control" rows="15" ng-mouseup="getClickedClient('whiteListPool', 'whiteListInput');" ng-model="whiteList.clients" readonly></textarea>
|
||||
</p>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" placeholder="IP Address" name="ipaddress"
|
||||
ng-model="whiteListInput">
|
||||
<input type="text" class="form-control" placeholder="IP Address" name="whiteListInput"
|
||||
ng-model="whiteList.toManipulate">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="button"
|
||||
ng-click="addWhiteListClient()">Add</button>
|
||||
<button class="btn btn-default" type="button"
|
||||
ng-click="removeWhiteListClient()">Remove</button>
|
||||
<button class="btn btn-default" type="button" ng-click="addWhiteListClient()">Add</button>
|
||||
<button class="btn btn-default" type="button" ng-click="removeClientFromList('whiteList')">Remove</button>
|
||||
</span>
|
||||
</div>
|
||||
<br/>
|
||||
<button class="btn btn-default btn-sm" type="button" ng-click="getList('whiteList')">Refresh</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -169,22 +204,24 @@
|
||||
</div>
|
||||
<div id="collapseAuthorizedClients" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<p class="text-muted" ng-show="running">
|
||||
<i>This is a list of clients who have been authorized through the captive portal.</i>
|
||||
</p>
|
||||
<p ng-show="running">
|
||||
<textarea class="form-control" rows="15" ng-model="accessList" readonly></textarea>
|
||||
</p>
|
||||
<div class="input-group" ng-show="running">
|
||||
<input type="text" class="form-control" placeholder="IP Address" name="ipaddress"
|
||||
ng-model="accessListInput">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="button"
|
||||
ng-click="authorizeClient()">Authorize</button>
|
||||
<button class="btn btn-default" type="button" ng-click="revokeClient()">Revoke</button>
|
||||
</span>
|
||||
<div ng-show="evilPortal.running">
|
||||
<p class="text-muted">
|
||||
<i>This is a list of clients who have been authorized through the captive portal.</i>
|
||||
</p>
|
||||
<p>
|
||||
<textarea id='authorizedPool' class="form-control" rows="15" ng-mouseup="getClickedClient('authorizedPool', 'accessListInput');" ng-model="accessList.clients" readonly></textarea>
|
||||
</p>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" placeholder="IP Address" name="accessListInput" ng-model="accessList.toManipulate">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="button" ng-click="authorizeClient()">Authorize</button>
|
||||
<button class="btn btn-default" type="button" ng-click="removeClientFromList('accessList')">Revoke</button>
|
||||
</span>
|
||||
</div>
|
||||
<br />
|
||||
<button class="btn btn-default btn-sm" type="button" ng-click="getList('accessList')">Refresh</button>
|
||||
</div>
|
||||
<div ng-hide="running">
|
||||
<div ng-hide="evilPortal.running">
|
||||
<p class="text-muted text-center"><i>Evil Portal must be started first.</i></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -200,14 +237,12 @@
|
||||
</div>
|
||||
<div id="collapsePreview" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<div ng-show="running">
|
||||
<div ng-show="evilPortal.running">
|
||||
<iframe src="http://172.16.42.1" style="width:100%;height:300px;border:none;"
|
||||
id="livePreviewIframe"></iframe>
|
||||
<button type="submit" ng-click="refreshLivePreview()" class="btn btn-default btn-sm">
|
||||
Refresh
|
||||
</button>
|
||||
<button type="submit" ng-click="refreshLivePreview()" class="btn btn-default btn-sm">Refresh</button>
|
||||
</div>
|
||||
<div ng-hide="running">
|
||||
<div ng-hide="evilPortal.running">
|
||||
<p class="text-muted text-center"><i>Evil Portal must be started first.</i></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -218,35 +253,72 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
|
||||
data-target="#collapseChangelog" class="text-muted">Evil Portal Change
|
||||
Log</a></h5>
|
||||
data-target="#collapseChangelog" class="text-muted">Evil Portal Info</a></h5>
|
||||
</div>
|
||||
<div id="collapseChangelog" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li><b>2.1</b></li>
|
||||
<fieldset>
|
||||
<legend>Disclaimer</legend>
|
||||
<p><b>Evil Portal and all of its components are intended for professional use only. No one associated with this project is an anyway liable for your actions.</b></p>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Help</legend>
|
||||
<h5>Summary</h5>
|
||||
<p>Evil Portal is a captive portal program that enables you to easily create a captive portal for whatever your needs are. There are two kinds of portals Basic and Targeted.
|
||||
Basic portals are just a simple page that gets served to all clients. Targeted portals allow you to serve a unique page to different clients based on a given rule.</p>
|
||||
<h5>Basic Portals</h5>
|
||||
<p>A Basic Portal is a one-size serves all kind of portal. These portals are designed to be a single page that all clients will land on. This is the traditional way
|
||||
that captive portals work and the way Evil Portal as been doing things from the beginning.</p>
|
||||
<h5>Targeted Portals</h5>
|
||||
<p>A Targeted Portal allows you to serve a different page on a per-client basis based on a condition. This can be something like their mac address, user-agent, etc...
|
||||
Targeted Portals give you a whole new dynamic to what Evil Portal can do, if you want clients who are connected to the SSID "Coffee Shop" to see a "Coffee Shop" branded portal
|
||||
while at the same time clients with Android phones seeing an Android branded portal then this is what you want.</p>
|
||||
<h5>Useful Links</h5>
|
||||
<a href="https://forums.hak5.org/index.php?/topic/37874-official-evilportal/">Hak5 Forum Thread</a>
|
||||
<br />
|
||||
<a href="https://github.com/frozenjava/EvilPortalNano">GitHub Project</a>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Change Log</legend>
|
||||
<ul>
|
||||
<li class="text-muted">Removed un-needed verbosity</li>
|
||||
<li class="text-muted">Made tab key indent in the editor instead of change elements</li>
|
||||
<li class="text-muted">Added confirmation dialogue box when deleting a portal</li>
|
||||
<li class="text-muted">Created auto-start feature</li>
|
||||
<li class="text-muted">Various other quality of life updates</li>
|
||||
<li><b>3.0</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Added ability to route clients to different portals based upon some identifier [ssid, mac vendor, ip, etc...]</li>
|
||||
<li class="text-muted">Updated the work bench so users can choose between targeted and non-targeted portals</li>
|
||||
<li class="text-muted">Created easy-to-use interface for creating targeting rules</li>
|
||||
<li class="text-muted">Created some consistency throughout the UI</li>
|
||||
<li class="text-muted">Added ability to create portals on an SD card and move between SD and Internal storage easily</li>
|
||||
<li class="text-muted">Made white listed and authorized clients IP addresses clickable like SSIDs in PineAP</li>
|
||||
<li class="text-muted">Created helper functions getClientMac, getClientSSID, getClientHostName</li>
|
||||
<li class="text-muted">Sending notification when a client goes through a portal.</li>
|
||||
<li class="text-muted">Various quality of life improvements</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>2.0</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Captive Portal is now purely iptables (because F***
|
||||
NoDogSplash)
|
||||
</li>
|
||||
<li><b>2.1</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Removed un-needed verbosity</li>
|
||||
<li class="text-muted">Made tab key indent in the editor instead of change elements</li>
|
||||
<li class="text-muted">Added confirmation dialogue box when deleting a portal</li>
|
||||
<li class="text-muted">Created auto-start feature</li>
|
||||
<li class="text-muted">Various other quality of life updates</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>1.0</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Initial Pineapple Nano Release</li>
|
||||
<li><b>2.0</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Captive Portal is now purely iptables (because F***
|
||||
NoDogSplash)
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>1.0</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Initial Pineapple Nano Release</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -254,6 +326,7 @@
|
||||
</div>
|
||||
<!--</div>-->
|
||||
|
||||
<!-- Edit file modal -->
|
||||
<div id="fileModal" class="modal fade" role="dialog">
|
||||
|
||||
<script type="text/javascript">
|
||||
@ -263,7 +336,7 @@
|
||||
|
||||
if (keyCode == 9) {
|
||||
e.preventDefault();
|
||||
var start = $(this).get(0).selectionStart;
|
||||
var start = $(this).get(0).selection;
|
||||
var end = $(this).get(0).selectionEnd;
|
||||
|
||||
// set textarea value to: text before caret + tab + text after caret
|
||||
@ -284,30 +357,27 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"
|
||||
ng-click="editPortalFile = {}">×</button>
|
||||
<h4 class="modal-title">File Editor {{ editPortalFile.file }}</h4>
|
||||
ng-click="workshop.editFile = {}">×</button>
|
||||
<h4 class="modal-title" ng-show="!workshop.editFile.isNewFile">Editing File {{ workshop.editFile.name }}</h4>
|
||||
<h4 class="modal-title" ng-show="workshop.editFile.isNewFile">Creating New File</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="control-label">File Name</label>
|
||||
<input type="text" class="form-control" ng-model="editPortalFile.file"
|
||||
placeholder="Notes.txt" disabled>
|
||||
<input type="text" class="form-control" ng-model="workshop.editFile.name" placeholder="Notes.txt" ng-disabled="!workshop.editFile.isNewFile">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">File Contents</label> <a href="javascript:;"
|
||||
ng-click="editPortalFile.code = ''">Clear</a>
|
||||
<textarea class="form-control" rows="10" ng-model="editPortalFile.code"
|
||||
<label class="control-label">File Contents</label> <a href="javascript:;" ng-click="workshop.editFile.content = null">Clear</a>
|
||||
<textarea class="form-control" rows="10" ng-model="workshop.editFile.content"
|
||||
placeholder="Write some text here" id="evilportalEditor"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" ng-click="savePortalCode(editPortalFile)" class="btn btn-success pull-left"
|
||||
data-dismiss="modal">Save
|
||||
</button>
|
||||
<button type="button" class="btn btn-default pull-right" data-dismiss="modal"
|
||||
ng-click="editPortalFile = {}">Cancel
|
||||
<button type="button" ng-click="saveFileContent(workshop.editFile);" class="btn btn-success pull-right" data-dismiss="modal" ng-disabled="workshop.editFile.content == null">Save</button>
|
||||
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"
|
||||
ng-click="workshop.editFile = {}">Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -315,7 +385,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Delete file Modal -->
|
||||
<!-- Delete Portal Modal -->
|
||||
<div id="deleteModal" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
|
||||
@ -323,7 +393,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" ng-click="portalToDelete = null; portalDeleteValidation = null">×</button>
|
||||
<h4 class="modal-title">Delete Portal {{ portalToDelete.title }}</h4>
|
||||
<h4 class="modal-title">Delete Portal <i>{{ portalToDelete.title }}</i>?</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>You are about to delete {{ portalToDelete.title }} on {{ portalToDelete.storage }} storage. Once you do this it can not be undone.</p>
|
||||
@ -331,8 +401,121 @@
|
||||
<input type="text" class="form-control" placeholder="PortalName" name="portalName" ng-model="portalDeleteValidation">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary pull-left" data-dismiss="modal" ng-click="portalToDelete = null; portalDeleteValidation = null">Cancel</button>
|
||||
<button type="button" class="btn btn-danger pull-right" data-dismiss="modal" ng-click="deletePortal(portalToDelete)" ng-disabled="portalDeleteValidation != portalToDelete.title">Delete</button>
|
||||
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" ng-click="portalToDelete = null; portalDeleteValidation = null">Cancel</button>
|
||||
<button type="button" class="btn btn-danger pull-right" data-dismiss="modal" ng-click="deletePortal(true, portalToDelete)" ng-disabled="portalDeleteValidation.toLowerCase() != portalToDelete.title.toLowerCase()">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete file Modal -->
|
||||
<div id="deleteFileModal" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
|
||||
<!-- Modal content-->
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" ng-click="workshop.deleteFile = {}">×</button>
|
||||
<h4 class="modal-title">Delete File <i><b>{{ workshop.deleteFile.name }}</b></i>?</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>You are about to delete <b>{{ workshop.deleteFile.path }}</b>. Once you do this it can not be undone.</p>
|
||||
<p><b>Are you absolutely sure you want to delete <i>{{ workshop.deleteFile.name }}</i>?</b></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" ng-click="workshop.deleteFile = {}">Cancel</button>
|
||||
<button type="button" class="btn btn-danger pull-right" data-dismiss="modal" ng-click="deleteFile()">Delete {{ workshop.deleteFile.name }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Rule Editor Modal -->
|
||||
<div id="ruleEditorModal" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
|
||||
<!-- Modal content-->
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" ng-click="">×</button>
|
||||
<h4 class="modal-title">Editing Rules for {{ workshop.portal.title }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div ng-repeat="(key, data) in workshop.concreteTargetedRules.rules">
|
||||
<fieldset>
|
||||
<legend style="text-transform: uppercase">{{ key }}</legend>
|
||||
<div ng-repeat="(specifier, values) in data">
|
||||
<h5 style="text-transform: capitalize">{{ specifier }} <a href="javascript:;" data-target="#" ng-click="newTargetedRule(key, specifier);">Add Rule</a></h5>
|
||||
<div class="table-responsive" ng-hide="isObjectEmpty(workshop.workingTargetedRules.rules[key][specifier])">
|
||||
<table class="table table-striped" align="center">
|
||||
<thead>
|
||||
<th>Rule Key</th>
|
||||
<th>Destination</th>
|
||||
<!--<th>Commit</th>-->
|
||||
<th>Remove</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="(i, rules) in workshop.workingTargetedRules.rules[key][specifier]">
|
||||
<td><input type="text" placeholder="Key Value" ng-model="rules.key"></td>
|
||||
<td><input type="text" placeholder="Destination.php" ng-model="rules.destination"></td>
|
||||
<!--<td><a href="javascript:;" data-target="#" ng-click="commitPortalRule(key, specifier, i, rules.key, rules.destination)">Commit</a></td>-->
|
||||
<td><button ng-click="removeTargetedRule(key, specifier, i)" class="btn btn-sm btn-danger">Remove</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" ng-click="">Cancel</button>
|
||||
<button type="button" class="btn btn-success pull-right" data-dismiss="modal" ng-click="saveTargetedRules()" >Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toggled command editor -->
|
||||
<div id="commandEditorModal" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
|
||||
<!-- Modal content-->
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Toggle Commands for {{ workshop.portal.title }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<fieldset>
|
||||
<legend>On Activation - <a ng-click="saveToggleCommands('enable')">Save</a></legend>
|
||||
<div class="center-block">
|
||||
<!-- For sake of getting EP 3.0 release, I'm not going to implement this just yet.
|
||||
<span class="center-block">
|
||||
<button type="submit" class="btn btn-link btn-sm">Enable PineAP</button>
|
||||
<button type="submit" class="btn btn-link btn-sm">Enable Karma Associations</button>
|
||||
<button type="submit" class="btn btn-link btn-sm">Enable Beacon Response</button>
|
||||
</span>-->
|
||||
</div>
|
||||
<textarea style="width:100%;" rows="10" ng-model="workshop.onEnable"></textarea>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>On Deactivation - <a ng-click="saveToggleCommands('disable')">Save</a></legend>
|
||||
<div class="row-fluid">
|
||||
<!-- For sake of getting EP 3.0 release, I'm not going to implement this just yet.
|
||||
<span class="center-block">
|
||||
<button type="submit" class="btn btn-link btn-sm">Disable PineAP</button>
|
||||
<button type="submit" class="btn btn-link btn-sm">Disable Karma Associations</button>
|
||||
<button type="submit" class="btn btn-link btn-sm">Disable Beacon Response</button>
|
||||
</span>-->
|
||||
</div>
|
||||
<textarea style="width:100%;" rows="10" ng-model="workshop.onDisable"></textarea>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success pull-right" data-dismiss="modal" ng-click="saveToggleCommands('all')">Save All</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "Evil Portal",
|
||||
"version": "2.1"
|
||||
}
|
||||
"version": "3.0"
|
||||
}
|
||||
|
||||
@ -56,18 +56,18 @@ class LEDController extends Module
|
||||
|
||||
private function getTetraYellow()
|
||||
{
|
||||
$trigger = $this->uciGet('system.@led[2].trigger');
|
||||
$trigger = $this->uciGet('system.led_eth0.trigger');
|
||||
|
||||
if ($trigger == 'none') {
|
||||
$default = $this->uciGet('system.@led[2].default');
|
||||
$default = $this->uciGet('system.led_eth0.default');
|
||||
if ($default == 0) {
|
||||
$this->response = array('enabled' => false, 'trigger' => $trigger);
|
||||
} elseif ($default == 1) {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger);
|
||||
}
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$mode = $this->uciGet('system.@led[2].mode');
|
||||
$interface = $this->uciGet('system.@led[2].dev');
|
||||
$mode = $this->uciGet('system.led_eth0.mode');
|
||||
$interface = $this->uciGet('system.led_eth0.dev');
|
||||
if ($mode == 'link tx rx') {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'mode' => 'link tx rx', 'interface' => $interface);
|
||||
@ -79,8 +79,8 @@ class LEDController extends Module
|
||||
'mode' => 'link rx', 'interface' => $interface);
|
||||
}
|
||||
} elseif ($trigger == 'timer') {
|
||||
$delayOn = $this->uciGet('system.@led[2].delayon');
|
||||
$delayOff = $this->uciGet('system.@led[2].delayoff');
|
||||
$delayOn = $this->uciGet('system.led_eth0.delayon');
|
||||
$delayOff = $this->uciGet('system.led_eth0.delayoff');
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'delayOn' => $delayOn, 'delayOff' => $delayOff);
|
||||
} else {
|
||||
@ -99,23 +99,23 @@ class LEDController extends Module
|
||||
|
||||
if ($enabled == true) {
|
||||
if ($trigger == 'none') {
|
||||
$this->uciSet('system.@led[2].trigger', 'none');
|
||||
$this->uciSet('system.@led[2].default', '1');
|
||||
$this->uciSet('system.led_eth0.trigger', 'none');
|
||||
$this->uciSet('system.led_eth0.default', '1');
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$this->uciSet('system.@led[2].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[2].mode', "$mode");
|
||||
$this->uciSet('system.@led[2].dev', "$interface");
|
||||
$this->uciSet('system.led_eth0.trigger', 'netdev');
|
||||
$this->uciSet('system.led_eth0.mode', "$mode");
|
||||
$this->uciSet('system.led_eth0.dev', "$interface");
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'timer') {
|
||||
$this->uciSet('system.@led[2].trigger', 'timer');
|
||||
$this->uciSet('system.@led[2].delayon', "$delayOn");
|
||||
$this->uciSet('system.@led[2].delayoff', "$delayOff");
|
||||
$this->uciSet('system.led_eth0.trigger', 'timer');
|
||||
$this->uciSet('system.led_eth0.delayon', "$delayOn");
|
||||
$this->uciSet('system.led_eth0.delayoff', "$delayOff");
|
||||
$this->restartLEDs();
|
||||
}
|
||||
} elseif ($enabled == false) {
|
||||
$this->uciSet('system.@led[2].trigger', 'none');
|
||||
$this->uciSet('system.@led[2].default', '0');
|
||||
$this->uciSet('system.led_eth0.trigger', 'none');
|
||||
$this->uciSet('system.led_eth0.default', '0');
|
||||
$this->restartLEDs();
|
||||
}
|
||||
|
||||
@ -126,18 +126,18 @@ class LEDController extends Module
|
||||
|
||||
private function getTetraBlue()
|
||||
{
|
||||
$trigger = $this->uciGet('system.@led[0].trigger');
|
||||
$trigger = $this->uciGet('system.led_wlan0.trigger');
|
||||
|
||||
if ($trigger == 'none') {
|
||||
$default = $this->uciGet('system.@led[0].default');
|
||||
$default = $this->uciGet('system.led_wlan0.default');
|
||||
if ($default == 0) {
|
||||
$this->response = array('enabled' => false, 'trigger' => $trigger);
|
||||
} elseif ($default == 1) {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger);
|
||||
}
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$mode = $this->uciGet('system.@led[0].mode');
|
||||
$interface = $this->uciGet('system.@led[0].dev');
|
||||
$mode = $this->uciGet('system.led_wlan0.mode');
|
||||
$interface = $this->uciGet('system.led_wlan0.dev');
|
||||
if ($mode == 'link tx rx') {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'mode' => 'link tx rx', 'interface' => $interface);
|
||||
@ -149,8 +149,8 @@ class LEDController extends Module
|
||||
'mode' => 'link rx', 'interface' => $interface);
|
||||
}
|
||||
} elseif ($trigger == 'timer') {
|
||||
$delayOn = $this->uciGet('system.@led[0].delayon');
|
||||
$delayOff = $this->uciGet('system.@led[0].delayoff');
|
||||
$delayOn = $this->uciGet('system.led_wlan0.delayon');
|
||||
$delayOff = $this->uciGet('system.led_wlan0.delayoff');
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'delayOn' => $delayOn, 'delayOff' => $delayOff);
|
||||
} else {
|
||||
@ -169,23 +169,23 @@ class LEDController extends Module
|
||||
|
||||
if ($enabled == true) {
|
||||
if ($trigger == 'none') {
|
||||
$this->uciSet('system.@led[0].trigger', 'none');
|
||||
$this->uciSet('system.@led[0].default', '1');
|
||||
$this->uciSet('system.led_wlan0.trigger', 'none');
|
||||
$this->uciSet('system.led_wlan0.default', '1');
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$this->uciSet('system.@led[0].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[0].mode', "$mode");
|
||||
$this->uciSet('system.@led[0].dev', "$interface");
|
||||
$this->uciSet('system.led_wlan0.trigger', 'netdev');
|
||||
$this->uciSet('system.led_wlan0.mode', "$mode");
|
||||
$this->uciSet('system.led_wlan0.dev', "$interface");
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'timer') {
|
||||
$this->uciSet('system.@led[0].trigger', 'timer');
|
||||
$this->uciSet('system.@led[0].delayon', "$delayOn");
|
||||
$this->uciSet('system.@led[0].delayoff', "$delayOff");
|
||||
$this->uciSet('system.led_wlan0.trigger', 'timer');
|
||||
$this->uciSet('system.led_wlan0.delayon', "$delayOn");
|
||||
$this->uciSet('system.led_wlan0.delayoff', "$delayOff");
|
||||
$this->restartLEDs();
|
||||
}
|
||||
} elseif ($enabled == false) {
|
||||
$this->uciSet('system.@led[0].trigger', 'none');
|
||||
$this->uciSet('system.@led[0].default', '0');
|
||||
$this->uciSet('system.led_wlan0.trigger', 'none');
|
||||
$this->uciSet('system.led_wlan0.default', '0');
|
||||
$this->restartLEDs();
|
||||
}
|
||||
|
||||
@ -196,18 +196,18 @@ class LEDController extends Module
|
||||
|
||||
private function getTetraRed()
|
||||
{
|
||||
$trigger = $this->uciGet('system.@led[1].trigger');
|
||||
$trigger = $this->uciGet('system.led_wlan1mon.trigger');
|
||||
|
||||
if ($trigger == 'none') {
|
||||
$default = $this->uciGet('system.@led[1].default');
|
||||
$default = $this->uciGet('system.led_wlan1mon.default');
|
||||
if ($default == 0) {
|
||||
$this->response = array('enabled' => false, 'trigger' => $trigger);
|
||||
} elseif ($default == 1) {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger);
|
||||
}
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$mode = $this->uciGet('system.@led[1].mode');
|
||||
$interface = $this->uciGet('system.@led[1].dev');
|
||||
$mode = $this->uciGet('system.led_wlan1mon.mode');
|
||||
$interface = $this->uciGet('system.led_wlan1mon.dev');
|
||||
if ($mode == 'link tx rx') {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'mode' => 'link tx rx', 'interface' => $interface);
|
||||
@ -219,8 +219,8 @@ class LEDController extends Module
|
||||
'mode' => 'link rx', 'interface' => $interface);
|
||||
}
|
||||
} elseif ($trigger == 'timer') {
|
||||
$delayOn = $this->uciGet('system.@led[1].delayon');
|
||||
$delayOff = $this->uciGet('system.@led[1].delayoff');
|
||||
$delayOn = $this->uciGet('system.led_wlan1mon.delayon');
|
||||
$delayOff = $this->uciGet('system.led_wlan1mon.delayoff');
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'delayOn' => $delayOn, 'delayOff' => $delayOff);
|
||||
} else {
|
||||
@ -239,23 +239,23 @@ class LEDController extends Module
|
||||
|
||||
if ($enabled == true) {
|
||||
if ($trigger == 'none') {
|
||||
$this->uciSet('system.@led[1].trigger', 'none');
|
||||
$this->uciSet('system.@led[1].default', '1');
|
||||
$this->uciSet('system.led_wlan1mon.trigger', 'none');
|
||||
$this->uciSet('system.led_wlan1mon.default', '1');
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$this->uciSet('system.@led[1].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[1].mode', "$mode");
|
||||
$this->uciSet('system.@led[1].dev', "$interface");
|
||||
$this->uciSet('system.led_wlan1mon.trigger', 'netdev');
|
||||
$this->uciSet('system.led_wlan1mon.mode', "$mode");
|
||||
$this->uciSet('system.led_wlan1mon.dev', "$interface");
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'timer') {
|
||||
$this->uciSet('system.@led[1].trigger', 'timer');
|
||||
$this->uciSet('system.@led[1].delayon', "$delayOn");
|
||||
$this->uciSet('system.@led[1].delayoff', "$delayOff");
|
||||
$this->uciSet('system.led_wlan1mon.trigger', 'timer');
|
||||
$this->uciSet('system.led_wlan1mon.delayon', "$delayOn");
|
||||
$this->uciSet('system.led_wlan1mon.delayoff', "$delayOff");
|
||||
$this->restartLEDs();
|
||||
}
|
||||
} elseif ($enabled == false) {
|
||||
$this->uciSet('system.@led[1].trigger', 'none');
|
||||
$this->uciSet('system.@led[1].default', '0');
|
||||
$this->uciSet('system.led_wlan1mon.trigger', 'none');
|
||||
$this->uciSet('system.led_wlan1mon.default', '0');
|
||||
$this->restartLEDs();
|
||||
}
|
||||
|
||||
@ -266,18 +266,18 @@ class LEDController extends Module
|
||||
|
||||
private function getNanoBlue()
|
||||
{
|
||||
$trigger = $this->uciGet('system.@led[0].trigger');
|
||||
$trigger = $this->uciGet('system.led_wlan0.trigger');
|
||||
|
||||
if ($trigger == 'none') {
|
||||
$default = $this->uciGet('system.@led[0].default');
|
||||
$default = $this->uciGet('system.led_wlan0.default');
|
||||
if ($default == 0) {
|
||||
$this->response = array('enabled' => false, 'trigger' => $trigger);
|
||||
} elseif ($default == 1) {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger);
|
||||
}
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$mode = $this->uciGet('system.@led[0].mode');
|
||||
$interface = $this->uciGet('system.@led[0].dev');
|
||||
$mode = $this->uciGet('system.led_wlan0.mode');
|
||||
$interface = $this->uciGet('system.led_wlan0.dev');
|
||||
if ($mode == 'link tx rx') {
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'mode' => 'link tx rx', 'interface' => $interface);
|
||||
@ -289,8 +289,8 @@ class LEDController extends Module
|
||||
'mode' => 'link rx', 'interface' => $interface);
|
||||
}
|
||||
} elseif ($trigger == 'timer') {
|
||||
$delayOn = $this->uciGet('system.@led[0].delayon');
|
||||
$delayOff = $this->uciGet('system.@led[0].delayoff');
|
||||
$delayOn = $this->uciGet('system.led_wlan0.delayon');
|
||||
$delayOff = $this->uciGet('system.led_wlan0.delayoff');
|
||||
$this->response = array('enabled' => true, 'trigger' => $trigger,
|
||||
'delayOn' => $delayOn, 'delayOff' => $delayOff);
|
||||
} else {
|
||||
@ -309,23 +309,23 @@ class LEDController extends Module
|
||||
|
||||
if ($enabled == true) {
|
||||
if ($trigger == 'none') {
|
||||
$this->uciSet('system.@led[0].trigger', 'none');
|
||||
$this->uciSet('system.@led[0].default', '1');
|
||||
$this->uciSet('system.led_wlan0.trigger', 'none');
|
||||
$this->uciSet('system.led_wlan0.default', '1');
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'netdev') {
|
||||
$this->uciSet('system.@led[0].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[0].mode', "$mode");
|
||||
$this->uciSet('system.@led[0].dev', "$interface");
|
||||
$this->uciSet('system.led_wlan0.trigger', 'netdev');
|
||||
$this->uciSet('system.led_wlan0.mode', "$mode");
|
||||
$this->uciSet('system.led_wlan0.dev', "$interface");
|
||||
$this->restartLEDs();
|
||||
} elseif ($trigger == 'timer') {
|
||||
$this->uciSet('system.@led[0].trigger', 'timer');
|
||||
$this->uciSet('system.@led[0].delayon', "$delayOn");
|
||||
$this->uciSet('system.@led[0].delayoff', "$delayOff");
|
||||
$this->uciSet('system.led_wlan0.trigger', 'timer');
|
||||
$this->uciSet('system.led_wlan0.delayon', "$delayOn");
|
||||
$this->uciSet('system.led_wlan0.delayoff', "$delayOff");
|
||||
$this->restartLEDs();
|
||||
}
|
||||
} elseif ($enabled == false) {
|
||||
$this->uciSet('system.@led[0].trigger', 'none');
|
||||
$this->uciSet('system.@led[0].default', '0');
|
||||
$this->uciSet('system.led_wlan0.trigger', 'none');
|
||||
$this->uciSet('system.led_wlan0.default', '0');
|
||||
$this->restartLEDs();
|
||||
}
|
||||
|
||||
@ -339,21 +339,21 @@ class LEDController extends Module
|
||||
$device = $this->getDevice();
|
||||
|
||||
if ($device == 'tetra') {
|
||||
$this->uciSet('system.@led[0].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[0].mode', 'link tx rx');
|
||||
$this->uciSet('system.@led[0].dev', 'wlan0');
|
||||
$this->uciSet('system.@led[1].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[1].mode', 'link tx rx');
|
||||
$this->uciSet('system.@led[1].dev', 'wlan1mon');
|
||||
$this->uciSet('system.@led[2].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[2].mode', 'link tx rx');
|
||||
$this->uciSet('system.@led[2].dev', 'eth0');
|
||||
$this->uciSet('system.led_wlan0.trigger', 'netdev');
|
||||
$this->uciSet('system.led_wlan0.mode', 'link tx rx');
|
||||
$this->uciSet('system.led_wlan0.dev', 'wlan0');
|
||||
$this->uciSet('system.led_wlan1mon.trigger', 'netdev');
|
||||
$this->uciSet('system.led_wlan1mon.mode', 'link tx rx');
|
||||
$this->uciSet('system.led_wlan1mon.dev', 'wlan1mon');
|
||||
$this->uciSet('system.led_eth0.trigger', 'netdev');
|
||||
$this->uciSet('system.led_eth0.mode', 'link tx rx');
|
||||
$this->uciSet('system.led_eth0.dev', 'eth0');
|
||||
$this->restartLEDs();
|
||||
$this->response = array('success' => true);
|
||||
} else {
|
||||
$this->uciSet('system.@led[0].trigger', 'netdev');
|
||||
$this->uciSet('system.@led[0].mode', 'link tx rx');
|
||||
$this->uciSet('system.@led[0].dev', 'wlan0');
|
||||
$this->uciSet('system.led_wlan0.trigger', 'netdev');
|
||||
$this->uciSet('system.led_wlan0.mode', 'link tx rx');
|
||||
$this->uciSet('system.led_wlan0.dev', 'wlan0');
|
||||
$this->restartLEDs();
|
||||
$this->response = array('success' => true);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<div id="LEDController" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<h3 style="text-align: center;">LED Controller</h3>
|
||||
<h6 style="text-align: center;">Version 1.1</h6>
|
||||
<h6 style="text-align: center;">Version 1.3</h6>
|
||||
<p style="text-align: center;">Written by Foxtrot</p>
|
||||
|
||||
<p style="text-align: center;">This module allows you to control the LEDs behaviour on both the NANO and the TETRA.</p>
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "LED Controller",
|
||||
"version": "1.1"
|
||||
}
|
||||
"version": "1.3"
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ class MACInfo extends Module
|
||||
private function getMACInfo($mac)
|
||||
{
|
||||
if($this->IsValidMAC($mac)){
|
||||
$url = "http://macvendors.co/api/" . $mac . "/JSON";
|
||||
$url = "https://macvendors.co/api/" . $mac . "/JSON";
|
||||
$retJSON = file_get_contents($url);
|
||||
if($retJSON != false){
|
||||
$mInfo = json_decode($retJSON);
|
||||
@ -42,4 +42,4 @@ class MACInfo extends Module
|
||||
$pregResult = preg_match('/([a-fA-F0-9]{2}[:|\-]?){6}/', $mac);
|
||||
return ($pregResult != 0 && $pregResult != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "MAC Info",
|
||||
"version": "1.2"
|
||||
"version": "1.3"
|
||||
}
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "Online Hash Crack",
|
||||
"version": "1.2"
|
||||
"version": "1.3"
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ if [ -n "$EMAIL" ]; then
|
||||
|
||||
echo -e "" >> ${LOG}
|
||||
|
||||
curl -s -v -d emailHashes="${EMAIL}" -d textareaHashes="${HASH}" http://www.onlinehashcrack.com/hash-cracking.php > /dev/null 2>> ${LOG}
|
||||
curl -s -v -d emailHashes="${EMAIL}" -d textareaHashes="${HASH}" https://www.onlinehashcrack.com/hash-cracking.php > /dev/null 2>> ${LOG}
|
||||
else
|
||||
echo -e "Notification email not set in settings." > ${LOG}
|
||||
fi
|
||||
|
||||
@ -25,7 +25,7 @@ if [ -n "$EMAIL" ]; then
|
||||
|
||||
echo -e "" >> ${LOG}
|
||||
|
||||
curl -s -v -F submit="Submit" -F emailWpa="${EMAIL}" -F wpaFile=@${FILE} http://www.onlinehashcrack.com/wifi-wpa-rsna-psk-crack.php > /dev/null 2>> ${LOG}
|
||||
curl -s -v -F submit="Submit" -F emailWpa="${EMAIL}" -F wpaFile=@${FILE} https://www.onlinehashcrack.com/wifi-wpa-rsna-psk-crack.php > /dev/null 2>> ${LOG}
|
||||
|
||||
fi
|
||||
else
|
||||
|
||||
214
OpenVPNConnect/api/module.php
Normal file
214
OpenVPNConnect/api/module.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
// Define the pineapple namespace
|
||||
namespace pineapple;
|
||||
|
||||
// Upload Directory where we store vpn_configs
|
||||
define('__UPLOAD__', "/root/vpn_config/");
|
||||
|
||||
/* Main module class for OpenVPNConnect */
|
||||
class OpenVPNConnect extends Module{
|
||||
|
||||
// Set up our routes for our angular functions to call
|
||||
public function route(){
|
||||
|
||||
switch ($this->request->action) {
|
||||
|
||||
case 'startVPN':
|
||||
$this->startVPN();
|
||||
break;
|
||||
case 'stopVPN':
|
||||
$this->stopVPN();
|
||||
break;
|
||||
case 'initializeModule':
|
||||
$this->initializeModule();
|
||||
break;
|
||||
case 'handleDependencies':
|
||||
$this->handleDependencies();
|
||||
break;
|
||||
case 'checkDependencies':
|
||||
$this->checkDependencies();
|
||||
break;
|
||||
case 'uploadFile':
|
||||
$this->uploadFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Checks the dependencies using the pineapple API functions
|
||||
private function checkDependencies(){
|
||||
|
||||
if($this->checkDependency('openvpn')){
|
||||
$installLabel = 'success';
|
||||
$installLabelText = 'Installed';
|
||||
}else{
|
||||
$installLabel = 'danger';
|
||||
$installLabelText = 'Not Installed';
|
||||
}
|
||||
|
||||
$this->response = array("success" => true,
|
||||
"label" => $installLabel,
|
||||
"text" => $installLabelText);
|
||||
|
||||
}
|
||||
|
||||
// Initializes the module by checking for/creating the required vpn_config directory in /root
|
||||
private function initializeModule(){
|
||||
|
||||
$result = exec('cd /root && ls | grep vpn_config');
|
||||
|
||||
if($result == 'vpn_config'){
|
||||
$result = "VPN Connect is ready!";
|
||||
}else{
|
||||
$this->execBackground('cd /root && mkdir vpn_config');
|
||||
|
||||
$result = exec('cd /root && ls | grep vpn_config');
|
||||
|
||||
if($result == 'vpn_config'){
|
||||
$result = "VPN Connect is ready!";
|
||||
}else{
|
||||
$result = "VPN Connect setup failed :(";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Get Available Certs
|
||||
|
||||
$certs = preg_grep('/^([^.])/', scandir("/root/vpn_config/"));
|
||||
$cert_arr = array();
|
||||
foreach ($certs as $cert){
|
||||
array_push($cert_arr, (object)array('name' => $cert));
|
||||
}
|
||||
|
||||
$this->response = array("success" => true,
|
||||
"content" => $result,
|
||||
"certs" => $cert_arr);
|
||||
|
||||
}
|
||||
|
||||
// Handles dependency installation and removal
|
||||
private function handleDependencies(){
|
||||
|
||||
|
||||
if($this->checkDependency('openvpn')){
|
||||
exec('opkg remove openvpn-openssl');
|
||||
$messsage = "Dependencies should now be removed! Note: the vpn_config directory is NOT removed in this process. Please wait for the page to refresh...";
|
||||
}else{
|
||||
$this->installDependency('openvpn-openssl');
|
||||
$messsage = "Depedencies should now be installed! Please wait for the page to refresh...";
|
||||
}
|
||||
|
||||
$this->response = array("success" => true,
|
||||
"content" => $messsage);
|
||||
}
|
||||
|
||||
// Builds the openvpn command string and calls it to star the VPN
|
||||
private function startVPN(){
|
||||
|
||||
$inputData = $this->request->data;
|
||||
|
||||
$open_vpn_cmd = "openvpn --config ";
|
||||
|
||||
if($inputData[0] != ''){
|
||||
$config_name = $inputData[0];
|
||||
$open_vpn_cmd .= "/root/vpn_config/" . $config_name . " ";
|
||||
}else{
|
||||
$this->response = array("success" => false,
|
||||
"content" => "Please specify a VPN config name..");
|
||||
return;
|
||||
}
|
||||
|
||||
if($inputData[1] != ''){
|
||||
|
||||
//Create password file for openvpn command to read in
|
||||
$config_pass = $inputData[1];
|
||||
$pass_file = fopen("/tmp/vpn_pass.txt", "w");
|
||||
fwrite($pass_file, $config_pass);
|
||||
fclose($pass_file);
|
||||
$open_vpn_cmd .= "--auth-nocache --askpass /tmp/vpn_pass.txt ";
|
||||
}
|
||||
|
||||
if($inputData[2] != ''){
|
||||
$openvpn_flags = $inputData[2];
|
||||
$open_vpn_cmd .= $openvpn_flags;
|
||||
}
|
||||
|
||||
|
||||
if($inputData[3] == true){
|
||||
//Share VPN With Clients Connecting
|
||||
$this->execBackground("iptables -t nat -A POSTROUTING -s 172.16.42.0/24 -o tun0 -j MASQUERADE");
|
||||
$this->execBackground("iptables -A FORWARD -s 172.16.42.0/24 -o tun0 -j ACCEPT");
|
||||
$this->execBackground("iptables -A FORWARD -d 172.16.42.0/24 -m state --state ESTABLISHED,RELATED -i tun0 -j ACCEPT");
|
||||
}
|
||||
|
||||
$result = $this->execBackground($open_vpn_cmd);
|
||||
|
||||
$this->response = array("success" => true,
|
||||
"content" => "VPN Running... ");
|
||||
}
|
||||
|
||||
|
||||
// Calls pkill to kill the OpenVPN process and stop the VPN
|
||||
private function stopVPN(){
|
||||
|
||||
//Remove password file that could have been created, don't want any creds lying around ;)
|
||||
unlink("/tmp/vpn_pass.txt");
|
||||
|
||||
exec("pkill openvpn");
|
||||
|
||||
$this->response = array("success" => true,
|
||||
"content" => "VPN Stopped...");
|
||||
}
|
||||
|
||||
// Uploads the .ovnp recieved from the service
|
||||
private function uploadFile(){
|
||||
|
||||
$inputData = $this->request->file;
|
||||
|
||||
$fileName = $inputData[0];
|
||||
|
||||
$file = base64_decode($inputData[1]);
|
||||
|
||||
$response = [];
|
||||
|
||||
$name = $fileName;
|
||||
$type = pathinfo($fileName, PATHINFO_EXTENSION);
|
||||
|
||||
// Do not accept any file other than .ovpn
|
||||
if ($type != "ovpn") {
|
||||
$this->response = array("success" => false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the upload directory exists
|
||||
if (!file_exists(__UPLOAD__)) {
|
||||
if (!mkdir(__UPLOAD__, 0755, true)) {
|
||||
$response[$name] = "Failed. Unable to upload because vpn_certs directory does not exist/could not be created!";
|
||||
$this->response = array("success" => false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$uploadPath = __UPLOAD__ . $name;
|
||||
$res = file_put_contents( $uploadPath, $file );
|
||||
|
||||
if ($res) {
|
||||
$response[$name] = true;
|
||||
} else {
|
||||
$response[$name] = false;
|
||||
}
|
||||
|
||||
|
||||
$this->response = array("success" => $response[$name]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
222
OpenVPNConnect/js/module.js
Normal file
222
OpenVPNConnect/js/module.js
Normal file
@ -0,0 +1,222 @@
|
||||
/* Main AngularJS openVPNConnectController */
|
||||
registerController('openVPNConnectController', ['$api', '$scope', '$timeout', '$window', '$http', function($api, $scope, $timeout, $window, $http) {
|
||||
|
||||
|
||||
// Workspace Variables. Each value is populated by the form or displays to the form.
|
||||
$scope.workspace = {config: "",
|
||||
pass: "",
|
||||
flags: "",
|
||||
sharedconnection: false,
|
||||
setupcontent: "",
|
||||
outputcontent: "",
|
||||
availablecerts: [],
|
||||
uploadstatusLabel: "",
|
||||
uploadstatus: ""};
|
||||
|
||||
/* Other variables used to display content or assist the dependency installation and file upload
|
||||
functions
|
||||
*/
|
||||
$scope.content = "";
|
||||
$scope.installLabel = "default";
|
||||
$scope.installLabelText = "Checking..."
|
||||
$scope.selectedFiles = [];
|
||||
$scope.uploading = false;
|
||||
|
||||
// Call a function to install/uninstall dependencies for the module
|
||||
$scope.handleDependencies = function(){
|
||||
|
||||
$scope.workspace.setupcontent = "Handling dependencies please wait...";
|
||||
|
||||
$api.request({
|
||||
module: 'OpenVPNConnect',
|
||||
action: 'handleDependencies',
|
||||
}, function(response) {
|
||||
if (response.success === true) {
|
||||
|
||||
$scope.workspace.setupcontent = response.content;
|
||||
|
||||
checkDependencies();
|
||||
|
||||
$timeout(function() {$window.location.reload();}, 5000);
|
||||
}
|
||||
//console.log(response) //Log the response to the console, this is useful for debugging.
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* Checks the current status of the dependencies for the module and displays
|
||||
it via the dependency install/uninstall button to the user.
|
||||
This is checked each time the app is loaded or when the user
|
||||
installs/uninstalls dependencies manually
|
||||
*/
|
||||
var checkDependencies = function(){
|
||||
$api.request({
|
||||
module: 'OpenVPNConnect',
|
||||
action: 'checkDependencies',
|
||||
}, function(response) {
|
||||
if (response.success === true) {
|
||||
$scope.installLabel = response.label;
|
||||
$scope.installLabelText = response.text;
|
||||
}
|
||||
//console.log(response) //Log the response to the console, this is useful for debugging.
|
||||
});
|
||||
}
|
||||
|
||||
// Call the checkDependencies function on page load
|
||||
checkDependencies();
|
||||
|
||||
/* Initializes module by creating necessary folder structures and scanning for uploaded certs
|
||||
this function is called each time the app is loaded to make sure the module is set up correctly
|
||||
*/
|
||||
var initializeModule = function(){
|
||||
$api.request({
|
||||
module: 'OpenVPNConnect',
|
||||
action: 'initializeModule',
|
||||
}, function(response) {
|
||||
if (response.success === true) {
|
||||
$scope.workspace.setupcontent = response.content;
|
||||
|
||||
for(var i = 0; i <= response.certs.length - 1; i++){
|
||||
$scope.workspace.availablecerts.push(response.certs[i].name);
|
||||
}
|
||||
}
|
||||
//console.log(response) //Log the response to the console, this is useful for debugging.
|
||||
});
|
||||
}
|
||||
|
||||
// Call the initializeModule function on page load
|
||||
initializeModule();
|
||||
|
||||
/* Just calls the initializeModule function to refresh the cert list when the
|
||||
user clicks the drop down menu button
|
||||
*/
|
||||
$scope.refreshCertList = function(){
|
||||
$scope.workspace.availablecerts = [];
|
||||
initializeModule();
|
||||
}
|
||||
|
||||
// Sets the current config to use for the VPN connection
|
||||
$scope.setConfig = function(cert){
|
||||
$scope.workspace.config = cert;
|
||||
}
|
||||
|
||||
|
||||
/* Calls the startVPN function, passes all the form params to the API to run the OpenVPN command
|
||||
Users can pass a config, an option password, and optional command line flags to run with the
|
||||
openvpn command line utility. Also the shared connection open lets the user share the
|
||||
VPN connection with its clients
|
||||
*/
|
||||
$scope.startVPN = function() {
|
||||
$api.request({
|
||||
module: 'OpenVPNConnect',
|
||||
action: 'startVPN',
|
||||
data: [$scope.workspace.config,
|
||||
$scope.workspace.pass,
|
||||
$scope.workspace.flags,
|
||||
$scope.workspace.sharedconnection]
|
||||
}, function(response) {
|
||||
if (response.success === true) {
|
||||
$scope.workspace.outputcontent = response.content;
|
||||
}
|
||||
//console.log(response) //Log the response to the console, this is useful for debugging.
|
||||
});
|
||||
}
|
||||
|
||||
// This function calls the API to kill the openvpn process and stop the VPN
|
||||
$scope.stopVPN = function() {
|
||||
$api.request({
|
||||
module: 'OpenVPNConnect',
|
||||
action: 'stopVPN'
|
||||
}, function(response) {
|
||||
if (response.success === true) {
|
||||
$scope.workspace.outputcontent = response.content;
|
||||
}
|
||||
//console.log(response) //Log the response to the console, this is useful for debugging.
|
||||
});
|
||||
}
|
||||
|
||||
//File Upload Code, the first two functions prep the files for upload in the modal
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* File upload function. Instaitates a FileReader object the makes a promise call to
|
||||
doUpload once the async reader call is complete on each iteration
|
||||
*/
|
||||
$scope.uploadFile = function(){
|
||||
|
||||
$scope.uploading = true;
|
||||
|
||||
|
||||
for (x = 0; x < $scope.selectedFiles.length; x++) {
|
||||
|
||||
var fileReader = new FileReader();
|
||||
|
||||
var fileName = $scope.selectedFiles[x].name;
|
||||
|
||||
var filesToUpload = $scope.selectedFiles.length;
|
||||
|
||||
readFile($scope.selectedFiles[x], fileName, filesToUpload);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Read file function to handle a Promise for multiple file uploads using FilerReader
|
||||
function readFile(file, file_name, files_to_upload){
|
||||
return new Promise((resolve, reject) => {
|
||||
var fr = new FileReader();
|
||||
fr.onload = () => {
|
||||
final_file = fr.result.split(',')[1]
|
||||
resolve(doUpload(file_name, final_file, files_to_upload - 1));
|
||||
};
|
||||
fr.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Actually performs the upload request to the API. Passes the file name and a base64 encoded
|
||||
file to be uploaded by the service
|
||||
*/
|
||||
var doUpload = function(file_name, file, files_to_upload){
|
||||
|
||||
$api.request({
|
||||
module: 'OpenVPNConnect',
|
||||
action: 'uploadFile',
|
||||
file: [file_name,
|
||||
file
|
||||
]
|
||||
}, function(response) {
|
||||
|
||||
if(response.success){
|
||||
$scope.workspace.uploadstatusLabel = "Upload Success!";
|
||||
$scope.workspace.uploadstatus = "success";
|
||||
}else{
|
||||
$scope.workspace.uploadstatusLabel = "One or more files failed to upload!";
|
||||
$scope.workspace.uploadstatus = "danger";
|
||||
}
|
||||
|
||||
if(files_to_upload === 0){
|
||||
$scope.selectedFiles = [];
|
||||
$scope.uploading = false;
|
||||
}
|
||||
|
||||
//console.log(response) //Log the response to the console, this is useful for debugging.
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
}]);
|
||||
151
OpenVPNConnect/module.html
Normal file
151
OpenVPNConnect/module.html
Normal file
@ -0,0 +1,151 @@
|
||||
<div class="col-md-12" ng-controller="openVPNConnectController">
|
||||
<div class="panel-group">
|
||||
<div class="col-md-12">
|
||||
<!-- OpenVPN Connect Title Panel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-header text-muted text-center">
|
||||
<h3>OpenVPN Connect
|
||||
</h5>
|
||||
</div>
|
||||
<div id="main-panel" class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<!-- Dependency Installer UI -->
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label text-center">Dependencies:</label>
|
||||
<button type="button" style="width: 90px;" class="btn btn-{{installLabel}} btn-xs" ng-click="handleDependencies()">{{installLabelText}}</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label text-center">Setup Status</label>
|
||||
<p>
|
||||
<input class="form-control" ng-model="workspace.setupcontent" placeholder="" readonly></input>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenVPN Cert Selector -->
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<p>
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#ovpn_upload_view">Upload Cert</button>
|
||||
</p>
|
||||
<p>
|
||||
<div>
|
||||
<label class="control-label">
|
||||
<a href="javascript:;" data-toggle="collapse" data-parent="#accordion" data-target="#collapseCertList">
|
||||
<button type="button" class="btn btn-default" ng-click="refreshCertList()">
|
||||
Select Cert +
|
||||
</button>
|
||||
</a>
|
||||
</label>
|
||||
<div id="collapseCertList" class="panel-collapse collapse">
|
||||
<div class="panel panel-default">
|
||||
<div>
|
||||
<ul class="list-group text-center" ng-repeat="cert in workspace.availablecerts">
|
||||
<li class="list-group-item">
|
||||
<button type="button" class="btn btn-default" ng-click="setConfig(cert)">{{cert}}</button>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<!-- OpenVPN Connect Option Form -->
|
||||
<label class="control-label text-center">VPN Config Name:</label>
|
||||
<a href="javascript:;" ng-click="workspace.config = ''">Clear</a>
|
||||
<p>
|
||||
<input class="form-control" ng-model="workspace.config" placeholder="Enter input"></input>
|
||||
</p>
|
||||
<label class="control-label text-center">VPN Config Password (Optional):</label>
|
||||
<a href="javascript:;" ng-click="workspace.pass = ''">Clear</a>
|
||||
<p>
|
||||
<input class="form-control" type="password" ng-model="workspace.pass" placeholder="Enter input"></input>
|
||||
</p>
|
||||
<label class="control-label text-center">OpenVPN Flags (Optional):</label>
|
||||
<a href="javascript:;" ng-click="workspace.flags = ''">Clear</a>
|
||||
<p>
|
||||
<input class="form-control" ng-model="workspace.flags" placeholder="Enter input"></input>
|
||||
</p>
|
||||
<label class="control-label text-center">Share Connection With Clients:</label>
|
||||
<input type="checkbox" ng-model="workspace.sharedconnection">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn text-center">
|
||||
<button class="btn btn-default" type="button" ng-click="startVPN()">Start VPN</button>
|
||||
<button class="btn btn-default" type="button" ng-click="stopVPN()">Stop VPN</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- OpenVPN Status Section -->
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label text-center">OpenVPN Status</label>
|
||||
<p>
|
||||
<textarea class="form-control" rows="1" ng-model="workspace.outputcontent" placeholder="" readonly></textarea>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenVPN Cert Upload Modal -->
|
||||
<div id="ovpn_upload_view" 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 btn-danger" ng-click="removeSelectedFile(file);">Remove
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align:center">
|
||||
<input type="file" accept=".ovpn" id="selectedFiles" onchange="angular.element(this).scope().setSelectedFiles()" style="visibility: hidden;" multiple>
|
||||
<img ng-show="uploading" ng-hide="!uploading">
|
||||
<button class="btn" ng-show="!uploading" ng-hide="uploading" ng-disabled="selectedFiles.length == 0" ng-click="uploadFile();">Upload</button>
|
||||
<div class="alert alert-{{workspace.uploadstatus}}">{{workspace.uploadstatusLabel}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Change Log Pannel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-header text-muted text-center">
|
||||
<h5>
|
||||
<a href="javascript:;" data-toggle="collapse" data-parent="#accordion" data-target="#collapseChangelog">Change Log</a>
|
||||
</h5>
|
||||
</div>
|
||||
<div id="collapseChangelog" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li>
|
||||
<b>1.0</b>
|
||||
</li>
|
||||
<ul>
|
||||
<li class="text-muted">Initial Pineapple Nano Release</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
10
OpenVPNConnect/module.info
Normal file
10
OpenVPNConnect/module.info
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"author": "3ndG4me",
|
||||
"description": "OpenVPN Connection Utility",
|
||||
"devices": [
|
||||
"nano",
|
||||
"tetra"
|
||||
],
|
||||
"title": "OpenVPNConnect",
|
||||
"version": "1.0"
|
||||
}
|
||||
@ -89,7 +89,7 @@ private function hello()
|
||||
{
|
||||
$this->response = array('text' => "Hello World");
|
||||
}
|
||||
```.
|
||||
```
|
||||
|
||||
**Note:** You should never use the closing `?>` PHP tag in your `module.php` file.
|
||||
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "SSLsplit",
|
||||
"version": "1.0"
|
||||
}
|
||||
"version": "1.2"
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ MYTIME=`date +%s`
|
||||
killall sslsplit
|
||||
|
||||
echo '1' > /proc/sys/net/ipv4/ip_forward
|
||||
iptables-save > /pineapple/modules/SSLsplit/rules/saved
|
||||
iptables -X
|
||||
iptables -F
|
||||
iptables -t nat -F
|
||||
@ -20,4 +21,8 @@ sh /pineapple/modules/SSLsplit/rules/iptables
|
||||
|
||||
iptables -t nat -A POSTROUTING -j MASQUERADE
|
||||
|
||||
if [ ! -d /pineapple/modules/SSLsplit/log ]; then
|
||||
mkdir /pineapple/modules/SSLsplit/log
|
||||
fi
|
||||
|
||||
sslsplit -D -l /pineapple/modules/SSLsplit/connections.log -L /pineapple/modules/SSLsplit/log/output_${MYTIME}.log -k /pineapple/modules/SSLsplit/cert/certificate.key -c /pineapple/modules/SSLsplit/cert/certificate.crt ssl 0.0.0.0 8443 tcp 0.0.0.0 8080
|
||||
|
||||
@ -8,9 +8,14 @@ MYTIME=`date +%s`
|
||||
|
||||
killall sslsplit
|
||||
|
||||
if [ ! -d /pineapple/modules/SSLsplit/log ]; then
|
||||
mkdir /pineapple/modules/SSLsplit/log
|
||||
fi
|
||||
|
||||
if [ "$1" = "start" ]; then
|
||||
|
||||
echo '1' > /proc/sys/net/ipv4/ip_forward
|
||||
iptables-save > /pineapple/modules/SSLsplit/rules/saved
|
||||
iptables -X
|
||||
iptables -F
|
||||
iptables -t nat -F
|
||||
@ -37,5 +42,6 @@ elif [ "$1" = "stop" ]; then
|
||||
iptables -P INPUT ACCEPT
|
||||
iptables -P FORWARD ACCEPT
|
||||
iptables -P OUTPUT ACCEPT
|
||||
|
||||
|
||||
iptables-restore < /pineapple/modules/SSLsplit/rules/saved
|
||||
fi
|
||||
|
||||
@ -385,7 +385,7 @@ class SiteSurvey extends Module
|
||||
|
||||
private function getMACInfo()
|
||||
{
|
||||
$content = file_get_contents("http://api.macvendors.com/".$this->request->mac);
|
||||
$content = file_get_contents("https://api.macvendors.com/".$this->request->mac);
|
||||
$this->response = array('title' => $this->request->mac, "output" => $content);
|
||||
}
|
||||
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "Site Survey",
|
||||
"version": "1.2"
|
||||
}
|
||||
"version": "1.4"
|
||||
}
|
||||
|
||||
@ -55,6 +55,11 @@ if [ "$1" = "start" ]; then
|
||||
|
||||
echo ${BSSID} > ${LOCK}
|
||||
|
||||
# make sure the folder exists
|
||||
if [ ! -d /pineapple/modules/SiteSurvey/capture ]; then
|
||||
mkdir /pineapple/modules/SiteSurvey/capture
|
||||
fi
|
||||
|
||||
airodump-ng -c ${CHANNEL} --bssid ${BSSID} -w /pineapple/modules/SiteSurvey/capture/capture_${MYTIME} ${MYMONITOR} &> /dev/null &
|
||||
|
||||
echo -e "Capture is running..." >> ${LOG}
|
||||
|
||||
@ -23,6 +23,8 @@ if [ "$1" = "install" ]; then
|
||||
uci set sitesurvey.module.installed=1
|
||||
uci commit sitesurvey.module.installed
|
||||
|
||||
mkdir /pineapple/modules/SiteSurvey/capture
|
||||
|
||||
elif [ "$1" = "remove" ]; then
|
||||
rm -rf /etc/config/sitesurvey
|
||||
fi
|
||||
|
||||
@ -248,7 +248,7 @@ class Status extends Module
|
||||
|
||||
private function getMACInfo()
|
||||
{
|
||||
$content = file_get_contents("http://api.macvendors.com/".$this->request->mac);
|
||||
$content = file_get_contents("https://api.macvendors.com/".$this->request->mac);
|
||||
$this->response = array('title' => $this->request->mac, "output" => $content);
|
||||
}
|
||||
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "Status",
|
||||
"version": "1.1"
|
||||
}
|
||||
"version": "1.2"
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
499
Themes/css/1980.css
Normal file
499
Themes/css/1980.css
Normal file
@ -0,0 +1,499 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:lime;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
i {
|
||||
color: lime;
|
||||
font: monospace;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: lime;
|
||||
text-align: center;
|
||||
background-color: black;
|
||||
border: 1px solid lime;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid lime;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: lime;
|
||||
white-space:nowrap;
|
||||
background-color: black;
|
||||
border: lime;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: lime;
|
||||
background-color: black;
|
||||
background-image: none;
|
||||
border: 1px solid lime;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid lime;
|
||||
border-top: 1px solid lime;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
* {
|
||||
color: lime;
|
||||
border-color: lime;
|
||||
border-top: lime;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #000;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: lime;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #000000;
|
||||
border: 1px solid lime;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: limegreen;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #18ff00;
|
||||
color:lime;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: lime;
|
||||
background-color: black;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
p {
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:forestgreen;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:lime;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:lime;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:lime;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:lime;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: lime;
|
||||
background-color: lime;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #000000;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: #000;
|
||||
opacity: 1;
|
||||
color: lime;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: #000000;
|
||||
border-top: 1px solid #0F0;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: #000;
|
||||
opacity: 1;
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #000 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #000 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:lime;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: lime;
|
||||
background-color: black;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:black;
|
||||
color: lime;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: lime;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:black;
|
||||
font-family:monospace;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: lime;
|
||||
background-color: black;
|
||||
border-color: lime;
|
||||
border-bottom-color: lime;
|
||||
border-bottom: lime;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:black;
|
||||
}
|
||||
.nav {
|
||||
background-color:black;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:black;
|
||||
border-color: lime;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: monospace;
|
||||
background-color: lime;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: black;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid lime;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: middle;
|
||||
border-top: 1px solid lime;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: darkgray;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: black;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: lime;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px lime;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
250
Themes/css/default.css
Normal file
250
Themes/css/default.css
Normal file
@ -0,0 +1,250 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #000;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #e7e7e7;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #e7e7e7;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #fff !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #ccc !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "WiFi Pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #2196F3;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #2196F3;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
526
Themes/css/evilrose.css
Normal file
526
Themes/css/evilrose.css
Normal file
@ -0,0 +1,526 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:#ff0066;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #ff0066;
|
||||
font: monospace;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #ff0066;
|
||||
text-align: center;
|
||||
background-color: black;
|
||||
border: 1px solid #ff0066;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: #ff0066;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid #ff0066;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: #ff0066;
|
||||
white-space:nowrap;
|
||||
background-color: black;
|
||||
border: #ff0066;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: #ff0066;
|
||||
background-color: black;
|
||||
background-image: none;
|
||||
border: 1px solid #ff0066;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #ff0066;
|
||||
border-top: 1px solid #ff0066;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
* {
|
||||
color: #ff0066;
|
||||
border-color: #ff0066;
|
||||
border-top: #ff0066;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid black;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: #ff0066;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: black;
|
||||
border: 1px solid #ff0066;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: #ff66a3;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #ff0000;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #ff66a3;
|
||||
color:#ff0066;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #ff0066;
|
||||
background-color: black;
|
||||
border-color: #ff0066;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #ff0066;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:#ff66a3;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:#ff0066;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:#ff0066;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:#ff0066;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:#ff0066;
|
||||
border-color: #ff0066;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: #ff0066;
|
||||
background-color: #ff0066;
|
||||
border-color: #ff0066;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: black;
|
||||
opacity: 1;
|
||||
color: #ff0066;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: black;
|
||||
border-top: 1px solid #ff66a3;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: black;
|
||||
opacity: 1;
|
||||
color: #ff0066;
|
||||
font-family: monospace;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #000 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #000 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:#ff0066;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: #ff0066;
|
||||
background-color: black;
|
||||
border-color: #ff0066;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:black;
|
||||
color: #ff0066;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: #ff0066;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:black;
|
||||
font-family:monospace;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: #ff0066;
|
||||
background-color: black;
|
||||
border-color: #ff0066;
|
||||
border-bottom-color: #ff0066;
|
||||
border-bottom: #ff0066;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:black;
|
||||
}
|
||||
.nav {
|
||||
background-color:black;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:black;
|
||||
border-color: #ff0066;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: monospace;
|
||||
background-color: #ff0066;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: black;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid #ff0066;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #ff0066;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: black;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #ff0066;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #ff0066;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
522
Themes/css/hackerblues.css
Normal file
522
Themes/css/hackerblues.css
Normal file
@ -0,0 +1,522 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:#0066ff;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #0066ff;
|
||||
font: monospace;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #0066ff;
|
||||
text-align: center;
|
||||
background-color: black;
|
||||
border: 1px solid #0066ff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: #0066ff;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid #0066ff;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: #0066ff;
|
||||
white-space:nowrap;
|
||||
background-color: black;
|
||||
border: #0066ff;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: #0066ff;
|
||||
background-color: black;
|
||||
background-image: none;
|
||||
border: 1px solid #0066ff;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #0066ff;
|
||||
border-top: 1px solid #0066ff;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
* {
|
||||
color: #0066ff;
|
||||
border-color: #0066ff;
|
||||
border-top: #0066ff;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid black;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: #0066ff;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: black;
|
||||
border: 1px solid #0066ff;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: #00004d;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #ff0000;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #00004d;
|
||||
color:#0066ff;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #0066ff;
|
||||
background-color: black;
|
||||
border-color: #0066ff;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #0066ff;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:blue;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:#0066ff;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:#0066ff;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:#0066ff;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:#0066ff;
|
||||
border-color: #0066ff;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: #0066ff;
|
||||
background-color: #0066ff;
|
||||
border-color: #0066ff;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: black;
|
||||
opacity: 1;
|
||||
color: #0066ff;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: black;
|
||||
border-top: 1px solid #00004d;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: black;
|
||||
opacity: 1;
|
||||
color: #0066ff;
|
||||
font-family: monospace;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #000 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #000 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:#0066ff;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: #0066ff;
|
||||
background-color: black;
|
||||
border-color: #0066ff;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:black;
|
||||
color: #0066ff;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: #0066ff;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:black;
|
||||
font-family:monospace;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: #0066ff;
|
||||
background-color: black;
|
||||
border-color: #0066ff;
|
||||
border-bottom-color: #0066ff;
|
||||
border-bottom: #0066ff;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:black;
|
||||
}
|
||||
.nav {
|
||||
background-color:black;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:black;
|
||||
border-color: #0066ff;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: monospace;
|
||||
background-color: #0066ff;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: black;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: middle;
|
||||
border-bottom: 2px solid #0066ff;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: middle;
|
||||
border-top: 1px solid #0066ff;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: black;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #0066ff;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #0066ff;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
499
Themes/css/hak5.css
Normal file
499
Themes/css/hak5.css
Normal file
@ -0,0 +1,499 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:blue;
|
||||
font-family:webkit-pictograph;
|
||||
}
|
||||
|
||||
i {
|
||||
color: blue;
|
||||
font: webkit-pictograph;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: webkit-pictograph;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: webkit-pictograph;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: red;
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
border: 1px solid red;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: blue;
|
||||
white-space:nowrap;
|
||||
background-color: white;
|
||||
border: red;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: red;
|
||||
background-color: white;
|
||||
background-image: none;
|
||||
border: 1px solid red;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid red;
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
* {
|
||||
color: red;
|
||||
border-color: red;
|
||||
border-top: red;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid white;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: red;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: white;
|
||||
border: 1px solid red;
|
||||
border-radius: 4px;
|
||||
font-family: webkit-pictograph;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: red;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid red;
|
||||
color:blue;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: white;
|
||||
font-family: webkit-pictograph;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: red;
|
||||
background-color: white;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
p {
|
||||
color: red;
|
||||
font-family: webkit-pictograph;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:blue;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:blue;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:blue;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:blue;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:red;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: red;
|
||||
background-color: red;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid white;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: white;
|
||||
opacity: 1;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: white;
|
||||
border-top: 1px solid red;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: white;
|
||||
opacity: 1;
|
||||
color: red;
|
||||
font-family: webkit-pictograph;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: white !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid white !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:red;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: red;
|
||||
background-color: white;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:white;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: red;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:white;
|
||||
font-family: webkit-pictograph;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:white;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: blue;
|
||||
background-color: white;
|
||||
border-color: red;
|
||||
border-bottom-color: red;
|
||||
border-bottom: red;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:white;
|
||||
}
|
||||
.nav {
|
||||
background-color:white;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:white;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:white;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:white;
|
||||
border-color: red;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: webkit-pictograph;
|
||||
background-color: red;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: white;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid red;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: red;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px red;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
525
Themes/css/halflife-inverted.css
Normal file
525
Themes/css/halflife-inverted.css
Normal file
@ -0,0 +1,525 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:#991f00 ;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #991f00 ;
|
||||
font: monospace;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #991f00 ;
|
||||
text-align: center;
|
||||
background-color: black;
|
||||
border: 1px solid #991f00 ;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: #991f00 ;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid #991f00 ;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: #991f00 ;
|
||||
white-space:nowrap;
|
||||
background-color: black;
|
||||
border: #991f00 ;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: #991f00 ;
|
||||
background-color: black;
|
||||
background-image: none;
|
||||
border: 1px solid #991f00 ;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #991f00 ;
|
||||
border-top: 1px solid #991f00 ;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
* {
|
||||
color: #991f00 ;
|
||||
border-color: #991f00 ;
|
||||
border-top: #991f00 ;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid black;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: #991f00 ;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: black;
|
||||
border: 1px solid #991f00 ;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: #e62e00;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: black;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #e62e00;
|
||||
color:#991f00 ;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #991f00 ;
|
||||
background-color: black;
|
||||
border-color: #991f00 ;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #991f00 ;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:#e62e00;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:#991f00 ;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:#991f00 ;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:#991f00 ;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:#991f00 ;
|
||||
border-color: #991f00 ;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: #991f00 ;
|
||||
background-color: #991f00 ;
|
||||
border-color: #991f00 ;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: black;
|
||||
opacity: 1;
|
||||
color: #991f00 ;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: black;
|
||||
border-top: 1px solid #e62e00;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: black;
|
||||
opacity: 1;
|
||||
color: #991f00 ;
|
||||
font-family: monospace;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: black !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid black !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:#991f00 ;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: #991f00 ;
|
||||
background-color: black;
|
||||
border-color: #991f00 ;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:black;
|
||||
color: #991f00 ;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: #991f00 ;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:black;
|
||||
font-family:monospace;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: #991f00 ;
|
||||
background-color: black;
|
||||
border-color: #991f00 ;
|
||||
border-bottom-color: #991f00 ;
|
||||
border-bottom: #991f00 ;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:black;
|
||||
}
|
||||
.nav {
|
||||
background-color:black;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:black;
|
||||
border-color: #991f00 ;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: monospace;
|
||||
background-color: #991f00 ;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: black;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid #991f00 ;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #991f00 ;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: black;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #991f00;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #991f00;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
525
Themes/css/halflife.css
Normal file
525
Themes/css/halflife.css
Normal file
@ -0,0 +1,525 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:black;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
i {
|
||||
color: black;
|
||||
font: monospace;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: black;
|
||||
text-align: center;
|
||||
background-color: #991f00;
|
||||
border: 1px solid black;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: black;
|
||||
white-space:nowrap;
|
||||
background-color: #991f00;
|
||||
border: black;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: black;
|
||||
background-color: #991f00;
|
||||
background-image: none;
|
||||
border: 1px solid black;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid black;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: #991f00;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: #991f00;
|
||||
}
|
||||
|
||||
* {
|
||||
color: black;
|
||||
border-color: black;
|
||||
border-top: black;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #991f00;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: black;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #991f00;
|
||||
border: 1px solid black;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #991f00;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #991f00;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: #e62e00;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #991f00;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
|
||||
background-color: #991f00;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #e62e00;
|
||||
color:black;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: #991f00;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: black;
|
||||
background-color: #991f00;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
p {
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:#e62e00;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:black;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:black;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:black;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:black;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: black;
|
||||
background-color: black;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #991f00;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: #991f00;
|
||||
opacity: 1;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: #991f00;
|
||||
border-top: 1px solid #e62e00;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: #991f00;
|
||||
opacity: 1;
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #991f00;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #991f00 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #991f00 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:black;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: black;
|
||||
background-color: #991f00;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:#991f00;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: black;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:#991f00;
|
||||
font-family:monospace;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:#991f00;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: black;
|
||||
background-color: #991f00;
|
||||
border-color: black;
|
||||
border-bottom-color: black;
|
||||
border-bottom: black;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:#991f00;
|
||||
}
|
||||
.nav {
|
||||
background-color:#991f00;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:#991f00;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:#991f00;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:#991f00;
|
||||
border-color: black;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: monospace;
|
||||
background-color: black;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: #991f00;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #991f00;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: black;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px black;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
576
Themes/css/kbeflo-dark.css
Normal file
576
Themes/css/kbeflo-dark.css
Normal file
@ -0,0 +1,576 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #000;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #0c0c0c;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #131313;
|
||||
}
|
||||
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #181818;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #131313;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #202020;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #fff !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #ccc !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "WiFi Pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.navbar-default {
|
||||
background-color: #0c0c0c;
|
||||
border-color: #181818;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
background-color: #0e0e0e;
|
||||
border-top: 1px solid #202020;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: #202020;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: #c6c6c6;
|
||||
background-color: #0e0e0e;
|
||||
border-color: #202020;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
color: #c6c6c6;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color: #c6c6c6;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table,
|
||||
.panel>.panel-body+.table-responsive,
|
||||
.panel>.table+.panel-body,
|
||||
.panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid #202020;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #c6c6c6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:focus, a:hover {
|
||||
color: #c6c6c6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: #131313;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #454545;
|
||||
}
|
||||
|
||||
.btn-default.active, .btn-default:active {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: #c6c6c6;
|
||||
background-color: #131313;
|
||||
border-color: #767676;
|
||||
}
|
||||
|
||||
.btn-default.focus, .btn-default:focus {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-default.active.focus, .btn-default.active:focus, .btn-default.active:hover, .btn-default:active.focus, .btn-default:active:focus, .btn-default:active:hover, .open>.dropdown-toggle.btn-default.focus, .open>.dropdown-toggle.btn-default:focus, .open>.dropdown-toggle.btn-default:hover {
|
||||
color: #212121;
|
||||
background-color: #010101;
|
||||
border-color: #171717;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav>li>a {
|
||||
color: #404041;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
|
||||
color: #404041;
|
||||
background-color: #0c0c0c;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #a2a2a2;
|
||||
text-align: center;
|
||||
background-color: #131313;
|
||||
border: 1px solid #2e2e2e;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
background-color: #000;
|
||||
border: 1px solid #202020;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
color: #c6c6c6;
|
||||
border: 1px solid #202020;
|
||||
border-bottom: none;
|
||||
background-color: #000;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
background-color: #111111;
|
||||
border: 1px solid #333333;
|
||||
color: #c6c6c6;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #454545;
|
||||
}
|
||||
|
||||
.btn-success.active, .btn-success:active {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-success.focus, .btn-success:focus {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-success.active.focus, .btn-success.active:focus, .btn-success.active:hover, .btn-success:active.focus, .btn-success:active:focus, .btn-success:active:hover, .open>.dropdown-toggle.btn-success.focus, .open>.dropdown-toggle.btn-success:focus, .open>.dropdown-toggle.success:hover {
|
||||
color: #212121;
|
||||
background-color: #010101;
|
||||
border-color: #171717;
|
||||
}
|
||||
|
||||
.btn-default.disabled, .btn-default.disabled.active, .btn-default.disabled.focus, .btn-default.disabled:active, .btn-default.disabled:focus, .btn-default.disabled:hover, .btn-default[disabled], .btn-default[disabled].active, .btn-default[disabled].focus, .btn-default[disabled]:active, .btn-default[disabled]:focus, .btn-default[disabled]:hover, fieldset[disabled] .btn-default, fieldset[disabled] .btn-default.active, fieldset[disabled] .btn-default.focus, fieldset[disabled] .btn-default:active, fieldset[disabled] .btn-default:focus, fieldset[disabled] .btn-default:hover {
|
||||
|
||||
background-color: #111;
|
||||
border-color: #333;
|
||||
color: #333;
|
||||
|
||||
}
|
||||
|
||||
.panel-group .panel-heading+.panel-collapse>.list-group, .panel-group .panel-heading+.panel-collapse>.panel-body {
|
||||
border-top: 1px solid #212121;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: #111111;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
pre {
|
||||
color: #c6c6c6;
|
||||
background-color: #111111;
|
||||
border: 1px solid #333333;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #a94442;
|
||||
background-color: #000;
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
color: #a94442;
|
||||
background-color: #000;
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.table {
|
||||
color: #c6c6c6;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.table > thead > tr > th {
|
||||
border-bottom: 2px solid #333;
|
||||
}
|
||||
|
||||
.table > tbody > tr.active > td, .table > tbody > tr.active > th, .table > tbody > tr > td.active, .table > tbody > tr > th.active, .table > tfoot > tr.active > td, .table > tfoot > tr.active > th, .table > tfoot > tr > td.active, .table > tfoot > tr > th.active, .table > thead > tr.active > td, .table > thead > tr.active > th, .table > thead > tr > td.active, .table > thead > tr > th.active {
|
||||
color: #c6c6c6;
|
||||
background-color: #000;
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {
|
||||
border-top: 1px solid #333;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: #202020;
|
||||
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: #a94442;
|
||||
background-color: #000;
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.table-striped > tbody > tr:nth-of-type(2n+1) {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
tr:hover td {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.text-info {
|
||||
color: #a94442;
|
||||
}
|
||||
|
||||
.open > .dropdown-menu {
|
||||
background-color: #0c0c0c;
|
||||
border-color: #181818;
|
||||
color: #c6c6c6;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a:focus, .dropdown-menu > li > a:hover {
|
||||
color: #777;
|
||||
background-color: #131313;
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #454545;
|
||||
}
|
||||
|
||||
.btn-info:hover {
|
||||
color: #c6c6c6;
|
||||
background-color: #131313;
|
||||
border-color: #767676;
|
||||
}
|
||||
|
||||
.btn-info.active, .btn-info:active {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-info.focus, .btn-info:focus {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-info.active.focus, .btn-info.active:focus, .btn-info.active:hover, .btn-info:active.focus, .btn-info:active:focus, .btn-info:active:hover, .open>.dropdown-toggle.btn-info.focus, .open>.dropdown-toggle.btn-info:focus, .open>.dropdown-toggle.btn-info:hover {
|
||||
color: #212121;
|
||||
background-color: #010101;
|
||||
border-color: #171717;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #454545;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
color: #c6c6c6;
|
||||
background-color: #131313;
|
||||
border-color: #767676;
|
||||
}
|
||||
|
||||
.btn-danger.active, .btn-danger:active {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-danger.focus, .btn-danger:focus {
|
||||
color: #c6c6c6;
|
||||
background-color: #010101;
|
||||
border-color: #212121;
|
||||
}
|
||||
|
||||
.btn-danger.active.focus, .btn-danger.active:focus, .btn-danger.active:hover, .btn-danger:active.focus, .btn-danger:active:focus, .btn-danger:active:hover, .open>.dropdown-toggle.btn-danger.focus, .open>.dropdown-toggle.btn-danger:focus, .open>.dropdown-toggle.btn-danger:hover {
|
||||
color: #212121;
|
||||
background-color: #010101;
|
||||
border-color: #171717;
|
||||
}
|
||||
.btn-switch {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 50px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
background-color: darkgray;
|
||||
border: 2px solid darkgray;
|
||||
border-radius: 40px;
|
||||
|
||||
}
|
||||
.btn-switch--on {
|
||||
background-color: #ccffff;
|
||||
border: 2px solid #ccffff;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: gray;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: black;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px whitesmoke;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
250
Themes/css/main.css
Normal file
250
Themes/css/main.css
Normal file
@ -0,0 +1,250 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #000;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #e7e7e7;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #e7e7e7;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #fff !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #ccc !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "WiFi Pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #2196F3;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #2196F3;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
525
Themes/css/malware.css
Normal file
525
Themes/css/malware.css
Normal file
@ -0,0 +1,525 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:red;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
i {
|
||||
color: red;
|
||||
font: monospace;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: red;
|
||||
text-align: center;
|
||||
background-color: black;
|
||||
border: 1px solid red;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: red;
|
||||
white-space:nowrap;
|
||||
background-color: black;
|
||||
border: red;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: red;
|
||||
background-color: black;
|
||||
background-image: none;
|
||||
border: 1px solid red;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid red;
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
* {
|
||||
color: red;
|
||||
border-color: red;
|
||||
border-top: red;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #000;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: red;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #000000;
|
||||
border: 1px solid red;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: darkred;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #ff0000;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid darkred;
|
||||
color:red;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: red;
|
||||
background-color: black;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
p {
|
||||
color: red;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:darkred;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:red;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:red;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:red;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:red;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: red;
|
||||
background-color: red;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #000000;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: #000;
|
||||
opacity: 1;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: #000000;
|
||||
border-top: 1px solid darkred;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: #000;
|
||||
opacity: 1;
|
||||
color: red;
|
||||
font-family: monospace;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #000 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #000 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:red;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: red;
|
||||
background-color: black;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:black;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: red;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:black;
|
||||
font-family:monospace;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: red;
|
||||
background-color: black;
|
||||
border-color: red;
|
||||
border-bottom-color: red;
|
||||
border-bottom: red;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:black;
|
||||
}
|
||||
.nav {
|
||||
background-color:black;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:black;
|
||||
border-color: red;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: monospace;
|
||||
background-color: red;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: black;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid red;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: black;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: darkgray;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: black;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: red;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px red;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
511
Themes/css/morning.css
Normal file
511
Themes/css/morning.css
Normal file
@ -0,0 +1,511 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:cornflowerblue;
|
||||
font-family:cursive;
|
||||
}
|
||||
|
||||
i {
|
||||
color: cornflowerblue;
|
||||
font: cursive;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: cursive;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: cursive;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: cornflowerblue;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: rosybrown;
|
||||
text-align: center;
|
||||
background-color: wheat;
|
||||
border: 1px solid rosybrown;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: rosybrown;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid rosybrown;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: cornflowerblue;
|
||||
white-space:nowrap;
|
||||
background-color: wheat;
|
||||
border: rosybrown;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: rosybrown;
|
||||
background-color: wheat;
|
||||
background-image: none;
|
||||
border: 1px solid rosybrown;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid rosybrown;
|
||||
border-top: 1px solid rosybrown;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: wheat;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: wheat;
|
||||
}
|
||||
|
||||
* {
|
||||
color: rosybrown;
|
||||
border-color: rosybrown;
|
||||
border-top: rosybrown;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid wheat;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: rosybrown;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: wheat;
|
||||
border: 1px solid rosybrown;
|
||||
border-radius: 4px;
|
||||
font-family: cursive;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: wheat;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: wheat;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: rosybrown;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rosybrown;
|
||||
color:cornflowerblue;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: wheat;
|
||||
font-family: cursive;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: rosybrown;
|
||||
background-color: wheat;
|
||||
border-color: rosybrown;
|
||||
}
|
||||
|
||||
p {
|
||||
color: rosybrown;
|
||||
font-family: cursive;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:darkmagenta;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:cornflowerblue;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:cornflowerblue;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:cornflowerblue;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:rosybrown;
|
||||
border-color: rosybrown;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: rosybrown;
|
||||
background-color: rosybrown;
|
||||
border-color: rosybrown;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: wheat;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid wheat;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: wheat;
|
||||
opacity: 1;
|
||||
color: rosybrown;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: wheat;
|
||||
border-top: 1px solid rosybrown;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: wheat;
|
||||
opacity: 1;
|
||||
color: rosybrown;
|
||||
font-family: cursive;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: wheat;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: wheat !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid wheat !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:rosybrown;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: rosybrown;
|
||||
background-color: wheat;
|
||||
border-color: rosybrown;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:wheat;
|
||||
color: rosybrown;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: rosybrown;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:wheat;
|
||||
font-family: cursive;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:wheat;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: cornflowerblue;
|
||||
background-color: wheat;
|
||||
border-color: rosybrown;
|
||||
border-bottom-color: rosybrown;
|
||||
border-bottom: rosybrown;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:wheat;
|
||||
}
|
||||
.nav {
|
||||
background-color:wheat;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:wheat;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:wheat;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:wheat;
|
||||
border-color: rosybrown;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: cursive;
|
||||
background-color: rosybrown;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: wheat;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid rosybrown;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid rosybrown;
|
||||
}
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: wheat;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: rosybrown;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px rosybrown;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
504
Themes/css/neon.css
Normal file
504
Themes/css/neon.css
Normal file
@ -0,0 +1,504 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:magenta;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
i {
|
||||
color: lime;
|
||||
font: monospace;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: monospace;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: lime;
|
||||
text-align: center;
|
||||
background-color: purple;
|
||||
border: 1px solid lime;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid lime;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: lime;
|
||||
white-space:nowrap;
|
||||
background-color: purple;
|
||||
border: lime;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: lime;
|
||||
background-color: purple;
|
||||
background-image: none;
|
||||
border: 1px solid lime;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid lime;
|
||||
border-top: 1px solid lime;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: purple;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: purple;
|
||||
}
|
||||
|
||||
* {
|
||||
color: lime;
|
||||
border-color: lime;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #000;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: lime;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #000000;
|
||||
border: 1px solid lime;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: limegreen;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #18ff00;
|
||||
color:lime;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: purple;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: lime;
|
||||
background-color: purple;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
p {
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:violet;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:lime;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:lime;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:lime;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:lime;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: magenta;
|
||||
background-color: lime;
|
||||
border-color: #adadad;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #000000;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: #000;
|
||||
opacity: 1;
|
||||
color: lime;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: #000000;
|
||||
border-top: 1px solid #0F0;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: #000;
|
||||
opacity: 1;
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #000 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #000 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "Neon Pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:lime;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: lime;
|
||||
background-color: purple;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:purple;
|
||||
color: lime;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:black;
|
||||
font-family:monospace;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:purple;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: lime;
|
||||
background-color: purple;
|
||||
border-color: lime;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:black;
|
||||
}
|
||||
.nav {
|
||||
background-color:black;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:black;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:black;
|
||||
border-color: lime;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: monospace;
|
||||
background-color: lime;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: magenta;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid lime;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid lime;
|
||||
}
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: black;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: lime;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: purple;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px purple;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
526
Themes/css/spring.css
Normal file
526
Themes/css/spring.css
Normal file
@ -0,0 +1,526 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:#00e673;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #00e673;
|
||||
font: sans-serif;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: sans-serif;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #00e673;
|
||||
text-align: center;
|
||||
background-color: #00e673;
|
||||
border: 1px solid #00e673;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: #00e673;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid #00e673;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: #00e673;
|
||||
white-space:nowrap;
|
||||
background-color: #6666ff;
|
||||
border: #00e673;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: #00e673;
|
||||
background-color: #6666ff;
|
||||
background-image: none;
|
||||
border: 1px solid #00e673;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #00e673;
|
||||
border-top: 1px solid #00e673;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: #6666ff;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: #6666ff;
|
||||
}
|
||||
|
||||
* {
|
||||
color: #00e673;
|
||||
border-color: #00e673;
|
||||
border-top: #00e673;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #6666ff;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: #00e673;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #6666ff;
|
||||
border: 1px solid #00e673;
|
||||
border-radius: 4px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #6666ff;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #6666ff;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: lightblue;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #ff0000;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
|
||||
background-color: #6666ff;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid dark#00e673;
|
||||
color:#00e673;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: #6666ff;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #00e673;
|
||||
background-color: springgreen;
|
||||
border-color: #00e673;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #00e673;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:#00e673;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:#00e673;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:#00e673;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:#00e673;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:#00e673;
|
||||
border-color: #00e673;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: #00e673;
|
||||
background-color: #00e673;
|
||||
border-color: #00e673;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #00e673;
|
||||
color:black
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #6666ff;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: #6666ff;
|
||||
opacity: 1;
|
||||
color: #00e673;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: #6666ff;
|
||||
border-top: 1px solid dark#00e673;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: #6666ff;
|
||||
opacity: 1;
|
||||
color: #00e673;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #6666ff;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #000038 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #000038 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:#00e673;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: #00e673;
|
||||
background-color: #6666ff;
|
||||
border-color: #00e673;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:#6666ff;
|
||||
color: #00e673;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: #00e673;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:#6666ff;
|
||||
font-family:sans-serif;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:#6666ff;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: #00e673;
|
||||
background-color: #6666ff;
|
||||
border-color: #00e673;
|
||||
border-bottom-color: #00e673;
|
||||
border-bottom: #00e673;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:#6666ff;
|
||||
}
|
||||
.nav {
|
||||
background-color:#6666ff;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:#6666ff;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:#6666ff;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:#6666ff;
|
||||
border-color: #00e673;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: sans-serif;
|
||||
background-color: #00e673;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: #6666ff;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid #00e673;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #00e673;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #6666ff;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: darkslategray;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: #6666ff;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #00e673;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #00e673;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
525
Themes/css/starstuff.css
Normal file
525
Themes/css/starstuff.css
Normal file
@ -0,0 +1,525 @@
|
||||
.truncated {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
a {
|
||||
color:gold;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
i {
|
||||
color: gold;
|
||||
font: sans-serif;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: 700;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: sans-serif;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: gold;
|
||||
text-align: center;
|
||||
background-color: #000038;
|
||||
border: 1px solid gold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.panel-default {
|
||||
border-color: gold;
|
||||
}
|
||||
|
||||
.panel>.panel-body+.table, .panel>.panel-body+.table-responsive, .panel>.table+.panel-body, .panel>.table-responsive+.panel-body {
|
||||
border-top: 1px solid gold;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
display:block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
color: gold;
|
||||
white-space:nowrap;
|
||||
background-color: #000038;
|
||||
border: gold;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: gold;
|
||||
background-color: #000038;
|
||||
background-image: none;
|
||||
border: 1px solid gold;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-bottom: 1px solid gold;
|
||||
border-top: 1px solid gold;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: #000038;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
min-height: .01%;
|
||||
overflow-x: auto;
|
||||
background-color: #000038;
|
||||
}
|
||||
|
||||
* {
|
||||
color: gold;
|
||||
border-color: gold;
|
||||
border-top: gold;
|
||||
}
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.table-layout-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
display: inline;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.fixed-addon-width {
|
||||
min-width: 70px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-addon-width-2 {
|
||||
min-width: 90px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.fixed-addon-width-3 {
|
||||
min-width: 110px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-width-200 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.caret-reversed {
|
||||
border-top-width: 0;
|
||||
border-bottom: 4px solid #000038;
|
||||
}
|
||||
|
||||
.image-small-18 {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scrollable-pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9.5px;
|
||||
margin: 0 0 10px;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
color: gold;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #000038;
|
||||
border: 1px solid gold;
|
||||
border-radius: 4px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.log-pre {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.btn-fixed-length {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.title-message {
|
||||
margin-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.select-inline {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #000038;
|
||||
}
|
||||
|
||||
.logout {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-nav li a {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.module-nav li:hover {
|
||||
background-color: #000038;
|
||||
}
|
||||
|
||||
.nav>li>a:focus, .nav>li>a:hover {
|
||||
text-decoration: none;
|
||||
background-color: lightblue;
|
||||
}
|
||||
.sidebar .sidebar-nav.navbar-collapse {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #ff0000;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
|
||||
background-color: #000038;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid darkgold;
|
||||
color:gold;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: #000038;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: gold;
|
||||
background-color: blue;
|
||||
border-color: gold;
|
||||
}
|
||||
|
||||
p {
|
||||
color: gold;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color:darkgold;
|
||||
}
|
||||
|
||||
.h3 h3 {
|
||||
color:gold;
|
||||
}
|
||||
.h2, h2 {
|
||||
font-size: 30px;
|
||||
color:gold;
|
||||
}
|
||||
.h1, h1 {
|
||||
font-size: 30px;
|
||||
color:gold;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color:gold;
|
||||
border-color: gold;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
color: gold;
|
||||
background-color: gold;
|
||||
border-color: gold;
|
||||
}
|
||||
|
||||
.sidebar .active {
|
||||
background-color: #13033a;
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
.sidebar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
margin-top: 51px;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
position: inherit;
|
||||
margin: 0 0 0 250px;
|
||||
padding: 15px 30px;
|
||||
border-left: 1px solid #000038;
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-top-links {
|
||||
margin-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.navbar-top-links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
|
||||
background-color: #000038;
|
||||
opacity: 1;
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: #000038;
|
||||
border-top: 1px solid darkgold;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
background-color: #000038;
|
||||
opacity: 1;
|
||||
color: gold;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-top-links .dropdown-menu li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
padding: 15px 15px;
|
||||
background-color: #000038;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu-top {
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
.dropdown-menu-top {
|
||||
margin: auto !important;
|
||||
position: absolute !important;
|
||||
background-color: #000038 !important;
|
||||
word-wrap: break-word !important;
|
||||
border: 1px solid #000038 !important;
|
||||
width: 300px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
.dropdown-menu-top li a {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.dropdown-menu-logout {
|
||||
max-width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 10px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
content: url('/img/logo.png');
|
||||
max-height: 30px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.brand-text::after {
|
||||
content: "pineapple";
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color:gold;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: gold;
|
||||
background-color: #000038;
|
||||
border-color: gold;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
background-color:#000038;
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading+.panel-collapse>.panel-body {
|
||||
border-top-color: gold;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color:#000038;
|
||||
font-family:sans-serif;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
background-color:#000038;
|
||||
}
|
||||
|
||||
.panel-default>.panel-heading {
|
||||
color: gold;
|
||||
background-color: #000038;
|
||||
border-color: gold;
|
||||
border-bottom-color: gold;
|
||||
border-bottom: gold;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color:#000038;
|
||||
}
|
||||
.nav {
|
||||
background-color:#000038;
|
||||
}
|
||||
.sidebar-nav.navbar-collapse {
|
||||
background-color:#000038;
|
||||
}
|
||||
.navbar-default{
|
||||
background-color:#000038;
|
||||
}
|
||||
.navbar-static-top {
|
||||
background-color:#000038;
|
||||
border-color: gold;
|
||||
}
|
||||
.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child>.btn, .input-group-btn:first-child>.btn-group>.btn, .input-group-btn:first-child>.dropdown-toggle, .input-group-btn:last-child>.btn-group:not(:last-child)>.btn, .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
|
||||
font-family: sans-serif;
|
||||
background-color: gold;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: #000038;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid gold;
|
||||
}
|
||||
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid gold;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background-color: #000038;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
box-shadow: 0 3px 9px rgba(0,0,0,.5);
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 20px;
|
||||
}
|
||||
.switch input {display:none;}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: darkgray;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: #000038;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: gold;
|
||||
}
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px gold;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
BIN
Themes/img/favicon-dark.ico
Normal file
BIN
Themes/img/favicon-dark.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 533 B |
BIN
Themes/img/logo-dark.png
Normal file
BIN
Themes/img/logo-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
Themes/img/throbber-dark.gif
Normal file
BIN
Themes/img/throbber-dark.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
604
Themes/js/module.js
Normal file
604
Themes/js/module.js
Normal file
@ -0,0 +1,604 @@
|
||||
registerController("ThemesController", ['$api', '$scope','$window','$route', '$http', function ($api, $scope, $window, $route, $http) {
|
||||
|
||||
getThemes();
|
||||
getCurrentTheme();
|
||||
backupFiles();
|
||||
|
||||
$scope.debug = false;
|
||||
$scope.themes = [];
|
||||
$scope.themeToDelete = null;
|
||||
$scope.themeDeleteValidation = '';
|
||||
$scope.messages = [];
|
||||
$scope.newThemeName = '';
|
||||
$scope.throbber = true;
|
||||
$scope.running = false;
|
||||
$scope.current = '';
|
||||
$scope.library = true;
|
||||
$scope.editor = true;
|
||||
$scope.workshopTheme = {themeName: "", file: "", code: "", title: ""};
|
||||
$scope.editThemeFile = {themeName: "", file: "", code: ""};
|
||||
$scope.colors = ['dark', 'light', 'red', 'blue', 'green', 'purple', 'orange', 'yellow', 'pink'];
|
||||
$scope.brightness = ['light', 'normal', 'dark'];
|
||||
$scope.working = false;
|
||||
$scope.autoRefresh = true;
|
||||
// Dark and White
|
||||
$scope.throbbercontrast = true; // true == light -> false == dark
|
||||
$scope.logocontrast = true;
|
||||
$scope.faviconcontrast = true;
|
||||
$scope.reconcontrast = true;
|
||||
$scope.logocontrastText = 'light';
|
||||
$scope.faviconcontrastText = 'light';
|
||||
$scope.throbbercontrastText = 'light';
|
||||
// Color and brightness
|
||||
$scope.allcontrastText = 'light';
|
||||
$scope.allcontrastBrightness = 'normal';
|
||||
$scope.dashboardcontrastText = 'light';
|
||||
$scope.dashboardcontrastBrightness = 'normal';
|
||||
$scope.reconcontrastText = 'light';
|
||||
$scope.reconcontrastBrightness = 'normal';
|
||||
$scope.profilingcontrastText = 'light';
|
||||
$scope.profilingcontrastBrightness = 'normal';
|
||||
$scope.clientscontrastText = 'light';
|
||||
$scope.clientscontrastBrightness = 'normal';
|
||||
$scope.modulescontrastText = 'light';
|
||||
$scope.modulescontrastBrightness = 'normal';
|
||||
$scope.filterscontrastText = 'light';
|
||||
$scope.filterscontrastBrightness = 'normal';
|
||||
$scope.pineapcontrastText = 'light';
|
||||
$scope.pineapcontrastBrightness = 'normal';
|
||||
$scope.trackingcontrastText = 'light';
|
||||
$scope.trackingcontrastBrightness = 'normal';
|
||||
$scope.loggingcontrastText = 'light';
|
||||
$scope.loggingcontrastBrightness = 'normal';
|
||||
$scope.reportingcontrastText = 'light';
|
||||
$scope.reportingcontrastBrightness = 'normal';
|
||||
$scope.networkingcontrastText = 'light';
|
||||
$scope.networkingcontrastBrightness = 'normal';
|
||||
$scope.configurationcontrastText = 'light';
|
||||
$scope.configurationcontrastBrightness = 'normal';
|
||||
$scope.advancedcontrastText = 'light';
|
||||
$scope.advancedcontrastBrightness = 'normal';
|
||||
$scope.helpcontrastText = 'light';
|
||||
$scope.helpcontrastBrightness = 'normal';
|
||||
$scope.switchOn = {
|
||||
"position" : "relative",
|
||||
"display" : "block",
|
||||
"width" : "50px",
|
||||
"height" : "25px",
|
||||
"cursor" : "pointer",
|
||||
"border" : "2px solid darkgray",
|
||||
"background-color" : "darkgray",
|
||||
"border-radius" : "40px"
|
||||
}
|
||||
$scope.switchOff = {
|
||||
"position" : "relative",
|
||||
"display" : "block",
|
||||
"width" : "50px",
|
||||
"height" : "25px",
|
||||
"cursor" : "pointer",
|
||||
"border" : "2px solid darkgray",
|
||||
"background-color" : "white",
|
||||
"border-radius" : "40px"
|
||||
}
|
||||
$scope.selectOptions = {
|
||||
"position" : "relative",
|
||||
"display" : "block",
|
||||
"width" : "100px",
|
||||
"height" : "25px",
|
||||
"cursor" : "pointer",
|
||||
"border" : "2px solid darkgray",
|
||||
"background-color" : "white",
|
||||
"color" : "black",
|
||||
"border-radius" : "40px"
|
||||
}
|
||||
$scope.changeThrobber = function(){
|
||||
$scope.throbbercontrast = !$scope.throbbercontrast;
|
||||
$scope.throbbercontrastText = 'light';
|
||||
if (!$scope.throbbercontrast) {
|
||||
$scope.throbbercontrastText = 'dark';
|
||||
}
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Throbber',
|
||||
light: $scope.throbbercontrast
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Throbber", "set to " + $scope.throbbercontrastText);
|
||||
log("changeThrobber", response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeLogo = function(){
|
||||
$scope.logocontrast = !$scope.logocontrast;
|
||||
$scope.logocontrastText = 'light';
|
||||
if (!$scope.logocontrast) {
|
||||
$scope.logocontrastText = 'dark';
|
||||
}
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Logo',
|
||||
light: $scope.logocontrast
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Logo", "set to " + $scope.logocontrastText);
|
||||
log("changeLogo", response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.changeFavicon = function(){
|
||||
$scope.faviconcontrast = !$scope.faviconcontrast;
|
||||
$scope.faviconcontrastText = 'light';
|
||||
if (!$scope.faviconcontrast) {
|
||||
$scope.faviconcontrastText = 'dark';
|
||||
}
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Icon',
|
||||
light: $scope.faviconcontrast
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Icon", "set to " + $scope.faviconcontrastText);
|
||||
log("changeFavicon", response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeAllIcons = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'All',
|
||||
color: $scope.allcontrastText,
|
||||
brightness: $scope.allcontrastBrightness
|
||||
}, function(response) {
|
||||
for (msg in response) {
|
||||
$scope.sendMessage("All Icons", "set to " + $scope.allcontrastText + "(" + $scope.allcontrastBrightness + ")");
|
||||
log("changeAllIcons", "Success? " + response.success + " " + response.message);
|
||||
}
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeDashboard = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Dashboard',
|
||||
color: $scope.dashboardcontrastText,
|
||||
brightness: $scope.dashboardcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Dashboard Icon", "set to " + $scope.dashboardcontrastText + " (" + $scope.dashboardcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeRecon = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Recon',
|
||||
color: $scope.reconcontrastText,
|
||||
brightness: $scope.reconcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Recon Icon", "set to " + $scope.reconcontrastText + " (" + $scope.reconcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeProfiling = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Profiling',
|
||||
color: $scope.profilingcontrastText,
|
||||
brightness: $scope.profilingcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Profiling Icon", "set to " + $scope.profilingcontrastText + " (" + $scope.profilingcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeClients = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Clients',
|
||||
color: $scope.clientscontrastText,
|
||||
brightness: $scope.clientscontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Clients Icon", "set to " + $scope.clientscontrastText + " (" + $scope.clientscontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeModules = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'ModuleManager',
|
||||
color: $scope.modulescontrastText,
|
||||
brightness: $scope.modulescontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("ModuleManager Icon", "set to " + $scope.modulescontrastText + " (" + $scope.modulescontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeFilters = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Filters',
|
||||
color: $scope.filterscontrastText,
|
||||
brightness: $scope.filterscontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Filters Icon", "set to " + $scope.filterscontrastText + " (" + $scope.filterscontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changePineap = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'PineAP',
|
||||
color: $scope.pineapcontrastText,
|
||||
brightness: $scope.pineapcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Filters Icon", "set to " + $scope.pineapcontrastText + " (" + $scope.pineapcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeTracking = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Tracking',
|
||||
color: $scope.trackingcontrastText,
|
||||
brightness: $scope.trackingcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Tracking Icon", "set to " + $scope.trackingcontrastText + " (" + $scope.trackingcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeLogging = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Logging',
|
||||
color: $scope.loggingcontrastText,
|
||||
brightness: $scope.loggingcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Logging Icon", "set to " + $scope.loggingcontrastText + " (" + $scope.loggingcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeReporting = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Reporting',
|
||||
color: $scope.reportingcontrastText,
|
||||
brightness: $scope.reportingcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Reporting Icon", "set to " + $scope.reportingcontrastText + " (" + $scope.reportingcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeNetworking = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Networking',
|
||||
color: $scope.networkingcontrastText,
|
||||
brightness: $scope.networkingcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Networking Icon", "set to " + $scope.networkingcontrastText + " (" + $scope.networkingcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeConfiguration = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Configuration',
|
||||
color: $scope.configurationcontrastText,
|
||||
brightness: $scope.configurationcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Configuration Icon", "set to " + $scope.configurationcontrastText + " (" + $scope.configurationcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeAdvanced = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Advanced',
|
||||
color: $scope.advancedcontrastText,
|
||||
brightness: $scope.advancedcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Advanced Icon", "set to " + $scope.advancedcontrastText + " (" + $scope.advancedcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.changeHelp = function(){
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "replaceImage",
|
||||
img: 'Help',
|
||||
color: $scope.helpcontrastText,
|
||||
brightness: $scope.helpcontrastBrightness
|
||||
}, function(response) {
|
||||
$scope.sendMessage("Help Icon", "set to " + $scope.helpcontrastText + " (" + $scope.helpcontrastBrightness + ")");
|
||||
log("changeDashboard", "Success? " + response.success + " " + response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
function log(fn, message) {
|
||||
if ($scope.debug === true) {
|
||||
console.log("fn[" + fn + "]-> " + message);
|
||||
}
|
||||
};
|
||||
function backupFiles() {
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "backupFiles"
|
||||
}, function(response) {
|
||||
log('backupFiles', response.message);
|
||||
for (i=0; i<response.modules.length; i++) {
|
||||
log('backupFiles', response.modules[i]);
|
||||
}
|
||||
});
|
||||
};
|
||||
function getCurrentTheme() {
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "getCurrentTheme"
|
||||
}, function(response) {
|
||||
$scope.current = response.current;
|
||||
$scope.logocontrastText = response.logo;
|
||||
$scope.faviconcontrastText = response.icon;
|
||||
$scope.throbbercontrastText = response.throbber;
|
||||
$scope.dashboardcontrastText = response.dashboard;
|
||||
$scope.dashboardcontrastBrightness = response.dashboardbrightness;
|
||||
$scope.reconcontrastText = response.recon;
|
||||
$scope.reconcontrastBrightness = response.reconbrightness;
|
||||
$scope.profilingcontrastText = response.profiling;
|
||||
$scope.profilingcontrastBrightness = response.profilingbrightness;
|
||||
$scope.clientscontrastText = response.clients;
|
||||
$scope.clientscontrastBrightness = response.clientsbrightness;
|
||||
$scope.modulescontrastText = response.modulemanager;
|
||||
$scope.modulescontrastBrightness = response.modulemanagerbrightness;
|
||||
$scope.filterscontrastText = response.filters;
|
||||
$scope.filterscontrastBrightness = response.filtersbrightness;
|
||||
$scope.pineapcontrastText = response.pineap;
|
||||
$scope.pineapcontrastBrightness = response.pineapbrightness;
|
||||
$scope.trackingcontrastText = response.tracking;
|
||||
$scope.trackingcontrastBrightness = response.trackingbrightness;
|
||||
$scope.loggingcontrastText = response.logging;
|
||||
$scope.loggingcontrastBrightness = response.loggingbrightness;
|
||||
$scope.reportingcontrastText = response.reporting;
|
||||
$scope.reportingcontrastBrightness = response.reportingbrightness;
|
||||
$scope.networkingcontrastText = response.networking;
|
||||
$scope.networkingcontrastBrightness = response.networkingbrightness;
|
||||
$scope.configurationcontrastText = response.configuration;
|
||||
$scope.configurationcontrastBrightness = response.configurationbrightness;
|
||||
$scope.advancedcontrastText = response.advanced;
|
||||
$scope.advancedcontrastBrightness = response.advancedbrightness;
|
||||
$scope.helpcontrastText = response.help;
|
||||
$scope.helpcontrastBrightness = response.helpbrightness;
|
||||
$scope.throbbercontrast = true;
|
||||
$scope.faviconcontrast = true;
|
||||
$scope.logocontrast = true;
|
||||
if (response.throbber === 'dark') {
|
||||
$scope.throbbercontrast = false;
|
||||
}
|
||||
if (response.icon === 'dark') {
|
||||
$scope.faviconcontrast = false;
|
||||
}
|
||||
if (response.logo === 'dark') {
|
||||
$scope.logocontrast = false;
|
||||
}
|
||||
log("getCurrentTheme", "Current theme is " + $scope.current);
|
||||
log("getCurrentTheme", "Current throbber is " + response.throbber);
|
||||
log("getCurrentTheme", "Current icon is " + response.icon);
|
||||
log("getCurrentTheme", "Current logo is " + response.logo);
|
||||
log("getCurrentTheme", "Current Dashboard is " + response.dashboard);
|
||||
});
|
||||
};
|
||||
$scope.file_changed = function(element) {
|
||||
$scope.$apply(function(scope) {
|
||||
var photofile = element.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
$scope.$apply(function() {
|
||||
$scope.prev_img = e.target.result;
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(photofile);
|
||||
});
|
||||
};
|
||||
$scope.restoreDefault = function() {
|
||||
$scope.working = "Working..";
|
||||
console.log("Restore Default Function Called");
|
||||
$scope.throbber = true;
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "restoreDefault"
|
||||
}, function (response) {
|
||||
log("restoreDefault", "default CSS restored");
|
||||
$scope.sendMessage("Restore", "Default CSS restored");
|
||||
$scope.throbber = false;
|
||||
log("restoreDefault", "Successful? "+ response.success + ". " + response.message);
|
||||
$scope.working = "Done!";
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.sendMessage = function (t, m) {
|
||||
// Add a new message to the top of the list
|
||||
$scope.messages.unshift({title: t, msg: m});
|
||||
log("sendMessage", m);
|
||||
// if there are 4 items in the list remove the 4th item
|
||||
if ($scope.messages.length == 4) {
|
||||
$scope.dismissMessage(3);
|
||||
}
|
||||
};
|
||||
$scope.dismissMessage = function ($index) {
|
||||
//var index = $scope.messages.indexOf(message);
|
||||
$scope.messages.splice($index, 1);
|
||||
log("dismissMessage", "message at index " + $index + " dismissed" );
|
||||
};
|
||||
$scope.createNewTheme = function () {
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "createNewTheme",
|
||||
themeName: $scope.newThemeName
|
||||
}, function (response) {
|
||||
if (response.create_success) {
|
||||
log("createNewTheme", "success! new theme '"+ $scope.newThemeName + "' created");
|
||||
getThemes();
|
||||
$scope.newThemeName = '';
|
||||
} else {
|
||||
$scope.sendMessage("Error Creating Theme", response.create_message);
|
||||
log("createNewTheme", "error! " + response.create_message);
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.deleteTheme = function (theme) {
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "deleteTheme",
|
||||
name: theme.title
|
||||
}, function (response) {
|
||||
$scope.sendMessage("Delete", response.message);
|
||||
getThemes();
|
||||
});
|
||||
log('deleteTheme', 'Deleting Theme: ' + theme.title );
|
||||
};
|
||||
$scope.activateTheme = function (theme) {
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "activateTheme",
|
||||
name: theme.title
|
||||
}, function (response) {
|
||||
if (response.return === true) {
|
||||
$scope.currentTheme = theme.title;
|
||||
getThemes();
|
||||
$scope.sendMessage("Activated", response.message);
|
||||
if ($scope.autoRefresh) {
|
||||
$window.location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.editTheme = function (theme) {
|
||||
console.log("action: edit " + theme.name);
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "getThemeCode",
|
||||
name: theme.name
|
||||
}, function (response) {
|
||||
$scope.editThemeFile.code = response.code;
|
||||
$scope.editThemeFile.file = response.file;
|
||||
$scope.editThemeFile.themeName = theme.name;
|
||||
});
|
||||
};
|
||||
$scope.saveThemeCode = function (editFile) {
|
||||
console.log("action: save " + editFile.themeName);
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "submitThemeCode",
|
||||
themeCode: editFile.code,
|
||||
name: editFile.themeName,
|
||||
fileName: editFile.file
|
||||
}, function (response) {
|
||||
$scope.sendMessage("Saved", editFile.themeName);
|
||||
});
|
||||
if ($scope.current === editFile.themeName)
|
||||
{
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "activateTheme",
|
||||
name: editFile.themeName
|
||||
}, function (response) {
|
||||
if (response.return === true) {
|
||||
$scope.currentTheme = editFile.themeName;
|
||||
$scope.sendMessage("Activated", response.message);
|
||||
}
|
||||
});
|
||||
log('saveThemeCode', "Theme code saved, also current so set to inactive");
|
||||
}
|
||||
};
|
||||
$scope.getThemeFields = function (theme) {
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "themeFields",
|
||||
name: theme.title
|
||||
}, function (response) {
|
||||
$scope.workshopTheme.themeName = theme.title;
|
||||
$scope.workshopTheme.title = theme.title;
|
||||
$scope.workshopTheme.code = response.code;
|
||||
console.log(response);
|
||||
$scope.library = false;
|
||||
});
|
||||
};
|
||||
function getThemes() {
|
||||
$api.request({
|
||||
module: "Themes",
|
||||
action: "getThemeList"
|
||||
}, function (response) {
|
||||
$scope.themes = [];
|
||||
for (var i = 0; i < response.length; i++) {
|
||||
$scope.themes.unshift({
|
||||
title: response[i].title,
|
||||
storage: response[i].location,
|
||||
active: response[i].active
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]);
|
||||
786
Themes/module.html
Normal file
786
Themes/module.html
Normal file
@ -0,0 +1,786 @@
|
||||
<div class="row" ng-controller="ThemesController">
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="javascript:;" data-toggle="collapse" data-target="#collapseControls" class="text-muted"><h4
|
||||
class="panel-title"><b>Theme:</b> {{ current.substring(0, current.length - 4); }}</h4></a>
|
||||
</div>
|
||||
<div id="collapseControls" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<td>
|
||||
Auto Refresh
|
||||
</td>
|
||||
<td>
|
||||
<label class="switch" >
|
||||
<input type="checkbox" ng-model="autoRefresh">
|
||||
<span class="slider round">
|
||||
</span>
|
||||
</label>
|
||||
</td>
|
||||
|
||||
<td style="text-align:right;">
|
||||
<button class="btn btn-default"
|
||||
data-toggle="modal"
|
||||
data-target="#loadingModal"
|
||||
type="button"
|
||||
ng-click="restoreDefault()">Restore Default</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="javascript:;" data-toggle="collapse" data-target="#collapseMessages" class="text-muted"><h4
|
||||
class="panel-title">Themes Messages</h4></a>
|
||||
</div>
|
||||
<div id="collapseMessages" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<p ng-show="(messages.length == 0)" class="text-muted"><i>No Messages...</i></p>
|
||||
<a ng-hide="(messages.length < 2)" ng-click="messages = []" class="pull-right" href="javascript:;">Clear
|
||||
All</a>
|
||||
<table style="width:100%" ng-hide="(messages.length == 0)">
|
||||
<tr ng-repeat="message in messages">
|
||||
<td>
|
||||
<hr/>
|
||||
<h5><b>{{ message.title }}</b> <a ng-click="dismissMessage($index)" href="javascript:;"
|
||||
class="pull-right">Dismiss</a></h5>
|
||||
<p class="text-muted"><i>{{ message.msg }}</i></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="javascript:;" data-toggle="collapse" data-target="#collapseIconColors" class="text-muted"><h4
|
||||
class="panel-title">Icon Colors</h4></a>
|
||||
</div>
|
||||
<div id="collapseIconColors" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped" align="left">
|
||||
<thead>
|
||||
<th>Icon</th>
|
||||
<th>Color</th>
|
||||
<th>Brightness</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Throbber</td><td> {{ throbbercontrastText }}</td><td> N/A </td> </tr>
|
||||
<tr><td>Logo</td><td> {{ logocontrastText }}</td><td> N/A </td> </tr>
|
||||
<tr><td>Favicon</td><td> {{ faviconcontrastText }}</td><td> N/A </td> </tr>
|
||||
<tr><td>Dashboard</td><td> {{ dashboardcontrastText }}</td><td> {{ dashboardcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Recon</td><td> {{ reconcontrastText }}</td><td> {{ reconcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Profiling</td><td> {{ profilingcontrastText }}</td><td> {{ profilingcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Clients</td><td> {{ clientscontrastText }}</td><td> {{ clientscontrastBrightness }}</td> </tr>
|
||||
<tr><td>Modules</td><td> {{ modulescontrastText }}</td><td> {{ modulescontrastBrightness }}</td> </tr>
|
||||
<tr><td>Filters</td><td> {{ filterscontrastText }}</td><td> {{ filterscontrastBrightness }}</td> </tr>
|
||||
<tr><td>PineAP</td><td> {{ pineapcontrastText }}</td><td> {{ pineapcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Tracking</td><td> {{ trackingcontrastText }}</td><td> {{ trackingcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Logging</td><td> {{ loggingcontrastText }}</td><td> {{ loggingcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Reporting</td><td> {{ reportingcontrastText }}</td><td> {{ reportingcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Networking</td><td> {{ networkingcontrastText }}</td><td> {{ networkingcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Configuration</td><td> {{ configurationcontrastText }}</td><td> {{ configurationcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Advanced</td><td> {{ advancedcontrastText }}</td><td> {{ advancedcontrastBrightness }}</td> </tr>
|
||||
<tr><td>Help</td><td> {{ helpcontrastText }}</td><td> {{ helpcontrastBrightness }}</td> </tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-group" id="accordion">
|
||||
<div class="col-md-9">
|
||||
<!-- Library panel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
|
||||
data-target="#collapseLibrary" class="text-muted">Themes</a></h5>
|
||||
</div>
|
||||
<div id="collapseLibrary" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<div class="input-group" ng-show="library">
|
||||
<input type="text" class="form-control" placeholder="Theme Name" name="themeName"
|
||||
ng-model="newThemeName">
|
||||
<span class="input-group-btn">
|
||||
<button ng-disabled="newThemeName == ''" class="btn btn-default" type="button" ng-click="createNewTheme()">Create New Theme</button>
|
||||
</span>
|
||||
</div>
|
||||
<hr ng-show="library"/>
|
||||
<div ng-show="themes.length > 0 && library == true">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" align="center">
|
||||
<thead>
|
||||
<th>Theme Name</th>
|
||||
<th>Location</th>
|
||||
<th>Activate</th>
|
||||
<th>Delete</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="theme in themes">
|
||||
<td><a href="javascript:;" ng-click="getThemeFields(theme)">
|
||||
<b>{{ theme.title.substring(0, theme.title.length - 4); }}</b></a></td>
|
||||
<td class="text-muted"><i>{{ theme.storage }}</i></td>
|
||||
<td><a href="javascript:;"
|
||||
ng-click="activateTheme(theme)">Activate</a>
|
||||
</td>
|
||||
<td><a href="javascript:;" data-toggle="modal"
|
||||
ng-click="deleteTheme(theme)"
|
||||
> Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-hide="themes.length > 0 || library == false">
|
||||
<p class="text-muted text-center">
|
||||
<i>No Themes in Library to Display.</i>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div ng-show="library == false">
|
||||
<button type="submit" class="btn btn-default btn-sm" ng-click="library = true">Back To
|
||||
Library
|
||||
</button>
|
||||
<hr />
|
||||
<h3>Theme Editor | {{ workshopTheme.themeName }}</h3>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" align="center">
|
||||
<thead>
|
||||
<th>CSS Editor</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<textarea class="form-control" rows="30" ng-model="workshopTheme.code"> </textarea>
|
||||
|
||||
<div class="modal-footer">
|
||||
<div style="padding-right:5em" >
|
||||
<button type="button" ng-click="saveThemeCode(workshopTheme)" class="btn btn-success pull-left"
|
||||
data-dismiss="modal">Save
|
||||
</button>
|
||||
</div>
|
||||
<div style="padding-left:5em" >
|
||||
<button type="button" ng-click="saveThemeCode(workshopTheme); activateTheme(workshopTheme)" class="btn btn-success pull-left"
|
||||
data-dismiss="modal" >Save and Activate
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default pull-right" data-dismiss="modal"
|
||||
ng-click="library = true">Cancel
|
||||
</button>
|
||||
</div>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
|
||||
data-target="#collapseImages" class="text-muted">Icons</a></h5>
|
||||
</div>
|
||||
<div id="collapseImages" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<hr style="height:1px;border:none;color:#333;background-color:#333;">
|
||||
<h3>Generic</h3>
|
||||
<hr style="height:1px;border:none;color:#333;background-color:#333;">
|
||||
<table class="table table-striped" align="center">
|
||||
<thead>
|
||||
<th>Type</th>
|
||||
<th>Image</th>
|
||||
<th>Light Theme</th>
|
||||
<th>Dark Theme</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Throbber</b>
|
||||
</td>
|
||||
<td>
|
||||
<img src="/img/throbber.gif"/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-switch"
|
||||
ng-hide="throbbercontrast == false"
|
||||
ng-style="switchOff"
|
||||
ng-model="throbbercontrast"
|
||||
ng-click="changeThrobber()">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-switch"
|
||||
ng-hide="throbbercontrast == true"
|
||||
ng-style="switchOn"
|
||||
ng-model="throbbercontrast"
|
||||
ng-click="changeThrobber()">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Logo</b>
|
||||
</td>
|
||||
<td>
|
||||
<img src="/img/logo.png" width="30" height="30" />
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-switch"
|
||||
ng-hide="logocontrast == false"
|
||||
ng-style="switchOff"
|
||||
ng-model="logocontrast"
|
||||
ng-click="changeLogo()">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-switch"
|
||||
ng-hide="logocontrast == true"
|
||||
ng-style="switchOn"
|
||||
ng-model="logocontrast"
|
||||
ng-click="changeLogo()">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Icon</b>
|
||||
</td>
|
||||
<td>
|
||||
<img src="/img/favicon.ico"/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-switch"
|
||||
ng-hide="faviconcontrast == false"
|
||||
ng-style="switchOff"
|
||||
ng-model="faviconcontrast"
|
||||
ng-click="changeFavicon()">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-switch"
|
||||
ng-hide="faviconcontrast == true"
|
||||
ng-style="switchOn"
|
||||
ng-model="faviconcontrast"
|
||||
ng-click="changeFavicon()">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr style="height:1px;border:none;color:#333;background-color:#333;">
|
||||
<h3>Modules</h3>
|
||||
<hr style="height:1px;border:none;color:#333;background-color:#333;">
|
||||
<table class="table table-striped" align="center">
|
||||
<thead>
|
||||
<th>Type</th>
|
||||
<th>Image</th>
|
||||
<th>Color</th>
|
||||
<th>Brightness</th>
|
||||
<th></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<b>ALL</b>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<select ng-model="allcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ allcontrastText }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select ng-model="allcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ allcontrastBrightness }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeAllIcons()">
|
||||
Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Dashboard</b>
|
||||
</td>
|
||||
<td>
|
||||
<img src="/modules/Dashboard/module_icon.svg" width="30" height="30" />
|
||||
</td>
|
||||
<td>
|
||||
<select ng-model="dashboardcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ dashboardcontrastText }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select ng-model="dashboardcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ dashboardcontrastBrightness }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeDashboard()">
|
||||
Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Recon</b></td>
|
||||
<td><img src="/modules/Recon/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="reconcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ reconcontrastText }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="reconcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ reconcontrastBrightness }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeRecon()">
|
||||
Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<td><b>Profiling</b></td>
|
||||
<td><img src="/modules/Profiling/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="profilingcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ profilingcontrastText }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="profilingcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
|
||||
ng-value="{{ profilingcontrastBrightness }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeProfiling()">
|
||||
Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<td><b>Clients</b></td>
|
||||
<td><img src="/modules/Clients/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="clientscontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ clientscontrastText }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="clientscontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ clientscontrastBrightness }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeClients()">
|
||||
Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Modules</b></td>
|
||||
<td><img src="/modules/ModuleManager/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="modulescontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ modulescontrastText }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="modulescontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ modulescontrastBrightness }}"
|
||||
>
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeModules()">
|
||||
Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Filters</b></td>
|
||||
<td><img src="/modules/Filters/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="filterscontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ filterscontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="filterscontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ filterscontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeFilters()">
|
||||
Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>PineAP</b></td>
|
||||
<td><img src="/modules/PineAP/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="pineapcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ pineapcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="pineapcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ pineapcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changePineap()">Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>Tracking</b></td>
|
||||
<td><img src="/modules/Tracking/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="trackingcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ trackingcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="trackingcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ trackingcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeTracking()">Apply</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Logging</b></td>
|
||||
<td><img src="/modules/Logging/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="loggingcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ loggingcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="loggingcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ loggingcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeLogging()">Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Reporting</b></td>
|
||||
<td><img src="/modules/Reporting/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="reportingcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ reportingcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="reportingcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ reportingcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeReporting()">Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Networking</b></td>
|
||||
<td><img src="/modules/Networking/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="networkingcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ networkingcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="networkingcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ networkingcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeNetworking()">Apply</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Configuration</b></td>
|
||||
<td><img src="/modules/Configuration/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="configurationcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ configurationcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="configurationcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ configurationcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeConfiguration()">Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Advanced</b></td>
|
||||
<td><img src="/modules/Advanced/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="advancedcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ advancedcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="advancedcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ advancedcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeAdvanced()">Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Help</b></td>
|
||||
<td><img src="/modules/Help/module_icon.svg" width="30" height="30" /></td>
|
||||
<td><select ng-model="helpcontrastText"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in colors"
|
||||
ng-value="{{ helpcontrastText }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><select ng-model="helpcontrastBrightness"
|
||||
ng-style="selectOptions"
|
||||
ng-options="x for x in brightness"
|
||||
ng-value="{{ helpcontrastBrightness }}">
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="btn btn-default"
|
||||
type="button"
|
||||
ng-click="changeHelp()">Apply
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contribution Pannel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
|
||||
data-target="#collapseContribution" class="text-muted">How To</a></h5>
|
||||
</div>
|
||||
<div id="collapseContribution" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li><b>Share your new theme</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Navigate to the wifi pineapple modules repository</li>
|
||||
<li class="text-muted">Add your theme .css file in the css directory of this module</li>
|
||||
<li class="text-muted">Create a new pull request</li>
|
||||
<li class="text-muted">Update the version number</li>
|
||||
<li class="text-muted">Update the module version in module.info</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>Fix Images appearing broken/unable to be loaded</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Refresh the page</li>
|
||||
<li class="text-muted">If the problem persists, see "Submit a Bug"</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>Fix a messy looking page after a save/refresh</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Reselect 'Activate' beside your theme</li>
|
||||
<li class="text-muted">Refresh the page</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>Select the proper Image type</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Beside each Image type are two options "Light" and "Dark"</li>
|
||||
<li class="text-muted">"Dark" images are intended for dark backgrounds </li>
|
||||
<li class="text-muted">"Light" images are intended for light backgrounds </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>Use a theme once without a module</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Navigate to https://github.com/kbeflo/pineapple-themes</li>
|
||||
<li class="text-muted">Select a theme and run the install.sh script</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>Submit a Bug</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Navigate to https://github.com/hak5/wifipineapple-modules/issues</li>
|
||||
<li class="text-muted">Select the "New Issue" button </li>
|
||||
<li class="text-muted">Tag @trashbo4t in your issue description </li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
|
||||
data-target="#collapseTips" class="text-muted">Community Tips</a></h5>
|
||||
</div>
|
||||
<div id="collapseTips" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li><b>Creating a New Theme</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">
|
||||
The set of .css files bundled with the Themes module are already configured to handle
|
||||
undefined colors from the standard bootstrap .css file in the default settings.
|
||||
</li>
|
||||
<li class="text-muted">
|
||||
A reccommended method to ensure larger coverage is to create a new .css file with the theme creator
|
||||
then copy another .css files code.
|
||||
</li>
|
||||
<li class="text-muted">
|
||||
Once you copied the code do a search and replace for the colors of your choosing!
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>Working with .css files in a browser</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Modyfing a .css file with active updating is possible in modern browsers.</li>
|
||||
<li class="text-muted">Select 'ctrl'+'shift'+'I', then select the sourses tab.</li>
|
||||
<li class="text-muted">Select the 'css' folder, then the main.css file</li>
|
||||
<li class="text-muted">Modify the main.css file until you like the appearance of the page.</li>
|
||||
<li class="text-muted">From there select all of the code ('ctrl'+'a') and paste it into your theme files CSS Editor box</li>
|
||||
<li class="text-muted">Then select "Save" and "Activate"</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><b>Dark Theme vs Light Theme Icons</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">If your background is dark, its best to choose a "Dark Theme" icon.</li>
|
||||
<li class="text-muted">Overlooked transparency pixels will be harder to see this way!</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Change Log Pannel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
|
||||
data-target="#collapseChangelog" class="text-muted">Themes Change Log</a></h5>
|
||||
</div>
|
||||
<div id="collapseChangelog" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li><b>1.0</b></li>
|
||||
<ul>
|
||||
<li class="text-muted">Pending release of 1.0</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="loadingModal" class="modal fade" role="dialog" >
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">Loading</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="panel-title"><img src="/img/throbber.gif" ng-show="throbber"/>
|
||||
<p><b>{{ working }}</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
10
Themes/module.info
Normal file
10
Themes/module.info
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"author": "trashbo4t",
|
||||
"description": "Create, download, and share custom themes.",
|
||||
"devices": [
|
||||
"nano",
|
||||
"tetra"
|
||||
],
|
||||
"title": "Themes",
|
||||
"version": "1.0"
|
||||
}
|
||||
52
Themes/module_icon.svg
Normal file
52
Themes/module_icon.svg
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="370.589px" height="370.589px" viewBox="0 0 370.589 370.589" style="enable-background:new 0 0 370.589 370.589;"
|
||||
xml:space="preserve" fill="#808080">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M5.806,224.753c-7.741,7.741-7.741,20.291,0.002,28.034l10.114,10.114l24.18-9.46L30.99,277.97l50.811,50.812
|
||||
l39.014-22.66l-19.858,41.815l16.843,16.844c7.743,7.743,20.293,7.743,28.034,0.002l91.812-91.812L97.618,132.941L5.806,224.753z"
|
||||
/>
|
||||
<path d="M358.83,11.841l-0.082-0.083c-9.66-9.66-21.981-13.478-35.631-11.043c-27.59,4.924-56.519,34.861-77.384,80.087
|
||||
c-5.788,12.546-13.997,19.607-25.101,21.588c-21.311,3.803-48.293-11.741-64.344-27.792c-3.362-3.362-8.814-3.361-12.176,0.001
|
||||
l-16.685,16.686l24.651,24.651c3.202,3.202,3.202,8.392,0,11.594c-3.202,3.202-8.393,3.202-11.594,0l-24.651-24.651l-6.178,6.178
|
||||
c-3.364,3.364-3.364,8.815-0.002,12.178l139.703,139.703c3.361,3.361,8.812,3.36,12.177-0.002l34.458-34.458
|
||||
c3.361-3.362,3.362-8.814,0.001-12.177c-16.051-16.051-31.595-43.034-27.792-64.344c1.98-11.103,9.042-19.312,21.588-25.1
|
||||
c45.226-20.865,75.163-49.793,80.087-77.383C372.309,33.822,368.49,21.501,358.83,11.841z M343.056,48.746
|
||||
c-5.857,5.857-15.354,5.857-21.213,0c-5.856-5.858-5.856-15.355,0-21.213c5.858-5.858,15.355-5.858,21.213,0
|
||||
C348.914,33.391,348.914,42.888,343.056,48.746z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "ettercap",
|
||||
"version": "1.4"
|
||||
"version": "1.5"
|
||||
}
|
||||
@ -14,13 +14,13 @@ if [ "$1" = "install" ]; then
|
||||
if [ "$2" = "internal" ]; then
|
||||
opkg install ettercap
|
||||
|
||||
sed -i "/redir_command_on = \"iptables/ s/# *//" /etc/ettercap/etter.conf
|
||||
sed -i "/redir_command_off = \"iptables/ s/# *//" /etc/ettercap/etter.conf
|
||||
sed -i "/redir_command_on = \"iptables/ s/# *//" /etc/ettercap/etter.conf
|
||||
sed -i "/redir_command_off = \"iptables/ s/# *//" /etc/ettercap/etter.conf
|
||||
|
||||
sed -i 's/^\(ec_uid = \).*/\10/' /etc/ettercap/etter.conf
|
||||
sed -i 's/^\(ec_gid = \).*/\10/' /etc/ettercap/etter.conf
|
||||
sed -i 's/^\(ec_uid = \).*/\10/' /etc/ettercap/etter.conf
|
||||
sed -i 's/^\(ec_gid = \).*/\10/' /etc/ettercap/etter.conf
|
||||
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
elif [ "$2" = "sd" ]; then
|
||||
opkg install ettercap --dest sd
|
||||
@ -34,6 +34,10 @@ if [ "$1" = "install" ]; then
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/lib/libpcap.so ] && [ -f /usr/lib/libpcap.so.1.3 ]; then
|
||||
ln -s /usr/lib/libpcap.so /usr/lib/libpcap.so.1.3
|
||||
fi
|
||||
|
||||
touch /etc/config/ettercap
|
||||
echo "config ettercap 'module'" > /etc/config/ettercap
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "ngrep",
|
||||
"version": "1.4"
|
||||
"version": "1.5"
|
||||
}
|
||||
@ -12,12 +12,16 @@ touch /tmp/ngrep.progress
|
||||
|
||||
if [ "$1" = "install" ]; then
|
||||
if [ "$2" = "internal" ]; then
|
||||
opkg update
|
||||
opkg update
|
||||
opkg install ngrep
|
||||
elif [ "$2" = "sd" ]; then
|
||||
opkg update
|
||||
opkg install ngrep --dest sd
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/lib/libpcap.so ] && [ -f /usr/lib/libpcap.so.1.3 ]; then
|
||||
ln -s /usr/lib/libpcap.so /usr/lib/libpcap.so.1.3
|
||||
fi
|
||||
|
||||
touch /etc/config/ngrep
|
||||
echo "config ngrep 'module'" > /etc/config/ngrep
|
||||
|
||||
@ -7,10 +7,10 @@ class nmap extends Module
|
||||
public function route()
|
||||
{
|
||||
switch ($this->request->action) {
|
||||
case 'refreshInfo':
|
||||
$this->refreshInfo();
|
||||
break;
|
||||
case 'refreshOutput':
|
||||
case 'refreshInfo':
|
||||
$this->refreshInfo();
|
||||
break;
|
||||
case 'refreshOutput':
|
||||
$this->refreshOutput();
|
||||
break;
|
||||
case 'refreshStatus':
|
||||
@ -37,33 +37,30 @@ class nmap extends Module
|
||||
case 'deleteHistory':
|
||||
$this->deleteHistory();
|
||||
break;
|
||||
case 'downloadHistory':
|
||||
$this->downloadHistory();
|
||||
break;
|
||||
case 'downloadHistory':
|
||||
$this->downloadHistory();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkDependency($dependencyName)
|
||||
{
|
||||
return ((exec("which {$dependencyName}") == '' ? false : true) && ($this->uciGet("nmap.module.installed")));
|
||||
}
|
||||
protected function checkDependency($dependencyName)
|
||||
{
|
||||
return ((exec("which {$dependencyName}") == '' ? false : true) && ($this->uciGet("nmap.module.installed")));
|
||||
}
|
||||
|
||||
protected function getDevice()
|
||||
{
|
||||
return trim(exec("cat /proc/cpuinfo | grep machine | awk -F: '{print $2}'"));
|
||||
}
|
||||
protected function getDevice()
|
||||
{
|
||||
return trim(exec("cat /proc/cpuinfo | grep machine | awk -F: '{print $2}'"));
|
||||
}
|
||||
|
||||
protected function refreshInfo()
|
||||
{
|
||||
$moduleInfo = @json_decode(file_get_contents("/pineapple/modules/nmap/module.info"));
|
||||
$this->response = array('title' => $moduleInfo->title, 'version' => $moduleInfo->version);
|
||||
}
|
||||
protected function refreshInfo()
|
||||
{
|
||||
$moduleInfo = @json_decode(file_get_contents("/pineapple/modules/nmap/module.info"));
|
||||
$this->response = array('title' => $moduleInfo->title, 'version' => $moduleInfo->version);
|
||||
}
|
||||
|
||||
private function handleDependencies()
|
||||
{
|
||||
if (!file_exists("/usr/lib/libpcap.so.1.3") && file_exists("/usr/lib/libpcap.so")) {
|
||||
symlink("/usr/lib/libpcap.so", "/usr/lib/libpcap.so.1.3");
|
||||
}
|
||||
if(!$this->checkDependency("nmap"))
|
||||
{
|
||||
$this->execBackground("/pineapple/modules/nmap/scripts/dependencies.sh install ".$this->request->destination);
|
||||
@ -88,17 +85,17 @@ class nmap extends Module
|
||||
}
|
||||
}
|
||||
|
||||
private function scanStatus()
|
||||
{
|
||||
if (!$this->checkRunning("nmap"))
|
||||
{
|
||||
$this->response = array('success' => true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->response = array('success' => false);
|
||||
}
|
||||
}
|
||||
private function scanStatus()
|
||||
{
|
||||
if (!$this->checkRunning("nmap"))
|
||||
{
|
||||
$this->response = array('success' => true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->response = array('success' => false);
|
||||
}
|
||||
}
|
||||
|
||||
private function togglenmap()
|
||||
{
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "nmap",
|
||||
"version": "1.5"
|
||||
"version": "1.6"
|
||||
}
|
||||
@ -12,12 +12,16 @@ touch /tmp/nmap.progress
|
||||
|
||||
if [ "$1" = "install" ]; then
|
||||
if [ "$2" = "internal" ]; then
|
||||
opkg update
|
||||
opkg update
|
||||
opkg install nmap
|
||||
elif [ "$2" = "sd" ]; then
|
||||
opkg update
|
||||
opkg install nmap --dest sd
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/lib/libpcap.so ] && [ -f /usr/lib/libpcap.so.1.3 ]; then
|
||||
ln -s /usr/lib/libpcap.so /usr/lib/libpcap.so.1.3
|
||||
fi
|
||||
|
||||
touch /etc/config/nmap
|
||||
echo "config nmap 'module'" > /etc/config/nmap
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "p0f",
|
||||
"version": "1.0"
|
||||
"version": "1.1"
|
||||
}
|
||||
@ -18,6 +18,10 @@ if [ "$1" = "install" ]; then
|
||||
opkg update
|
||||
opkg install p0f --dest sd
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/lib/libpcap.so ] && [ -f /usr/lib/libpcap.so.1.3 ]; then
|
||||
ln -s /usr/lib/libpcap.so /usr/lib/libpcap.so.1.3
|
||||
fi
|
||||
|
||||
touch /etc/config/p0f
|
||||
echo "config p0f 'module'" > /etc/config/p0f
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "tcpdump",
|
||||
"version": "1.4"
|
||||
"version": "1.5"
|
||||
}
|
||||
@ -12,12 +12,16 @@ touch /tmp/tcpdump.progress
|
||||
|
||||
if [ "$1" = "install" ]; then
|
||||
if [ "$2" = "internal" ]; then
|
||||
opkg update
|
||||
opkg update
|
||||
opkg install tcpdump
|
||||
elif [ "$2" = "sd" ]; then
|
||||
opkg update
|
||||
opkg install tcpdump --dest sd
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/lib/libpcap.so ] && [ -f /usr/lib/libpcap.so.1.3 ]; then
|
||||
ln -s /usr/lib/libpcap.so /usr/lib/libpcap.so.1.3
|
||||
fi
|
||||
|
||||
touch /etc/config/tcpdump
|
||||
echo "config tcpdump 'module'" > /etc/config/tcpdump
|
||||
|
||||
302
tor/api/module.php
Executable file
302
tor/api/module.php
Executable file
@ -0,0 +1,302 @@
|
||||
<?php namespace pineapple;
|
||||
|
||||
class Tor extends Module
|
||||
{
|
||||
private $progressFile = '/tmp/tor.progress';
|
||||
private $moduleConfigFile = '/etc/config/tor/config';
|
||||
private $dependenciesScriptFile = '/pineapple/modules/tor/scripts/dependencies.sh';
|
||||
|
||||
// Error Constants
|
||||
const INVALID_NAME = 'Invalid name';
|
||||
const INVALID_PORT = 'Invalid port';
|
||||
const INVALID_DESTINATION = 'Invalid destination';
|
||||
|
||||
// Display Constants
|
||||
const DANGER = 'danger';
|
||||
const WARNING = 'warning';
|
||||
const SUCCESS = 'success';
|
||||
|
||||
public function route()
|
||||
{
|
||||
switch ($this->request->action) {
|
||||
case 'refreshInfo':
|
||||
$this->refreshInfo();
|
||||
break;
|
||||
case 'refreshStatus':
|
||||
$this->refreshStatus();
|
||||
break;
|
||||
case 'handleDependencies':
|
||||
$this->handleDependencies();
|
||||
break;
|
||||
case 'handleDependenciesStatus':
|
||||
$this->handleDependenciesStatus();
|
||||
break;
|
||||
case 'toggletor':
|
||||
$this->toggletor();
|
||||
break;
|
||||
case 'refreshHiddenServices':
|
||||
$this->refreshHiddenServices();
|
||||
break;
|
||||
case 'addHiddenService':
|
||||
$this->addHiddenService();
|
||||
break;
|
||||
case 'removeHiddenService':
|
||||
$this->removeHiddenService();
|
||||
break;
|
||||
case 'addServiceForward':
|
||||
$this->addServiceForward();
|
||||
break;
|
||||
case 'removeServiceForward':
|
||||
$this->removeServiceForward();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function success($value)
|
||||
{
|
||||
$this->response = array('success' => $value);
|
||||
}
|
||||
|
||||
private function error($message)
|
||||
{
|
||||
$this->response = array('error' => $message);
|
||||
}
|
||||
|
||||
private function isValidName($name)
|
||||
{
|
||||
return preg_match('/^[a-zA-Z0-9_]+$/', $name) === 1;
|
||||
}
|
||||
|
||||
private function isValidPort($port)
|
||||
{
|
||||
return preg_match('/^[0-9]+$/', $port) === 1;
|
||||
}
|
||||
|
||||
private function isValidRedirectTo($redirect_to)
|
||||
{
|
||||
return preg_match('/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+$/', $redirect_to) === 1;
|
||||
}
|
||||
|
||||
protected function checkDependency($dependencyName)
|
||||
{
|
||||
return (exec("which {$dependencyName}") != '' && !file_exists($this->progressFile));
|
||||
}
|
||||
|
||||
protected function refreshInfo()
|
||||
{
|
||||
$moduleInfo = @json_decode(file_get_contents("/pineapple/modules/tor/module.info"));
|
||||
$this->response = array('title' => $moduleInfo->title, 'version' => $moduleInfo->version);
|
||||
}
|
||||
|
||||
protected function checkRunning($processName)
|
||||
{
|
||||
return (exec("pgrep '{$processName}$'") != '');
|
||||
}
|
||||
|
||||
private function handleDependencies()
|
||||
{
|
||||
$destination = "";
|
||||
if (isset($this->request->destination)) {
|
||||
$destination = $this->request->destination;
|
||||
if ($destination != "internal" && $destination != "sd") {
|
||||
$this->error(self::INVALID_DESTINATION);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->checkDependency("tor")) {
|
||||
$this->execBackground($this->dependenciesScriptFile . " install " . $destination);
|
||||
} else {
|
||||
$this->execBackground($this->dependenciesScriptFile . " remove");
|
||||
}
|
||||
$this->success(true);
|
||||
}
|
||||
|
||||
private function handleDependenciesStatus()
|
||||
{
|
||||
if (file_exists($this->progressFile)) {
|
||||
$this->success(false);
|
||||
} else {
|
||||
$this->success(true);
|
||||
}
|
||||
}
|
||||
|
||||
private function toggletor()
|
||||
{
|
||||
if ($this->checkRunning("tor")) {
|
||||
exec("/etc/init.d/tor stop");
|
||||
} else {
|
||||
exec("/etc/init.d/tor start");
|
||||
}
|
||||
}
|
||||
|
||||
private function refreshStatus()
|
||||
{
|
||||
|
||||
$device = $this->getDevice();
|
||||
$sdAvailable = $this->isSDAvailable();
|
||||
$installed = false;
|
||||
$install = "Not Installed";
|
||||
$processing = false;
|
||||
|
||||
if (file_exists($this->progressFile)) {
|
||||
// TOR Is installing, please wait.
|
||||
$install = "Installing...";
|
||||
$installLabel = self::WARNING;
|
||||
$processing = true;
|
||||
|
||||
$status = "Not running";
|
||||
$statusLabel = self::DANGER;
|
||||
} elseif (!$this->checkDependency("tor")) {
|
||||
// TOR is not installed, please install.
|
||||
$installLabel = self::DANGER;
|
||||
|
||||
$status = "Start";
|
||||
$statusLabel = self::DANGER;
|
||||
} else {
|
||||
// TOR is installed, please configure.
|
||||
$installed = true;
|
||||
$install = "Installed";
|
||||
$installLabel = self::SUCCESS;
|
||||
|
||||
if ($this->checkRunning("tor")) {
|
||||
$status = "Started";
|
||||
$statusLabel = self::SUCCESS;
|
||||
} else {
|
||||
$status = "Stopped";
|
||||
$statusLabel = self::DANGER;
|
||||
}
|
||||
}
|
||||
|
||||
$this->response = array("device" => $device,
|
||||
"sdAvailable" => $sdAvailable,
|
||||
"status" => $status,
|
||||
"statusLabel" => $statusLabel,
|
||||
"installed" => $installed,
|
||||
"install" => $install,
|
||||
"installLabel" => $installLabel,
|
||||
"processing" => $processing);
|
||||
}
|
||||
|
||||
private function generateConfig()
|
||||
{
|
||||
$output = file_get_contents("/etc/config/tor/torrc");
|
||||
$output .= "\n";
|
||||
$hiddenServices = @json_decode(file_get_contents($this->moduleConfigFile));
|
||||
foreach ($hiddenServices as $hiddenService) {
|
||||
$output .= "HiddenServiceDir /etc/config/tor/services/{$hiddenService->name}\n";
|
||||
$forwards = $hiddenService->forwards;
|
||||
foreach ($forwards as $forward) {
|
||||
$output .= "HiddenServicePort {$forward->port} {$forward->redirect_to}\n";
|
||||
}
|
||||
}
|
||||
file_put_contents("/etc/tor/torrc", $output);
|
||||
}
|
||||
|
||||
private function reloadTor()
|
||||
{
|
||||
$this->generateConfig();
|
||||
//Sending SIGHUP to tor process cause config reload.
|
||||
exec("pkill -sighup tor$");
|
||||
}
|
||||
|
||||
private function refreshHiddenServices()
|
||||
{
|
||||
$hiddenServices = @json_decode(file_get_contents($this->moduleConfigFile));
|
||||
foreach ($hiddenServices as $hiddenService) {
|
||||
if (file_exists("/etc/config/tor/services/{$hiddenService->name}/hostname")) {
|
||||
$hostname = file_get_contents("/etc/config/tor/services/{$hiddenService->name}/hostname");
|
||||
$hiddenService->hostname = trim($hostname);
|
||||
}
|
||||
}
|
||||
$this->response = array("hiddenServices" => $hiddenServices);
|
||||
}
|
||||
|
||||
private function addHiddenService()
|
||||
{
|
||||
$name = $this->request->name;
|
||||
if (!$this->isValidName($name)) {
|
||||
$this->error(self::INVALID_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
$hiddenService = array("name" => $name, "forwards" => array() );
|
||||
$hiddenServices = array();
|
||||
if (file_exists($this->moduleConfigFile)) {
|
||||
$hiddenServices = @json_decode(file_get_contents($this->moduleConfigFile));
|
||||
}
|
||||
array_push($hiddenServices, $hiddenService);
|
||||
file_put_contents($this->moduleConfigFile, @json_encode($hiddenServices, JSON_PRETTY_PRINT));
|
||||
$this->reloadTor();
|
||||
}
|
||||
|
||||
private function removeHiddenService()
|
||||
{
|
||||
$hiddenServices = @json_decode(file_get_contents($this->moduleConfigFile));
|
||||
foreach ($hiddenServices as $key => $hiddenService) {
|
||||
if ($hiddenService->name == $this->request->name) {
|
||||
unset($hiddenServices[$key]);
|
||||
}
|
||||
}
|
||||
file_put_contents($this->moduleConfigFile, @json_encode($hiddenServices, JSON_PRETTY_PRINT));
|
||||
$this->reloadTor();
|
||||
}
|
||||
|
||||
private function addServiceForward()
|
||||
{
|
||||
$name = $this->request->name;
|
||||
$port = $this->request->port;
|
||||
$redirect_to = $this->request->redirect_to;
|
||||
|
||||
if (!$this->isValidName($name)) {
|
||||
$this->error(self::INVALID_NAME);
|
||||
return;
|
||||
}
|
||||
if (!$this->isValidPort($port)) {
|
||||
$this->error(self::INVALID_PORT);
|
||||
return;
|
||||
}
|
||||
if (!$this->isValidRedirectTo($redirect_to)) {
|
||||
$this->error(self::INVALID_DESTINATION);
|
||||
return;
|
||||
}
|
||||
|
||||
$hiddenServices = @json_decode(file_get_contents($this->moduleConfigFile));
|
||||
foreach ($hiddenServices as $key => $hiddenService) {
|
||||
if ($hiddenService->name == $name) {
|
||||
$forwards = $hiddenService->forwards;
|
||||
$forward = array("port" => $port, "redirect_to" => $redirect_to);
|
||||
array_push($forwards, $forward);
|
||||
$hiddenServices[$key]->forwards = $forwards;
|
||||
}
|
||||
}
|
||||
file_put_contents($this->moduleConfigFile, @json_encode($hiddenServices, JSON_PRETTY_PRINT));
|
||||
|
||||
$this->reloadTor();
|
||||
}
|
||||
|
||||
private function removeServiceForward()
|
||||
{
|
||||
$name = $this->request->name;
|
||||
$port = $this->request->port;
|
||||
$redirect_to = $this->request->redirect_to;
|
||||
|
||||
$hiddenServices = @json_decode(file_get_contents($this->moduleConfigFile));
|
||||
foreach ($hiddenServices as $hiddenService) {
|
||||
if ($hiddenService->name == $name) {
|
||||
$forwards = $hiddenService->forwards;
|
||||
foreach ($forwards as $key => $forward) {
|
||||
if ($forward->port == $port && $forward->redirect_to == $redirect_to) {
|
||||
unset($forwards[$key]);
|
||||
}
|
||||
}
|
||||
$hiddenService->forwards = $forwards;
|
||||
}
|
||||
}
|
||||
file_put_contents($this->moduleConfigFile, @json_encode($hiddenServices, JSON_PRETTY_PRINT));
|
||||
|
||||
$this->reloadTor();
|
||||
}
|
||||
}
|
||||
193
tor/files/torrc
Normal file
193
tor/files/torrc
Normal file
@ -0,0 +1,193 @@
|
||||
## Configuration file for a typical Tor user
|
||||
## Last updated 9 October 2013 for Tor 0.2.5.2-alpha.
|
||||
## (may or may not work for much older or much newer versions of Tor.)
|
||||
##
|
||||
## Lines that begin with "## " try to explain what's going on. Lines
|
||||
## that begin with just "#" are disabled commands: you can enable them
|
||||
## by removing the "#" symbol.
|
||||
##
|
||||
## See 'man tor', or https://www.torproject.org/docs/tor-manual.html,
|
||||
## for more options you can use in this file.
|
||||
##
|
||||
## Tor will look for this file in various places based on your platform:
|
||||
## https://www.torproject.org/docs/faq#torrc
|
||||
|
||||
## Tor opens a socks proxy on port 9050 by default -- even if you don't
|
||||
## configure one below. Set "SocksPort 0" if you plan to run Tor only
|
||||
## as a relay, and not make any local application connections yourself.
|
||||
#SocksPort 9050 # Default: Bind to localhost:9050 for local connections.
|
||||
#SocksPort 192.168.0.1:9100 # Bind to this address:port too.
|
||||
|
||||
## Entry policies to allow/deny SOCKS requests based on IP address.
|
||||
## First entry that matches wins. If no SocksPolicy is set, we accept
|
||||
## all (and only) requests that reach a SocksPort. Untrusted users who
|
||||
## can access your SocksPort may be able to learn about the connections
|
||||
## you make.
|
||||
#SocksPolicy accept 192.168.0.0/16
|
||||
#SocksPolicy reject *
|
||||
|
||||
## Logs go to stdout at level "notice" unless redirected by something
|
||||
## else, like one of the below lines. You can have as many Log lines as
|
||||
## you want.
|
||||
##
|
||||
## We advise using "notice" in most cases, since anything more verbose
|
||||
## may provide sensitive information to an attacker who obtains the logs.
|
||||
##
|
||||
## Send all messages of level 'notice' or higher to /var/log/tor/notices.log
|
||||
#Log notice file /var/log/tor/notices.log
|
||||
## Send every possible message to /var/log/tor/debug.log
|
||||
#Log debug file /var/log/tor/debug.log
|
||||
## Use the system log instead of Tor's logfiles
|
||||
#Log notice syslog
|
||||
## To send all messages to stderr:
|
||||
#Log debug stderr
|
||||
|
||||
## Uncomment this to start the process in the background... or use
|
||||
## --runasdaemon 1 on the command line. This is ignored on Windows;
|
||||
## see the FAQ entry if you want Tor to run as an NT service.
|
||||
RunAsDaemon 1
|
||||
|
||||
## The directory for keeping all the keys/etc. By default, we store
|
||||
## things in $HOME/.tor on Unix, and in Application Data\tor on Windows.
|
||||
DataDirectory /var/lib/tor
|
||||
|
||||
## The port on which Tor will listen for local connections from Tor
|
||||
## controller applications, as documented in control-spec.txt.
|
||||
#ControlPort 9051
|
||||
## If you enable the controlport, be sure to enable one of these
|
||||
## authentication methods, to prevent attackers from accessing it.
|
||||
#HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C
|
||||
#CookieAuthentication 1
|
||||
|
||||
############### This section is just for location-hidden services ###
|
||||
|
||||
## Once you have configured a hidden service, you can look at the
|
||||
## contents of the file ".../hidden_service/hostname" for the address
|
||||
## to tell people.
|
||||
##
|
||||
## HiddenServicePort x y:z says to redirect requests on port x to the
|
||||
## address y:z.
|
||||
|
||||
#HiddenServiceDir /var/lib/tor/hidden_service/
|
||||
#HiddenServicePort 80 127.0.0.1:80
|
||||
|
||||
#HiddenServiceDir /var/lib/tor/other_hidden_service/
|
||||
#HiddenServicePort 80 127.0.0.1:80
|
||||
#HiddenServicePort 22 127.0.0.1:22
|
||||
|
||||
################ This section is just for relays #####################
|
||||
#
|
||||
## See https://www.torproject.org/docs/tor-doc-relay for details.
|
||||
|
||||
## Required: what port to advertise for incoming Tor connections.
|
||||
#ORPort 9001
|
||||
## If you want to listen on a port other than the one advertised in
|
||||
## ORPort (e.g. to advertise 443 but bind to 9090), you can do it as
|
||||
## follows. You'll need to do ipchains or other port forwarding
|
||||
## yourself to make this work.
|
||||
#ORPort 443 NoListen
|
||||
#ORPort 127.0.0.1:9090 NoAdvertise
|
||||
|
||||
## The IP address or full DNS name for incoming connections to your
|
||||
## relay. Leave commented out and Tor will guess.
|
||||
#Address noname.example.com
|
||||
|
||||
## If you have multiple network interfaces, you can specify one for
|
||||
## outgoing traffic to use.
|
||||
# OutboundBindAddress 10.0.0.5
|
||||
|
||||
## A handle for your relay, so people don't have to refer to it by key.
|
||||
#Nickname ididnteditheconfig
|
||||
|
||||
## Define these to limit how much relayed traffic you will allow. Your
|
||||
## own traffic is still unthrottled. Note that RelayBandwidthRate must
|
||||
## be at least 20 KB.
|
||||
## Note that units for these config options are bytes per second, not bits
|
||||
## per second, and that prefixes are binary prefixes, i.e. 2^10, 2^20, etc.
|
||||
#RelayBandwidthRate 100 KB # Throttle traffic to 100KB/s (800Kbps)
|
||||
#RelayBandwidthBurst 200 KB # But allow bursts up to 200KB/s (1600Kbps)
|
||||
|
||||
## Use these to restrict the maximum traffic per day, week, or month.
|
||||
## Note that this threshold applies separately to sent and received bytes,
|
||||
## not to their sum: setting "4 GB" may allow up to 8 GB total before
|
||||
## hibernating.
|
||||
##
|
||||
## Set a maximum of 4 gigabytes each way per period.
|
||||
#AccountingMax 4 GB
|
||||
## Each period starts daily at midnight (AccountingMax is per day)
|
||||
#AccountingStart day 00:00
|
||||
## Each period starts on the 3rd of the month at 15:00 (AccountingMax
|
||||
## is per month)
|
||||
#AccountingStart month 3 15:00
|
||||
|
||||
## Administrative contact information for this relay or bridge. This line
|
||||
## can be used to contact you if your relay or bridge is misconfigured or
|
||||
## something else goes wrong. Note that we archive and publish all
|
||||
## descriptors containing these lines and that Google indexes them, so
|
||||
## spammers might also collect them. You may want to obscure the fact that
|
||||
## it's an email address and/or generate a new address for this purpose.
|
||||
#ContactInfo Random Person <nobody AT example dot com>
|
||||
## You might also include your PGP or GPG fingerprint if you have one:
|
||||
#ContactInfo 0xFFFFFFFF Random Person <nobody AT example dot com>
|
||||
|
||||
## Uncomment this to mirror directory information for others. Please do
|
||||
## if you have enough bandwidth.
|
||||
#DirPort 9030 # what port to advertise for directory connections
|
||||
## If you want to listen on a port other than the one advertised in
|
||||
## DirPort (e.g. to advertise 80 but bind to 9091), you can do it as
|
||||
## follows. below too. You'll need to do ipchains or other port
|
||||
## forwarding yourself to make this work.
|
||||
#DirPort 80 NoListen
|
||||
#DirPort 127.0.0.1:9091 NoAdvertise
|
||||
## Uncomment to return an arbitrary blob of html on your DirPort. Now you
|
||||
## can explain what Tor is if anybody wonders why your IP address is
|
||||
## contacting them. See contrib/tor-exit-notice.html in Tor's source
|
||||
## distribution for a sample.
|
||||
#DirPortFrontPage /etc/tor/tor-exit-notice.html
|
||||
|
||||
## Uncomment this if you run more than one Tor relay, and add the identity
|
||||
## key fingerprint of each Tor relay you control, even if they're on
|
||||
## different networks. You declare it here so Tor clients can avoid
|
||||
## using more than one of your relays in a single circuit. See
|
||||
## https://www.torproject.org/docs/faq#MultipleRelays
|
||||
## However, you should never include a bridge's fingerprint here, as it would
|
||||
## break its concealability and potentionally reveal its IP/TCP address.
|
||||
#MyFamily $keyid,$keyid,...
|
||||
|
||||
## A comma-separated list of exit policies. They're considered first
|
||||
## to last, and the first match wins. If you want to _replace_
|
||||
## the default exit policy, end this with either a reject *:* or an
|
||||
## accept *:*. Otherwise, you're _augmenting_ (prepending to) the
|
||||
## default exit policy. Leave commented to just use the default, which is
|
||||
## described in the man page or at
|
||||
## https://www.torproject.org/documentation.html
|
||||
##
|
||||
## Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
|
||||
## for issues you might encounter if you use the default exit policy.
|
||||
##
|
||||
## If certain IPs and ports are blocked externally, e.g. by your firewall,
|
||||
## you should update your exit policy to reflect this -- otherwise Tor
|
||||
## users will be told that those destinations are down.
|
||||
##
|
||||
## For security, by default Tor rejects connections to private (local)
|
||||
## networks, including to your public IP address. See the man page entry
|
||||
## for ExitPolicyRejectPrivate if you want to allow "exit enclaving".
|
||||
##
|
||||
#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more
|
||||
#ExitPolicy accept *:119 # accept nntp as well as default exit policy
|
||||
#ExitPolicy reject *:* # no exits allowed
|
||||
|
||||
## Bridge relays (or "bridges") are Tor relays that aren't listed in the
|
||||
## main directory. Since there is no complete public list of them, even an
|
||||
## ISP that filters connections to all the known Tor relays probably
|
||||
## won't be able to block all the bridges. Also, websites won't treat you
|
||||
## differently because they won't know you're running Tor. If you can
|
||||
## be a real relay, please do; but if not, be a bridge!
|
||||
#BridgeRelay 1
|
||||
## By default, Tor will advertise your bridge to users through various
|
||||
## mechanisms like https://bridges.torproject.org/. If you want to run
|
||||
## a private bridge, for example because you'll give out your bridge
|
||||
## address manually to your friends, uncomment this line:
|
||||
#PublishServerDescriptor 0
|
||||
|
||||
User tor
|
||||
156
tor/js/module.js
Executable file
156
tor/js/module.js
Executable file
@ -0,0 +1,156 @@
|
||||
registerController('tor_DependenciesController', ['$api', '$scope', '$rootScope', '$interval', '$timeout', function($api, $scope, $rootScope, $interval, $timeout) {
|
||||
$scope.status = "Loading...";
|
||||
$scope.statusLabel = "default";
|
||||
$scope.starting = false;
|
||||
|
||||
$scope.install = "Loading...";
|
||||
$scope.installLabel = "default";
|
||||
$scope.processing = false;
|
||||
|
||||
$scope.saveSettingsLabel = "default";
|
||||
|
||||
$scope.device = '';
|
||||
$scope.sdAvailable = false;
|
||||
|
||||
$rootScope.status = {
|
||||
installed : false
|
||||
};
|
||||
|
||||
$scope.refreshStatus = (function() {
|
||||
$api.request({
|
||||
module: "tor",
|
||||
action: "refreshStatus"
|
||||
}, function(response) {
|
||||
$scope.status = response.status;
|
||||
$scope.statusLabel = response.statusLabel;
|
||||
|
||||
$rootScope.status.installed = response.installed;
|
||||
$scope.device = response.device;
|
||||
$scope.sdAvailable = response.sdAvailable;
|
||||
if(response.processing) $scope.processing = true;
|
||||
$scope.install = response.install;
|
||||
$scope.installLabel = response.installLabel;
|
||||
})
|
||||
});
|
||||
|
||||
$scope.toggletor = (function() {
|
||||
if($scope.status != "Stop")
|
||||
$scope.status = "Starting...";
|
||||
else
|
||||
$scope.status = "Stopping...";
|
||||
|
||||
$scope.statusLabel = "warning";
|
||||
$scope.starting = true;
|
||||
|
||||
$rootScope.status.refreshOutput = false;
|
||||
$rootScope.status.refreshHistory = false;
|
||||
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'toggletor'
|
||||
}, function(response) {
|
||||
$timeout(function(){
|
||||
$scope.starting = false;
|
||||
$scope.refreshStatus();
|
||||
}, 2000);
|
||||
})
|
||||
});
|
||||
|
||||
$scope.handleDependencies = (function(param) {
|
||||
if(!$rootScope.status.installed)
|
||||
$scope.install = "Installing...";
|
||||
else
|
||||
$scope.install = "Removing...";
|
||||
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'handleDependencies',
|
||||
destination: param
|
||||
}, function(response){
|
||||
if (response.success === true) {
|
||||
$scope.installLabel = "warning";
|
||||
$scope.processing = true;
|
||||
|
||||
$scope.handleDependenciesInterval = $interval(function(){
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'handleDependenciesStatus'
|
||||
}, function(response) {
|
||||
if (response.success === true){
|
||||
$scope.processing = false;
|
||||
$interval.cancel($scope.handleDependenciesInterval);
|
||||
$scope.refreshStatus();
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
});
|
||||
$scope.refreshStatus();
|
||||
}]);
|
||||
|
||||
registerController('tor_ConfigurationController', ['$api', '$scope', '$rootScope', '$interval', '$timeout', function($api, $scope, $rootScope, $interval, $timeout) {
|
||||
|
||||
$scope.refreshHiddenServices = (function() {
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'refreshHiddenServices'
|
||||
}, function(response) {
|
||||
$scope.hiddenServices = response.hiddenServices;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.addHiddenService = (function() {
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'addHiddenService',
|
||||
name: $scope.name
|
||||
}, function(response){
|
||||
$scope.refreshHiddenServices();
|
||||
});
|
||||
});
|
||||
|
||||
$scope.removeHiddenService = (function(name) {
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'removeHiddenService',
|
||||
name: name
|
||||
}, function(response) {
|
||||
$scope.refreshHiddenServices();
|
||||
});
|
||||
});
|
||||
|
||||
$scope.addServiceForward = (function() {
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'addServiceForward',
|
||||
name: $scope.name,
|
||||
port: $scope.port,
|
||||
redirect_to: $scope.redirect_to
|
||||
}, function(response) {
|
||||
$scope.hiddenServicesLoad = '(reloading...)';
|
||||
$timeout(function() {
|
||||
$scope.hiddenServicesLoad = '';
|
||||
$scope.refreshHiddenServices();
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
$scope.removeServiceForward = (function(name, port, redirect_to) {
|
||||
$api.request({
|
||||
module: 'tor',
|
||||
action: 'removeServiceForward',
|
||||
name: name,
|
||||
port: port,
|
||||
redirect_to: redirect_to
|
||||
}, function(response) {
|
||||
$scope.hiddenServicesLoad = '(reloading...)';
|
||||
$timeout(function() {
|
||||
$scope.hiddenServicesLoad = '';
|
||||
$scope.refreshHiddenServices();
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
$scope.refreshHiddenServices();
|
||||
}]);
|
||||
158
tor/module.html
Executable file
158
tor/module.html
Executable file
@ -0,0 +1,158 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="panel panel-default" ng-controller="tor_DependenciesController">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Dependencies</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<td style="padding-bottom: .5em;" class="text-muted">Dependencies</td>
|
||||
<td ng-hide="$root.status.installed" style="text-align:right;padding-bottom: .5em;">
|
||||
<button type="button" style="width: 90px;" class="btn btn-{{installLabel}} btn-xs" data-toggle="modal" data-target="#dependenciesInstallModal" ng-disabled="processing">{{install}}</button>
|
||||
</td>
|
||||
<td ng-show="$root.status.installed" style="text-align:right;padding-bottom: .5em;">
|
||||
<button type="button" style="width: 90px;" class="btn btn-{{installLabel}} btn-xs" data-toggle="modal" data-target="#dependenciesRemoveModal" ng-disabled="processing">{{install}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="form-inline" ng-show="$root.status.installed">
|
||||
<td style="padding-bottom: .5em;" class="text-muted">tor</td>
|
||||
<td style="text-align:right;padding-bottom: .5em;">
|
||||
<button type="button" style="width: 90px;" class="btn btn-{{statusLabel}} btn-xs" ng-disabled="starting" ng-click="toggletor()">{{status}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="dependenciesInstallModal" tabindex="-1" role="dialog" aria-labelledby="dependenciesModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="dependenciesInstallModalLabel">Install dependencies</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
All required dependencies have to be installed first. This may take a few minutes.<br /><br />
|
||||
Please wait, do not leave or refresh this page. Once the install is complete, this page will refresh automatically.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-info" ng-click="handleDependencies('internal')" data-dismiss="modal">Internal</button>
|
||||
<button type="button" class="btn btn-info" ng-hide="device == 'tetra' || sdAvailable == false" ng-click="handleDependencies('sd')" data-dismiss="modal">SD Card</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="dependenciesRemoveModal" tabindex="-1" role="dialog" aria-labelledby="dependenciesModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="dependenciesRemoveModalLabel">Remove dependencies</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
All required dependencies will be removed. This may take a few minutes.<br /><br />
|
||||
Please wait, do not leave or refresh this page. Once the remove is complete, this page will refresh automatically.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" ng-click="handleDependencies()" data-dismiss="modal">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="panel panel-default" ng-controller="tor_ConfigurationController" ng-show="$root.status.installed">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Hidden Services {{ hiddenServicesLoad }}</h3>
|
||||
{{ config }}
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addHiddenService" ng-disabled="processing">Add Service</button>
|
||||
<button type="button" class="btn btn-info" ng-show="hiddenServices.length > 0" data-toggle="modal" data-target="#addServiceForward" ng-disabled="processing">Add Forward</button>
|
||||
<div ng-repeat="service in hiddenServices">
|
||||
<h4>
|
||||
<span>{{ service.name }}</span>
|
||||
<span ng-show="service.hostname">(<a href="http://{{service.hostname}}">{{service.hostname}}</a>)</span>
|
||||
<span>
|
||||
<button type="button" class="btn btn-danger btn-xs pull-right" data-toggle="modal" ng-click="removeHiddenService(service.name)" ng-disabled="processing">Remove Service</button>
|
||||
</span>
|
||||
</h4>
|
||||
<div>
|
||||
<table style="width: 100%">
|
||||
<th>Port</th>
|
||||
<th>Redirect to</th>
|
||||
<th></th>
|
||||
<tr ng-repeat="forward in service.forwards">
|
||||
<td>{{ forward.port }}</td>
|
||||
<td>{{ forward.redirect_to }}</td>
|
||||
<td style="text-align:right;padding-bottom: .5em;"><button type="button" class="btn btn-danger btn-xs" data-toggle="modal" data-target="#removeServiceForward" ng-click="removeServiceForward(service.name, forward.port, forward.redirect_to);" ng-disabled="processing" aria-label="Delete Forward">X</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="addHiddenService" tabindex="-1" role="dialog" aria-labelledby="addHiddenServiceLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="addHiddenServiceRemoveModalLabel">Add Hidden Service</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td style="padding-bottom: .5em;" class="text-muted">Directory:</td>
|
||||
<td><input type="text" class="form-control" placeholder="hidden_service" ng-model="name"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" ng-click="addHiddenService()" data-dismiss="modal">Add Service</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="addServiceForward" tabindex="-1" role="dialog" aria-labelledby="addServiceForwardLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="addServiceForwardRemoveModalLabel">Add Forward to Service</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>Service:</td>
|
||||
<td style="padding-bottom: .5em">
|
||||
<select ng-model="name">
|
||||
<option ng-repeat="service in hiddenServices">{{service.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-bottom: .5em;" class="text-muted">Port:</td>
|
||||
<td><input type="text" class="form-control" placeholder="80" ng-model="port"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-bottom: .5em;" class="text-muted">Redirect to:</td>
|
||||
<td><input type="text" class="form-control" placeholder="127.0.0.1:1471" ng-model="redirect_to"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" ng-click="addServiceForward()" data-dismiss="modal">Add Forward</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
7
tor/module.info
Executable file
7
tor/module.info
Executable file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"author":"catatonicprime",
|
||||
"description":"Connect device to tor network, manage hidden services, etc.",
|
||||
"devices": [ "nano", "tetra" ],
|
||||
"title":"tor",
|
||||
"version":"1.0"
|
||||
}
|
||||
29
tor/scripts/dependencies.sh
Executable file
29
tor/scripts/dependencies.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# author: catatonicprime
|
||||
# date: March 2018
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/sd/lib:/sd/usr/lib
|
||||
export PATH=$PATH:/sd/usr/bin:/sd/usr/sbin
|
||||
|
||||
touch /tmp/tor.progress
|
||||
|
||||
if [ "$1" = "install" ]; then
|
||||
opkg update
|
||||
if [ "$2" = "internal" ]; then
|
||||
opkg install tor-geoip tor
|
||||
elif [ "$2" = "sd" ]; then
|
||||
opkg install tor-geoip tor --dest sd
|
||||
fi
|
||||
mkdir -p /etc/config/tor/
|
||||
cp /pineapple/modules/tor/files/torrc /etc/config/tor
|
||||
mkdir -p /etc/config/tor/services
|
||||
chown tor:tor /etc/config/tor/services
|
||||
chown root:tor /etc/tor/torrc
|
||||
chmod g+r /etc/tor/torrc
|
||||
elif [ "$1" = "remove" ]; then
|
||||
opkg remove tor-geoip tor
|
||||
sed -i '/tor\/scripts\/autostart_tor.sh/d' /etc/rc.local
|
||||
rm -rf /etc/config/tor
|
||||
fi
|
||||
|
||||
rm /tmp/tor.progress
|
||||
@ -349,7 +349,7 @@ class wps extends Module
|
||||
|
||||
private function getMACInfo()
|
||||
{
|
||||
$content = file_get_contents("http://api.macvendors.com/".$this->request->mac);
|
||||
$content = file_get_contents("https://api.macvendors.com/".$this->request->mac);
|
||||
$this->response = array('title' => $this->request->mac, "output" => $content);
|
||||
}
|
||||
|
||||
|
||||
@ -485,7 +485,7 @@ registerController('wps_OptionsController', ['$api', '$scope', '$rootScope', fun
|
||||
|
||||
angular.forEach($scope.reaverAdvancedOptions, function(value, key) {
|
||||
if(value.check != false)
|
||||
return_value += value.check + " " + value.val;
|
||||
return_value += value.check + " " + value.val + " ";
|
||||
});
|
||||
|
||||
return return_value;
|
||||
@ -507,7 +507,7 @@ registerController('wps_OptionsController', ['$api', '$scope', '$rootScope', fun
|
||||
|
||||
angular.forEach($scope.bullyAdvancedOptions, function(value, key) {
|
||||
if(value.check != false)
|
||||
return_value += value.check + " " + value.val;
|
||||
return_value += value.check + " " + value.val + " ";
|
||||
});
|
||||
|
||||
return return_value;
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
"tetra"
|
||||
],
|
||||
"title": "wps",
|
||||
"version": "1.2"
|
||||
}
|
||||
"version": "1.5"
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ touch /tmp/wps.progress
|
||||
|
||||
if [ "$1" = "install" ]; then
|
||||
if [ "$2" = "internal" ]; then
|
||||
opkg update
|
||||
opkg update
|
||||
|
||||
opkg install reaver
|
||||
opkg install bully
|
||||
@ -24,6 +24,10 @@ if [ "$1" = "install" ]; then
|
||||
opkg install bully --dest sd
|
||||
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/lib/libpcap.so ] && [ -f /usr/lib/libpcap.so.1.3 ]; then
|
||||
ln -s /usr/lib/libpcap.so /usr/lib/libpcap.so.1.3
|
||||
fi
|
||||
|
||||
touch /etc/config/wps
|
||||
echo "config wps 'module'" > /etc/config/wps
|
||||
@ -32,6 +36,8 @@ if [ "$1" = "install" ]; then
|
||||
uci commit wps.module.installed
|
||||
|
||||
elif [ "$1" = "remove" ]; then
|
||||
opkg remove reaver
|
||||
opkg remove bully
|
||||
rm -rf /etc/config/wps
|
||||
fi
|
||||
|
||||
|
||||
@ -6,6 +6,13 @@ export PATH=$PATH:/sd/usr/bin:/sd/usr/sbin
|
||||
|
||||
MYTIME=`date +%s`
|
||||
MYCMD=`cat /tmp/wps.run`
|
||||
MODULEDIR=/pineapple/modules/wps
|
||||
LOGDIR=$MODULEDIR/log
|
||||
|
||||
# ensure log directory is created
|
||||
if [ ! -d $LOGDIR ]; then
|
||||
mkdir $LOGDIR
|
||||
fi
|
||||
|
||||
if [ "$1" = "start" ]; then
|
||||
eval ${MYCMD}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user