TIMESTAMP | +2020-09-16 21:28:27 | +||||
---|---|---|---|---|---|
ID | +9CACC065 | +||||
NAME | +Default | +||||
ENGINEER | +Default | +||||
SOURCE IP | +127.0.0.1 | +
CRITICAL | +0 | +
---|---|
HIGH | +4 | +
MEDIUM | +2 | +
LOW | +7 | +
INFO | +19 | +
SVC_Z115 | +Checks for SMB Ports | + +
---|---|
TITLE | +Checks for SMB Ports | +
FINDINGS | +Remote Server Exposes SMB Port(s) | +
ADDRESS | +192.168.0.1 | +
PORT | +445 | +
DETAILS | +Open Port: 445 (SMB) | +
MITIGATION | +Bind all possible network services to localhost, and configure only those which require remote clients on an external interface. | +
CFG_FOQW | +Checks if SSH password authentication is supported | + +
TITLE | +Checks if SSH password authentication is supported | +
FINDINGS | +Remote Server Supports SSH Passwords | +
ADDRESS | +192.168.0.10 | +
PORT | +22 | +
DETAILS | +Dropbear sshd | +
MITIGATION | +SSH Allows Password authentication, this is considered bad security practice. +SSH Key based authentication should be enabled on the server, and passwords should be disabled. | +
SVC_6509 | +Checks for Remote Management Ports | + +
TITLE | +Checks for Remote Management Ports | +
FINDINGS | +Remote Server Exposes Administration Port(s) | +
ADDRESS | +192.168.0.10 | +
PORT | +22 | +
DETAILS | +Open Port: 22 (SSH) | +
MITIGATION | +Bind all possible services to localhost, and confirm only those which require remote clients are allowed remotely. | +
SVC_6509 | +Checks for Remote Management Ports | + +
TITLE | +Checks for Remote Management Ports | +
FINDINGS | +Remote Server Exposes Administration Port(s) | +
ADDRESS | +192.168.0.1 | +
PORT | +139 | +
DETAILS | +Open Port: 139 (NetBIOS) | +
MITIGATION | +Bind all possible services to localhost, and confirm only those which require remote clients are allowed remotely. | +
VLN_SKKF | +Checks for password forms in HTTP | + +
TITLE | +Checks for password forms in HTTP | +
FINDINGS | +Unencrypted Login Form | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Login Page over HTTP | +
MITIGATION | +Website login form should be done over SSL. | +
SVC_0C1Z | +Checks for Rare Ports | + +
TITLE | +Checks for Rare Ports | +
FINDINGS | +Remote Server Exposes Rare Port(s) | +
ADDRESS | +192.168.0.14 | +
PORT | +9999 | +
DETAILS | +Open Port: 9999 (distinct) | +
MITIGATION | +Bind all possible network services to localhost, and configure only those which require remote clients on an external interface. | +
SVC_ZGZA | +Checks for HTTP Ports | + +
TITLE | +Checks for HTTP Ports | +
FINDINGS | +Remote Server Exposes HTTP Port(s) | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Open Port: 80 (HTTP) | +
MITIGATION | +Bind all possible network services to localhost, and configure only those which require remote clients on an external interface. | +
DSC_A4F1 | +Checks if a Web Panel is exposed | + +
TITLE | +Checks if a Web Panel is exposed | +
FINDINGS | +Identified a Known Web Panel | +
ADDRESS | +192.168.0.1 | +
PORT | +80 | +
DETAILS | +Generic Indicator: "Login" (Login Page) | +
MITIGATION | +Identify whether the application in question is supposed to be exposed to the local network. | +
DSC_A4F1 | +Checks if a Web Panel is exposed | + +
TITLE | +Checks if a Web Panel is exposed | +
FINDINGS | +Identified a Known Web Panel | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Generic Indicator: "Login" (Login Page) | +
MITIGATION | +Identify whether the application in question is supposed to be exposed to the local network. | +
SVC_ZGZA | +Checks for HTTP Ports | + +
TITLE | +Checks for HTTP Ports | +
FINDINGS | +Remote Server Exposes HTTP Port(s) | +
ADDRESS | +192.168.0.1 | +
PORT | +80 | +
DETAILS | +Open Port: 80 (HTTP) | +
MITIGATION | +Bind all possible network services to localhost, and configure only those which require remote clients on an external interface. | +
DSC_A4F1 | +Checks if a Web Panel is exposed | + +
TITLE | +Checks if a Web Panel is exposed | +
FINDINGS | +Identified a Known Web Panel | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Generic Indicator: "Login" (Login Page) | +
MITIGATION | +Identify whether the application in question is supposed to be exposed to the local network. | +
SVC_ZGZA | +Checks for HTTP Ports | + +
TITLE | +Checks for HTTP Ports | +
FINDINGS | +Remote Server Exposes HTTP Port(s) | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Open Port: 8080 (HTTP) | +
MITIGATION | +Bind all possible network services to localhost, and configure only those which require remote clients on an external interface. | +
SVC_ZGZA | +Checks for HTTP Ports | + +
TITLE | +Checks for HTTP Ports | +
FINDINGS | +Remote Server Exposes HTTP Port(s) | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Open Port: 443 (HTTP) | +
MITIGATION | +Bind all possible network services to localhost, and configure only those which require remote clients on an external interface. | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Missing Security Header: content-security-policy | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Missing Security Header: x-xss-protection | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Missing Security Header: x-frame-options | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Missing Security Header: content-security-policy | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Missing Security Header: x-frame-options | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Missing Security Header: x-xss-protection | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Missing Security Header: x-content-type-options | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Missing Security Header: content-security-policy | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_DFFF | +Checks if CORS Headers support Wildcard Origins | + +
TITLE | +Checks if CORS Headers support Wildcard Origins | +
FINDINGS | +Webserver is allowing all domains in CORS | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Access-Control-Allow-Origin is set to: * | +
MITIGATION | +Consider hardening your CORS Policy to define specific Origins | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Missing Security Header: x-content-type-options | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Missing Security Header: referrer-policy | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Missing Security Header: strict-transport-security | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Missing Security Header: x-frame-options | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.10 | +
PORT | +80 | +
DETAILS | +Missing Security Header: referrer-policy | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Missing Security Header: strict-transport-security | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.14 | +
PORT | +8080 | +
DETAILS | +Missing Security Header: referrer-policy | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Missing Security Header: x-content-type-options | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Missing Security Header: strict-transport-security | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
CFG_BS0F | +Checks if Security Headers exist | + +
TITLE | +Checks if Security Headers exist | +
FINDINGS | +Webserver is missing Security Headers | +
ADDRESS | +192.168.0.1 | +
PORT | +443 | +
DETAILS | +Missing Security Header: x-xss-protection | +
MITIGATION | +Consider using security headers for your server. https://www.keycdn.com/blog/http-security-headers | +
DEBUG'],
+ 'title':'Django Error'
+ },
+ self.generate_str():{
+ 'app':'MYSQL',
+ 'match':['MySQL Error', 'You have an error in your SQL syntax', 'mysql_fetch_array'],
+ 'title':'MySQL Error'
+ },
+ self.generate_str():{
+ 'app':'APACHE_TOMCAT',
+ 'match':['The full stack trace of the root cause is available', 'An exception occurred processing'],
+ 'title':'Apache Tomcat Error'
+ },
+ self.generate_str():{
+ 'app':'APACHE_STRUTS',
+ 'match':['Struts has detected an unhandled exception', 'Stacktraces', 'struts.devMode=false'],
+ 'title':'Apache Struts Error'
+ },
+ self.generate_str():{
+ 'app':'GENERIC',
+ 'match':['The debugger caught an exception'],
+ 'title':'Generic Error'
+ },
+ '/public%c0':{
+ 'app':'OUCH_JS',
+ 'match':['copy exception into clipboard', 'Ouch container', 'Server/Request Data'],
+ 'title':'Ouch JS Error'
+ },
+ '/public..':{
+ 'app':'OUCH_JS',
+ 'match':['copy exception into clipboard', 'Ouch container', 'Server/Request Data'],
+ 'title':'Ouch JS Error'
+ },
+ '/php_errors.log':{
+ 'app':'PHP_ERROR_LOG',
+ 'match':['require_once', 'Fatal error', 'Stack trace'],
+ 'title':'PHP Error Log'
+ }
+ }
+ self.intensity = 2
+
+ def generate_str(self):
+ return '/' + ''.join(random.choices(string.ascii_letters + string.digits, k=8))
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ module = p.get_module()
+ domain = p.get_domain()
+
+ if 'http' not in module:
+ return
+
+ resp = None
+
+ for uri, values in self.rule_match_string.items():
+ app_name = values['app']
+ app_title = values['title']
+
+ resp = t.http_request(ip, port, uri=uri)
+
+ if resp is not None:
+ for match in values['match']:
+ if match in resp.text:
+ self.rule_details = 'Info Leakage - {}, Path: {}'.format(app_title, uri)
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+ return
diff --git a/rules/vulnerabilities/rule_front-page.py b/rules/vulnerabilities/rule_front-page.py
new file mode 100644
index 0000000..caea7e1
--- /dev/null
+++ b/rules/vulnerabilities/rule_front-page.py
@@ -0,0 +1,48 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_65C8'
+ self.rule_severity = 2
+ self.rule_description = 'FrontPage configuration information disclosure'
+ self.rule_confirm = 'FrontPage misconfiguration'
+ self.rule_details = ''
+ self.rule_mitigation = '''Make sure SharePoint is not anonymously accessible'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = t.http_request(ip, port, uri='/_vti_inf.html')
+
+ if not resp:
+ return
+
+ if resp.headers['Content-Length'] == '247':
+ self.rule_details = 'Exposed FrontPage at /_vti_inf.html'
+ js_data = {
+ 'ip': ip,
+ 'port': port,
+ 'domain': domain,
+ 'rule_id': self.rule,
+ 'rule_sev': self.rule_severity,
+ 'rule_desc': self.rule_description,
+ 'rule_confirm': self.rule_confirm,
+ 'rule_details': self.rule_details,
+ 'rule_mitigation': self.rule_mitigation
+ }
+
+ rds.store_vuln(js_data)
+
+ return
diff --git a/rules/vulnerabilities/rule_ftp-anon-access.py b/rules/vulnerabilities/rule_ftp-anon-access.py
new file mode 100644
index 0000000..73a10b7
--- /dev/null
+++ b/rules/vulnerabilities/rule_ftp-anon-access.py
@@ -0,0 +1,50 @@
+from ftplib import FTP
+
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+from db.db_ports import ftp_ports
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_242C'
+ self.rule_severity = 4
+ self.rule_description = 'Checks if FTP allows Anonymous Access'
+ self.rule_details = ''
+ self.rule_confirm = 'FTP Anonymous Access Allowed'
+ self.rule_mitigation = '''Disable Anonymous FTP access.'''
+ self.rule_match_port = ftp_ports
+ self.intensity = 0
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+ product = p.get_product()
+
+ if port in self.rule_match_port:
+ try:
+ ftp = FTP(ip)
+ res = ftp.login()
+ if res:
+ if '230' in res or 'user logged in' in res or 'successful' in res:
+ self.rule_details = 'FTP with Anonymous Access Enabled'
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+ except:
+ pass
+
+ return
diff --git a/rules/vulnerabilities/rule_git-repo.py b/rules/vulnerabilities/rule_git-repo.py
new file mode 100644
index 0000000..db770fc
--- /dev/null
+++ b/rules/vulnerabilities/rule_git-repo.py
@@ -0,0 +1,51 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+from db.db_paths import COMMON_WEB_PATHS
+from core.logging import logger
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_92F9'
+ self.rule_severity = 4
+ self.rule_description = 'Checks for Git Repositories'
+ self.rule_confirm = 'Remote Server Exposes Git Repository'
+ self.rule_details = ''
+ self.rule_mitigation = '''Configure the server in a way that makes git repository unreachable'''
+ self.intensity = 3
+ self.uris = COMMON_WEB_PATHS
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = None
+
+ for uri in self.uris:
+ resp = t.http_request(ip, port, uri=uri + '/.git/HEAD')
+
+ if resp and resp.text.startswith('ref:'):
+ self.rule_details = 'Git Path: {}'.format(uri)
+
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+
+ rds.store_vuln(js_data)
+
+ return
diff --git a/rules/vulnerabilities/rule_graphql.py b/rules/vulnerabilities/rule_graphql.py
new file mode 100644
index 0000000..4cbaca2
--- /dev/null
+++ b/rules/vulnerabilities/rule_graphql.py
@@ -0,0 +1,52 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_FBQP'
+ self.rule_severity = 2
+ self.rule_description = 'Checks for GraphQL Interfaces'
+ self.rule_confirm = 'Exposed GraphQL Interface'
+ self.rule_details = ''
+ self.rule_mitigation = '''Restrict access to the GraphQL Interface to trusted sources \
+or disabled it completely if not in use.'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ graphql_uris = ['/graphql', '/graphiql']
+ resp = None
+
+ for uri in graphql_uris:
+ resp = t.http_request(ip, port, uri=uri)
+
+ if resp is None:
+ return
+
+ if resp.status_code == 400 and 'GET query missing.' in resp.text:
+ self.rule_details = 'GraphQL Enabled on the Server'
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+ return
+
+ return
diff --git a/rules/vulnerabilities/rule_host-inject.py b/rules/vulnerabilities/rule_host-inject.py
new file mode 100644
index 0000000..45e9d92
--- /dev/null
+++ b/rules/vulnerabilities/rule_host-inject.py
@@ -0,0 +1,49 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_4SD5'
+ self.rule_severity = 1
+ self.rule_description = 'Checks for Host Header Injections'
+ self.rule_confirm = 'Host Header Injection'
+ self.rule_details = ''
+ self.rule_mitigation = '''Redirect only to allowed hosts, otherwise ignore the Host Header'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = t.http_request(ip, port, follow_redirects=False,
+ headers={'X-Forwarded-Host':'112000as0az7s62s9d7.com',
+ 'Host': '112000as0az7s62s9d7.com'})
+
+ if resp:
+ if 'Location' in resp.headers and '112000as0az7s62s9d7.com' in resp.headers['Location']:
+ self.rule_details = 'Host header injection'
+
+ js_data = {
+ 'ip': ip,
+ 'port': port,
+ 'domain': domain,
+ 'rule_id': self.rule,
+ 'rule_sev': self.rule_severity,
+ 'rule_desc': self.rule_description,
+ 'rule_confirm': self.rule_confirm,
+ 'rule_details': self.rule_details,
+ 'rule_mitigation': self.rule_mitigation
+ }
+
+ rds.store_vuln(js_data)
+
+ return
diff --git a/rules/vulnerabilities/rule_intellij-idea.py b/rules/vulnerabilities/rule_intellij-idea.py
new file mode 100644
index 0000000..d43eac7
--- /dev/null
+++ b/rules/vulnerabilities/rule_intellij-idea.py
@@ -0,0 +1,49 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+from db.db_paths import COMMON_WEB_PATHS
+from core.logging import logger
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_ZBKK'
+ self.rule_severity = 1
+ self.rule_description = 'Checks for Intellij IDEA files'
+ self.rule_confirm = 'Remote Server contains IDE related files'
+ self.rule_details = ''
+ self.rule_mitigation = '''Add the files to gitignore to prevent them from getting pushed.'''
+ self.rule_match_string = ['ChangeListManager']
+ self.uris = COMMON_WEB_PATHS
+ self.intensity = 3
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = None
+
+ for uri in self.uris:
+ resp = t.http_request(ip, port, uri=uri+'/.idea/workspace.xml')
+ if resp:
+ for match in self.rule_match_string:
+ if match in resp.text:
+ self.rule_details = 'Found Intelli IDEA files at {}/.idea/workspace.xml'.format(uri)
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+ return
diff --git a/rules/vulnerabilities/rule_redis-dump-keys.py b/rules/vulnerabilities/rule_redis-dump-keys.py
new file mode 100644
index 0000000..c826df7
--- /dev/null
+++ b/rules/vulnerabilities/rule_redis-dump-keys.py
@@ -0,0 +1,57 @@
+import socket
+
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+from db.db_ports import database_ports
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_E034'
+ self.rule_severity = 3
+ self.rule_description = 'Checks for Open Redis Instances'
+ self.rule_confirm = 'Remote Server Exposes Redis Keys'
+ self.rule_details = ''
+ self.rule_mitigation = '''Bind redis to the local network, and add authentication using --require-auth config parameter.'''
+ self.intensity = 0
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if port != 6379 or module == 'redis':
+ return
+
+ try:
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((ip, port))
+ s.sendall(b'INFO\n')
+ data = s.recv(1024)
+
+ if data and 'redis_version' in str(data):
+ self.rule_details = 'Redis version: ..snip.. {} ..snip..'.format(str(data)[0:100])
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+
+ rds.store_vuln(js_data)
+ return
+ except:
+ pass
+
+ return
+
+
+
\ No newline at end of file
diff --git a/rules/vulnerabilities/rule_s3-takeover.py b/rules/vulnerabilities/rule_s3-takeover.py
new file mode 100644
index 0000000..dd0695a
--- /dev/null
+++ b/rules/vulnerabilities/rule_s3-takeover.py
@@ -0,0 +1,47 @@
+
+
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_ZZ13'
+ self.rule_severity = 3
+ self.rule_description = 'Checks for Beanstalk Takeovers'
+ self.rule_confirm = 'DNS Entry allows takeover of Beanstalk server'
+ self.rule_details = ''
+ self.rule_mitigation = '''Verify the DNS is in use, remove if unnecessary.'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+
+ if not domain:
+ return
+
+ resp = t.http_request(domain, port)
+
+ if resp is None:
+ return
+
+ if resp.status_code == 404 and 'NoSuchBucket' in resp.text:
+ self.rule_details = 'S3 Takeover at {}'.format(domain)
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+
+ return
diff --git a/rules/vulnerabilities/rule_shellshock.py b/rules/vulnerabilities/rule_shellshock.py
new file mode 100644
index 0000000..6996134
--- /dev/null
+++ b/rules/vulnerabilities/rule_shellshock.py
@@ -0,0 +1,49 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+import re
+
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_88GV'
+ self.rule_severity = 4
+ self.rule_description = 'Remote Code Execution Via User-Agent shellshock'
+ self.rule_confirm = 'Shellshock RCE'
+ self.rule_details = ''
+ self.rule_mitigation = '''Patch the vulnerable system'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = t.http_request(ip, port, uri='/cgi-bin/status', headers={'User-Agent':"() { :; }; echo; echo; /bin/bash -c 'cat /etc/passwd;'"})
+
+ if not resp:
+ return
+
+ if re.search('root:[x*]:0:0', resp.text):
+ self.rule_details = 'Remote Code Execution Shellshock'
+ js_data = {
+ 'ip': ip,
+ 'port': port,
+ 'domain': domain,
+ 'rule_id': self.rule,
+ 'rule_sev': self.rule_severity,
+ 'rule_desc': self.rule_description,
+ 'rule_confirm': self.rule_confirm,
+ 'rule_details': self.rule_details,
+ 'rule_mitigation': self.rule_mitigation
+ }
+
+ rds.store_vuln(js_data)
+
+ return
\ No newline at end of file
diff --git a/rules/vulnerabilities/rule_ssh_filedisclosure.py b/rules/vulnerabilities/rule_ssh_filedisclosure.py
new file mode 100644
index 0000000..9525396
--- /dev/null
+++ b/rules/vulnerabilities/rule_ssh_filedisclosure.py
@@ -0,0 +1,83 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_EZSD'
+ self.rule_severity = 4
+ self.rule_description = 'Finds Exposed UNIX Filesystems'
+ self.rule_confirm = 'UNIX File Disclosure'
+ self.rule_details = ''
+ self.rule_mitigation = '''Disable any ability to directly browse to file system paths'''
+ self.rule_match_string = {
+ '/.ssh/authorized_keys':{
+ 'app':'SSH_AUTH_KEYS',
+ 'match':['ssh-rsa'],
+ 'title':'SSH Authorized Keystore'
+ },
+ '/etc/hosts':{
+ 'app':'LOCAL_HOSTS_FILE',
+ 'match':['localhost is used to configure'],
+ 'title':'Local Host Resolver'
+ },
+ '/etc/passwd':{
+ 'app':'UNIX_PASSWD_FILE',
+ 'match':['root:x:0:0'],
+ 'title':'UNIX Local Users File'
+ },
+ '/etc/shadow':{
+ 'app':'UNIX_SHADOW_FILE',
+ 'match':['bin:x:', 'nobody:x:'],
+ 'title':'UNIX Hashes File Leak'
+ },
+ '/.ssh/id_rsa':{
+ 'app':'SSH_PRIVATE_KEY',
+ 'match':['-----BEGIN RSA PRIVATE KEY-----'],
+ 'title':'Private SSH Key Leak'
+ },
+ '/.ssh/id_rsa.pub':{
+ 'app':'SSH_PUBLIC_KEY',
+ 'match':['ssh-rsa'],
+ 'title':'SSH Public Key'
+ },
+ }
+ self.intensity = 2
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = None
+
+ for uri, values in self.rule_match_string.items():
+ app_name = values['app']
+ app_title = values['title']
+
+ resp = t.http_request(ip, port, uri=uri)
+
+ if resp is not None:
+ for match in values['match']:
+ if match in resp.text:
+ self.rule_details = '{} at {}'.format(app_title, uri)
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+
+ rds.store_vuln(js_data)
+ return
\ No newline at end of file
diff --git a/rules/vulnerabilities/rule_svn-repo.py b/rules/vulnerabilities/rule_svn-repo.py
new file mode 100644
index 0000000..23ba6f6
--- /dev/null
+++ b/rules/vulnerabilities/rule_svn-repo.py
@@ -0,0 +1,47 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+from core.utils import Utils
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_BLKK'
+ self.rule_severity = 4
+ self.rule_description = 'Checks for SVN Repositories'
+ self.rule_confirm = 'SVN Repository Found'
+ self.rule_details = ''
+ self.rule_mitigation = '''Block remote access to SVN.'''
+ self.intensity = 0
+
+ def check_rule(self, ip, port, values, conf):
+ t = Triage()
+ c = ConfParser(conf)
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+ product = p.get_product()
+
+ if 'http' not in module:
+ return
+
+ resp = t.http_request(ip, port, uri='/.svn/text-base')
+
+ if resp and 'Index of /' in resp.text:
+ self.rule_details = 'SVN Repository exposed at /.svn/text-base'
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+
+ rds.store_vuln(js_data)
+
+ return
+
diff --git a/rules/vulnerabilities/rule_unencrypted_login.py b/rules/vulnerabilities/rule_unencrypted_login.py
new file mode 100644
index 0000000..741a3f7
--- /dev/null
+++ b/rules/vulnerabilities/rule_unencrypted_login.py
@@ -0,0 +1,62 @@
+from bs4 import BeautifulSoup
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+from db.db_ports import http_ports
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_SKKF'
+ self.rule_severity = 2
+ self.rule_description = 'Checks for password forms in HTTP'
+ self.rule_confirm = 'Unencrypted Login Form'
+ self.rule_details = ''
+ self.rule_mitigation = '''Website login form should be done over SSL.'''
+ self.intensity = 1
+
+ def contains_password_form(self, text):
+ try:
+ if text:
+ soup = BeautifulSoup(text, 'html.parser')
+ inputs = soup.findAll('input')
+ if inputs:
+ for i in inputs:
+ if i.attrs.get('type') == 'password':
+ return True
+ except:
+ pass
+
+ return False
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+ product = p.get_product()
+
+
+ if module == 'http' or port in http_ports:
+ resp = t.http_request(ip, port, follow_redirects=False)
+
+ if resp:
+ form = self.contains_password_form(resp.text)
+ if form:
+ if not resp.url.startswith('https://'):
+ self.rule_details = 'Login Page over HTTP'
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+ return
+
diff --git a/rules/vulnerabilities/rule_wordpress-listing.py b/rules/vulnerabilities/rule_wordpress-listing.py
new file mode 100644
index 0000000..6a4d2ef
--- /dev/null
+++ b/rules/vulnerabilities/rule_wordpress-listing.py
@@ -0,0 +1,42 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_FF00'
+ self.rule_severity = 4
+ self.rule_description = 'Checks for Open Wordpress Upload Directories'
+ self.rule_confirm = 'Remote Wordpress has an Uploads Folder with Indexing Enabled'
+ self.rule_details = ''
+ self.rule_mitigation = '''Disable Directory Indexing on the Wordpress instance'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = t.http_request(ip, port, uri='/wp-content/uploads/')
+
+ if resp and 'Index of /wp-content/uploads' in resp.text:
+ self.rule_details = 'Found Uploads Directory at /wp-content/uploads/'
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+ return
diff --git a/rules/vulnerabilities/rule_xfh-injection.py b/rules/vulnerabilities/rule_xfh-injection.py
new file mode 100644
index 0000000..2da0577
--- /dev/null
+++ b/rules/vulnerabilities/rule_xfh-injection.py
@@ -0,0 +1,48 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_ZD10'
+ self.rule_severity = 2
+ self.rule_description = 'Checks for X-Forwarded-Host Injection'
+ self.rule_confirm = 'Remote Server suffers from X-Forwarded-Host Injection'
+ self.rule_details = ''
+ self.rule_mitigation = '''Configure the server to not redirect based on arbitrary \
+XFH headers provided by the user.'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ target = 'www.nerve.local'
+ resp = t.http_request(ip, port, follow_redirects=False, headers={'X-Forwarded-Host':target})
+
+ if resp is None:
+ return
+
+ if 'Location' in resp.headers and resp.headers['Location'] == target:
+ self.rule_details = 'Server Redirected to an Arbitrary Location'
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+
+ return
diff --git a/rules/vulnerabilities/rule_xmlrpc.py b/rules/vulnerabilities/rule_xmlrpc.py
new file mode 100644
index 0000000..6597059
--- /dev/null
+++ b/rules/vulnerabilities/rule_xmlrpc.py
@@ -0,0 +1,47 @@
+from core.redis import rds
+from core.triage import Triage
+from core.parser import ScanParser, ConfParser
+
+class Rule:
+ def __init__(self):
+ self.rule = 'VLN_FAZZ'
+ self.rule_severity = 2
+ self.rule_description = 'Checks for XMLRPC Interfaces'
+ self.rule_confirm = 'Remote Server has XMLRPC Interface enabled'
+ self.rule_details = ''
+ self.rule_mitigation = '''Restrict access to the XMLRPC Interface \
+or disabled it completely if not in use.'''
+ self.intensity = 1
+
+ def check_rule(self, ip, port, values, conf):
+ c = ConfParser(conf)
+ t = Triage()
+ p = ScanParser(port, values)
+
+ domain = p.get_domain()
+ module = p.get_module()
+
+ if 'http' not in module:
+ return
+
+ resp = t.http_request(ip, port, uri='/xmlrpc.php')
+
+ if resp is None:
+ return
+
+ if resp.status_code == 405:
+ self.rule_details = 'Server Allows XMLRPC Connections'
+ js_data = {
+ 'ip':ip,
+ 'port':port,
+ 'domain':domain,
+ 'rule_id':self.rule,
+ 'rule_sev':self.rule_severity,
+ 'rule_desc':self.rule_description,
+ 'rule_confirm':self.rule_confirm,
+ 'rule_details':self.rule_details,
+ 'rule_mitigation':self.rule_mitigation
+ }
+ rds.store_vuln(js_data)
+
+ return
diff --git a/start.sh b/start.sh
new file mode 100644
index 0000000..a7c8e14
--- /dev/null
+++ b/start.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+nohup redis-server --bind 127.0.0.1 & &> /dev/null
+/usr/bin/python3 main.py
\ No newline at end of file
diff --git a/static/components/navbar/navbar-dropdowns.css b/static/components/navbar/navbar-dropdowns.css
new file mode 100644
index 0000000..80a59d1
--- /dev/null
+++ b/static/components/navbar/navbar-dropdowns.css
@@ -0,0 +1,72 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+.nav-dropdown .nav-link {
+ color: #B2EBF2;
+ line-height: 1.42857;
+ padding: 1rem 0 1rem 1rem !important;
+}
+
+.nav-dropdown .nav-link:hover {
+ color: #fff;
+}
+
+.nav-dropdown.show a {
+ color: #fff;
+}
+
+.nav-dropdown .nav-link::after {
+ display: none;
+}
+
+.nav-dropdown .nav-link-menu {
+ position: absolute;
+ border: none;
+ min-width: 220px;
+ padding: 0;
+ line-height: 1.4;
+ box-shadow: 0 1px 10px 0 rgba(69, 90, 100, 0.2);
+ margin-top: -5px;
+}
+
+.nav-dropdown .nav-link-menu::before {
+ top: -4px;
+ right: 25%;
+ margin: 0 0 0 -.25em;
+ display: block;
+ position: absolute;
+ pointer-events: none;
+ content: '';
+ visibility: visible;
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+ width: .5em;
+ height: .5em;
+ background: #ffffff;
+ z-index: 2;
+}
+
+.nav-dropdown .nav-link-menu .nav-list {
+ padding: 5px 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+
+.nav-dropdown .nav-link-menu .nav-list li {
+ line-height: 1.2;
+}
+
+.nav-dropdown .nav-link-menu .nav-list li a {
+ color: #888;
+ font-size: 14px;
+ padding: .8rem;
+}
+
+.nav-dropdown .dropdown-divider {
+ margin: 3px 0;
+}
\ No newline at end of file
diff --git a/static/components/sidebar/sidebar-default.css b/static/components/sidebar/sidebar-default.css
new file mode 100755
index 0000000..2bd8b13
--- /dev/null
+++ b/static/components/sidebar/sidebar-default.css
@@ -0,0 +1,79 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+#sidebar {
+ min-width: 250px;
+ max-width: 250px;
+ background: #293142;
+ color: #fff;
+ transition: all 0.3s;
+}
+
+#sidebar.active {
+ margin-left: -250px;
+}
+
+#sidebar .sidebar-header {
+ padding: .6rem 1rem;
+}
+
+#sidebar ul.components {
+ padding: 0 0;
+}
+
+#sidebar ul p {
+ color: #fff;
+ padding: 10px;
+}
+
+#sidebar ul li a {
+ padding: .8rem 1.5rem;
+ font-size: 1rem;
+ display: block;
+ color: #b6cdff;
+}
+
+#sidebar ul li a .svg-inline--fa {
+ min-width: 20px;
+ margin-right: 5px;
+}
+
+#sidebar ul li a:hover,
+#sidebar ul li a.active {
+ color: #fff;
+ background: #2196F3;
+}
+
+#sidebar ul li.active>a,
+a[aria-expanded="true"] {
+ color: inherit;
+}
+
+#sidebar ul ul a {
+ font-size: 1rem;
+ background: #1f293e;
+}
+
+#sidebar a[data-toggle="collapse"] {
+ position: relative;
+}
+
+#sidebar .dropdown-toggle::after {
+ display: block;
+ position: absolute;
+ top: 50%;
+ right: 20px;
+ transform: translateY(-50%);
+ display: none;
+}
+
+@media (max-width: 768px) {
+ #sidebarCollapse span {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/static/css/auth.css b/static/css/auth.css
new file mode 100644
index 0000000..c0f642d
--- /dev/null
+++ b/static/css/auth.css
@@ -0,0 +1,109 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------
+[Table of contents]
+
+1. Body / #body
+2. Contents / #auth-content
+3. Cards / .card
+4. Miscellaneous
+5. Adjustments to dafault behaviors
+-------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------
+[1. Body / #body]
+*/
+body {
+ background: #f1f1f1;
+}
+
+.wrapper {
+ position: relative;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ overflow: hidden;
+ min-width: 100%;
+ min-height: 100vh;
+}
+
+/*------------------------------------------------------------------
+[2. Contents / #auth-content]
+*/
+.auth-content {
+ position: relative;
+ width: 480px;
+ padding: 15px;
+ z-index: 5;
+}
+
+/*------------------------------------------------------------------
+[3. Cards / .card]
+*/
+.auth-content .card {
+ margin-bottom: 0;
+ -webkit-box-shadow: 0 1px 20px 0 rgba(69, 90, 100, 0.08);
+ box-shadow: 0 1px 20px 0 rgba(69, 90, 100, 0.08);
+ border: none;
+ -webkit-transition: all 0.5s ease-in-out;
+ transition: all 0.5s ease-in-out;
+ background-color: rgba(0,0,0,.075);
+}
+
+.auth-content .card .card-block,
+.auth-content .card .card-body {
+ padding: 30px 25px;
+}
+
+.auth-content .form-control {
+ background: #f4f7fa;
+ min-height: 42px;
+ line-height: 42px;
+ font-size: 14px;
+ padding: 10px 15px;
+ height: 42px;
+}
+
+/*------------------------------------------------------------------
+[4. Miscellaneous]
+*/
+.shadow-2 {
+ -webkit-box-shadow: 0 10px 18px 0 rgba(62, 57, 107, 0.2);
+ box-shadow: 0 10px 18px 0 rgba(62, 57, 107, 0.2);
+}
+
+p.text-muted {
+ font-size: 13px;
+}
+
+/*------------------------------------------------------------------
+[5. Adjustments to dafault behaviors]
+*/
+.btn {
+ padding: 10px 20px;
+ border-radius: 0.25rem;
+ font-size: 14px;
+ margin-bottom: 5px;
+ margin-right: 10px;
+ -webkit-transition: all 0.3s ease-in-out;
+ transition: all 0.3s ease-in-out;
+}
+
+.wrapper a,
+.wrapper p>a {
+ color: #3e8ef7;
+ font-weight: 600;
+}
\ No newline at end of file
diff --git a/static/css/error.css b/static/css/error.css
new file mode 100644
index 0000000..a12f324
--- /dev/null
+++ b/static/css/error.css
@@ -0,0 +1,131 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------
+[Table of contents]
+
+1. Body / .wrapper
+2. Contents / .page
+3. Miscellaneous
+4. Adjustments to dafault behaviors
+5. Responsive properties
+-------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------
+[1. Body / .wrapper]
+*/
+@font-face {
+ font-family: "Lato";
+ font-style: normal;
+ font-weight: 400;
+ font-display: auto;
+ src: url("../font/Lato-Regular.eot");
+ src: url("../font/Lato-Regular.eot?#iefix") format("embedded-opentype"), url("../font/Lato-Regular.woff") format("woff"), url("../font/Lato-Regular.ttf") format("truetype");
+}
+
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3,
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6,
+p,
+a,
+td,
+body {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+}
+
+body,
+html {
+ width: 100%;
+ height: 100%;
+ background: #f1f1f1;
+ font-family: "Lato", "Helvetica Neue", Arial, Helvetica, sans-serif;
+}
+
+.wrapper {
+ position: relative;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ overflow: hidden;
+ min-width: 100%;
+ min-height: 100vh;
+}
+
+/*------------------------------------------------------------------
+[2. Contents / .page]
+*/
+.page {
+ height: 100%;
+ max-width: none !important;
+ margin: 0 !important;
+ padding: 0;
+ position: relative;
+ min-height: calc(100% - 44px);
+}
+
+.page header h1 {
+ font-size: 10em;
+ font-weight: 400;
+}
+
+.page header p {
+ margin-bottom: 30px;
+ font-size: 30px;
+ text-transform: uppercase;
+}
+
+.page .error-advise {
+ margin-bottom: 25px;
+ color: #a9afb5;
+}
+
+/*------------------------------------------------------------------
+[3. Miscellaneous]
+*/
+.page-copyright {
+ color: #37474f;
+ font-size: .858rem;
+ letter-spacing: 1px;
+}
+
+/*------------------------------------------------------------------
+[4. Adjustments to dafault behaviors]
+*/
+.btn-round {
+ border-radius: 1000px;
+}
+
+/*------------------------------------------------------------------
+[5. Responsive Properties]
+*/
+@media (max-width: 480px) {
+ .page header h1 {
+ font-size: 8em;
+ }
+
+ .page header p {
+ font-size: 2rem;
+ }
+}
\ No newline at end of file
diff --git a/static/css/master.css b/static/css/master.css
new file mode 100644
index 0000000..d323c1d
--- /dev/null
+++ b/static/css/master.css
@@ -0,0 +1,422 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+
+@import "../components/navbar/navbar-dropdowns.css";
+@import "../components/sidebar/sidebar-default.css";
+
+/*------------------------------------------------------------------
+# [Color codes]
+
+# teal: #00b5ad
+# olive: #b5cc18
+# violet: #6435c9
+# orange: #f2711c
+# darkgray: darkgray
+# blue: #2185d0
+# grey: #767676
+# */
+
+/*------------------------------------------------------------------
+[Typography]
+
+Body: 1em / "Lato", "Helvetica Neue", Arial, Helvetica, sans-serif;
+Headers: 2em / "Lato", "Helvetica Neue", Arial, Helvetica, sans-serif;
+parapgraph: 1em / "Lato", "Helvetica Neue", Arial, Helvetica, sans-serif;
+
+Notes: decreasing heading by 0.4em with every subsequent heading level
+-------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------
+[Table of contents]
+
+1. Body / #body
+2. Header / #header
+3. Navigation / #navbar
+4. Content / #content
+5. Sidebar / #sidebar
+6. Boxes / .box
+7. Dashboard cards / .card
+8. Miscellaneous
+9. Adjustments to dafault behaviors
+10. Colors / .teal, .olive, .violet, .orange, .darkgray, .blue, .grey
+11. Responsive properties
+-------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------
+[1. Body / #body]
+*/
+@font-face {
+ font-family: "Lato";
+ font-style: normal;
+ font-weight: 400;
+ font-display: auto;
+ src: url("../font/Lato-Regular.eot");
+ src: url("../font/Lato-Regular.eot?#iefix") format("embedded-opentype"), url("../font/Lato-Regular.woff") format("woff"), url("../font/Lato-Regular.ttf") format("truetype");
+}
+
+body, h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6, p, a, td {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+}
+
+body {
+ width: 100%;
+ height: 100%;
+ background: #f1f1f1;
+ font-family: "Lato", "Helvetica Neue", Arial, Helvetica, sans-serif;
+ font-size: 1rem;
+ color: #444;
+}
+
+.wrapper {
+ display: flex;
+ width: 100%;
+ align-items: stretch;
+ overflow-x: hidden
+}
+
+#body {
+ width: 100%;
+ padding: 0;
+ min-height: 100vh;
+ transition: all 0.3s;
+}
+
+/*------------------------------------------------------------------
+[2. Header / #header]
+*/
+#body>.navbar {
+ padding: 0 1.5rem;
+ min-height: 54px;
+}
+
+/*------------------------------------------------------------------
+[3. Navigation / #navbar] - see /components/navbar/navbar-dropdown.css
+*/
+.default-light-menu {
+ border: none !important;
+ box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.5) inset !important;
+ color: #fff;
+}
+
+.default-light-menu:hover {
+ background: #2196F3 !important;
+ color: #fff;
+}
+
+/*------------------------------------------------------------------
+[4. Content / #content]
+*/
+#body>.content {
+ position: relative;
+ padding: .5rem;
+}
+
+#body .content .page-title h3 {
+ margin: 1rem 0;
+}
+
+/*------------------------------------------------------------------
+[5. Sidebar / #sidebar] - see /components/sidebar/sidebar-default.css
+*/
+
+/*------------------------------------------------------------------
+[6. Boxes / .box]
+*/
+.box {
+ position: relative;
+ border-radius: 3px;
+ background: #ffffff;
+ border-top: 3px solid #d2d6de;
+ margin-bottom: 20px;
+ width: 100%;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+}
+
+.box-body {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ padding: 10px;
+}
+
+.box-footer {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ border-top: 1px solid #f4f4f4;
+ padding: 10px 20px;
+ background-color: #FAFAFA;
+ text-align: right;
+}
+
+.box-primary {
+ border-top-color: #22a1f9;
+}
+
+/*------------------------------------------------------------------
+[7. Dashboard Cards / .card]
+*/
+.card {
+ margin-bottom: 15px;
+}
+
+.card .content {
+ padding: 15px 15px 10px 15px;
+}
+
+.card .content .icon-big {
+ font-size: 3em;
+ min-height: 64px;
+ line-height: 64px;
+}
+
+.card .content .number {
+ font-size: 1.5em;
+ text-align: right;
+ font-weight: bolder;
+}
+
+.card .content .footer {
+ background-attachment: fixed;
+ position: relative;
+ padding: 0;
+ line-height: 30px;
+}
+
+.card .content .stats {
+ display: inline-block;
+ color: #a9a9a9;
+}
+
+/*------------------------------------------------------------------
+[8. Miscellaneous ]
+*/
+.line {
+ border-bottom: 1px solid #E0E0E0;
+}
+
+.nav-pills {
+ padding: 15px;
+ background-color: #E0E0E0;
+ -webkit-box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.05);
+ box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.05);
+}
+
+.btn-rounded {
+ border-radius: 10em;
+ padding: 6px 8px;
+ font-size: small;
+ text-transform: none;
+ text-shadow: none !important;
+ background: #eaeaea;
+ border-color: transparent;
+ border: none;
+}
+
+.btn-rounded:hover {
+ border-color: transparent;
+ border: none;
+}
+
+#myTab {
+ margin-bottom: 15px;
+}
+
+.no-margin {
+ margin: 0;
+}
+
+.dfd {
+ width: 100%;
+}
+
+.bg-lighter-grey {
+ background: #FAFAFA;
+}
+
+/*------------------------------------------------------------------
+[9. Adjustments to default behaviors]
+*/
+a,
+a:hover,
+a:focus {
+ text-decoration: none;
+ transition: all 0.3s;
+}
+
+.btn.focus,
+.btn:focus {
+ box-shadow: none;
+}
+
+.btn.btn-square {
+ border-radius: 0;
+}
+
+.table td,
+.table th {
+ vertical-align: middle;
+}
+
+table.dataTable thead .sorting:before,
+table.dataTable thead .sorting:after,
+table.dataTable thead .sorting_asc:before,
+table.dataTable thead .sorting_asc:after,
+table.dataTable thead .sorting_desc:before,
+table.dataTable thead .sorting_desc:after,
+table.dataTable thead .sorting_asc_disabled:before,
+table.dataTable thead .sorting_asc_disabled:after,
+table.dataTable thead .sorting_desc_disabled:before,
+table.dataTable thead .sorting_desc_disabled:after {
+ font-size: .8rem;
+ bottom: .9rem;
+}
+
+.dataTables_info {
+ visibility: hidden;
+}
+
+table.dataTable>tbody>tr.child ul.dtr-details {
+ display: block;
+}
+
+.nav-tabs {
+ border-bottom: 2px solid #dee2e6;
+}
+
+.nav-tabs .nav-item {
+ margin-bottom: -2px;
+}
+
+.nav-tabs .nav-link {
+ border: none;
+ -webkit-transition: color .1s ease;
+ transition: color .1s ease;
+}
+
+.nav-tabs .nav-item.show .nav-link,
+.nav-tabs .nav-link.active {
+ color: #007bff;
+ background-color: #fff;
+ border-bottom: 2px solid #22a1f9;
+
+}
+
+.tab-content {
+ padding: 15px;
+}
+
+.svg-inline--fa {
+ min-width: 15px;
+}
+
+.display-absolute {
+ position: absolute;
+}
+
+.large-icon {
+ font-size: 3em;
+}
+
+.license span {
+ margin-bottom: 1em;
+}
+
+/*------------------------------------------------------------------
+[10. Colors / .teal, .olive, .violet, .orange, .darkgray, .blue, .grey]
+*/
+.teal {
+ color: #00b5ad !important;
+}
+
+.olive {
+ color: #b5cc18 !important;
+}
+
+.violet {
+ color: #6435c9 !important;
+}
+
+.orange {
+ color: #f2711c !important;
+}
+
+.darkgray {
+ color: darkgray !important;
+}
+
+.blue {
+ color: #2185d0 !important;
+}
+
+.grey {
+ color: #767676 !important;
+}
+
+/*------------------------------------------------------------------
+[11. Responsive properties]
+*/
+@media (max-width: 768px) {
+ .display-absolute {
+ position: relative;
+ }
+}
+
+@media (max-width: 680px) {
+ #body.active .navbar-collapse {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto;
+ }
+
+ .nav-dropdown .nav-link-menu {
+ position: fixed !important;
+ top: 52px !important;
+ width: 100% !important;
+ margin-top: 0;
+ }
+
+ .nav-dropdown .nav-link {
+ padding: 10px;
+ }
+
+ .nav-dropdown .nav-link-menu::before {
+ right: 50%;
+ }
+
+ #body .navbar-collapse {
+ display: none !important;
+ }
+
+ #body .nav-dropdown .nav-item span {
+ display: none !important;
+ }
+
+ .btn-header {
+ display: none;
+ }
+}
+
+@media (min-width: 200px) {
+ .navbar-expand-lg .navbar-collapse {
+ display: -ms-flexbox !important;
+ display: flex !important;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto;
+ }
+
+ .navbar-expand-lg .navbar-nav {
+ -ms-flex-direction: row;
+ flex-direction: row;
+ }
+}
\ No newline at end of file
diff --git a/static/css/nerve.css b/static/css/nerve.css
new file mode 100644
index 0000000..52a147c
--- /dev/null
+++ b/static/css/nerve.css
@@ -0,0 +1,131 @@
+#toc_container {
+ background: #f9f9f9 none repeat scroll 0 0;
+ border: 1px solid #aaa;
+ display: table;
+ font-size: 95%;
+ margin-bottom: 1em;
+ padding: 20px;
+ width: auto;
+}
+
+.toc_title {
+ font-weight: 700;
+ text-align: center;
+}
+
+#toc_container li, #toc_container ul, #toc_container ul li{
+ list-style: outside none none !important;
+}
+
+pre.bash {
+ background-color: #000;
+ border: 1px solid #000;
+ color: white;
+ padding: 8px;
+ font-family: courier new;
+}
+
+pre.topology {
+ background-color: #000;
+ border: 1px solid #000;
+ color: white;
+ padding: 8px;
+ font-family: courier new;
+ height: auto;
+ max-height: 200px;
+ overflow: auto;
+ word-break: normal !important;
+ word-wrap: normal !important;
+ white-space: pre !important;
+ display: flex;
+ flex-direction: column-reverse;
+}
+
+span.required {
+ font-style: italic;
+ font-size: 10px;
+ color:blue;
+ font-weight: bold;
+}
+span.banner_sm {
+ font-size: 7px;
+}
+
+.navbar-status {
+ font-size: 14px;
+}
+
+.scan_type_indicator {
+ font-size:10px;
+ font-weight: bold;
+ color:red;
+ letter-spacing: 2px;
+}
+
+.logo-text {
+ font-size:8px;
+ letter-spacing: 2.5px;
+ position:relative;
+ color:lightgrey;
+ top:4px;
+ right:-5px;
+ font-weight: bold;
+}
+
+.c-lightgreen {
+ color:lightgreen;
+}
+
+.c-grey {
+ color:grey;
+}
+
+.c-white {
+ color:white;
+}
+.c-yellow {
+ color:yellow
+}
+
+.c-green {
+ color:lightgreen;
+}
+
+.c-lightgreen {
+ color:rgb(78, 177, 78);
+}
+
+.c-black {
+ color:black
+}
+
+.c-darkgreen {
+ color:darkgreen
+}
+.c-orange {
+ color:orange
+}
+
+.c-red {
+ color:red
+}
+
+.critical {
+ color:black
+}
+
+.high {
+ color:red
+}
+
+.medium {
+ color:orange
+}
+
+.low {
+ color:green
+}
+
+.informational {
+ color:blue
+}
diff --git a/static/font/Lato-Regular.eot b/static/font/Lato-Regular.eot
new file mode 100755
index 0000000..f36f480
Binary files /dev/null and b/static/font/Lato-Regular.eot differ
diff --git a/static/font/Lato-Regular.ttf b/static/font/Lato-Regular.ttf
new file mode 100755
index 0000000..db3c3a5
Binary files /dev/null and b/static/font/Lato-Regular.ttf differ
diff --git a/static/font/Lato-Regular.woff b/static/font/Lato-Regular.woff
new file mode 100755
index 0000000..52074ee
Binary files /dev/null and b/static/font/Lato-Regular.woff differ
diff --git a/static/img/black_circle.png b/static/img/black_circle.png
new file mode 100644
index 0000000..a9c1313
Binary files /dev/null and b/static/img/black_circle.png differ
diff --git a/static/img/black_triangle.jpg b/static/img/black_triangle.jpg
new file mode 100644
index 0000000..c3b6ab2
Binary files /dev/null and b/static/img/black_triangle.jpg differ
diff --git a/static/img/black_triangle.png b/static/img/black_triangle.png
new file mode 100644
index 0000000..1027086
Binary files /dev/null and b/static/img/black_triangle.png differ
diff --git a/static/img/blue_square.png b/static/img/blue_square.png
new file mode 100644
index 0000000..ab5d3cc
Binary files /dev/null and b/static/img/blue_square.png differ
diff --git a/static/img/green_circle.png b/static/img/green_circle.png
new file mode 100644
index 0000000..8dfa29c
Binary files /dev/null and b/static/img/green_circle.png differ
diff --git a/static/img/nerve_logo.png b/static/img/nerve_logo.png
new file mode 100644
index 0000000..711a63c
Binary files /dev/null and b/static/img/nerve_logo.png differ
diff --git a/static/img/nerve_logo_black.png b/static/img/nerve_logo_black.png
new file mode 100644
index 0000000..6663953
Binary files /dev/null and b/static/img/nerve_logo_black.png differ
diff --git a/static/img/network.png b/static/img/network.png
new file mode 100644
index 0000000..510ffa2
Binary files /dev/null and b/static/img/network.png differ
diff --git a/static/img/orange_circle.png b/static/img/orange_circle.png
new file mode 100644
index 0000000..ab8a0d6
Binary files /dev/null and b/static/img/orange_circle.png differ
diff --git a/static/img/paytm-black.png b/static/img/paytm-black.png
new file mode 100644
index 0000000..46732ee
Binary files /dev/null and b/static/img/paytm-black.png differ
diff --git a/static/img/red_circle.png b/static/img/red_circle.png
new file mode 100644
index 0000000..9655c17
Binary files /dev/null and b/static/img/red_circle.png differ
diff --git a/static/img/report.png b/static/img/report.png
new file mode 100644
index 0000000..622ff84
Binary files /dev/null and b/static/img/report.png differ
diff --git a/static/img/report_csv.png b/static/img/report_csv.png
new file mode 100644
index 0000000..3094e39
Binary files /dev/null and b/static/img/report_csv.png differ
diff --git a/static/img/report_html.png b/static/img/report_html.png
new file mode 100644
index 0000000..ee28ee5
Binary files /dev/null and b/static/img/report_html.png differ
diff --git a/static/img/report_txt.png b/static/img/report_txt.png
new file mode 100644
index 0000000..b0b5011
Binary files /dev/null and b/static/img/report_txt.png differ
diff --git a/static/js/dashboard-charts.js b/static/js/dashboard-charts.js
new file mode 100644
index 0000000..7a6ce20
--- /dev/null
+++ b/static/js/dashboard-charts.js
@@ -0,0 +1,84 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+var trafficchart = document.getElementById("trafficflow");
+var saleschart = document.getElementById("sales");
+
+var myChart1 = new Chart(trafficchart, {
+ type: 'line',
+ data: {
+ labels: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
+ datasets: [{
+ backgroundColor: "rgba(48, 164, 255, 0.5)",
+ borderColor: "rgba(48, 164, 255, 0.8)",
+ data: ['1135', '1135', '1140','1168', '1150', '1145','1155', '1155', '1150','1160', '1185', '1190'],
+ label: '',
+ fill: true
+ }]
+ },
+ options: {
+ responsive: true,
+ title: {display: false,text: 'Chart'},
+ legend: {position: 'top',display: false,},
+ tooltips: {mode: 'index',intersect: false,},
+ hover: {mode: 'nearest',intersect: true},
+ scales: {
+ xAxes: [{
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'Months'
+ }
+ }],
+ yAxes: [{
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'Number of Visitors'
+ }
+ }]
+ }
+ }
+});
+
+var myChart2 = new Chart(saleschart, {
+ type: 'bar',
+ data: {
+ labels: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
+ datasets: [{
+ label: 'Income',
+ backgroundColor: "rgba(76, 175, 80, 0.5)",
+ borderColor: "#6da252",
+ borderWidth: 1,
+ data: ["280","300","400","600","450","400","500","550","450","650","950","1000"],
+ }]
+ },
+ options: {
+ responsive: true,
+ title: {display: false,text: 'Chart'},
+ legend: {position: 'top',display: false,},
+ tooltips: {mode: 'index',intersect: false,},
+ hover: {mode: 'nearest',intersect: true},
+ scales: {
+ xAxes: [{
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'Months'
+ }
+ }],
+ yAxes: [{
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'Number of Sales'
+ }
+ }]
+ }
+ }
+});
\ No newline at end of file
diff --git a/static/js/form-validator.js b/static/js/form-validator.js
new file mode 100644
index 0000000..5dc5c27
--- /dev/null
+++ b/static/js/form-validator.js
@@ -0,0 +1,26 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+// Starter JavaScript for disabling form submissions if there are invalid fields
+(function() {
+ 'use strict';
+ window.addEventListener('load', function() {
+ // Fetch all the forms we want to apply custom Bootstrap validation styles to
+ var forms = document.getElementsByClassName('needs-validation');
+ // Loop over them and prevent submission
+ var validation = Array.prototype.filter.call(forms, function(form) {
+ form.addEventListener('submit', function(event) {
+ if (form.checkValidity() === false) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ form.classList.add('was-validated');
+ }, false);
+ });
+ }, false);
+})();
\ No newline at end of file
diff --git a/static/js/fullcalendar-script.js b/static/js/fullcalendar-script.js
new file mode 100644
index 0000000..3dc5552
--- /dev/null
+++ b/static/js/fullcalendar-script.js
@@ -0,0 +1,160 @@
+document.addEventListener('DOMContentLoaded', function() {
+ var calendarEl = document.getElementById('calendar');
+ var calendar = new FullCalendar.Calendar(calendarEl, {
+ plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
+ height: 'parent',
+ header: {
+ left: 'prev,next today',
+ center: 'title',
+ right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
+ },
+ defaultView: 'dayGridMonth',
+ defaultDate: '2019-06-12',
+ navLinks: true, // can click day/week names to navigate views
+ editable: true,
+ eventLimit: true, // allow "more" link when too many events
+ events: [
+ {
+ title: 'All Day Event',
+ start: '2019-06-01',
+ },
+ {
+ title: 'Long Event',
+ start: '2019-06-07',
+ end: '2019-06-10'
+ },
+ {
+ groupId: 999,
+ title: 'Repeating Event',
+ start: '2019-06-09T16:00:00'
+ },
+ {
+ groupId: 999,
+ title: 'Repeating Event',
+ start: '2019-06-16T16:00:00'
+ },
+ {
+ title: 'Conference',
+ start: '2019-06-11',
+ end: '2019-06-13'
+ },
+ {
+ title: 'Meeting',
+ start: '2019-06-12T10:30:00',
+ end: '2019-06-12T12:30:00'
+ },
+ {
+ title: 'Lunch',
+ start: '2019-06-12T12:00:00'
+ },
+ {
+ title: 'Meeting',
+ start: '2019-06-12T14:30:00'
+ },
+ {
+ title: 'Happy Hour',
+ start: '2019-06-12T17:30:00'
+ },
+ {
+ title: 'Dinner',
+ start: '2019-06-12T20:00:00'
+ },
+ {
+ title: 'Birthday Party',
+ start: '2019-06-13T07:00:00'
+ },
+ {
+ title: 'Click for Google',
+ url: 'http://google.com/',
+ start: '2019-06-28'
+ }
+ ]
+ });
+
+ calendar.render();
+});
+
+document.addEventListener('DOMContentLoaded', function() {
+ var calendarList = document.getElementById('calendar-list');
+
+ var calendarL = new FullCalendar.Calendar(calendarList, {
+ plugins: [ 'list' ],
+
+ header: {
+ left: 'prev,next today',
+ center: 'title',
+ right: 'listDay,listWeek,dayGridMonth'
+ },
+
+ // customize the button names,
+ // otherwise they'd all just say "list"
+ views: {
+ listDay: { buttonText: 'list day' },
+ listWeek: { buttonText: 'list week' }
+ },
+
+ defaultView: 'listWeek',
+ defaultDate: '2019-06-12',
+ navLinks: true, // can click day/week names to navigate views
+ editable: true,
+ eventLimit: true, // allow "more" link when too many events
+ events: [
+ {
+ title: 'All Day Event',
+ start: '2019-06-01'
+ },
+ {
+ title: 'Long Event',
+ start: '2019-06-07',
+ end: '2019-06-10'
+ },
+ {
+ groupId: 999,
+ title: 'Repeating Event',
+ start: '2019-06-09T16:00:00'
+ },
+ {
+ groupId: 999,
+ title: 'Repeating Event',
+ start: '2019-06-16T16:00:00'
+ },
+ {
+ title: 'Conference',
+ start: '2019-06-11',
+ end: '2019-06-13'
+ },
+ {
+ title: 'Meeting',
+ start: '2019-06-12T10:30:00',
+ end: '2019-06-12T12:30:00'
+ },
+ {
+ title: 'Lunch',
+ start: '2019-06-12T12:00:00'
+ },
+ {
+ title: 'Meeting',
+ start: '2019-06-12T14:30:00'
+ },
+ {
+ title: 'Happy Hour',
+ start: '2019-06-12T17:30:00'
+ },
+ {
+ title: 'Dinner',
+ start: '2019-06-12T20:00:00'
+ },
+ {
+ title: 'Birthday Party',
+ start: '2019-06-13T07:00:00'
+ },
+ {
+ title: 'Click for Google',
+ url: 'http://google.com/',
+ start: '2019-06-28'
+ }
+ ]
+ });
+
+ calendarL.render();
+});
\ No newline at end of file
diff --git a/static/js/initiate-datatables.js b/static/js/initiate-datatables.js
new file mode 100644
index 0000000..d2bbcc3
--- /dev/null
+++ b/static/js/initiate-datatables.js
@@ -0,0 +1,8 @@
+// Initiate datatables in roles, tables, users page
+$('#dataTables-example').DataTable({
+ responsive: true,
+ pageLength: 20,
+ lengthChange: false,
+ searching: true,
+ ordering: true
+});
\ No newline at end of file
diff --git a/static/js/initiate-summernote.js b/static/js/initiate-summernote.js
new file mode 100644
index 0000000..0b9a2b0
--- /dev/null
+++ b/static/js/initiate-summernote.js
@@ -0,0 +1,12 @@
+// Initiate summernote wysiwyg editor
+$('#summernote').summernote({
+ dialogsInBody: true,
+ minHeight: 300,
+ toolbar: [
+ ['style', ['bold', 'italic', 'underline', 'clear']],
+ ['font', ['strikethrough']],
+ ['para', ['paragraph']],
+ ['list', ['ul']],
+ ['numberlist', ['ol']]
+ ]
+});
\ No newline at end of file
diff --git a/static/js/script.js b/static/js/script.js
new file mode 100644
index 0000000..0b508de
--- /dev/null
+++ b/static/js/script.js
@@ -0,0 +1,27 @@
+/*------------------------------------------------------------------
+* Bootstrap Simple Admin Template
+* Email: heyalexluna@gmail.com
+* Version: 1.1
+* Author: Alexis Luna
+* Copyright 2019 Alexis Luna
+* Website: https://github.com/mralexisluna/bootstrap-simple-admin-template
+-------------------------------------------------------------------*/
+// Toggle sidebar on Menu button click
+$('#sidebarCollapse').on('click', function () {
+ $('#sidebar').toggleClass('active');
+ $('#body').toggleClass('active');
+});
+
+// Auto-hide sidebar on window resize if window size is small
+// $(window).on('resize', function () {
+// if ($(window).width() <= 768) {
+// $('#sidebar, #body').addClass('active');
+// }
+// });
+
+
+toastr.options = {
+ "debug": false,
+ "positionClass": "toast-bottom-right",
+ "closeButton": true
+}
diff --git a/static/js/vis-network.min.js b/static/js/vis-network.min.js
new file mode 100644
index 0000000..fced473
--- /dev/null
+++ b/static/js/vis-network.min.js
@@ -0,0 +1,59 @@
+/**
+ * vis-network
+ * https://visjs.github.io/vis-network/
+ *
+ * A dynamic, browser-based visualization library.
+ *
+ * @version 7.10.0
+ * @date 2020-07-11T12:33:22.079Z
+ *
+ * @copyright (c) 2011-2017 Almende B.V, http://almende.com
+ * @copyright (c) 2017-2019 visjs contributors, https://github.com/visjs
+ *
+ * @license
+ * vis.js is dual licensed under both
+ *
+ * 1. The Apache 2.0 License
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * and
+ *
+ * 2. The MIT License
+ * http://opensource.org/licenses/MIT
+ *
+ * vis.js may be distributed under either license.
+ */
+!function(g,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((g=g||self).vis=g.vis||{})}(this,(function(g){var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function e(g,t,e){return g(e={path:t,exports:{},require:function(g,t){return C(null==t&&e.path)}},e.exports),e.exports}function A(g){return g&&g.default||g}function C(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}var I=function(g){return g&&g.Math==Math&&g},i=I("object"==typeof globalThis&&globalThis)||I("object"==typeof window&&window)||I("object"==typeof self&&self)||I("object"==typeof t&&t)||Function("return this")(),n=function(g){try{return!!g()}catch(g){return!0}},o=!n((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),r={}.propertyIsEnumerable,s=Object.getOwnPropertyDescriptor,a={f:s&&!r.call({1:2},1)?function(g){var t=s(this,g);return!!t&&t.enumerable}:r},h=function(g,t){return{enumerable:!(1&g),configurable:!(2&g),writable:!(4&g),value:t}},d={}.toString,l=function(g){return d.call(g).slice(8,-1)},c="".split,u=n((function(){return!Object("z").propertyIsEnumerable(0)}))?function(g){return"String"==l(g)?c.call(g,""):Object(g)}:Object,f=function(g){if(null==g)throw TypeError("Can't call method on "+g);return g},p=function(g){return u(f(g))},v=function(g){return"object"==typeof g?null!==g:"function"==typeof g},y=function(g,t){if(!v(g))return g;var e,A;if(t&&"function"==typeof(e=g.toString)&&!v(A=e.call(g)))return A;if("function"==typeof(e=g.valueOf)&&!v(A=e.call(g)))return A;if(!t&&"function"==typeof(e=g.toString)&&!v(A=e.call(g)))return A;throw TypeError("Can't convert object to primitive value")},m={}.hasOwnProperty,b=function(g,t){return m.call(g,t)},w=i.document,k=v(w)&&v(w.createElement),x=function(g){return k?w.createElement(g):{}},D=!o&&!n((function(){return 7!=Object.defineProperty(x("div"),"a",{get:function(){return 7}}).a})),O=Object.getOwnPropertyDescriptor,T={f:o?O:function(g,t){if(g=p(g),t=y(t,!0),D)try{return O(g,t)}catch(g){}if(b(g,t))return h(!a.f.call(g,t),g[t])}},E=/#|\.prototype\./,N=function(g,t){var e=M[R(g)];return e==S||e!=P&&("function"==typeof t?n(t):!!t)},R=N.normalize=function(g){return String(g).replace(E,".").toLowerCase()},M=N.data={},P=N.NATIVE="N",S=N.POLYFILL="P",z=N,_={},Z=function(g){if("function"!=typeof g)throw TypeError(String(g)+" is not a function");return g},B=function(g,t,e){if(Z(g),void 0===t)return g;switch(e){case 0:return function(){return g.call(t)};case 1:return function(e){return g.call(t,e)};case 2:return function(e,A){return g.call(t,e,A)};case 3:return function(e,A,C){return g.call(t,e,A,C)}}return function(){return g.apply(t,arguments)}},F=function(g){if(!v(g))throw TypeError(String(g)+" is not an object");return g},Y=Object.defineProperty,G={f:o?Y:function(g,t,e){if(F(g),t=y(t,!0),F(e),D)try{return Y(g,t,e)}catch(g){}if("get"in e||"set"in e)throw TypeError("Accessors not supported");return"value"in e&&(g[t]=e.value),g}},L=o?function(g,t,e){return G.f(g,t,h(1,e))}:function(g,t,e){return g[t]=e,g},j=T.f,V=function(g){var t=function(t,e,A){if(this instanceof g){switch(arguments.length){case 0:return new g;case 1:return new g(t);case 2:return new g(t,e)}return new g(t,e,A)}return g.apply(this,arguments)};return t.prototype=g.prototype,t},W=function(g,t){var e,A,C,I,n,o,r,s,a=g.target,h=g.global,d=g.stat,l=g.proto,c=h?i:d?i[a]:(i[a]||{}).prototype,u=h?_:_[a]||(_[a]={}),f=u.prototype;for(C in t)e=!z(h?C:a+(d?".":"#")+C,g.forced)&&c&&b(c,C),n=u[C],e&&(o=g.noTargetGet?(s=j(c,C))&&s.value:c[C]),I=e&&o?o:t[C],e&&typeof n==typeof I||(r=g.bind&&e?B(I,i):g.wrap&&e?V(I):l&&"function"==typeof I?B(Function.call,I):I,(g.sham||I&&I.sham||n&&n.sham)&&L(r,"sham",!0),u[C]=r,l&&(b(_,A=a+"Prototype")||L(_,A,{}),_[A][C]=I,g.real&&f&&!f[C]&&L(f,C,I)))},H=[].slice,U={},Q=function(g,t,e){if(!(t in U)){for(var A=[],C=0;C0?tg:gg)(g)},Ag=Math.min,Cg=function(g){return g>0?Ag(eg(g),9007199254740991):0},Ig=Math.max,ig=Math.min,ng=function(g,t){var e=eg(g);return e<0?Ig(e+t,0):ig(e,t)},og=function(g){return function(t,e,A){var C,I=p(t),i=Cg(I.length),n=ng(A,i);if(g&&e!=e){for(;i>n;)if((C=I[n++])!=C)return!0}else for(;i>n;n++)if((g||n in I)&&I[n]===e)return g||n||0;return!g&&-1}},rg={includes:og(!0),indexOf:og(!1)},sg={},ag=rg.indexOf,hg=function(g,t){var e,A=p(g),C=0,I=[];for(e in A)!b(sg,e)&&b(A,e)&&I.push(e);for(;t.length>C;)b(A,e=t[C++])&&(~ag(I,e)||I.push(e));return I},dg=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],lg=Object.keys||function(g){return hg(g,dg)},cg={f:Object.getOwnPropertySymbols},ug=function(g){return Object(f(g))},fg=Object.assign,pg=Object.defineProperty,vg=!fg||n((function(){if(o&&1!==fg({b:1},fg(pg({},"a",{enumerable:!0,get:function(){pg(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var g={},t={},e=Symbol();return g[e]=7,"abcdefghijklmnopqrst".split("").forEach((function(g){t[g]=g})),7!=fg({},g)[e]||"abcdefghijklmnopqrst"!=lg(fg({},t)).join("")}))?function(g,t){for(var e=ug(g),A=arguments.length,C=1,I=cg.f,i=a.f;A>C;)for(var n,r=u(arguments[C++]),s=I?lg(r).concat(I(r)):lg(r),h=s.length,d=0;h>d;)n=s[d++],o&&!i.call(r,n)||(e[n]=r[n]);return e}:fg;W({target:"Object",stat:!0,forced:Object.assign!==vg},{assign:vg});var yg=_.Object.assign;function mg(g,t,e,A){g.beginPath(),g.arc(t,e,A,0,2*Math.PI,!1),g.closePath()}function bg(g,t,e,A,C,I){var i=Math.PI/180;A-2*I<0&&(I=A/2),C-2*I<0&&(I=C/2),g.beginPath(),g.moveTo(t+I,e),g.lineTo(t+A-I,e),g.arc(t+A-I,e+I,I,270*i,360*i,!1),g.lineTo(t+A,e+C-I),g.arc(t+A-I,e+C-I,I,0,90*i,!1),g.lineTo(t+I,e+C),g.arc(t+I,e+C-I,I,90*i,180*i,!1),g.lineTo(t,e+I),g.arc(t+I,e+I,I,180*i,270*i,!1),g.closePath()}function wg(g,t,e,A,C){var I=A/2*.5522848,i=C/2*.5522848,n=t+A,o=e+C,r=t+A/2,s=e+C/2;g.beginPath(),g.moveTo(t,s),g.bezierCurveTo(t,s-i,r-I,e,r,e),g.bezierCurveTo(r+I,e,n,s-i,n,s),g.bezierCurveTo(n,s+i,r+I,o,r,o),g.bezierCurveTo(r-I,o,t,s+i,t,s),g.closePath()}function kg(g,t,e,A,C){var I=C*(1/3),i=A/2*.5522848,n=I/2*.5522848,o=t+A,r=e+I,s=t+A/2,a=e+I/2,h=e+(C-I/2),d=e+C;g.beginPath(),g.moveTo(o,a),g.bezierCurveTo(o,a+n,s+i,r,s,r),g.bezierCurveTo(s-i,r,t,a+n,t,a),g.bezierCurveTo(t,a-n,s-i,e,s,e),g.bezierCurveTo(s+i,e,o,a-n,o,a),g.lineTo(o,h),g.bezierCurveTo(o,h+n,s+i,d,s,d),g.bezierCurveTo(s-i,d,t,h+n,t,h),g.lineTo(t,a)}function xg(g,t,e,A,C,I){g.beginPath(),g.moveTo(t,e);for(var i=I.length,n=A-t,o=C-e,r=o/n,s=Math.sqrt(n*n+o*o),a=0,h=!0,d=0,l=+I[0];s>=.1;)(l=+I[a++%i])>s&&(l=s),d=Math.sqrt(l*l/(1+r*r)),t+=d=n<0?-d:d,e+=r*d,!0===h?g.lineTo(t,e):g.moveTo(t,e),s-=l,h=!h}var Dg={circle:mg,dashedLine:xg,database:kg,diamond:function(g,t,e,A){g.beginPath(),g.lineTo(t,e+A),g.lineTo(t+A,e),g.lineTo(t,e-A),g.lineTo(t-A,e),g.closePath()},ellipse:wg,ellipse_vis:wg,hexagon:function(g,t,e,A){g.beginPath();var C=2*Math.PI/6;g.moveTo(t+A,e);for(var I=1;I<6;I++)g.lineTo(t+A*Math.cos(C*I),e+A*Math.sin(C*I));g.closePath()},roundRect:bg,square:function(g,t,e,A){g.beginPath(),g.rect(t-A,e-A,2*A,2*A),g.closePath()},star:function(g,t,e,A){g.beginPath(),e+=.1*(A*=.82);for(var C=0;C<10;C++){var I=C%2==0?1.3*A:.5*A;g.lineTo(t+I*Math.sin(2*C*Math.PI/10),e-I*Math.cos(2*C*Math.PI/10))}g.closePath()},triangle:function(g,t,e,A){g.beginPath(),e+=.275*(A*=1.15);var C=2*A,I=C/2,i=Math.sqrt(3)/6*C,n=Math.sqrt(C*C-I*I);g.moveTo(t,e-(n-i)),g.lineTo(t+I,e+i),g.lineTo(t-I,e+i),g.lineTo(t,e-(n-i)),g.closePath()},triangleDown:function(g,t,e,A){g.beginPath(),e-=.275*(A*=1.15);var C=2*A,I=C/2,i=Math.sqrt(3)/6*C,n=Math.sqrt(C*C-I*I);g.moveTo(t,e+(n-i)),g.lineTo(t+I,e-i),g.lineTo(t-I,e-i),g.lineTo(t,e+(n-i)),g.closePath()}};var Og=e((function(g){function t(g){if(g)return function(g){for(var e in t.prototype)g[e]=t.prototype[e];return g}(g)}g.exports=t,t.prototype.on=t.prototype.addEventListener=function(g,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+g]=this._callbacks["$"+g]||[]).push(t),this},t.prototype.once=function(g,t){function e(){this.off(g,e),t.apply(this,arguments)}return e.fn=t,this.on(g,e),this},t.prototype.off=t.prototype.removeListener=t.prototype.removeAllListeners=t.prototype.removeEventListener=function(g,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var e,A=this._callbacks["$"+g];if(!A)return this;if(1==arguments.length)return delete this._callbacks["$"+g],this;for(var C=0;CI;)G.f(g,e=A[I++],t[e]);return g};W({target:"Object",stat:!0,forced:!o,sham:!o},{defineProperties:Ng});var Rg=e((function(g){var t=_.Object,e=g.exports=function(g,e){return t.defineProperties(g,e)};t.defineProperties.sham&&(e.sham=!0)})),Mg=function(g){return"function"==typeof g?g:void 0},Pg=function(g,t){return arguments.length<2?Mg(_[g])||Mg(i[g]):_[g]&&_[g][t]||i[g]&&i[g][t]},Sg=dg.concat("length","prototype"),zg={f:Object.getOwnPropertyNames||function(g){return hg(g,Sg)}},_g=Pg("Reflect","ownKeys")||function(g){var t=zg.f(F(g)),e=cg.f;return e?t.concat(e(g)):t},Zg=function(g,t,e){var A=y(t);A in g?G.f(g,A,h(0,e)):g[A]=e};W({target:"Object",stat:!0,sham:!o},{getOwnPropertyDescriptors:function(g){for(var t,e,A=p(g),C=T.f,I=_g(A),i={},n=0;I.length>n;)void 0!==(e=C(A,t=I[n++]))&&Zg(i,t,e);return i}});var Bg=_.Object.getOwnPropertyDescriptors,Fg=T.f,Yg=n((function(){Fg(1)}));W({target:"Object",stat:!0,forced:!o||Yg,sham:!o},{getOwnPropertyDescriptor:function(g,t){return Fg(p(g),t)}});var Gg,Lg=e((function(g){var t=_.Object,e=g.exports=function(g,e){return t.getOwnPropertyDescriptor(g,e)};t.getOwnPropertyDescriptor.sham&&(e.sham=!0)})),jg=Lg,Vg=!!Object.getOwnPropertySymbols&&!n((function(){return!String(Symbol())})),Wg=Vg&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Hg=Array.isArray||function(g){return"Array"==l(g)},Ug=Pg("document","documentElement"),Qg=i["__core-js_shared__"]||function(g,t){try{L(i,g,t)}catch(e){i[g]=t}return t}("__core-js_shared__",{}),Kg=e((function(g){(g.exports=function(g,t){return Qg[g]||(Qg[g]=void 0!==t?t:{})})("versions",[]).push({version:"3.6.4",mode:"pure",copyright:"© 2020 Denis Pushkarev (zloirock.ru)"})})),Xg=0,Jg=Math.random(),qg=function(g){return"Symbol("+String(void 0===g?"":g)+")_"+(++Xg+Jg).toString(36)},$g=Kg("keys"),gt=function(g){return $g[g]||($g[g]=qg(g))},tt=gt("IE_PROTO"),et=function(){},At=function(g){return"