From 65807d0f3866138ae46929e4fca9cadcc742b1ee Mon Sep 17 00:00:00 2001 From: Astatin3 <77305074+Astatin3@users.noreply.github.com> Date: Mon, 15 Apr 2024 22:28:20 -0600 Subject: [PATCH] Very WIP --- .vscode/launch.json | 15 + LICENSE | 2 +- README.md | 11 +- data/creds.json | 23 + data/ssl.crt | 20 + data/ssl.key | 28 + exclude.conf | 1450 +++++++++++++++++++++++++++++++ html/login.html | 26 + html/nav.html | 33 + html/src/UbuntuMono-R.ttf | Bin 0 -> 205748 bytes html/src/auth.js | 65 ++ html/src/jsonpack.js | 559 ++++++++++++ html/src/main.js | 45 + html/src/packets.js | 106 +++ html/src/pico.min.css | 5 + html/src/style.css | 293 +++++++ html/src/utils.js | 274 ++++++ libs/scanner.py | 68 ++ libs/scanutils.py | 12 + libs/test.py | 45 + main.py | 110 +++ modules/main/Dashboard.html | 19 + modules/main/adminSettings.html | 248 ++++++ modules/main/main.py | 206 +++++ modules/main/module.json | 38 + modules/main/userSettings.html | 105 +++ modules/scan/main.py | 46 + modules/scan/module.json | 20 + modules/scan/scan.html | 23 + paused.conf | 150 ++++ src/auth.py | 192 ++++ src/jsonpack.py | 273 ++++++ src/modules.py | 280 ++++++ src/packets.py | 113 +++ src/utils.py | 132 +++ src/web.py | 187 ++++ 36 files changed, 5219 insertions(+), 3 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 data/creds.json create mode 100644 data/ssl.crt create mode 100644 data/ssl.key create mode 100644 exclude.conf create mode 100755 html/login.html create mode 100755 html/nav.html create mode 100755 html/src/UbuntuMono-R.ttf create mode 100755 html/src/auth.js create mode 100755 html/src/jsonpack.js create mode 100755 html/src/main.js create mode 100755 html/src/packets.js create mode 100755 html/src/pico.min.css create mode 100755 html/src/style.css create mode 100755 html/src/utils.js create mode 100644 libs/scanner.py create mode 100644 libs/scanutils.py create mode 100644 libs/test.py create mode 100755 main.py create mode 100755 modules/main/Dashboard.html create mode 100755 modules/main/adminSettings.html create mode 100755 modules/main/main.py create mode 100755 modules/main/module.json create mode 100755 modules/main/userSettings.html create mode 100755 modules/scan/main.py create mode 100755 modules/scan/module.json create mode 100755 modules/scan/scan.html create mode 100644 paused.conf create mode 100755 src/auth.py create mode 100755 src/jsonpack.py create mode 100755 src/modules.py create mode 100755 src/packets.py create mode 100755 src/utils.py create mode 100755 src/web.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7af6f2b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Current File", + "type": "debugpy", + "request": "launch", + "program": "./main.py", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 6e485a0..113f700 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Astatin3 +Copyright (c) 2023 Astatin3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 4f2ba91..1ec5b55 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ -# Auto-Shodanner - A tool to scrape Shodan +# Polyboard + +### A very dynamic dashboard, with many features + +Polyboard is basically just a fancy dashboard template, but with a very extensible module system, and security features! + +[Read the wiki!](https://github.com/Astatin3/Modulator/wiki) + +![alt text](https://raw.githubusercontent.com/Astatin3/images/main/Modulator-1.png) diff --git a/data/creds.json b/data/creds.json new file mode 100644 index 0000000..79f73b9 --- /dev/null +++ b/data/creds.json @@ -0,0 +1,23 @@ +[ + { + "created": 1713223622034, + "id": "C9Be3ffc8bD4AAd5", + "passwordUpdated": 1713223622034, + "permGroups": [ + "Users" + ], + "sha256passwordhash": "3F76939A78A3A229B680159FE77E396034407EB5D6C3C6D478C83C9C89022085", + "username": "User" + }, + { + "created": 1713223622034, + "id": "067A14d766fDa6D8", + "passwordUpdated": 1713223622034, + "permGroups": [ + "Users", + "Admins" + ], + "sha256passwordhash": "FE851A5602AC9769E24B4D09B24298877AB0C0BA4D9AE1DEBF1CD11935A46299", + "username": "Admin" + } +] \ No newline at end of file diff --git a/data/ssl.crt b/data/ssl.crt new file mode 100644 index 0000000..3549987 --- /dev/null +++ b/data/ssl.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWzCCAkMCFERTJjsw8qFSMc10A9A3SmqMHowpMA0GCSqGSIb3DQEBCwUAMGkx +CzAJBgNVBAYTAklEMSUwIwYDVQQKDBxMb2NhbCBEaWdpdGFsIENlcnQgQXV0aG9y +aXR5MRUwEwYDVQQLDAx3d3cuY2EubG9jYWwxHDAaBgNVBAMME1NlbGYtU2lnbmVk +IFJvb3QgQ0EwIBcNMjQwMzIwMTkxOTMzWhgPMjEyNDAyMjUxOTE5MzNaMGkxCzAJ +BgNVBAYTAklEMSUwIwYDVQQKDBxMb2NhbCBEaWdpdGFsIENlcnQgQXV0aG9yaXR5 +MRUwEwYDVQQLDAx3d3cuY2EubG9jYWwxHDAaBgNVBAMME1NlbGYtU2lnbmVkIFJv +b3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxc2AUbcE9UDvQ +ba+WV3YY2TDrgodsv0FTAbCKQBgfqYcZroXVrYoyK9/8zOQ8k6lQT7fUOCAmjUCQ +77BKwFXnAZUeJc5ctnKYS9KZIW3JRA3Nc14tTXjRi+Xe1FMLTDWBE/1bYP4To56Y +e1+xq0I9Ojv0oUS4JYjFO9YWM1bZCBZsbUzv93zyY4v3P/Bjk02vGfsSqGZ5WmAc +q7Kz2luYfgmQ0X8h/ZYidGw9azGQEEu53VqGT1xlw4XHF/FxsUg0918JH1gzrBc4 +yl1bWxV1TN8Ph5xLoeF8s0wTZgGLErn54ZwVvSZ8cqUTROv251PqXMu54z23HwxP +YjcddRNhAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFAI/9cxxZqq95xs2WmnyUov +ks9lCJloON3g40cL4As+fTiTwsXA8ZEOiGex6OQ+A3/5hChpP/A95i43bba2QbK7 +7eoQhMp7SEj5ybOhIhW0gUsyT449Pp4nl/tnylzyXKTnumPfpl3zmL1nlUadxNDV +7s4roFlNEfLM5ybEfYvjueo5lZecS/U07Ttqs7FM+YAtwx48b/a+wXGCSBbXlImb +Ar+Yy2jEEY+XARdzqns1HHJLaoi3y4K47pozXTfAHpE2GzBVLhWOxqpRGrxzO8X7 +sa4cVhB15/brMFwBvnhUHi+fogrbVCEEvnzqj+aKQ7ISWATGCrirtV20Uw7jktA= +-----END CERTIFICATE----- diff --git a/data/ssl.key b/data/ssl.key new file mode 100644 index 0000000..f0c255e --- /dev/null +++ b/data/ssl.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxc2AUbcE9UDvQ +ba+WV3YY2TDrgodsv0FTAbCKQBgfqYcZroXVrYoyK9/8zOQ8k6lQT7fUOCAmjUCQ +77BKwFXnAZUeJc5ctnKYS9KZIW3JRA3Nc14tTXjRi+Xe1FMLTDWBE/1bYP4To56Y +e1+xq0I9Ojv0oUS4JYjFO9YWM1bZCBZsbUzv93zyY4v3P/Bjk02vGfsSqGZ5WmAc +q7Kz2luYfgmQ0X8h/ZYidGw9azGQEEu53VqGT1xlw4XHF/FxsUg0918JH1gzrBc4 +yl1bWxV1TN8Ph5xLoeF8s0wTZgGLErn54ZwVvSZ8cqUTROv251PqXMu54z23HwxP +YjcddRNhAgMBAAECggEAJWEFUyhPdUfqYZxJSWUBBnjxuhpTxo9/Bior8uNPcZP3 +VmyR2pHks27Ujt7mEPCV0MoKEhUEiLpmaGFlBEoBjlih/ai/EH6KIxSNtx34j1Xb +hnSP2QEhuxo6ALc/CvkxqA/65X3H54Emzj3myXkmydjzejNiU1vstIdHMIP9/ldA ++ghiEv8MUPjheGa1M++Tyc0z0VP45wsaPKa10soku89IvgRs0sA+N6188iWJPeac +yvi9nYXDiSVDF/2bI20cXSVKapt15BUXHzWBjEFS99r+nD4H7IQfUU3+jMsVuwmz +9ZlIIAVG82d02pLS94FsK5fa54p0PEg4tidU4kGB8QKBgQDZhTe78VDh3mzeA9n5 +Yxd/1XeGBBhDkxILeIwk1YlQ7Ii6cM6jIOZDt5ci3/5jBUvqPGQc7eq0iQRflANj +UOwe70fkRpNbkcZRDH/8/AgyhwjJDuyNUVzXegCoSa1zlNgoQ/T1qyLFL9ep1ApD +STn2lAIbPpPdTYde25K4e8+9pQKBgQDQ14hrROlp/dsA7hKnaulnf62EPA4s9/ky +uos/u7bNLj+DD6u5XF0MSRUqqbAFiRUSS+CFE9omQonZbDOO8X8y1g6U0PBy858P +4T/1kDVJPBPJ6XNtSEPRewFq3J/AYXXyd7ktUYYq6mOHsuAitd3Ou87bvM0EMrGa +KN+XFIAKDQKBgQCw/B/ZIAQ7g4r5KhEVRXc9YCccOAC2Gtg31SHSZpyP56VobZj0 +SjSRLLQggDivwQN/1xtuHnc15bZVPk1zZch5cx//sRz9CKNgFtectETHN/ACB86Z +PXZZLL+ULj6fKKCoQoLx0Qk9gCvt1sVy8gXjh5IfMM+G5SocGHRM/xCMsQKBgBom +QrCbylY5MQjmxnMsEdmhxQo/ss6ypgNSFEmAqZz7Y3x3o9rr08LMC9hxstaemYLW ++V/wYmpT/oq436PQXUryPpUnrFPYaVxFqgqHagSnfxrTHl7ao5NBQaYtxdsC2Q/p +Kcig4pnRC3FcVnBCMWnHXllpRIp4BoD1CToTmQypAoGBALg2BbzMgg4pCIbC/cVw +H2Con5VRYc+uyOvoxiiXNJmhfkg9i5bYXtDFMFBAM0N2NDABIRgSZboSKWg+Bne9 +CBFkN67+Q5mlNxBmvfZVEqZypxyReVrlijpNjG3tBayB2zonH1PLyl/ciKNGhFK8 +/abtipqo94ece5zPnBXVHywv +-----END PRIVATE KEY----- diff --git a/exclude.conf b/exclude.conf new file mode 100644 index 0000000..767b494 --- /dev/null +++ b/exclude.conf @@ -0,0 +1,1450 @@ +# https://github.com/arschlochnop/masscan-exclude/blob/master/exclude.conf + +# http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + +# http://tools.ietf.org/html/rfc5735 +# "This" network +0.0.0.0/8 +# Private networks +10.0.0.0/8 +# Carrier-grade NAT - RFC 6598 +100.64.0.0/10 +# Host loopback +127.0.0.0/8 +# Link local +169.254.0.0/16 +# Private networks +172.16.0.0/12 +# IETF Protocol Assignments +192.0.0.0/24 +# DS-Lite +192.0.0.0/29 +# NAT64 +192.0.0.170/32 +# DNS64 +192.0.0.171/32 +# Documentation (TEST-NET-1) +192.0.2.0/24 +# 6to4 Relay Anycast +192.88.99.0/24 +# Private networks +192.168.0.0/16 +# Benchmarking +198.18.0.0/15 +# Documentation (TEST-NET-2) +198.51.100.0/24 +# Documentation (TEST-NET-3) +203.0.113.0/24 +# Reserved +240.0.0.0/4 +# Limited Broadcast +255.255.255.255/32 +#Caltech IPs reported JC on 20150612 +131.215.0.0/16 +134.4.0.0/16 +192.12.19.0/24 +192.31.43.0/24 +192.41.208.0/24 +192.43.243.0/24 +192.54.249.0/24 + +#Received: from elbmasnwh002.us-ct-eb01.gdeb.com ([153.11.13.41] +# helo=ebsmtp.gdeb.com) by mx1.gd-ms.com with esmtp (Exim 4.76) (envelope-from +# ) id 1VS55c-0004qL-0F for support@erratasec.com; Fri, 04 +# Oct 2013 09:06:40 -0400 +#To: +#CC: +#Subject: Scanning and Probing our network +#From: Robert Mandes +#Date: Fri, 4 Oct 2013 09:06:36 -0400 +# +#Stop scanning and probing our network, 153.11.0.0/16. We are a defense +#contractor and report to Federal law enforcement authorities when scans +#and probes are directed at our network. I assume you don't want to be +#part of that report. Please permanently remove our network range from +#your current and future research. +# +#Thank you +# +#Robert Mandes +#Information Security Officer +#General Dynamics +#Electric Boat +# +#C 860-625-0605 +#P 860-433-1553 + +153.11.0.0/16 + +#Date: Mon, 7 Oct 2013 17:25:41 -0700 +#Subject: Re: please stop the attack to our router +#From: Di Li +# +#Make sure you stop the scan immediately, that's not OK for any company or +#organization scan our network at all. +# +#If you fail to do that we will block whole traffic from ASN 10439, and we +#will fail a police report after that. +# +#Let me know when you stop, since we still receive the attack from you, and +#by the way your scan are not going anywhere, it's was dropped from our edge +#since the first 5 scan +# +#Oct 7 17:17:32:I:SNMP: Auth. failure, intruder IP: 209.126.230.72 +#... +#Oct 7 16:55:27:I:SNMP: Auth. failure, intruder IP: 209.126.230.72 +# +#Di + +4.53.201.0/24 +5.152.179.0/24 +8.12.162.0-8.12.164.255 +8.14.84.0/22 +8.14.145.0-8.14.147.255 +8.17.250.0-8.17.252.255 +23.27.0.0/16 +23.231.128.0/17 +37.72.172.0/23 +38.72.200.0/22 +50.93.192.0-50.93.197.255 +50.115.128.0/20 +50.117.0.0/17 +50.118.128.0/17 +63.141.222.0/24 +64.62.253.0/24 +64.92.96.0/19 +64.145.79.0/24 +64.145.82.0/23 +64.158.146.0/23 +65.49.24.0/24 +65.49.93.0/24 +65.162.192.0/22 +66.79.160.0/19 +66.160.191.0/24 +68.68.96.0/20 +69.46.64.0/19 +69.176.80.0/20 +72.13.80.0/20 +72.52.76.0/24 +74.82.43.0/24 +74.82.160.0/19 +74.114.88.0/22 +74.115.0.0/24 +74.115.2.0/24 +74.115.4.0/24 +74.122.100.0/22 +75.127.0.0/24 +103.251.91.0/24 +108.171.32.0/24 +108.171.42.0/24 +108.171.52.0/24 +108.171.62.0/24 +118.193.78.0/23 +130.93.16.0/23 +136.0.0.0/16 +142.111.0.0/16 +142.252.0.0/16 +146.82.55.93 +149.54.136.0/21 +149.54.152.0/21 +166.88.0.0/16 +172.252.0.0/16 +173.245.64.0/19 +173.245.194.0/23 +173.245.220.0/22 +173.252.192.0/18 +178.18.16.0/22 +178.18.26.0-178.18.29.255 +183.182.22.0/24 +192.92.114.0/24 +192.155.160.0/19 +192.177.0.0/16 +192.186.0.0/18 +192.249.64.0/20 +192.250.240.0/20 +194.110.214.0/24 +198.12.120.0-198.12.122.255 +198.144.240.0/20 +199.33.120.0/24 +199.33.124.0/22 +199.48.147.0/24 +199.68.196.0/22 +199.127.240.0/21 +199.187.168.0/22 +199.188.238.0/23 +199.255.208.0/24 +203.12.6.0/24 +204.13.64.0/21 +204.16.192.0/21 +204.19.238.0/24 +204.74.208.0/20 +205.159.189.0/24 +205.164.0.0/18 +205.209.128.0/18 +206.108.52.0/23 +206.165.4.0/24 +208.77.40.0/21 +208.80.4.0/22 +208.123.223.0/24 +209.51.185.0/24 +209.54.48.0/20 +209.107.192.0/23 +209.107.210.0/24 +209.107.212.0/24 +211.156.110.0/23 +216.83.33.0-216.83.49.255 +216.83.51.0-216.83.63.255 +216.151.183.0/24 +216.151.190.0/23 +216.172.128.0/19 +216.185.36.0/24 +216.218.233.0/24 +216.224.112.0/20 + +#Received: from [194.77.40.242] (HELO samba.agouros.de) +# for abuse@erratasec.com; Sat, 12 Oct 2013 09:55:35 -0500 +#Received: from rumba.agouros.de (rumba-internal [192.168.8.1]) by +# samba.agouros.de (Postfix) with ESMTPS id 9055FBAD1D for +# ; Sat, 12 Oct 2013 16:55:32 +0200 (CEST) +#Received: from rumba.agouros.de (localhost [127.0.0.1]) by rumba.agouros.de +# (Postfix) with ESMTP id 7B5DD206099 for ; Sat, 12 Oct +# 2013 16:55:32 +0200 (CEST) +#Received: from localhost.localdomain (localhost [127.0.0.1]) by +# rumba.agouros.de (Postfix) with ESMTP id 5FBC420601D for +# ; Sat, 12 Oct 2013 16:55:32 +0200 (CEST) +#To: +#Subject: Loginattempts from Your net +#Message-ID: <20131012145532.5FBC420601D@rumba.agouros.de> +#Date: Sat, 12 Oct 2013 16:55:32 +0200 +#From: +# +#The address 209.126.230.72 from Your network tried to log in to +#our network using Port 22 (1)/tcp. Below You will find a listing of the dates and +#times the incidents occured as well as the attacked IP-Addresses. +#This is a matter of concern for us and continued tries might result in +#legal action. If the machine was victim to a hack take it offline, repair +#the damage and use better protection next time. +#The times included are in Central European (Summer) Time. +#Date Sourceip port destips +# +#07.10.2013 22:34:40 CEST 209.126.230.72 22 194.77.40.242 (1) +#08.10.2013 01:44:15 CEST 209.126.230.72 22 194.77.40.246 (1) +# +#Regards, +#Konstantin Agouros + +194.77.40.242 +194.77.40.246 + +#Received: from [165.160.9.58] (HELO mx2.cscinfo.com) +#X-Virus-Scanned: amavisd-new at cscinfo.com +#Received: from mx2.cscinfo.com ([127.0.0.1]) by localhost +# (plmail02.wil.csc.local [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id +# GGQ7EiQaK2P0 for ; Wed, 30 Oct 2013 09:26:00 -0400 +# (EDT) +#Received: from casarray.cscinfo.com (pwmailch02.cscinfo.com [172.20.53.94]) by +# mx2.cscinfo.com (Postfix) with ESMTPS id 4BA5E58170 for +# ; Wed, 30 Oct 2013 09:26:00 -0400 (EDT) +#Received: from PWMAILM02.cscinfo.com ([169.254.7.52]) by +# PWMAILCH02.cscinfo.com ([172.20.53.94]) with mapi id 14.02.0247.003; Wed, 30 +# Oct 2013 09:26:00 -0400 +#From: "Derksen, Bill" +#Subject: Unauthorized Scanning +#Date: Wed, 30 Oct 2013 13:25:59 +0000 +#Message-ID: <1F80316A0C861F40A9A88F18465F138E01EF885F@PWMAILM02.cscinfo.com> +#x-originating-ip: [172.31.252.72] +# +#We have detected unauthorized activity from your systems on our public netw= +#ork. Please suspend scanning of our networks immediately. +# +#Our network block is 165.160/16 +# +#Further scanning will result in reports of unauthorized activity being file= +#d with law enforcement agencies. +# +#Corporation Service Company +# +# +# +#________________________________ +# +#NOTICE: This e-mail and any attachments is intended only for use by the add= +#ressee(s) named herein and may contain legally privileged, proprietary or c= +#onfidential information. If you are not the intended recipient of this e-ma= +#il, you are hereby notified that any dissemination, distribution or copying= +# of this email, and any attachments thereto, is strictly prohibited. If you= +# receive this email in error please immediately notify me via reply email o= +#r at (800) 927-9800 and permanently delete the original copy and any copy o= +#f any e-mail, and any printout. + +165.160.0.0/16 + +## These were grabbed from http://www.waraxe.us/ftopict-346.html +## They need to be cleaned up, reformatted, and verified +# +# Army Information Systems Center +6.0.0.0/8 +# US Defense Information Systems Agency +21.0.0.0/8 +# Defense Information Systems Agency +22.0.0.0/8 +# Comcast Cable Communications, Inc. I believe this is for residential customers. +24.8.0.0/15 +24.0.0.0/12 +# Roadrunner, USA. Time Warner Cable Internet LLC +24.88.0.0/16 +# James Cable, LLC +24.112.0.0/17 +# Hostmaster Liberty Global +24.132.0.0/23 +24.132.2.255/24 +# Optimum Online +24.188.0.0/14 +## Defense Information Systems Agency +#26.0.0.0 +## Defense Information Systems Agency +#29.0.0.0 +## Defense Information Systems Agency +#30.0.0.0 +## Joint Tactical Command +#49.0.0.0 +## Joint Tactical Command +#50.0.0.0 +## DaimlerChrysler AG +#53.0.0.0 +## Army National Guard Bureau +#55.0.0.0 +#62.0.0.1 - 62.30.255.255 +## Commundo +#62.52.0.0 +## Debitel +#62.52.0.0 +## lahm (9 Online French) +#62.62.0.0 +## AddCOM +#62.69.140.0 +## I-net +#62.96.0.0 +## Freeserve, UK +#62.137.0.0 +## bis 62.255.0.0 T-Online +#62.150.0.0 +## Erotik-Welt +#62.156.0.0 +## 1 & 1 +#62.157.0.0 +## [T-Online, Germany +#62.158. +## Planet Intercom +#62.180.0.0 +## Adelphia, USA +#64.9. 0 +## Darwin Networks Community, USA +#64.44. 0 +## (FBI's honeypot) +#64.224.0 +## (FBI's honeypot) +#64.225.0 +## (FBI's honeypot) +#64.226.0 +## lahm +#80.0.0.0 +## lahm +#81.0.0.0 +## University of Delaware +#128.4.0.0 +## University of Maryland +#128.8.0.0 +## Purdue University +#128.10.0.0 +## Yahoo, Inc. +#128.11.22.0 - 128.11.22.255 +## Yahoo, Inc. +#128.11.23.0 - 128.11.23.255 +## Yahoo, Inc. (NETBLK-FOUR11DS559-68-19) +#128.11.68.0 - 128.11.68.255 +## Yahoo, Inc. (NETBLK-FOUR11DS216-69-19) +#128.11.69.0 - 128.11.69.255 +## Yahoo, Inc. (NETBLK-FOUR11DS698-70-19) +#128.11.70.0 - 128.11.70.255 +## Yahoo, Inc. (NETBLK-FOUR11DS699-71-20) +#128.11.71.0 - 128.11.71.255 +## FortuneCity Ltd. +#128.11.96.32 - 128.11.96.63 +## Yale University (NET-YALE-NET) +#128.36.0.0 +## Army Yuma Proving Ground +#128.37.0.0 +## Naval Surface Warfare Center (NET-NSWC-NET) +#128.38.0.0 +## Norwegian Telecommunications Administration (NET-NTANET) +#128.39.0.0 +## University College London (NET-UCL-ETHERNET) +#128.40.0.0 +## University College London (NET-CL-CS-SERVICE) +#128.41.0.0 +## Rice University (NET-RICE-NET) +#128.42.0.0 +## Defence Researc +#128.43.0.0 +## Army Communications Electronics Command (NET-TACTNET) +#128.47.0.0 +## Department of Defense (NET-COINS) +#128.50.0.0 +## Department of Defense (NET-COINSTNET) +#128.51.0.0 +## U.S. Naval Academy (NET-USNA-NET) +#128.56.0.0 +## Army Ballistics Research Laboratory (NET-BRL-SUBNET) +#128.63.0.0 +## Army Communications Electronics Command (CECOM) (NET-CECOMNET) +#128.80.0.0 +## Defence Evaluation and Research Agency (NET-DERA-UK) +#128.98.0.0 +## Northrop Grumman Corporation - Automation Sciences Laboratory (NET-NORTHROP-NET) +#128.99.0.0 +## University of Toronto Computing and Communications (NET-TORONTO) +#128.100.0.0 +## Unversity of Minnesota (NET-UMN-NET) +#128.101.0.0 +## NASA Ames Research Center +#128.102.0.0 +## Harvard University (NET-HARVA +#128.103.0.0 +## NASA Headquarters +#128.149.0.0 +## National Science Foundation (NET-NSF-LAN) +#128.150.0.0 +## University of Rochester (NET-UR-NET) +#128.151.0.0 +## Hughes Electronics (NET- HAC-ENET) +#128.152.0.0 +## Clarkson University (NET-CLARKSON) +#128.153.0.0 +## NASA Wallops Flight Facility (NET-WFF-NET) +#128.154.0.0 +## NASA Langley Research Center (NET-LARC-NET) +#128.155.0.0 +## NASA Lewis Network Control Center (NET- LERC) +#128.156.0.0 +## NASA Johnson Space Center (NET-JSC-NET) +#128.157.0.0 +## NASA Ames Research Center (NET-MSFC-NET) +#128.158.0.0 +## NASA Ames Research Center (NET-KSC-NET) +#128.159.0.0 +## Naval Research Laboratory (NET- SSCNET) +#128.160.0.0 +## NASA Ames Research Center (NET-NSN-NET) +#128.161.0.0 +## NASA Goddard Space Flight Center (NET-GSFC) +#128.183.0.0 +## Army Belvoir Reasearch and Development Center +#128.190.0.0 +## MacDill Air Force Base (NET-CC-PRNET) +#128.216.0.0 +## NASA Kennedy Space Center (NET-NASA-KSC-OIS) +#128.217.0.0 +## U.S. Air Force Academy (NET-USAFA-NET +#128.236.0.0 +## University of Leeds (NET-LEEDS) +#129.11.0.0 +## University of Kent at Canterbury (NET-UKC) +#129.12.0.0 +#129.13.0.0 # University of Karlsruhe +## Wright-Patterson Air Force Base +#129.48.0.0 +## NASA Marshall Space Flight Center (NET-PSCN) +#129.50.0.0 +## Patrick Air Force Base (NET-NS) PAFB) +#129.51.0.0 +## Wright-Patterson Air Force Base +#129.52.0.0 +## Vandenberg Air Force Base +#129.54.0.0 +## University of Stuttgart (NET-NI-STG-NET) +#129.69.0.0 +## University of Bielefeld +#129.70.0.0 +## Siemens +#129.73.0.0 +## Air Force Institute of Technology +#129.92.0.0 +## NASA Ames Research Center +#129.99.0.0 +## Army Armament Research Development and Engineering Center +#129.139.0.0 +## NASA/Johnson Space Center (NET-NASA-JSCSSE) +#129.163.0.0 +## NASA IVV (NET-E) NASA-IVV) +#129.164.0.0 +## NASA Goddard Space Flight Center (NET-NASA-GSFCSSE) +#129.165.0.0 +## NASA - John F. Kennedy Space Center (NET-NASA-JFKSSE) +#129.166.0.0 +## NASA Marshall Space Flight Center (NET-NASA-MSFCSSE) +#129.167.0.0 +## NASA Lewis Research Center (NET-NASA-LRCSSE) +#129.168.0.0 +## Leibniz-Rechenzentrum der Bayerischen Akademie +#129.187.0.0 +## Air Force Flight Test Center +#129.198.0.0 +## Army Ballistics Research Laboratory +#129.209.0.0 +## University of Dortmund +#129.217.0.0 +## U.S. Army Corps of Engineers +#129.229.0.0 +## Fraunhofer Institut f?r Produktionstechnik u. Automatisierung +#129.233.0.0 +## United States Air Force Academy +#129.251.0.0 +# +## NASA Johnson Space Center +#130.40.0.0 +## University of Hannover +#130.75.0.0 +## Netherlands Energy Research Foundation ECN +#130.112.0.0 +## Army Aberdeen Proving Ground Installation Support Activity (NET-APGNET) +#130.114.0.0 +## Erasmus University Rotterdam +#130.115.0.0 +## Massey University +#130.123.0.0 +## Freie Universitaet Berlin +#130.133.0.0 +# +## U.S.Army Corps of Engineers +#130.165.0.0 +## NASA Headquarters +#130.167.0.0 +## Max-Planck-Institut fur Plasmaphysik +#130.183.0.0 +## UUNet +#130.211.0.0 +## Gothenburg University (NET-GU-NET) +#130.241.0.0 +## Boeing Military Aircraft +#130.247.0.0 +## Mather Air Force Base +#131.3.0.0 - 131.3.255.255 +## Langley Air Force Base +#131.6.0.0 +## Barksdale Air Force Base +#131.10.0.0 +## Sheppard Air Force Base +#131.17.0.0 +## Hahn Air Base (NET-HAHNNET) +#131.21.0.0 +## Keesler Air Force Base +#131.22.0.0 +## Patrick Air Force Base +#131.25.0.0 +## Fairchild Air Force Base +#131.35.0.0 +## Yokota Air Base +#131.36.0.0 +## Elmendorf Air Force Base +#131.37.0.0 +## Hickam Air Force Base +#131.38.0.0 +## Bergstrom Air Force Base +#131.40.0.0 +## Randolph Air Force Base +#131.44.0.0 +## Andersen Air Force Base +#131.47.0.0 +## Davis-Monthan Air Force Base +#131.50.0.0 +## Air Force Concentrator Network +#131.54.0.0 +## McConnell Air Force Base +#131.61.0.0 +## Norton Air Force Base +#131.62.0.0 +## Army Information Systems Command - Aberdeen +#131.92.0.0 +## NASA/Michoud Assembly Facility +#131.110.0.0 +## United States Naval Academy +#131.121.0.0 +## United States Naval Academy +#131.122.0.0 +## [Eindhoven University, Netherlands +#131.155. +## Deutsches Elektronen Synchrotron +#131.169.0.0 +## Nijmegen University, Netherlands +#131.174. 0 +## European Space Operations Center +#131.176.0.0 +## NASA Headquarters +#131.182.0.0 +## University Erlangen Nuremberg +#131.188.0.0 +## UUNet +#131.211.0.0 +## University of Bonn +#131.220.0.0 +## University College, Australian Defense Force Academy +#131.236.0.0 +## University Kaiserslautern +#131.246.0.0 +## [Technological Institute, Israel +#132.68. +## ??? +#132.95.0.0 - 132.108.0.0 +## Universitaet Tuebingen +#134.2.0.0 +## The Pentagon (NET-PENTNET) +#134.11.0.0 +## NASA Ames Research Center +#134.12.0.0 +## University of Fribourg +#134.21.0.0 +## Army Information Systems Command-ATCOM +#134.78.0.0 +## Army Information Systems Command +#134.80.0.0 +## Uni Duisburg +#134.91.0.0 +## Uni K?ln +#134.95.0.0 +## NASA/Johnson Space Center +#134.118.0.0 +## Ruhr-Universitaet Bochum +#134.147.0.0 +## University of Mannheim +#134.155.0.0 +## Army Engineer Waterways Experiment Station +#134.164.0.0 +## Universitaet Giessen +#134.176.0.0 +## U.S. Army Aberdeen Test Center +#134.194.0.0 +## Navy Regional Data Automation Center +#134.229.0.0 +## Navy Regional Data Automation Center +#134.230.0.0 +## U.S. Military Academy +#134.240.0.0 +## Universitaet Kiel +#134.245.0.0 +## European Centre for Medium-Range Weather Forecasts +#136.156.0.0 +## Deutsches Klimarechenzentrum +#136.172.0.0 +## NASA Research Network +#136.178.0.0 +## Universitaet Trier +#136.199.0.0 +## Whiteman Air Force Base +#137.1.0.0 +## George Air Force Base +#137.2.0.0 +## Little Rock Air Force Base +#137.3.0.0 +## Air Force Concentrator Network +#137.5.0.0 +## Air Force Concentrator Network +#137.6.0.0 +## Air Force Concentrator Network +#137.12.0.0 +## Siemens Nixdorf Information Systems +#137.223.0.0 +## Aachen University of Technology +#137.226.0.0 +## Air Force Materiel Command +#137.240.0.0 +## Air Force Logistics Command +#137.242.0.0 +## University of Augsburg (NET-AUX) +#137.250.0.0 +## Fraunhofer-Institut f?r Arbeitswirtschaft und Organisation +#137.251.0.0 +## Air Force Systems Command +#138.13.0.0 +## Army Information Systems Command +#138.27.0.0 +## National Space Development Agency of Japan +#138.30.0.0 +## Mainz +#138.61.0.0 +## NASA Headquarters +#138.76.0.0 +## NASA Information and Electronic Systems Laboratory +#138.115.0.0 +## Navy Computers and Telecommunications Station +#138.136.0.0 - 138.136.255.255 +## Navy Regional Data Automation Center +#138.137.0.0 +## Marine Corps Air Station +#138.139.0.0 +## Navy Regional Data Automation Center +#138.140.0.0 +## Navy Regional Data Automation Center +#138.141.0.0 +## Navy Regional Data Automation Center +#138.142.0.0 +## Navy Regional Data Automation Center +#138.143.0.0 +## Marine Corps Central Design & Prog. Activity +#138.156.0.0 +## Marine Corps Central Design & Prog. Activity +#138.158.0.0 +## Marine Corps Central Design & Prog. Activity +#138.168.0.0 +## NASA/Yellow Creek +#138.193.0.0 +## University of Dortmund +#139.2.0.0 +## EUnet Deutschland GmbH +#139.4.0.0 +## University of Dortmund +#139.5.0.0 +## Fachhochschule K?ln +#139.6.0.0 +## Mannesmann Mobilfunk GmbH +#139.7.0.0 +## S & P Media GmbH +#139.8.0.0 +## University of Dortmund (NETBLK-UNIDO11) +#139.10.0.0 - 139.16.0.0 +## University of Dortmund (NETBLK-UNIDO11) +#139.10.0.0 - 139.16.0.0 +## University of Dortmund (NETBLK-UNIDO11) +#139.10.0.0 - 139.16.0.0 +## University of Dortmund (NETBLK-UNIDO11) +#139.10.0.0 - 139.16.0.0 +## University of Dortmund (NETBLK-UNIDO11) +#139.10.0.0 - 139.16.0.0 +## University of Dortmund (NETBLK-UNIDO11) +#139.10.0.0 - 139.16.0.0 +## University of Dortmund (NETBLK-UNIDO11) +#139.10.0.0 - 139.16.0.0 +## Universit?t der Bundeswehr Hamburg +#139.11.0.0 +## Fachhochschule Wilhelmshaven +#139.13.0.0 +## Universit?t Koblenz-Landau +#139.14.0.0 +## Robert Bosch GmbH +#139.15.0.0 - 139.15.255.255 +## Geo-Forschungs-Zentrum Potsdam +#139.17.0.0 +## Universit?t Leipzig (NET-UNILE-LAN) +#139.18.0.0 +## Max-Planck-Institut f?r Informatik +#139.19.0.0 +## European Regional Internet Registry/RIPE NCC +#139.20.0.0 - 139.20.255.255 +## European Regional Internet Registry/RIPE NCC +#139.20.0.0 - 139.29.255.255 +## Siemens Business Services +#139.21.0.0 +## Siemens Business Services +#139.22.0.0 +## Siemens Business Services +#139.23.0.0 +## Siemens Business Services +#139.25.0.0 +## Thyssen Stahl AG +#139.27.0.0 - 139.27.255.255 +## Bremer Vulkan AG +#139.28.0.0 +## University of Rostock +#139.30.0.0 +## Alfred Wegener Institute for Polar and Marine Research +#139.75.0.0 +## NASA Lewis Research Center +#139.88.0.0 +## Front end portal of a security network filtering hundreds of client subscription IPs. If you find a vulnerable pub, IIS, SQL, or 0nix -- LEAVE IT ALONE +#139.142.0.0 +## Army Information Systems Command +#139.161.0.0 +## NASA/Johnson Space Center +#139.169.0.0 +## NASA Ames Research Center +#139.229.0.0 +## HQ US Army Medical Research and Development Command +#140.139.0.0 +## Marine Biological Laboratory +#140.239.81.184 - 140.239.81.191 +## Fast nur Deutsche Firmen +#141.0.0.0 - 141.255.255.255 +## United States Army Information Systems Command (NET-CRLSLBKS-NET) +#144.99.0.0 +## Army Information Systems Command (NET-NCMBRLNDNET) +#144.109.0.0 +## Headquarters, Third United States Army (NET-AC2IS) +#144.143.0.0 +## Headquarters, Third United States Army (NET-AC2IS1) +#144.144.0.0 +## Commander, Army Information Systems Center (NET-FTIRWIN1 ) +#144.146.0.0 +## Commander, Army Information Systems Center (NET-FTIRWIN2 ) +#144.147.0.0 +## United States Army Information Services Command-Campbell (NET-CAMPBELL-GW1) +#144.192.0.0 +## Sprintlink, USA +#144.232. 0 +## Defense Intelligence Agency (NET-DODIIS1) +#144.233.0.0 +## Defense Intelligence Agency (NET-DODIIS2) +#144.234.0.0 +## Defense Intelligence Agency (NET-DODIIS3) +#144.235.0.0 +## Defense Intelligence Agency (NET-DODIIS4) +#144.236.0.0 +## Defense Intelligence Agency (NET-DODIIS5) +#144.237.0.0 +## Defense Intelligence Agency (NET-DODIIS6) +#144.238.0.0 +## Defense Intelligence Agency (NET-DODIIS7) +#144.239.0.0 +## Defense Intelligence Agency (NET-DODIIS +#144.240.0.0 +## Defense Intelligence Agency (NET-DODIIS9) +#144.241.0.0 +## Defense Intelligence Agency (NET-DODIIS10) +#144.242.0.0 +## SUPSHIP, Groton, U.S.N. (NET-SOSGNET) +#144.247.0.0 +## Air Products and Chemicals Incorporated (NET-APCI-NET) +#144.249.0.0 +## U.S. Army LABCOM (NET-LABCOM-ETDL) +#144.252.0.0 +## Niederlande, Frankreich und Deutschland +#145.0.0.0 - 145.255.255.255 +## Army Information Systems Software Center +#147.103.0.0 +## Army Information Systems Software Center +#147.104.0.0 +## Army Information Systems Command +#147.164.0.0 +## Army Information Systems Command +#147.165.0.0 +## Army Information Systems Command +#147.198.0.0 +## Army Information Systems Command +#147.199.0.0 +## Army Information Systems Command +#147.238.0.0 +## US Army Tank-Automotive Command +#147.240.0.0 +## [ContacTel, Czech Republic +#147.251. +## Fachhochschule Aachen (NET-HAC-LAN) +#149.201.0.0 +## Siemens Nixdorf Informationssysteme AG +#149.202.0.0 - 149.202.255.255 +## European Regional Internet Registry/RIPE NCC +#149.202.0.0 - 149.204.255.255 +## Medizinische Akademie Magdeburg +#149.203.0.0 - 149.203.255.255 +## Alcanet International Deutschland GmbH +#149.204.0.0 - 149.204.255.255 +## FH Merseburg +#149.205.0.0 +## Thyssen Stahl AG +#149.206.0.0 - 149.206.255.255 +## European Regional Internet Registry/RIPE NCC +#149.206.0.0 - 149.251.255.255 +## Telefunken Systemtechnik Ulm +#149.207.0.0 +## Thyssen Stahl AG +#149.211.0.0 - 149.211.255.255 +## Siemens-Nixdorf Informationssystemer A/S +#149.212.0.0 +## Degussa AG +#149.216.0.0 - 149.216.255.255 +## Max-Planck-Institut f?r Kernphysik +#149.217.0.0 +## Hirschmann GmbH & Co +#149.218.0.0 +## Westdeutscher Rundfunk Koeln +#149.219.0.0 +## Forschungszentrum Rossendorf +#149.220.0.0 +## Rheinisch Bergische Presse-Data GmbH +#149.221.0.0 +## Fachhochschule Kiel +#149.222.0.0 - 149.222.255.255 +## Quantum Software GmbH +#149.232.0.0 - 149.232.255.255 +## Lahmeyer International GmbH +#149.233.0.0 +## Schering AG Berlin +#149.234.0.0 - 149.234.255.255 +## iXOS Software GmbH +#149.235.0.0 +## Bruker Analytische Messtechnik GmbH +#149.236.0.0 +## Wiechers & Partner Datentechnik GmbH +#149.237.0.0 - 149.237.255.255 +## ZF Friedrichshafen AG +#149.238.0.0 - 149.238.255.255 +## European Regional Internet Registry/RIPE NCC +#149.239.0.0 - 149.239.255.255 +## Carl Schenk AG +#149.240.0.0 - 149.240.255.255 +## Koerber AG +#149.242.0.0 - 149.242.255.255 +## ERNO Raumfahrttechnik +#149.243.0.0 +## Knorr-Bremse AG, M?nchen +#149.244.0.0 +## Siemens AG, OeN NKE A2 +#149.246.0.0 +## TA Triumph-Adler AG +#149.248.0.0 +## Hoechst AG, Frankfurt +#149.250.0.0 +## Electricite de France - Direction Etudes Recherche +#149.251.0.0 +## USDOE, NV Operations Office +#149.252.0.0 +## DIRM/ITD +#149.253.0.0 +## Mercury Personal Communications, Ltd. +#149.254.0.0 - 149.254.255.255 +## Kanadischer Provider +#149.99.130.0- 149.99.150.0 +## Arcor +#145.253.0.0 +## MSN +#149.225.0.0 +## NASA Goodard Space Flight Center +#150.144.0.0 +## Army Information Systems Command +#150.149.0.0 +## Korea Aerospace Research Institute +#150.197.0.0 +## IUnet (NET-IUNET-BNET3) +#151.3.0.0 - 151.3.255.255 +## Compuserv +#152.203.0.0 +## AOL +#152.166.0.0 +## AOL +#152.170.0.0 +## AOL +#152.172.0.0 +## AOL +#152.205.0.0 +## AOL +#152.207.0.0 +## Deutsches Forschungsnetz +#153.92.0.0 +## Bundesanstalt f?r Wasserbau +#153.93.0.0 +## Transtec AG +#153.94.0.0 +## Fraunhofer Institut f?r Informations- und Datenverarbeitung IITB +#153.96.0.0 +## Fraunhofer Institut f?r Informations- und Datenverarbeitung IITB +#153.97.0.0 +## Eurocontrol Karlsruhe +#153.98.0.0 +## European Regional Internet Registry/RIPE NCC +#153.99.0.0 - 153.99.255.255 +## RWE Energie AG +#153.100.0.0 +## European Regional Internet Registry/RIPE NCC +#153.101.0.0 - 153.101.255.255 +## American Forces Information (NET-AFISHQ-NET1) +#155.7.0.0 +## U.S. ArmyFort Gordon (NET-GORDON-NET5) +#155.8.0.0 +## United States Army Information Systems Command (NET-LWOOD-NET2) +#155.9.0.0 +## PEO STAMIS (NET-CEAP2) +#155.74.0.0 +## US Army Corps of Engineers (NET-CEAP3) +#155.75.0.0 +## PEO STAMIS (NET-CEAP4) +#155.76.0.0 +## PEO STAMIS (NET-CEAP5) +#155.77.0.0 +## PEO STAMIS (NET-CEAP6) +#155.78.0.0 +## US Army Corps of Engineers (NET-CEAP7) +#155.79.0.0 +## PEO STAMIS (NET-CEAP +#155.80.0.0 +## PEO STAMIS (NET-CEAP9) +#155.81.0.0 +## PEO STAMIS (NET-CEAP10) +#155.82.0.0 +## US Army Corps of Enginers (NET-CEAP11) +#155.83.0.0 +## PEO STAMIS (NET-CEAP12) +#155.84.0.0 +## PEO STAMIS (NET-CEAP13) +#155.85.0.0 +## US Army Corps of Engineers (NET-CEAP14) +#155.86.0.0 +## PEO STAMIS (NET-CEAP15) +#155.87.0.0 +## PEO STAMIS (NET-CEAP16) +#155.88.0.0 +## Federal Aviation Administration (NET-FAA) +#155.178.0.0 +## USAISC Fort Benning (NET-FTBENNNET3 +#155.213.0.0 +## Director of Information Management (NET-CARSON-TCACC ) +#155.214.0.0 +## USAISC-FT DRUM (NET-DRUM-TCACCIS) +#155.215.0.0 +## TCACCIS Project Management Office (NET-FTDIX-TCACCI) +#155.216.0.0 +## Directorate of Information Management (NET- EUSTIS-EMH1) +#155.217.0.0 +## USAISC (NET-WVA-EMH2) +#155.218.0.0 +## DOIM/USAISC Fort Sill (NET-SILL-TCACCIS) +#155.219.0.0 +## USAISC-DOIM (NET-FTKNOX-NET4) +#155.220.0.0 +## USAISC-Ft Ord (NET-FTORD-NET2) +#155.221.0.0 +## US Courts, Siemens, State of Minnesota +#156.0.0.0 +## U.S. Army TACOM +#158.3.0.0 +## US Army Soldier Support Center +#158.8.0.0 +## US Army Harry Diamond Laboratories +#158.12.0.0 +## Washington State Dept. of State and Ind. +#159.1.0.0 +## Air Canada +#159.206.0.0 +## BMW AG, Berlin production plant +#160.46.0.0 +## BMW AG, Dingolfingen production plant +#160.47.0.0 +## BMW AG, Landshut production plant +#160.48.0.0 +## BMW AG, Munich production plant +#160.49.0.0 +## BMW AG, Munich research and admin. sites +#160.50.0.0 +## BMW AG, Regensburg production plant +#160.51.0.0 +## BMW AG, Steyr production plant +#160.52.0.0 +## US Army Recruiting Command +#160.132.0.0 +## Navy Aviation Supply Office +#163.12.0.0 +## Schering AG (NETBLK-TBLK-SCHERING) +#164.59.0.0 - 164.60.0.0 +## Schering AG (NET-SCHERING2) +#164.60.0.0 +## Kaufhof Holding AG, Koeln +#164.61.0.0 +## Secretary of the Navy (NET-SECNAV-LAN) +#164.224.0.0 +## U.S. Army Intelligence and Security Command +#164.225.0.0 +## Military Sealift Command +#164.231.0.0 +## windows default +#169.0.0.0 +## J. P. Morgan & Co (USA) +#169.120.0.0 +## AOL Deutschland +#171.224.0.0 +## ??? +#171.223.0.0 +## [XS4ALL, Netherlands +#172.16. +## America Online, Inc. +#172.128-180.0.0 +## Netvision +#192.114.63.0 +## [private network +#192.168. +## lahm +#193.0.0.0 +## UUNet +#193.79.178.0 +##Siemens +#193.101.100.0 +##SONNET (Flatrate) (TOT) +#193.122.199.0 +## T-Online +#193.159.0.0 +##Siemens +#193.189.224.0 +##Siemens +#193.189.231.0 +## SONNET (Flatrate) (TOT) +#193.190.215.0 +## Net-Cologne +#194.8.193.0 +## Net-Cologne +#194.8.197.0 +## DE-CIX +#194.31.232.0 +## Netvision +#194.90.0.0 +## MBinternet, Finland +#194.100. 0 +## Microsoft +#194.121.59.0 +##Siemens +#194.174.230.0 +##Microsoft +#194.179.124.0 +##UUNet +#194.203.122.0 +## PLUSNET AG (Schweitz) +#194.230.0.0 +## T-Online +#195.3.0.0 +## Siemens +#195.7.49.0 +## (FBI's honeypot) +#195.10.0 +## Siemens +#195.40.101.0 +## Sonera, Netherlands +#195.66. 0 +## Chello/Capacity, Netherlands +#195.86. 0 +## AOL Deutschland +#195.93.0.0 +## [Pandora, Belgium +#195.130. +## Bluewin (Schweiz) +#195.186.0.0 +##SONNET (Flatrate) (TOT) +#195.238.160.0 +##SONNET (Flatrate) (TOT) +#195.238.164.0 +##SONNET (Flatrate) (TOT) +#195.238.163.0 +##SONNET (Flatrate) (TOT) +#195.238.174.0 +## US Army Information Systems Command +#199.31.0.0 - 199.31.255.0 +## Netvision +#199.203.4.0 +##Microsoft +#199.203.230.0 +## GSI (NET-GSI-13 +#204.34.138.0 +## HQ, JFMO Korea, Headquarters (NET-JFMO-KOREA) +#204.34.139.0 +## DISA D75 (NET-TPOCNET) +#204.34.140.0 +## U. S. Naval Air Facility, Atsugi Japan (NET-NAFATSUGI01) +#204.34.141.0 +## Naval Enlisted Personnel Management Center (NET-DMCCNHUB) +#204.34.142.0 +## Afloat Training Group Pacific (NET-ATGPAC) +#204.34.143.0 +## HQ Special Operations Command - Europe (HQ SOCEUR) (NET-SCCIS) +#204.34.144.0 +## Commander Naval Base Pearl Harbor (NET-CNBGW) +#204.34.145.0 +## NAVSEA Information Management Improvement Program (NET-TII-NET) +#204.34.147.0 +## Q112 (NET-Q112) +#204.34.148.0 +## Ctr. for Info. Sys.Security,CounterMeasures (NET-ASSIST-149) +#204.34.149.0 +## Resource Consultants, Inc. (NET-RCIADP) +#204.34.150.0 +## Personnel Support Activity, San Diego (NET-PSASD) +#204.34.151.0 +## NAVAL AIR FACILITY, ADAK (NET-LEVEL2ADAK) +#204.34.152.0 +## NAVSEA Logistics Command Detachment (NET-NSLC) +#204.34.153.0 +## PEARL HARBOR NAVAL SHIPYARD (NET-PHNSY-NET1) +#204.34.154.0 +## PEARL HARBOR NAVAL SHIPYARD (NET-PHNSY-NET2) +#204.34.155.0 +## Defense Photography School (NET-DPHSCH) +#204.34.156.0 +## Defense Information School (NETBLK-DINFOSNET1) +#204.34.157.0 - 204.34.160.0 +## Naval Air Systems Command (NET-PMA-222) +#204.34.161.0 +## Puget Sound Naval Shipyard (NET-PSNS-RMC) +#204.34.162.0 +## Joint Precision Strike Demonstration (NET-JPSD-EH) +#204.34.163.0 +## Naval Pacific Meteorology and Ocean (NET-NPMOCW-cool.gif +#204.34.164.0 +## Joint Precision Strike Demonstration (NET-JPSD-ES) +#204.34.165.0 +## USAF (NET-DMSHELPDESK) +#204.34.167.0 +## Commander (NET-THIRDNCB-LAN) +#204.34.168.0 +## Naval Air Warfare Center (NET-MSAICN) +#204.34.169.0 +## Naval Air Systems Command (NET-NADEP) +#204.34.170.0 +## NAVSTA SUPPLY DEPARTMENT (NET-GTMOSUPPLY) +#204.34.171.0 +## SUBMEPP Activity (NET-SUBMEPP-NET5) +#204.34.173.0 +## COMMANDER TASK FORCE 74 YOKOSUKA JAPAN (NET-SEVENFLEET) +#204.34.174.0 +## DISA-PAC,IPC-GUAM (NET-DIPCGU) +#204.34.176.0 +## Satellite Production Test Center (NET-SPTC-CS) +#204.34.177.0 +## 940 Air Refueling Wing (ARW) (NET-ARW940-NET) +#204.34.181.0 +## Defense Megacenter Warner Robins (NET-WR) +#204.34.182.0 +## GCCS Support Facility (NET-GCCS-SUPPFAC) +#204.34.183.0 +## Nav Air Tech Serv Facility-Detachment (NET-NATSFDET-WNY) +#204.34.184.0 +## NAVAL SUPPORT FACILITY, DIEGO GARCIA (NET-NSFDG) +#204.34.185.0 +## Defense Logistics Agency - Europe (NET-EURNET2) +#204.34.186.0 +## NAVMASSO (NET-SNAP1-MATSGMERIDIAN) +#204.34.187.0 +## Commander-In-Chief, US Pacific Fleet (NET-CPF-LAN1) +#204.34.188.0 +## Defense MegaCenter - St Louis (NET-DMC-S-DFAS) +#204.34.189.0 +## NAVMASSO (NET-HMX1MCAFQUANVA-SNAP) +#204.34.190.0 +## HQ SOCEUR (NET-U-SIN) +#204.34.192.0 +## Second Marine Expeditionary Force (NET-U22-NIP) +#204.34.193.0 +## Second Marine Expeditionary Force (NET-U24-NIP) +#204.34.194.0 +## Second Marine Expeditionary Force (NET-U26-NIP) +#204.34.195.0 +## NAVCOMTELSTAWASHDC (NET-MISSI) +#204.34.196.0 +## INFORMATION SYSTEMS TECHNOLOGY CENTER (ISTC) (NET-ISTC) +#204.34.197.0 +## Naval Observatory Detachment, Colorado (NET-FALCON1) +#204.34.198.0 +## NAVILCODETMECH (NET-NAVILCOMECH1) +#204.34.199.0 +## Navy Environmental Preventive Medicine (NET-NEHC-BURNED) +#204.34.200.0 +## Port Hueneme Division, Naval Surf (NET-PHDNSWC) +#204.34.201.0 +## Naval Facilities Engineering Housing (NET-NAVFAC) +#204.34.202.0 +## NAVSEA Logistics Command Detachment (NET-NSLC2) +#204.34.203.0 +## Naval Air Warfare Center (NET-OTT-NET) +#204.34.204.0 +## Portsmouth Naval Shipyard (NET-PORTSNET) +#204.34.205.0 +## INFORMATION SYSTEMS TECHNOLOGY CENTER (ISTC) (NET-ISTCTC) +#204.34.206.0 +## Military Sealift Command Pacific (NETBLK-NETBLK-USNSMERCY204) +#204.34.208.0 - 204.34.210.0 +## USAF Academy (NET-USAFA-GW-NET) +#204.34.211.0 +## 3rd Combat Service Support (NET-CSSG3-NIP) +#204.34.212.0 +## 1st Radio Battalion (NET-RDBN1-NIP) +#204.34.213.0 +## OASD (Health Affairs) (NET-TRICARE) +#204.34.214.0 +## Second Marine Expeditionary Force (NET-MEU26-SIP) +#204.34.215.0 +## 1st Marine Air Wing (NET-ASE1-NIP) +#204.34.216.0 +## SA-ALC/LTE (NET-ITACNET) +#204.34.217.0 +## 3rd Marine (NET-MAR3-NIP) +#204.34.218.0 +## Communications and Electronics (NET-MCBH-NIP) +#204.34.219.0 +## G-6 Operations, III MEF (NET-DFW5BR-NIP) +#204.34.220.0 +## G-6 Operations, III MEF (NET-DFW1-NIP) +#204.34.221.0 +## G-6 Operations, III MEF (NET-DFW2-NIP) +#204.34.222.0 +## G-6 Operations, III MEF (NET-DFW3-NIP) +#204.34.223.0 +## G-6 Operations, III MEF (NET-DFW4-NIP) +#204.34.224.0 +## Joint Interoperability Test Command (NET-JITC-RTD216.25.0 <-- REAL DANGEROUS +#204.34.225.0 +## +#205.96-103.0 +## (FBI's honeypot) +#205.97.0.0 +## (FBI's honeypot) +#205.98.0.0 +## (FBI's honeypot) +#205.99.0.0 +## (FBI's honeypot) +#205.100.0.0 +## (FBI's honeypot) +#205.101.0.0 +## (FBI's honeypot) +#205.102.0.0 +## (FBI's honeypot) +#205.103.0.0 +## [Sherbrooke University, Canada +#206.167. +## (FBI's honeypot) +#207.30.0.0 +## (FBI's honeypot) +#207.31.0.0 +## (FBI's honeypot) +#207.32.0.0 +## (FBI's honeypot) +#207.33.0.0 +## (FBI's honeypot) +#207.34.0.0 +## (FBI's honeypot) +#207.35.0.0 +## (FBI's honeypot) +#207.36.0.0 +## (FBI's honeypot) +#207.37.0.0 +## (FBI's honeypot) +#207.38.0.0 +## (FBI's honeypot) +#207.39.0.0 +## (FBI's honeypot) +#207.40.0.0 +## (FBI's honeypot) +#207.41.0.0 +## (FBI's honeypot) +#207.42.0.0 +## (FBI's honeypot) +#207.43.0.0 +## (FBI's honeypot) +#207.44.0.0 +## (FBI's honey07.60.14.255 J. A. Webster (NETBLK-TIAC-JAWFRT1-2) +#207.45.0.0 +## Trilogic (NETBLK-TIAC-LOGIC384) +#207.60.15.0 - 207.60.15.127 +## Area 54 (NETBLK-TIAC-AREA54) +#207.60.16.0 - 207.60.16.255 +## Vested Development Inc (NETBLK-TIAC-VESTEDT-2) +#207.60.18.0 - 207.60.18.63 +## Conventures (NETBLK-TIAC-CON56-2) +#207.60.18.64 - 207.60.18.127 +## Don Law Company (NETBLK-TIAC-DONLAWT1-2) +#207.60.21.0 - 207.60.21.255 +## Advanced Microsensors (NETBLK-TIAC-AMS384) +#207.60.22.0 - 207.60.22.255 +## Applied Business Center (NETBLK-TIAC-APP56K-2) +#207.60.28.0 - 207.60.28.63 +## Color and Design Exchange (NETBLK-TIAC-COLOR-2) +#207.60.28.64 - 207.60.28.127 +## Shaun McCusker (NETBLK-TIAC-FINLAY) +#207.60.36.8 - 207.60.36.15 +## Town of Framingham (NETBLK-TIAC-INFOSERV) +#207.60.36.16 - 207.60.36.23 +## AB Software (NETBLK-TIAC-ABSADSL) +#207.60.36.24 - 207.60.36.31 +## Seabass Dreams Too Much, Inc (NETBLK-TIAC-SEABASS) +#207.60.36.32 - 207.60.36.39 +## Next Ticketing (NETBLK-TIAC-NT256T1-2) +#207.60.36.40 - 207.60.36.47 +## Dulsi (NETBLK-TIAC-DULSI) +#207.60.36.48 - 207.60.36.55 +## The Internet Access Company (NETBLK-TIAC-PTIMJ) +#207.60.36.56 - 207.60.36.63 +## Maguire Group (NETBLK-TIAC-MAGISDN) +#207.60.36.64 - 207.60.36.71 +## Cogenex (NETBLK-TIAC-COGENEX-2) +#207.60.36.72 - 207.60.36.79 +## AKNDC (NETBLK-TIAC-AKNDC) +#207.60.36.88 - 207.60.36.95 +## McGovern election commitee (NETBLK-TIAC-MCGOVDED) +#207.60.36.96 - 207.60.36.103 +## Digital Equipment Corp (NETBLK-TIAC-DECISDN) +#207.60.36.104 - 207.60.36.111 +## PTR - Precision Technologies (NETBLK-TIAC-PTREB) +#207.60.36.112 - 207.60.36.119 +## Extech (NETBLK-TIAC-EXTECH-2) +#207.60.36.120 - 207.60.36.127 +## Manfreddi Architects (NETBLK-TIAC-MANELKUS-2) +#207.60.36.128 - 207.60.36.135 +## Parent Naffah (NETBLK-TIAC-PARENT) +#207.60.36.144 - 207.60.36.151 +## Darling Dolls Inc (NETBLK-TIAC-EMARTEL) +#207.60.36.152 - 207.60.36.159 +## Wright Communications (NETBLK-TIAC-WRIGHT56) +#207.60.36.160 - 207.60.36.167 +## Principle Software (NETBLK-TIAC-PRINCIPL) +#207.60.36.168 - 207.60.36.175 +## Chris Pet Store (NETBLK-TIAC-CPETDIAL) +#207.60.36.176 - 207.60.36.183 +## Fifteen Lilies (NETBLK-TIAC-GREYROSE) +#207.60.36.184 - 207.60.36.191 +## All-Com Technologies (NETBLK-TIAC-ALLCOM1-2) +#207.60.36.192 - 207.60.36.199 +## Cardio Thoracic Surgical Associates, P. A. (NETBLK-TIAC-HEARTDOC) +#207.60.37.0 - 207.60.37.31 +## Preferred Fixtures Inc (NETBLK-TIAC-PREFMFG-2) +#207.60.37.32 - 207.60.37.63 +## Apple and Eve Distributors (NETBLK-TIAC-AEDED99) +#207.60.37.64 - 207.60.37.95 +## Nelson Copy Supply (NETBLK-TIAC-NCOP56K) +#207.60.37.96 - 207.60.37.127 +## Boston Optical Fiber (NETBLK-TIAC-BOSISDN) +#207.60.37.128 - 207.60.37.159 +## Fantasia&Company (NETBLK-TIAC-FANTCOMP) +#207.60.37.192 - 207.60.37.223 +## Infoactive (NETBLK-TIAC-INFOACT-2) +#207.60.41.0 - 207.60.41.255 +## Curry College (NETBLK-TIAC-CURRY) +#207.60.48.0 - 207.60.48.255 +## Alternate Power Source (NETBLK-TIAC-APSIS) +#207.60.62.32 - 207.60.62.63 +## Keystone Howley-White (NETBLK-TIAC-KEYSTONE-2) +#207.60.62.64 - 207.60.62.95 +## Bridgehead Associates LTD (NETBLK-TIAC-BRIDG384) +#207.60.62.128 - 207.60.62.159 +## County Supply (NETBLK-TIAC-CS384) +#207.60.62.160 - 207.60.62.191 +## NH Board of Nursing (NETBLK-TIAC-NHBNDED99) +#207.60.62.192 - 207.60.62.223 +## Diversified Wireless Technologies (NETBLK-TIAC-LAUCHAM) +#207.60.64.0 - 207.60.64.63 +## Phytera (NETBLK-TIAC-PHYTERA1) +#207.60.64.64 - 207.60.64.127 +## The Network Connection (NETBLK-TIAC-TNC56) +#207.60.66.0 - 207.60.66.15 +## Young Refrigeration (NETBLK-TIAC-YRDED135) +#207.60.66.16 - 207.60.66.31 +## Vision Appraisal Technology (NETBLK-TIAC-VISIONT1) +#207.60.66.32 - 207.60.66.47 +## EffNet Inc (NETBLK-TIAC-EFFNETT1) +#207.60.66.48 - 207.60.66.63 +## Entropic Systems Inc (NETBLK-TIAC-ENTRO128-3) +#207.60.66.64 - 207.60.66.79 +## Finley Properties (NETBLK-TIAC-FPDED135) +#207.60.66.80 - 207.60.66.95 +## Nancy Plowman Associates (NETBLK-TIAC-NPAISDN) +#207.60.66.96 - 207.60.66.111 +## Northeast Financial Strategies (NETBLK-TIAC-NFSISDN) +#207.60.66.112 - 207.60.66.127 +## Textnology Corp (NETBLK-TIAC-TEXTC0RP) +#207.60.66.128 - 207.60.66.143 +## Groton Neochem LLC (NETBLK-TIAC-NEOCHEM) +#207.60.66.144 - 207.60.66.159 +## Tab Computers (NETBLK-TIAC-TCSI3) +#207.60.66.160 - 207.60.66.175 +## Patrons Insurance (NETBL +#207.60.66.176 - 207.60.66.191 \ No newline at end of file diff --git a/html/login.html b/html/login.html new file mode 100755 index 0000000..8b911a2 --- /dev/null +++ b/html/login.html @@ -0,0 +1,26 @@ + +
+
+

- Log in

+ + + + + + + +
+ +
+ + \ No newline at end of file diff --git a/html/nav.html b/html/nav.html new file mode 100755 index 0000000..435113e --- /dev/null +++ b/html/nav.html @@ -0,0 +1,33 @@ + + + + + + + + <!--Place title here!!!--> + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/html/src/UbuntuMono-R.ttf b/html/src/UbuntuMono-R.ttf new file mode 100755 index 0000000000000000000000000000000000000000..fdd309d716629f4e5339d5e5508225ed857a3ede GIT binary patch literal 205748 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ăESk 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 G(fmJpf?fdt literal 0 HcmV?d00001 diff --git a/html/src/auth.js b/html/src/auth.js new file mode 100755 index 0000000..94e5f7c --- /dev/null +++ b/html/src/auth.js @@ -0,0 +1,65 @@ +import * as utils from '/src/utils.js' +import * as jsonpack from '/src/jsonpack.js' + +let c = null + +export function authClient(rawClient) { + c = this + this.username = null + this.permGroups = null + this.accountCreated = null + this.passwordUpdated = null + this.id = null + this.rawClient = rawClient + + this.login = (username, password)=>{ + const salt = utils.getUnixTime() + const key = (utils.sha256( + username + + utils.sha256(password) + + salt + )) + //console.log(c.rawClient.send) + c.rawClient.send('login', { + data: key, + salt: salt + }) + } + + this.clidata = (data)=>{ + const session = utils.getCookie('session') + if(session != ''){ + this.rawClient.send('reauth', { + session: session + }) + } + } + + this.loginSuccess = (data)=>{ + utils.popupSuccess('Connection', 'Successfully logged in!') + utils.iconauth() + console.log(data.data.session) + if(data.data.session != null){ + utils.setCookie('session', data.data.session) + } + window.location = data.data.redir + } + + this.reauth = (data)=>{ + + this.username = data.data.username + this.id = data.data.id + this.permGroups = data.data.permGroups + this.accountCreated = data.data.created + this.passwordUpdated = data.data.passwordUpdated + + if(window.location.pathname == "/login"){ + utils.popupSuccess('Connection', 'Successfully logged in!') + } + utils.iconauth() + } + + this.rawClient.addRawTypeListener('clidata', this.clidata) + this.rawClient.addRawTypeListener('loginSuccess', this.loginSuccess) + this.rawClient.addRawTypeListener('reauth', this.reauth) +} \ No newline at end of file diff --git a/html/src/jsonpack.js b/html/src/jsonpack.js new file mode 100755 index 0000000..7569abc --- /dev/null +++ b/html/src/jsonpack.js @@ -0,0 +1,559 @@ +/* + Copyright (c) 2013, Rodrigo González, Sapienlab All Rights Reserved. + Available via MIT LICENSE. See https://github.com/roro89/jsonpack/blob/master/LICENSE.md for details. +*/ + + +var TOKEN_TRUE = -1; +var TOKEN_FALSE = -2; +var TOKEN_NULL = -3; +var TOKEN_EMPTY_STRING = -4; +var TOKEN_UNDEFINED = -5; + +export function pack(json, options) { + + // Canonizes the options + options = options || {}; + + // A shorthand for debugging + var verbose = options.verbose || false; + + verbose && console.log('Normalize the JSON Object'); + + // JSON as Javascript Object (Not string representation) + json = typeof json === 'string' ? this.JSON.parse(json) : json; + + verbose && console.log('Creating a empty dictionary'); + + // The dictionary + var dictionary = { + strings : [], + integers : [], + floats : [] + }; + + verbose && console.log('Creating the AST'); + + // The AST + var ast = (function recursiveAstBuilder(item) { + + verbose && console.log('Calling recursiveAstBuilder with ' + this.JSON.stringify(item)); + + // The type of the item + var type = typeof item; + + // Case 7: The item is null + if (item === null) { + return { + type : 'null', + index : TOKEN_NULL + }; + } + + //add undefined + if (typeof item === 'undefined') { + return { + type : 'undefined', + index : TOKEN_UNDEFINED + }; + } + + // Case 1: The item is Array Object + if ( item instanceof Array) { + + // Create a new sub-AST of type Array (@) + var ast = ['@']; + + // Add each items + for (var i in item) { + + if (!item.hasOwnProperty(i)) continue; + + ast.push(recursiveAstBuilder(item[i])); + } + + // And return + return ast; + + } + + // Case 2: The item is Object + if (type === 'object') { + + // Create a new sub-AST of type Object ($) + var ast = ['$']; + + // Add each items + for (var key in item) { + + if (!item.hasOwnProperty(key)) + continue; + + ast.push(recursiveAstBuilder(key)); + ast.push(recursiveAstBuilder(item[key])); + } + + // And return + return ast; + + } + + // Case 3: The item empty string + if (item === '') { + return { + type : 'empty', + index : TOKEN_EMPTY_STRING + }; + } + + // Case 4: The item is String + if (type === 'string') { + + // The index of that word in the dictionary + var index = _indexOf.call(dictionary.strings, item); + + // If not, add to the dictionary and actualize the index + if (index == -1) { + dictionary.strings.push(_encode(item)); + index = dictionary.strings.length - 1; + } + + // Return the token + return { + type : 'strings', + index : index + }; + } + + // Case 5: The item is integer + if (type === 'number' && item % 1 === 0) { + + // The index of that number in the dictionary + var index = _indexOf.call(dictionary.integers, item); + + // If not, add to the dictionary and actualize the index + if (index == -1) { + dictionary.integers.push(_base10To36(item)); + index = dictionary.integers.length - 1; + } + + // Return the token + return { + type : 'integers', + index : index + }; + } + + // Case 6: The item is float + if (type === 'number') { + // The index of that number in the dictionary + var index = _indexOf.call(dictionary.floats, item); + + // If not, add to the dictionary and actualize the index + if (index == -1) { + // Float not use base 36 + dictionary.floats.push(item); + index = dictionary.floats.length - 1; + } + + // Return the token + return { + type : 'floats', + index : index + }; + } + + // Case 7: The item is boolean + if (type === 'boolean') { + return { + type : 'boolean', + index : item ? TOKEN_TRUE : TOKEN_FALSE + }; + } + + // Default + throw new Error('Unexpected argument of type ' + typeof (item)); + + })(json); + + // A set of shorthands proxies for the length of the dictionaries + var stringLength = dictionary.strings.length; + var integerLength = dictionary.integers.length; + var floatLength = dictionary.floats.length; + + verbose && console.log('Parsing the dictionary'); + + // Create a raw dictionary + var packed = dictionary.strings.join('|'); + packed += '^' + dictionary.integers.join('|'); + packed += '^' + dictionary.floats.join('|'); + + verbose && console.log('Parsing the structure'); + + // And add the structure + packed += '^' + (function recursiveParser(item) { + + verbose && console.log('Calling a recursiveParser with ' + this.JSON.stringify(item)); + + // If the item is Array, then is a object of + // type [object Object] or [object Array] + if ( item instanceof Array) { + + // The packed resulting + var packed = item.shift(); + + for (var i in item) { + + if (!item.hasOwnProperty(i)) + continue; + + packed += recursiveParser(item[i]) + '|'; + } + + return (packed[packed.length - 1] === '|' ? packed.slice(0, -1) : packed) + ']'; + + } + + // A shorthand proxies + var type = item.type, index = item.index; + + if (type === 'strings') { + // Just return the base 36 of index + return _base10To36(index); + } + + if (type === 'integers') { + // Return a base 36 of index plus stringLength offset + return _base10To36(stringLength + index); + } + + if (type === 'floats') { + // Return a base 36 of index plus stringLength and integerLength offset + return _base10To36(stringLength + integerLength + index); + } + + if (type === 'boolean') { + return item.index; + } + + if (type === 'null') { + return TOKEN_NULL; + } + + if (type === 'undefined') { + return TOKEN_UNDEFINED; + } + + if (type === 'empty') { + return TOKEN_EMPTY_STRING; + } + + throw new TypeError('The item is alien!'); + + })(ast); + + verbose && console.log('Ending parser'); + + // If debug, return a internal representation of dictionary and stuff + if (options.debug) + return { + dictionary : dictionary, + ast : ast, + packed : packed + }; + + return packed; + +}; + +export function unpack(packed, options) { + + // Canonizes the options + options = options || {}; + + // A raw buffer + var rawBuffers = packed.split('^'); + + // Create a dictionary + options.verbose && console.log('Building dictionary'); + var dictionary = []; + + // Add the strings values + var buffer = rawBuffers[0]; + if (buffer !== '') { + buffer = buffer.split('|'); + options.verbose && console.log('Parse the strings dictionary'); + for (var i=0, n=buffer.length; i{ + window.utils.popupInfo(data.data.title, data.data.msg) +}) + +window.addListener('popupSuccess', (data)=>{ + window.utils.popupSuccess(data.data.title, data.data.msg) +}) + +window.addListener('popupWarning', (data)=>{ + window.utils.popupWarning(data.data.title, data.data.msg) +}) + +window.addListener('popupError', (data)=>{ + window.utils.popupError(data.data.title, data.data.msg) +}) + +window.addListener('popupColor', (data)=>{ + window.utils.addPopup(data.data.color, data.data.isDark, data.data.title, data.data.msg) +}) + +window.main() \ No newline at end of file diff --git a/html/src/packets.js b/html/src/packets.js new file mode 100755 index 0000000..d9335e9 --- /dev/null +++ b/html/src/packets.js @@ -0,0 +1,106 @@ +import * as jsonpack from '/src/jsonpack.js' +import * as utils from "/src/utils.js" + + +let cID = null +let evListeners = [] +let c = null + +function getErrorDesc(error){ + switch(error){ + case 'invalidLogin': + return 'Invalid username or password' + case 'invalidLoginRequest': + utils.setCookie('session', '') + return 'Some part of the login request is invalid, please try again' + case 'prelogin': + window.location.pathname = '/' + return 'You are already logged in' + } + return error +} + +function processData(data){ + data = jsonpack.unpack(data) + switch(data.type){ + case 'clidata': + c.cID = data.data.cid + if(window.location.pathname == "/login") { + utils.popupWarning('Connection', 'Connected to server!') + utils.iconunauth() + }else{ + utils.popupInfo('Connection', 'Connected to server!') + utils.iconauth() + } + break + case 'redir': + window.location.pathname = data.location + case 'data': + console.log(data.data) + break + case 'error': + utils.popupError(`Error: ${data.data}`, getErrorDesc(data.data)) + } + for(let i=0;i{} + this.onclose = ()=>{} + + this.cID = null + + this.evtSource.onmessage = (event) => { + console.log(`Data: ${event.data}`) + processData(event.data) + } + + this.evtSource.onerror = (event) => { + console.log('Error!') + this.connected = false + utils.icondisconnect() + utils.popupError('Connection', 'Disconnected from server') + this.onclose() + } + + this.evtSource.onopen = (event) => { + console.log('Connected!') + this.connected = true + utils.iconunauth() + this.onopen() + } + + this.send = (type, data)=>{ + //console.log({type, data}) + fetch(this.location, { + method: "post", + headers: { + 'Accept': '*', + 'Content-Type': 'text/plain' + }, + body: jsonpack.pack({ + type: type, + data: data, + cid: this.cID + }) + }) + } + + this.addRawTypeListener = (type, func)=>{ + evListeners.push({ + type: type, + func: func + }) + } +} \ No newline at end of file diff --git a/html/src/pico.min.css b/html/src/pico.min.css new file mode 100755 index 0000000..d0d5ba4 --- /dev/null +++ b/html/src/pico.min.css @@ -0,0 +1,5 @@ +@charset "UTF-8";/*! + * Pico CSS v1.5.11 (https://picocss.com) + * Copyright 2019-2023 - Licensed under MIT + */:root{--font-family:system-ui,-apple-system,"Segoe UI","Roboto","Ubuntu","Cantarell","Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--line-height:1.5;--font-weight:400;--font-size:16px;--border-radius:0.25rem;--border-width:1px;--outline-width:3px;--spacing:1rem;--typography-spacing-vertical:1.5rem;--block-spacing-vertical:calc(var(--spacing) * 2);--block-spacing-horizontal:var(--spacing);--grid-spacing-vertical:0;--grid-spacing-horizontal:var(--spacing);--form-element-spacing-vertical:0.75rem;--form-element-spacing-horizontal:1rem;--nav-element-spacing-vertical:1rem;--nav-element-spacing-horizontal:0.5rem;--nav-link-spacing-vertical:0.5rem;--nav-link-spacing-horizontal:0.5rem;--form-label-font-weight:var(--font-weight);--transition:0.2s ease-in-out;--modal-overlay-backdrop-filter:blur(0.25rem)}@media (min-width:576px){:root{--font-size:17px}}@media (min-width:768px){:root{--font-size:18px}}@media (min-width:992px){:root{--font-size:19px}}@media (min-width:1200px){:root{--font-size:20px}}@media (min-width:576px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 2.5)}}@media (min-width:768px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 3)}}@media (min-width:992px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 3.5)}}@media (min-width:1200px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 4)}}@media (min-width:576px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.25)}}@media (min-width:768px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.5)}}@media (min-width:992px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.75)}}@media (min-width:1200px){article{--block-spacing-horizontal:calc(var(--spacing) * 2)}}dialog>article{--block-spacing-vertical:calc(var(--spacing) * 2);--block-spacing-horizontal:var(--spacing)}@media (min-width:576px){dialog>article{--block-spacing-vertical:calc(var(--spacing) * 2.5);--block-spacing-horizontal:calc(var(--spacing) * 1.25)}}@media (min-width:768px){dialog>article{--block-spacing-vertical:calc(var(--spacing) * 3);--block-spacing-horizontal:calc(var(--spacing) * 1.5)}}a{--text-decoration:none}a.contrast,a.secondary{--text-decoration:underline}small{--font-size:0.875em}h1,h2,h3,h4,h5,h6{--font-weight:700}h1{--font-size:2rem;--typography-spacing-vertical:3rem}h2{--font-size:1.75rem;--typography-spacing-vertical:2.625rem}h3{--font-size:1.5rem;--typography-spacing-vertical:2.25rem}h4{--font-size:1.25rem;--typography-spacing-vertical:1.874rem}h5{--font-size:1.125rem;--typography-spacing-vertical:1.6875rem}[type=checkbox],[type=radio]{--border-width:2px}[type=checkbox][role=switch]{--border-width:3px}tfoot td,tfoot th,thead td,thead th{--border-width:3px}:not(thead,tfoot)>*>td{--font-size:0.875em}code,kbd,pre,samp{--font-family:"Menlo","Consolas","Roboto Mono","Ubuntu Monospace","Noto Mono","Oxygen Mono","Liberation Mono",monospace,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}kbd{--font-weight:bolder}:root:not([data-theme=dark]),[data-theme=light]{--background-color:#fff;--color:hsl(205, 20%, 32%);--h1-color:hsl(205, 30%, 15%);--h2-color:#24333e;--h3-color:hsl(205, 25%, 23%);--h4-color:#374956;--h5-color:hsl(205, 20%, 32%);--h6-color:#4d606d;--muted-color:hsl(205, 10%, 50%);--muted-border-color:hsl(205, 20%, 94%);--primary:hsl(195, 85%, 41%);--primary-hover:hsl(195, 90%, 32%);--primary-focus:rgba(16, 149, 193, 0.125);--primary-inverse:#fff;--secondary:hsl(205, 15%, 41%);--secondary-hover:hsl(205, 20%, 32%);--secondary-focus:rgba(89, 107, 120, 0.125);--secondary-inverse:#fff;--contrast:hsl(205, 30%, 15%);--contrast-hover:#000;--contrast-focus:rgba(89, 107, 120, 0.125);--contrast-inverse:#fff;--mark-background-color:#fff2ca;--mark-color:#543a26;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:transparent;--form-element-border-color:hsl(205, 14%, 68%);--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:transparent;--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205, 18%, 86%);--form-element-disabled-border-color:hsl(205, 14%, 68%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#c62828;--form-element-invalid-active-border-color:#d32f2f;--form-element-invalid-focus-color:rgba(211, 47, 47, 0.125);--form-element-valid-border-color:#388e3c;--form-element-valid-active-border-color:#43a047;--form-element-valid-focus-color:rgba(67, 160, 71, 0.125);--switch-background-color:hsl(205, 16%, 77%);--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:hsl(205, 18%, 86%);--range-active-border-color:hsl(205, 16%, 77%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:#f6f8f9;--code-background-color:hsl(205, 20%, 94%);--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330, 40%, 50%);--code-property-color:hsl(185, 40%, 40%);--code-value-color:hsl(40, 20%, 50%);--code-comment-color:hsl(205, 14%, 68%);--accordion-border-color:var(--muted-border-color);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:var(--background-color);--card-border-color:var(--muted-border-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(27, 40, 50, 0.01698),0.0335rem 0.067rem 0.402rem rgba(27, 40, 50, 0.024),0.0625rem 0.125rem 0.75rem rgba(27, 40, 50, 0.03),0.1125rem 0.225rem 1.35rem rgba(27, 40, 50, 0.036),0.2085rem 0.417rem 2.502rem rgba(27, 40, 50, 0.04302),0.5rem 1rem 6rem rgba(27, 40, 50, 0.06),0 0 0 0.0625rem rgba(27, 40, 50, 0.015);--card-sectionning-background-color:#fbfbfc;--dropdown-background-color:#fbfbfc;--dropdown-border-color:#e1e6eb;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:hsl(205, 20%, 94%);--modal-overlay-background-color:rgba(213, 220, 226, 0.7);--progress-background-color:hsl(205, 18%, 86%);--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(198, 40, 40)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(56, 142, 60)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:light}@media only screen and (prefers-color-scheme:dark){:root:not([data-theme]){--background-color:#11191f;--color:hsl(205, 16%, 77%);--h1-color:hsl(205, 20%, 94%);--h2-color:#e1e6eb;--h3-color:hsl(205, 18%, 86%);--h4-color:#c8d1d8;--h5-color:hsl(205, 16%, 77%);--h6-color:#afbbc4;--muted-color:hsl(205, 10%, 50%);--muted-border-color:#1f2d38;--primary:hsl(195, 85%, 41%);--primary-hover:hsl(195, 80%, 50%);--primary-focus:rgba(16, 149, 193, 0.25);--primary-inverse:#fff;--secondary:hsl(205, 15%, 41%);--secondary-hover:hsl(205, 10%, 50%);--secondary-focus:rgba(115, 130, 140, 0.25);--secondary-inverse:#fff;--contrast:hsl(205, 20%, 94%);--contrast-hover:#fff;--contrast-focus:rgba(115, 130, 140, 0.25);--contrast-inverse:#000;--mark-background-color:#d1c284;--mark-color:#11191f;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:#11191f;--form-element-border-color:#374956;--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:var(--form-element-background-color);--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205, 25%, 23%);--form-element-disabled-border-color:hsl(205, 20%, 32%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#b71c1c;--form-element-invalid-active-border-color:#c62828;--form-element-invalid-focus-color:rgba(198, 40, 40, 0.25);--form-element-valid-border-color:#2e7d32;--form-element-valid-active-border-color:#388e3c;--form-element-valid-focus-color:rgba(56, 142, 60, 0.25);--switch-background-color:#374956;--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:#24333e;--range-active-border-color:hsl(205, 25%, 23%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:rgba(115, 130, 140, 0.05);--code-background-color:#18232c;--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330, 30%, 50%);--code-property-color:hsl(185, 30%, 50%);--code-value-color:hsl(40, 10%, 50%);--code-comment-color:#4d606d;--accordion-border-color:var(--muted-border-color);--accordion-active-summary-color:var(--primary);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:#141e26;--card-border-color:var(--card-background-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),0 0 0 0.0625rem rgba(0, 0, 0, 0.015);--card-sectionning-background-color:#18232c;--dropdown-background-color:hsl(205, 30%, 15%);--dropdown-border-color:#24333e;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:rgba(36, 51, 62, 0.75);--modal-overlay-background-color:rgba(36, 51, 62, 0.8);--progress-background-color:#24333e;--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}}[data-theme=dark]{--background-color:#11191f;--color:hsl(205, 16%, 77%);--h1-color:hsl(205, 20%, 94%);--h2-color:#e1e6eb;--h3-color:hsl(205, 18%, 86%);--h4-color:#c8d1d8;--h5-color:hsl(205, 16%, 77%);--h6-color:#afbbc4;--muted-color:hsl(205, 10%, 50%);--muted-border-color:#1f2d38;--primary:hsl(195, 85%, 41%);--primary-hover:hsl(195, 80%, 50%);--primary-focus:rgba(16, 149, 193, 0.25);--primary-inverse:#fff;--secondary:hsl(205, 15%, 41%);--secondary-hover:hsl(205, 10%, 50%);--secondary-focus:rgba(115, 130, 140, 0.25);--secondary-inverse:#fff;--contrast:hsl(205, 20%, 94%);--contrast-hover:#fff;--contrast-focus:rgba(115, 130, 140, 0.25);--contrast-inverse:#000;--mark-background-color:#d1c284;--mark-color:#11191f;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:#11191f;--form-element-border-color:#374956;--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:var(--form-element-background-color);--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205, 25%, 23%);--form-element-disabled-border-color:hsl(205, 20%, 32%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#b71c1c;--form-element-invalid-active-border-color:#c62828;--form-element-invalid-focus-color:rgba(198, 40, 40, 0.25);--form-element-valid-border-color:#2e7d32;--form-element-valid-active-border-color:#388e3c;--form-element-valid-focus-color:rgba(56, 142, 60, 0.25);--switch-background-color:#374956;--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:#24333e;--range-active-border-color:hsl(205, 25%, 23%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:rgba(115, 130, 140, 0.05);--code-background-color:#18232c;--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330, 30%, 50%);--code-property-color:hsl(185, 30%, 50%);--code-value-color:hsl(40, 10%, 50%);--code-comment-color:#4d606d;--accordion-border-color:var(--muted-border-color);--accordion-active-summary-color:var(--primary);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:#141e26;--card-border-color:var(--card-background-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),0 0 0 0.0625rem rgba(0, 0, 0, 0.015);--card-sectionning-background-color:#18232c;--dropdown-background-color:hsl(205, 30%, 15%);--dropdown-border-color:#24333e;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:rgba(36, 51, 62, 0.75);--modal-overlay-background-color:rgba(36, 51, 62, 0.8);--progress-background-color:#24333e;--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}[type=checkbox],[type=radio],[type=range],progress{accent-color:var(--primary)}*,::after,::before{box-sizing:border-box;background-repeat:no-repeat}::after,::before{text-decoration:inherit;vertical-align:inherit}:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--background-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);line-height:var(--line-height);font-family:var(--font-family);text-rendering:optimizeLegibility;overflow-wrap:break-word;cursor:default;-moz-tab-size:4;-o-tab-size:4;tab-size:4}main{display:block}body{width:100%;margin:0}body>footer,body>header,body>main{width:100%;margin-right:auto;margin-left:auto;padding:var(--block-spacing-vertical) 0}.container,.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:var(--spacing);padding-left:var(--spacing)}@media (min-width:576px){.container{max-width:510px;padding-right:0;padding-left:0}}@media (min-width:768px){.container{max-width:700px}}@media (min-width:992px){.container{max-width:920px}}@media (min-width:1200px){.container{max-width:1130px}}section{margin-bottom:var(--block-spacing-vertical)}.grid{grid-column-gap:var(--grid-spacing-horizontal);grid-row-gap:var(--grid-spacing-vertical);display:grid;grid-template-columns:1fr;margin:0}@media (min-width:992px){.grid{grid-template-columns:repeat(auto-fit,minmax(0%,1fr))}}.grid>*{min-width:0}figure{display:block;margin:0;padding:0;overflow-x:auto}figure figcaption{padding:calc(var(--spacing) * .5) 0;color:var(--muted-color)}b,strong{font-weight:bolder}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}address,blockquote,dl,figure,form,ol,p,pre,table,ul{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-style:normal;font-weight:var(--font-weight);font-size:var(--font-size)}[role=link],a{--color:var(--primary);--background-color:transparent;outline:0;background-color:var(--background-color);color:var(--color);-webkit-text-decoration:var(--text-decoration);text-decoration:var(--text-decoration);transition:background-color var(--transition),color var(--transition),box-shadow var(--transition),-webkit-text-decoration var(--transition);transition:background-color var(--transition),color var(--transition),text-decoration var(--transition),box-shadow var(--transition);transition:background-color var(--transition),color var(--transition),text-decoration var(--transition),box-shadow var(--transition),-webkit-text-decoration var(--transition)}[role=link]:is([aria-current],:hover,:active,:focus),a:is([aria-current],:hover,:active,:focus){--color:var(--primary-hover);--text-decoration:underline}[role=link]:focus,a:focus{--background-color:var(--primary-focus)}[role=link].secondary,a.secondary{--color:var(--secondary)}[role=link].secondary:is([aria-current],:hover,:active,:focus),a.secondary:is([aria-current],:hover,:active,:focus){--color:var(--secondary-hover)}[role=link].secondary:focus,a.secondary:focus{--background-color:var(--secondary-focus)}[role=link].contrast,a.contrast{--color:var(--contrast)}[role=link].contrast:is([aria-current],:hover,:active,:focus),a.contrast:is([aria-current],:hover,:active,:focus){--color:var(--contrast-hover)}[role=link].contrast:focus,a.contrast:focus{--background-color:var(--contrast-focus)}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);font-family:var(--font-family)}h1{--color:var(--h1-color)}h2{--color:var(--h2-color)}h3{--color:var(--h3-color)}h4{--color:var(--h4-color)}h5{--color:var(--h5-color)}h6{--color:var(--h6-color)}:where(address,blockquote,dl,figure,form,ol,p,pre,table,ul)~:is(h1,h2,h3,h4,h5,h6){margin-top:var(--typography-spacing-vertical)}.headings,hgroup{margin-bottom:var(--typography-spacing-vertical)}.headings>*,hgroup>*{margin-bottom:0}.headings>:last-child,hgroup>:last-child{--color:var(--muted-color);--font-weight:unset;font-size:1rem;font-family:unset}p{margin-bottom:var(--typography-spacing-vertical)}small{font-size:var(--font-size)}:where(dl,ol,ul){padding-right:0;padding-left:var(--spacing);padding-inline-start:var(--spacing);padding-inline-end:0}:where(dl,ol,ul) li{margin-bottom:calc(var(--typography-spacing-vertical) * .25)}:where(dl,ol,ul) :is(dl,ol,ul){margin:0;margin-top:calc(var(--typography-spacing-vertical) * .25)}ul li{list-style:square}mark{padding:.125rem .25rem;background-color:var(--mark-background-color);color:var(--mark-color);vertical-align:baseline}blockquote{display:block;margin:var(--typography-spacing-vertical) 0;padding:var(--spacing);border-right:none;border-left:.25rem solid var(--blockquote-border-color);border-inline-start:0.25rem solid var(--blockquote-border-color);border-inline-end:none}blockquote footer{margin-top:calc(var(--typography-spacing-vertical) * .5);color:var(--blockquote-footer-color)}abbr[title]{border-bottom:1px dotted;text-decoration:none;cursor:help}ins{color:var(--ins-color);text-decoration:none}del{color:var(--del-color)}::-moz-selection{background-color:var(--primary-focus)}::selection{background-color:var(--primary-focus)}:where(audio,canvas,iframe,img,svg,video){vertical-align:middle}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}:where(iframe){border-style:none}img{max-width:100%;height:auto;border-style:none}:where(svg:not([fill])){fill:currentColor}svg:not(:root){overflow:hidden}button{margin:0;overflow:visible;font-family:inherit;text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}button{display:block;width:100%;margin-bottom:var(--spacing)}[role=button]{display:inline-block;text-decoration:none}[role=button],button,input[type=button],input[type=reset],input[type=submit]{--background-color:var(--primary);--border-color:var(--primary);--color:var(--primary-inverse);--box-shadow:var(--button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[role=button]:is([aria-current],:hover,:active,:focus),button:is([aria-current],:hover,:active,:focus),input[type=button]:is([aria-current],:hover,:active,:focus),input[type=reset]:is([aria-current],:hover,:active,:focus),input[type=submit]:is([aria-current],:hover,:active,:focus){--background-color:var(--primary-hover);--border-color:var(--primary-hover);--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));--color:var(--primary-inverse)}[role=button]:focus,button:focus,input[type=button]:focus,input[type=reset]:focus,input[type=submit]:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--primary-focus)}:is(button,input[type=submit],input[type=button],[role=button]).secondary,input[type=reset]{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);cursor:pointer}:is(button,input[type=submit],input[type=button],[role=button]).secondary:is([aria-current],:hover,:active,:focus),input[type=reset]:is([aria-current],:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover);--color:var(--secondary-inverse)}:is(button,input[type=submit],input[type=button],[role=button]).secondary:focus,input[type=reset]:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--secondary-focus)}:is(button,input[type=submit],input[type=button],[role=button]).contrast{--background-color:var(--contrast);--border-color:var(--contrast);--color:var(--contrast-inverse)}:is(button,input[type=submit],input[type=button],[role=button]).contrast:is([aria-current],:hover,:active,:focus){--background-color:var(--contrast-hover);--border-color:var(--contrast-hover);--color:var(--contrast-inverse)}:is(button,input[type=submit],input[type=button],[role=button]).contrast:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--contrast-focus)}:is(button,input[type=submit],input[type=button],[role=button]).outline,input[type=reset].outline{--background-color:transparent;--color:var(--primary)}:is(button,input[type=submit],input[type=button],[role=button]).outline:is([aria-current],:hover,:active,:focus),input[type=reset].outline:is([aria-current],:hover,:active,:focus){--background-color:transparent;--color:var(--primary-hover)}:is(button,input[type=submit],input[type=button],[role=button]).outline.secondary,input[type=reset].outline{--color:var(--secondary)}:is(button,input[type=submit],input[type=button],[role=button]).outline.secondary:is([aria-current],:hover,:active,:focus),input[type=reset].outline:is([aria-current],:hover,:active,:focus){--color:var(--secondary-hover)}:is(button,input[type=submit],input[type=button],[role=button]).outline.contrast{--color:var(--contrast)}:is(button,input[type=submit],input[type=button],[role=button]).outline.contrast:is([aria-current],:hover,:active,:focus){--color:var(--contrast-hover)}:where(button,[type=submit],[type=button],[type=reset],[role=button])[disabled],:where(fieldset[disabled]) :is(button,[type=submit],[type=button],[type=reset],[role=button]),a[role=button]:not([href]){opacity:.5;pointer-events:none}input,optgroup,select,textarea{margin:0;font-size:1rem;line-height:var(--line-height);font-family:inherit;letter-spacing:inherit}input{overflow:visible}select{text-transform:none}legend{max-width:100%;padding:0;color:inherit;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{padding:0}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}::-moz-focus-inner{padding:0;border-style:none}:-moz-focusring{outline:0}:-moz-ui-invalid{box-shadow:none}::-ms-expand{display:none}[type=file],[type=range]{padding:0;border-width:0}input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2)}fieldset{margin:0;margin-bottom:var(--spacing);padding:0;border:0}fieldset legend,label{display:block;margin-bottom:calc(var(--spacing) * .25);font-weight:var(--form-label-font-weight,var(--font-weight))}input:not([type=checkbox],[type=radio]),select,textarea{width:100%}input:not([type=checkbox],[type=radio],[type=range],[type=file]),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal)}input,select,textarea{--background-color:var(--form-element-background-color);--border-color:var(--form-element-border-color);--color:var(--form-element-color);--box-shadow:none;border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}:where(select,textarea):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus){--background-color:var(--form-element-active-background-color)}:where(select,textarea):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus){--border-color:var(--form-element-active-border-color)}input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus,select:focus,textarea:focus{--box-shadow:0 0 0 var(--outline-width) var(--form-element-focus-color)}:where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea),input:not([type=submit],[type=button],[type=reset])[disabled],select[disabled],textarea[disabled]{--background-color:var(--form-element-disabled-background-color);--border-color:var(--form-element-disabled-border-color);opacity:var(--form-element-disabled-opacity);pointer-events:none}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid]{padding-right:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--form-element-spacing-horizontal);padding-inline-start:var(--form-element-spacing-horizontal)!important;padding-inline-end:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid=false]{background-image:var(--icon-valid)}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid=true]{background-image:var(--icon-invalid)}:where(input,select,textarea)[aria-invalid=false]{--border-color:var(--form-element-valid-border-color)}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--border-color:var(--form-element-valid-active-border-color)!important;--box-shadow:0 0 0 var(--outline-width) var(--form-element-valid-focus-color)!important}:where(input,select,textarea)[aria-invalid=true]{--border-color:var(--form-element-invalid-border-color)}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--border-color:var(--form-element-invalid-active-border-color)!important;--box-shadow:0 0 0 var(--outline-width) var(--form-element-invalid-focus-color)!important}[dir=rtl] :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}input::-webkit-input-placeholder,input::placeholder,select:invalid,textarea::-webkit-input-placeholder,textarea::placeholder{color:var(--form-element-placeholder-color);opacity:1}input:not([type=checkbox],[type=radio]),select,textarea{margin-bottom:var(--spacing)}select::-ms-expand{border:0;background-color:transparent}select:not([multiple],[size]){padding-right:calc(var(--form-element-spacing-horizontal) + 1.5rem);padding-left:var(--form-element-spacing-horizontal);padding-inline-start:var(--form-element-spacing-horizontal);padding-inline-end:calc(var(--form-element-spacing-horizontal) + 1.5rem);background-image:var(--icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}[dir=rtl] select:not([multiple],[size]){background-position:center left .75rem}:where(input,select,textarea,.grid)+small{display:block;width:100%;margin-top:calc(var(--spacing) * -.75);margin-bottom:var(--spacing);color:var(--muted-color)}label>:where(input,select,textarea){margin-top:calc(var(--spacing) * .25)}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-right:.375em;margin-left:0;margin-inline-start:0;margin-inline-end:.375em;border-width:var(--border-width);font-size:inherit;vertical-align:middle;cursor:pointer}[type=checkbox]::-ms-check,[type=radio]::-ms-check{display:none}[type=checkbox]:checked,[type=checkbox]:checked:active,[type=checkbox]:checked:focus,[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--background-color:var(--primary);--border-color:var(--primary);background-image:var(--icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=checkbox]~label,[type=radio]~label{display:inline-block;margin-right:.375em;margin-bottom:0;cursor:pointer}[type=checkbox]:indeterminate{--background-color:var(--primary);--border-color:var(--primary);background-image:var(--icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=radio]{border-radius:50%}[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--background-color:var(--primary-inverse);border-width:.35em;background-image:none}[type=checkbox][role=switch]{--background-color:var(--switch-background-color);--border-color:var(--switch-background-color);--color:var(--switch-color);width:2.25em;height:1.25em;border:var(--border-width) solid var(--border-color);border-radius:1.25em;background-color:var(--background-color);line-height:1.25em}[type=checkbox][role=switch]:focus{--background-color:var(--switch-background-color);--border-color:var(--switch-background-color)}[type=checkbox][role=switch]:checked{--background-color:var(--switch-checked-background-color);--border-color:var(--switch-checked-background-color)}[type=checkbox][role=switch]:before{display:block;width:calc(1.25em - (var(--border-width) * 2));height:100%;border-radius:50%;background-color:var(--color);content:"";transition:margin .1s ease-in-out}[type=checkbox][role=switch]:checked{background-image:none}[type=checkbox][role=switch]:checked::before{margin-left:calc(1.125em - var(--border-width));margin-inline-start:calc(1.125em - var(--border-width))}[type=checkbox]:checked[aria-invalid=false],[type=checkbox][aria-invalid=false],[type=checkbox][role=switch]:checked[aria-invalid=false],[type=checkbox][role=switch][aria-invalid=false],[type=radio]:checked[aria-invalid=false],[type=radio][aria-invalid=false]{--border-color:var(--form-element-valid-border-color)}[type=checkbox]:checked[aria-invalid=true],[type=checkbox][aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true],[type=checkbox][role=switch][aria-invalid=true],[type=radio]:checked[aria-invalid=true],[type=radio][aria-invalid=true]{--border-color:var(--form-element-invalid-border-color)}[type=color]::-webkit-color-swatch-wrapper{padding:0}[type=color]::-moz-focus-inner{padding:0}[type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--border-radius) * .5)}[type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--border-radius) * .5)}input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--icon-position:0.75rem;--icon-width:1rem;padding-right:calc(var(--icon-width) + var(--icon-position));background-image:var(--icon-date);background-position:center right var(--icon-position);background-size:var(--icon-width) auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--icon-time)}[type=date]::-webkit-calendar-picker-indicator,[type=datetime-local]::-webkit-calendar-picker-indicator,[type=month]::-webkit-calendar-picker-indicator,[type=time]::-webkit-calendar-picker-indicator,[type=week]::-webkit-calendar-picker-indicator{width:var(--icon-width);margin-right:calc(var(--icon-width) * -1);margin-left:var(--icon-position);opacity:0}[dir=rtl] :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}@-moz-document url-prefix(){[type=date],[type=datetime-local],[type=month],[type=time],[type=week]{padding-right:var(--form-element-spacing-horizontal)!important;background-image:none!important}}[type=file]{--color:var(--muted-color);padding:calc(var(--form-element-spacing-vertical) * .5) 0;border:0;border-radius:0;background:0 0}[type=file]::file-selector-button{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::file-selector-button:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=file]::-webkit-file-upload-button{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;-webkit-transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::-webkit-file-upload-button:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=file]::-ms-browse{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;-ms-transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::-ms-browse:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:0 0}[type=range]::-webkit-slider-runnable-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-webkit-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-moz-range-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-moz-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-ms-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-ms-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-webkit-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-moz-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-ms-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]:focus,[type=range]:hover{--range-border-color:var(--range-active-border-color);--range-thumb-color:var(--range-thumb-hover-color)}[type=range]:active{--range-thumb-color:var(--range-thumb-active-color)}[type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}[type=range]:active::-moz-range-thumb{transform:scale(1.25)}[type=range]:active::-ms-thumb{transform:scale(1.25)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem);border-radius:5rem;background-image:var(--icon-search);background-position:center left 1.125rem;background-size:1rem auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--icon-search),var(--icon-valid)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--icon-search),var(--icon-invalid)}[type=search]::-webkit-search-cancel-button{-webkit-appearance:none;display:none}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}:where(table){width:100%;border-collapse:collapse;border-spacing:0;text-indent:0}td,th{padding:calc(var(--spacing)/ 2) var(--spacing);border-bottom:var(--border-width) solid var(--table-border-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);text-align:left;text-align:start}tfoot td,tfoot th{border-top:var(--border-width) solid var(--table-border-color);border-bottom:0}table[role=grid] tbody tr:nth-child(odd){background-color:var(--table-row-stripped-background-color)}code,kbd,pre,samp{font-size:.875em;font-family:var(--font-family)}pre{-ms-overflow-style:scrollbar;overflow:auto}code,kbd,pre{border-radius:var(--border-radius);background:var(--code-background-color);color:var(--code-color);font-weight:var(--font-weight);line-height:initial}code,kbd{display:inline-block;padding:.375rem .5rem}pre{display:block;margin-bottom:var(--spacing);overflow-x:auto}pre>code{display:block;padding:var(--spacing);background:0 0;font-size:14px;line-height:var(--line-height)}code b{color:var(--code-tag-color);font-weight:var(--font-weight)}code i{color:var(--code-property-color);font-style:normal}code u{color:var(--code-value-color);text-decoration:none}code em{color:var(--code-comment-color);font-style:normal}kbd{background-color:var(--code-kbd-background-color);color:var(--code-kbd-color);vertical-align:baseline}hr{height:0;border:0;border-top:1px solid var(--muted-border-color);color:inherit}[hidden],template{display:none!important}canvas{display:inline-block}details{display:block;margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:var(--border-width) solid var(--accordion-border-color)}details summary{line-height:1rem;list-style-type:none;cursor:pointer;transition:color var(--transition)}details summary:not([role]){color:var(--accordion-close-summary-color)}details summary::-webkit-details-marker{display:none}details summary::marker{display:none}details summary::-moz-list-bullet{list-style-type:none}details summary::after{display:block;width:1rem;height:1rem;margin-inline-start:calc(var(--spacing,1rem) * .5);float:right;transform:rotate(-90deg);background-image:var(--icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:"";transition:transform var(--transition)}details summary:focus{outline:0}details summary:focus:not([role=button]){color:var(--accordion-active-summary-color)}details summary[role=button]{width:100%;text-align:left}details summary[role=button]::after{height:calc(1rem * var(--line-height,1.5));background-image:var(--icon-chevron-button)}details summary[role=button]:not(.outline).contrast::after{background-image:var(--icon-chevron-button-inverse)}details[open]>summary{margin-bottom:calc(var(--spacing))}details[open]>summary:not([role]):not(:focus){color:var(--accordion-open-summary-color)}details[open]>summary::after{transform:rotate(0)}[dir=rtl] details summary{text-align:right}[dir=rtl] details summary::after{float:left;background-position:left center}article{margin:var(--block-spacing-vertical) 0;padding:var(--block-spacing-vertical) var(--block-spacing-horizontal);border-radius:var(--border-radius);background:var(--card-background-color);box-shadow:var(--card-box-shadow)}article>footer,article>header{margin-right:calc(var(--block-spacing-horizontal) * -1);margin-left:calc(var(--block-spacing-horizontal) * -1);padding:calc(var(--block-spacing-vertical) * .66) var(--block-spacing-horizontal);background-color:var(--card-sectionning-background-color)}article>header{margin-top:calc(var(--block-spacing-vertical) * -1);margin-bottom:var(--block-spacing-vertical);border-bottom:var(--border-width) solid var(--card-border-color);border-top-right-radius:var(--border-radius);border-top-left-radius:var(--border-radius)}article>footer{margin-top:var(--block-spacing-vertical);margin-bottom:calc(var(--block-spacing-vertical) * -1);border-top:var(--border-width) solid var(--card-border-color);border-bottom-right-radius:var(--border-radius);border-bottom-left-radius:var(--border-radius)}:root{--scrollbar-width:0px}dialog{display:flex;z-index:999;position:fixed;top:0;right:0;bottom:0;left:0;align-items:center;justify-content:center;width:inherit;min-width:100%;height:inherit;min-height:100%;padding:var(--spacing);border:0;-webkit-backdrop-filter:var(--modal-overlay-backdrop-filter);backdrop-filter:var(--modal-overlay-backdrop-filter);background-color:var(--modal-overlay-background-color);color:var(--color)}dialog article{max-height:calc(100vh - var(--spacing) * 2);overflow:auto}@media (min-width:576px){dialog article{max-width:510px}}@media (min-width:768px){dialog article{max-width:700px}}dialog article>footer,dialog article>header{padding:calc(var(--block-spacing-vertical) * .5) var(--block-spacing-horizontal)}dialog article>header .close{margin:0;margin-left:var(--spacing);float:right}dialog article>footer{text-align:right}dialog article>footer [role=button]{margin-bottom:0}dialog article>footer [role=button]:not(:first-of-type){margin-left:calc(var(--spacing) * .5)}dialog article p:last-of-type{margin:0}dialog article .close{display:block;width:1rem;height:1rem;margin-top:calc(var(--block-spacing-vertical) * -.5);margin-bottom:var(--typography-spacing-vertical);margin-left:auto;background-image:var(--icon-close);background-position:center;background-size:auto 1rem;background-repeat:no-repeat;opacity:.5;transition:opacity var(--transition)}dialog article .close:is([aria-current],:hover,:active,:focus){opacity:1}dialog:not([open]),dialog[open=false]{display:none}.modal-is-open{padding-right:var(--scrollbar-width,0);overflow:hidden;pointer-events:none;touch-action:none}.modal-is-open dialog{pointer-events:auto}:where(.modal-is-opening,.modal-is-closing) dialog,:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-duration:.2s;animation-timing-function:ease-in-out;animation-fill-mode:both}:where(.modal-is-opening,.modal-is-closing) dialog{animation-duration:.8s;animation-name:modal-overlay}:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-delay:.2s;animation-name:modal}.modal-is-closing dialog,.modal-is-closing dialog>article{animation-delay:0s;animation-direction:reverse}@keyframes modal-overlay{from{-webkit-backdrop-filter:none;backdrop-filter:none;background-color:transparent}}@keyframes modal{from{transform:translateY(-100%);opacity:0}}:where(nav li)::before{float:left;content:"​"}nav,nav ul{display:flex}nav{justify-content:space-between}nav ol,nav ul{align-items:center;margin-bottom:0;padding:0;list-style:none}nav ol:first-of-type,nav ul:first-of-type{margin-left:calc(var(--nav-element-spacing-horizontal) * -1)}nav ol:last-of-type,nav ul:last-of-type{margin-right:calc(var(--nav-element-spacing-horizontal) * -1)}nav li{display:inline-block;margin:0;padding:var(--nav-element-spacing-vertical) var(--nav-element-spacing-horizontal)}nav li>*{--spacing:0}nav :where(a,[role=link]){display:inline-block;margin:calc(var(--nav-link-spacing-vertical) * -1) calc(var(--nav-link-spacing-horizontal) * -1);padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal);border-radius:var(--border-radius);text-decoration:none}nav :where(a,[role=link]):is([aria-current],:hover,:active,:focus){text-decoration:none}nav[aria-label=breadcrumb]{align-items:center;justify-content:start}nav[aria-label=breadcrumb] ul li:not(:first-child){margin-inline-start:var(--nav-link-spacing-horizontal)}nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{position:absolute;width:calc(var(--nav-link-spacing-horizontal) * 2);margin-inline-start:calc(var(--nav-link-spacing-horizontal)/ 2);content:"/";color:var(--muted-color);text-align:center}nav[aria-label=breadcrumb] a[aria-current]{background-color:transparent;color:inherit;text-decoration:none;pointer-events:none}nav [role=button]{margin-right:inherit;margin-left:inherit;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}aside li,aside nav,aside ol,aside ul{display:block}aside li{padding:calc(var(--nav-element-spacing-vertical) * .5) var(--nav-element-spacing-horizontal)}aside li a{display:block}aside li [role=button]{margin:inherit}[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{content:"\\"}progress{display:inline-block;vertical-align:baseline}progress{-webkit-appearance:none;-moz-appearance:none;display:inline-block;appearance:none;width:100%;height:.5rem;margin-bottom:calc(var(--spacing) * .5);overflow:hidden;border:0;border-radius:var(--border-radius);background-color:var(--progress-background-color);color:var(--progress-color)}progress::-webkit-progress-bar{border-radius:var(--border-radius);background:0 0}progress[value]::-webkit-progress-value{background-color:var(--progress-color)}progress::-moz-progress-bar{background-color:var(--progress-color)}@media (prefers-reduced-motion:no-preference){progress:indeterminate{background:var(--progress-background-color) linear-gradient(to right,var(--progress-color) 30%,var(--progress-background-color) 30%) top left/150% 150% no-repeat;animation:progress-indeterminate 1s linear infinite}progress:indeterminate[value]::-webkit-progress-value{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}}@media (prefers-reduced-motion:no-preference){[dir=rtl] progress:indeterminate{animation-direction:reverse}}@keyframes progress-indeterminate{0%{background-position:200% 0}100%{background-position:-200% 0}}details[role=list],li[role=list]{position:relative}details[role=list] summary+ul,li[role=list]>ul{display:flex;z-index:99;position:absolute;top:auto;right:0;left:0;flex-direction:column;margin:0;padding:0;border:var(--border-width) solid var(--dropdown-border-color);border-radius:var(--border-radius);border-top-right-radius:0;border-top-left-radius:0;background-color:var(--dropdown-background-color);box-shadow:var(--card-box-shadow);color:var(--dropdown-color);white-space:nowrap}details[role=list] summary+ul li,li[role=list]>ul li{width:100%;margin-bottom:0;padding:calc(var(--form-element-spacing-vertical) * .5) var(--form-element-spacing-horizontal);list-style:none}details[role=list] summary+ul li:first-of-type,li[role=list]>ul li:first-of-type{margin-top:calc(var(--form-element-spacing-vertical) * .5)}details[role=list] summary+ul li:last-of-type,li[role=list]>ul li:last-of-type{margin-bottom:calc(var(--form-element-spacing-vertical) * .5)}details[role=list] summary+ul li a,li[role=list]>ul li a{display:block;margin:calc(var(--form-element-spacing-vertical) * -.5) calc(var(--form-element-spacing-horizontal) * -1);padding:calc(var(--form-element-spacing-vertical) * .5) var(--form-element-spacing-horizontal);overflow:hidden;color:var(--dropdown-color);text-decoration:none;text-overflow:ellipsis}details[role=list] summary+ul li a:hover,li[role=list]>ul li a:hover{background-color:var(--dropdown-hover-background-color)}details[role=list] summary::after,li[role=list]>a::after{display:block;width:1rem;height:calc(1rem * var(--line-height,1.5));margin-inline-start:.5rem;float:right;transform:rotate(0);background-image:var(--icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:""}details[role=list]{padding:0;border-bottom:none}details[role=list] summary{margin-bottom:0}details[role=list] summary:not([role]){height:calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2);padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--form-element-border-color);border-radius:var(--border-radius);background-color:var(--form-element-background-color);color:var(--form-element-placeholder-color);line-height:inherit;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}details[role=list] summary:not([role]):active,details[role=list] summary:not([role]):focus{border-color:var(--form-element-active-border-color);background-color:var(--form-element-active-background-color)}details[role=list] summary:not([role]):focus{box-shadow:0 0 0 var(--outline-width) var(--form-element-focus-color)}details[role=list][open] summary{border-bottom-right-radius:0;border-bottom-left-radius:0}details[role=list][open] summary::before{display:block;z-index:1;position:fixed;top:0;right:0;bottom:0;left:0;background:0 0;content:"";cursor:default}nav details[role=list] summary,nav li[role=list] a{display:flex;direction:ltr}nav details[role=list] summary+ul,nav li[role=list]>ul{min-width:-moz-fit-content;min-width:fit-content;border-radius:var(--border-radius)}nav details[role=list] summary+ul li a,nav li[role=list]>ul li a{border-radius:0}nav details[role=list] summary,nav details[role=list] summary:not([role]){height:auto;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}nav details[role=list][open] summary{border-radius:var(--border-radius)}nav details[role=list] summary+ul{margin-top:var(--outline-width);margin-inline-start:0}nav details[role=list] summary[role=link]{margin-bottom:calc(var(--nav-link-spacing-vertical) * -1);line-height:var(--line-height)}nav details[role=list] summary[role=link]+ul{margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));margin-inline-start:calc(var(--nav-link-spacing-horizontal) * -1)}li[role=list] a:active~ul,li[role=list] a:focus~ul,li[role=list]:hover>ul{display:flex}li[role=list]>ul{display:none;margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));margin-inline-start:calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal))}li[role=list]>a::after{background-image:var(--icon-chevron)}label>details[role=list]{margin-top:calc(var(--spacing) * .25);margin-bottom:var(--spacing)}[aria-busy=true]{cursor:progress}[aria-busy=true]:not(input,select,textarea,html)::before{display:inline-block;width:1em;height:1em;border:.1875em solid currentColor;border-radius:1em;border-right-color:transparent;content:"";vertical-align:text-bottom;vertical-align:-.125em;animation:spinner .75s linear infinite;opacity:var(--loading-spinner-opacity)}[aria-busy=true]:not(input,select,textarea,html):not(:empty)::before{margin-right:calc(var(--spacing) * .5);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing) * .5)}[aria-busy=true]:not(input,select,textarea,html):empty{text-align:center}a[aria-busy=true],button[aria-busy=true],input[type=button][aria-busy=true],input[type=reset][aria-busy=true],input[type=submit][aria-busy=true]{pointer-events:none}@keyframes spinner{to{transform:rotate(360deg)}}[data-tooltip]{position:relative}[data-tooltip]:not(a,button,input){border-bottom:1px dotted;text-decoration:none;cursor:help}[data-tooltip]::after,[data-tooltip]::before,[data-tooltip][data-placement=top]::after,[data-tooltip][data-placement=top]::before{display:block;z-index:99;position:absolute;bottom:100%;left:50%;padding:.25rem .5rem;overflow:hidden;transform:translate(-50%,-.25rem);border-radius:var(--border-radius);background:var(--tooltip-background-color);content:attr(data-tooltip);color:var(--tooltip-color);font-style:normal;font-weight:var(--font-weight);font-size:.875rem;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;opacity:0;pointer-events:none}[data-tooltip]::after,[data-tooltip][data-placement=top]::after{padding:0;transform:translate(-50%,0);border-top:.3rem solid;border-right:.3rem solid transparent;border-left:.3rem solid transparent;border-radius:0;background-color:transparent;content:"";color:var(--tooltip-background-color)}[data-tooltip][data-placement=bottom]::after,[data-tooltip][data-placement=bottom]::before{top:100%;bottom:auto;transform:translate(-50%,.25rem)}[data-tooltip][data-placement=bottom]:after{transform:translate(-50%,-.3rem);border:.3rem solid transparent;border-bottom:.3rem solid}[data-tooltip][data-placement=left]::after,[data-tooltip][data-placement=left]::before{top:50%;right:100%;bottom:auto;left:auto;transform:translate(-.25rem,-50%)}[data-tooltip][data-placement=left]:after{transform:translate(.3rem,-50%);border:.3rem solid transparent;border-left:.3rem solid}[data-tooltip][data-placement=right]::after,[data-tooltip][data-placement=right]::before{top:50%;right:auto;bottom:auto;left:100%;transform:translate(.25rem,-50%)}[data-tooltip][data-placement=right]:after{transform:translate(-.3rem,-50%);border:.3rem solid transparent;border-right:.3rem solid}[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{opacity:1}@media (hover:hover) and (pointer:fine){[data-tooltip]:hover::after,[data-tooltip]:hover::before,[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::before{animation-duration:.2s;animation-name:tooltip-slide-top}[data-tooltip]:hover::after,[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after{animation-name:tooltip-caret-slide-top}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover::after,[data-tooltip][data-placement=bottom]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-bottom}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover::after{animation-name:tooltip-caret-slide-bottom}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:focus::before,[data-tooltip][data-placement=left]:hover::after,[data-tooltip][data-placement=left]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-left}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:hover::after{animation-name:tooltip-caret-slide-left}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:focus::before,[data-tooltip][data-placement=right]:hover::after,[data-tooltip][data-placement=right]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-right}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:hover::after{animation-name:tooltip-caret-slide-right}}@keyframes tooltip-slide-top{from{transform:translate(-50%,.75rem);opacity:0}to{transform:translate(-50%,-.25rem);opacity:1}}@keyframes tooltip-caret-slide-top{from{opacity:0}50%{transform:translate(-50%,-.25rem);opacity:0}to{transform:translate(-50%,0);opacity:1}}@keyframes tooltip-slide-bottom{from{transform:translate(-50%,-.75rem);opacity:0}to{transform:translate(-50%,.25rem);opacity:1}}@keyframes tooltip-caret-slide-bottom{from{opacity:0}50%{transform:translate(-50%,-.5rem);opacity:0}to{transform:translate(-50%,-.3rem);opacity:1}}@keyframes tooltip-slide-left{from{transform:translate(.75rem,-50%);opacity:0}to{transform:translate(-.25rem,-50%);opacity:1}}@keyframes tooltip-caret-slide-left{from{opacity:0}50%{transform:translate(.05rem,-50%);opacity:0}to{transform:translate(.3rem,-50%);opacity:1}}@keyframes tooltip-slide-right{from{transform:translate(-.75rem,-50%);opacity:0}to{transform:translate(.25rem,-50%);opacity:1}}@keyframes tooltip-caret-slide-right{from{opacity:0}50%{transform:translate(-.05rem,-50%);opacity:0}to{transform:translate(-.3rem,-50%);opacity:1}}[aria-controls]{cursor:pointer}[aria-disabled=true],[disabled]{cursor:not-allowed}[aria-hidden=false][hidden]{display:initial}[aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}[tabindex],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation}[dir=rtl]{direction:rtl}@media (prefers-reduced-motion:reduce){:not([aria-busy=true]),:not([aria-busy=true])::after,:not([aria-busy=true])::before{background-attachment:initial!important;animation-duration:1ms!important;animation-delay:-1ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-delay:0s!important;transition-duration:0s!important}} +/*# sourceMappingURL=pico.min.css.map */ \ No newline at end of file diff --git a/html/src/style.css b/html/src/style.css new file mode 100755 index 0000000..35e1263 --- /dev/null +++ b/html/src/style.css @@ -0,0 +1,293 @@ +@font-face { + font-family: "UbuntuMono"; + src: url(/src/UbuntuMono-R.ttf) format("truetype"); +} + +:root { + --topnavheight: 45px; + --sidenavwidth: 150px; + --popupBoxWidth: 300px; + + --background-0: #212529; + --background-1: #404040; + + --nav-color: rgba(0,0,0,0.3); + + --text-0: #242424; + --text-1: #d3d3d3; + + --text-black: #242424; + --text-white: var(--pico-primary-inverse); + + --success-1:#059100; + --warning-1:#ffdc3e; + --error-1: #b60f0f; + + --font: "UbuntuMono"; + --pico-font-family: UbuntuMono, regular; +} + +* { + font-family: var(--font) !important; +} + +body { + position:fixed; + right: 0; + height: 0; + overflow: scroll; + width: calc( 100vw - var(--sidenavwidth) + 32px ); + height: calc( 100vh - var(--topnavheight) + 32px ); +} + +.maindiv { + position: fixed; + top: var(--topnavheight); + left: var(--sidenavwidth); + width: calc(100% - var(--sidenavwidth)); + height: calc(100% - var(--topnavheight)); + padding: 5px; + overflow: scroll; +} + +.text-invert { + color: var(--pico-primary-inverse) !important; + font-family: var(--font); +} + +/* .text-black { + color: var(--text-black) !important; + font-family: var(--font); +} */ + +.half-left { + position: relative; + display: inline-block; + width: 45%; + margin-right: calc(4%); +} + +.half-right { + position: relative; + display: inline-block; + width: 44%; + margin-left: 4%; +} + + +.navbar { + position: fixed; + top:0; + left:0; + right:0; + height:var(--topnavheight); + padding:5px; + padding-left: calc(var(--sidenavwidth) + 10px); + z-index: 10; + background-color: var(--nav-color); +} + +.navbar ul { + position: fixed; + top: calc(var(--topnavheight) * 0.1); + padding: 0px; + /* height: var(--topnavheight); */ + height: calc(var(--topnavheight) * 0.8); + padding-right: calc(var(--topnavheight) * 2.8); + left: var(--sidenavwidth); + width: calc(100% - var(--sidenavwidth)); + overflow-x: scroll; + overflow-y: hidden; +} + +.navpanel { + display: flex; + flex-direction: column; + flex-shrink: 0; + font-size: 16px; + font-weight: 400; + line-height: 24px; + overflow: hidden; + padding-left: 14px; + + + position:fixed; + top: var(--topnavheight); + bottom:0; + left:0; + width: var(--sidenavwidth); + height:100%; + resize: left; + z-index: 20; + background-color: var(--nav-color); +} + +.navpanel details { + padding-bottom: 0px; + padding-left: 5px; + margin-bottom: 0px; +} + +.navpanel summary { + font-size: 15px; + padding-top: 10px; + padding-bottom: 10px; + margin-bottom: 0px !important; +} + +.navpanel summary:hover { + color: var(--primary); + background-color: rgba(0,0,0,0.1); +} +.navpanel ul { + margin-top: 10px; + margin-bottom: 10px; + padding-left: 5px; +} + + +.navpanel li { + font-size: 14px; + margin-left: -5px; + margin-bottom: 0; + cursor: pointer; +} + +.navpanel li:hover { + color: var(--primary); + background-color: rgba(0,0,0,0.1); +} + +li::marker { + content: "- "; + padding-left: -20px; + padding-right: 5px; + } + + +.navconntext { + position: fixed; + font-size: calc(var(--topnavheight) * 0.3); + margin: calc((var(--topnavheight) * 0.25 * 0.75) - 5px); + background-color: rgba(255, 0, 0, 0.2); + border-style: solid; + border-width: 1px !important; + border-color: #ff0000; + padding: 8px; + right:0; + top:0; +} + +.sidenav-button { + width:100%; + margin-bottom: 10px; +} + +.topnav-button { + margin-left: 13px !important; + height: 100% !important; + + font-size: calc( var(--topnavheight) * ( 3 / 9 ) ); + line-height: calc( var(--topnavheight) * ( 3 / 9 ) ); + +} + +.navTitle { + position: fixed; + margin-bottom: 1px; + top: 0; + left: 0; + width: var(--sidenavwidth); + height: var(--topnavheight); + + text-align:center; + line-height: var(--topnavheight); + + text-decoration:none; +} + +.navTitle:hover { + background-color: rgba(0,0,0,0.1); +} + + +.popupBox { + position: fixed; + + /* display: flex; + box-sizing: content-box; + justify-content: flex-end; + flex-direction: column; */ + + width: var(--popupBoxWidth); + height: calc(100% - var(--topnavheight) - 10px); + pointer-events: none; + bottom: 0; + right: 20px; + overflow: auto; +} + +.popupBox dialog { + display: flex; + z-index: inherit; + position: relative; + top: inherit; + right: inherit; + bottom: inherit; + left: inherit; + align-items: inherit; + justify-content: inherit; + width: inherit; + min-width: inherit; + height: auto; + min-height: inherit; + padding: 0; + background-color: inherit; + + pointer-events: all; + + left: 0; + margin: 0; + margin-bottom: 20px; + + justify-content:right; + flex-direction: column; +} + +.popupBox article { + margin: 0; + opacity: 0.5; + padding-bottom: 10px; +} + +.popupBox header { + border: 0; + padding-left: 15px; + padding-right: 15px; + padding-top: 10px; + padding-bottom: 10px; + margin-bottom: 10px; +} + +.popupBox article:hover { + opacity: 1; +} + +dialog article a { + cursor: pointer; +} + + +.popupBox article p { + font-size: 15px; +} + +.noselect { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome, Edge, Opera and Firefox */ + } \ No newline at end of file diff --git a/html/src/utils.js b/html/src/utils.js new file mode 100755 index 0000000..870b6e0 --- /dev/null +++ b/html/src/utils.js @@ -0,0 +1,274 @@ +export const getel = (id)=>{return document.getElementById(id)} + +export const setCookie = (name, value, hours = 1, path = '/') => { + const expires = new Date(Date.now() + hours * 6e4).toUTCString() + document.cookie = `${name}=${encodeURIComponent(value)}; path=${path}; SameSite=None; secure=True; session=True` +} + +export const getCookie = (name) => { + return document.cookie.split('; ').reduce((r, v) => { + const parts = v.split('=') + return parts[0] === name ? decodeURIComponent(parts[1]) : r + }, '') +} + +export function genID(length = 8){ + // Declare all characters + let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + + // Pick characers randomly + let str = ''; + for (let i = 0; i < length; i++) { + str += chars.charAt(Math.floor(Math.random() * chars.length)); + } + + return str; +} + + +export function icondisconnect() { + let icon = document.getElementById('connecticon') + icon.style.backgroundColor = "rgba(255, 0, 0, 0.2)" + icon.style.borderColor = "#ff0000" + icon.innerText = "Disconnected" +} + +export function iconunauth() { + let icon = document.getElementById('connecticon') + icon.style.backgroundColor = "rgba(255, 255, 0, 0.2)" + icon.style.borderColor = "#ffff00" + icon.innerText = "Unauthenticated" +} + +export function iconauth() { + let icon = document.getElementById('connecticon') + icon.style.backgroundColor = "rgba(0, 255, 0, 0.2)" + icon.style.borderColor = "#00ff00" + icon.innerText = "Authenticated" +} + +// function addPopup(bgcolor, fgcolor, innerHTML) { +// const elem = document.getElementById('popupBox') +// const id = 'popup-'+genID(16) +// elem.innerHTML = `` + +// elem.innerHTML + +// setTimeout(()=>{ +// elem.parentNode.removeChild(elem) +// }, 30000) + +// } + +export function getatribinarr(arr, atribname, value){ + for(let i=0;i +
+
+

${formatTime(getUnixTime())}

+ + ${title} +
+ ${innerHTML} +
+ + ` +} + +export function addPopup(bgcolor, isDark, title, content) { + const elem = document.getElementById('popupBox') + let header + let textColor + if(isDark){ + header = 'rgba(255,255,255,0.05)' + textColor = "text-invert" + }else{ + header = 'rgba(0,0,0,0.2)' + textColor = "" + } + modal(elem, bgcolor, header, textColor, title, `

${content}

`) + +} + +export function popupInfo(title, text){ + addPopup('var(--card-sectionning-background-color)', true, title, text) +} + +export function popupSuccess(title, text){ + addPopup('#005000', true, title, text) +} + +export function popupWarning(title, text){ + addPopup('#393900', true, title, text) +} + +export function popupError(title, text){ + addPopup('#500000', true, title, text) +} + +export function confirmBox(bgcolor, isDark, title, yesFunc, noFunc) { + const elem = document.body + let header + let textColor + if(isDark){ + header = 'rgba(255,255,255,0.05)' + textColor = "text-invert" + }else{ + header = 'rgba(0,0,0,0.2)' + textColor = "" + } + modal(elem, bgcolor, header, textColor, title, ` + + `) +} + +export function getUnixTime() { + return (+ new Date()) +} + +export function formatTime(Millis){ + const date = new Date(Millis) + + if(date.getDate() != (new Date()).getDate()){ + return date.getMonth()+1 + "/" + date.getDate() + "/" + date.getFullYear() + }else{ + var Hour = "" + var Minute = "" + var AmPm = "" + + if(date.getHours() == 0){ + Hour = "12" + AmPm = "AM" + }else if(date.getHours() < 12){ + Hour = date.getHours() + AmPm = "AM" + }else if(date.getHours() == 12){ + Hour = "12" + AmPm = "PM" + }else{ + Hour = date.getHours() - 12 + AmPm = "PM" + } + + if(date.getMinutes() < 10){ + Minute = "0" + date.getMinutes() + }else{ + Minute = date.getMinutes() + } + + return Hour + ":" + Minute + " " + AmPm + + } +} + +export function sha256(ascii) { + function rightRotate(value, amount) { + return (value>>>amount) | (value<<(32 - amount)); + }; + + var mathPow = Math.pow; + var maxWord = mathPow(2, 32); + var lengthProperty = 'length' + var i, j; // Used as a counter across the whole file + var result = '' + + var words = []; + var asciiBitLength = ascii[lengthProperty]*8; + + //* caching results is optional - remove/add slash from front of this line to toggle + // Initial hash value: first 32 bits of the fractional parts of the square roots of the first 8 primes + // (we actually calculate the first 64, but extra values are just ignored) + var hash = sha256.h = sha256.h || []; + // Round constants: first 32 bits of the fractional parts of the cube roots of the first 64 primes + var k = sha256.k = sha256.k || []; + var primeCounter = k[lengthProperty]; + /*/ + var hash = [], k = []; + var primeCounter = 0; + //*/ + + var isComposite = {}; + for (var candidate = 2; primeCounter < 64; candidate++) { + if (!isComposite[candidate]) { + for (i = 0; i < 313; i += candidate) { + isComposite[i] = candidate; + } + hash[primeCounter] = (mathPow(candidate, .5)*maxWord)|0; + k[primeCounter++] = (mathPow(candidate, 1/3)*maxWord)|0; + } + } + + ascii += '\x80' // Append Ƈ' bit (plus zero padding) + while (ascii[lengthProperty]%64 - 56) ascii += '\x00' // More zero padding + for (i = 0; i < ascii[lengthProperty]; i++) { + j = ascii.charCodeAt(i); + if (j>>8) return; // ASCII check: only accept characters in range 0-255 + words[i>>2] |= j << ((3 - i)%4)*8; + } + words[words[lengthProperty]] = ((asciiBitLength/maxWord)|0); + words[words[lengthProperty]] = (asciiBitLength) + + // process each chunk + for (j = 0; j < words[lengthProperty];) { + var w = words.slice(j, j += 16); // The message is expanded into 64 words as part of the iteration + var oldHash = hash; + // This is now the undefinedworking hash", often labelled as variables a...g + // (we have to truncate as well, otherwise extra entries at the end accumulate + hash = hash.slice(0, 8); + + for (i = 0; i < 64; i++) { + var i2 = i + j; + // Expand the message into 64 words + // Used below if + var w15 = w[i - 15], w2 = w[i - 2]; + + // Iterate + var a = hash[0], e = hash[4]; + var temp1 = hash[7] + + (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) // S1 + + ((e&hash[5])^((~e)&hash[6])) // ch + + k[i] + // Expand the message schedule if needed + + (w[i] = (i < 16) ? w[i] : ( + w[i - 16] + + (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15>>>3)) // s0 + + w[i - 7] + + (rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2>>>10)) // s1 + )|0 + ); + // This is only used once, so *could* be moved below, but it only saves 4 bytes and makes things unreadble + var temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) // S0 + + ((a&hash[1])^(a&hash[2])^(hash[1]&hash[2])); // maj + + hash = [(temp1 + temp2)|0].concat(hash); // We don't bother trimming off the extra ones, they're harmless as long as we're truncating when we do the slice() + hash[4] = (hash[4] + temp1)|0; + } + + for (i = 0; i < 8; i++) { + hash[i] = (hash[i] + oldHash[i])|0; + } + } + + for (i = 0; i < 8; i++) { + for (j = 3; j + 1; j--) { + var b = (hash[i]>>(j*8))&255; + result += ((b < 16) ? 0 : '') + b.toString(16); + } + } + return result.toUpperCase(); +}; diff --git a/libs/scanner.py b/libs/scanner.py new file mode 100644 index 0000000..ca8219a --- /dev/null +++ b/libs/scanner.py @@ -0,0 +1,68 @@ +import subprocess +import random +import socket +import struct +from threading import Thread + +import src.utils as utils + +threads = [] + +def start(settings): + global threads + utils.makeDir("data/scans") + + + for i in range(0,settings['numJobs']): + c = ScanTask() + t = Thread(target = c.run, args=(settings['maxPingTimeout'],)) + t.start() + +# def getStdout(): +# global process +# return subprocess.check_output(process).decode() + # return "eee" + process.stdout.readline() + + +def stop(): + global threads + for thread in threads: + thread.stop() + threads = [] + print("\n\nstopped Scanner!") + + +def processStarted(): + global threads + return len(threads) != 0; + + + + + +class ScanTask: + def __init__(self): + self.running = True + + def stop(self): + self.running = False + + def run(self, maxPingTimeout): + while True: + address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff))) + + pingCommand = f"ping {address} -c 1 -W {maxPingTimeout}" + + try: + subprocess.check_output(pingCommand.split(" ")) + # print(f"{address}: FOUND") + except subprocess.CalledProcessError: + # print(f"{address}: FAIL") + continue + + nmapCommand = f"sudo nmap {address} -O --send-eth --privileged -v -sS" + + try: + print(subprocess.check_output(nmapCommand.split(" ")).decode()) + except subprocess.CalledProcessError: + continue \ No newline at end of file diff --git a/libs/scanutils.py b/libs/scanutils.py new file mode 100644 index 0000000..d58d9fa --- /dev/null +++ b/libs/scanutils.py @@ -0,0 +1,12 @@ +import src.utils as utils + +def countScannedIps(): + files = utils.listSubdirs("data/") + count = 0 + for file in files: + if file.split("-")[0] != "scan": + continue + with open('data/'+file) as f: + #Count lines in scan files, Masscan has a 2 line header, so hence -2 + count += sum(1 for _ in f)-2 + return count \ No newline at end of file diff --git a/libs/test.py b/libs/test.py new file mode 100644 index 0000000..da9a064 --- /dev/null +++ b/libs/test.py @@ -0,0 +1,45 @@ +import subprocess +import random +import socket +import struct +from threading import Thread + +maxPingTimeout = 3 + +class ScanTask: + def __init__(self): + self.running = True + + def terminate(self): + self.running = False + + def run(self): + while True: + address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff))) + + pingCommand = f"ping {address} -c 1 -W {maxPingTimeout}" + + try: + subprocess.check_output(pingCommand.split(" ")) + # print(f"{address}: FOUND") + except subprocess.CalledProcessError: + # print(f"{address}: FAIL") + continue + + nmapCommand = f"sudo nmap {address} -O --send-eth --privileged -v -sS" + + try: + print(subprocess.check_output(nmapCommand.split(" ")).decode()) + except subprocess.CalledProcessError: + continue + +threads = [] + +for i in range(0,500): + c = ScanTask() + t = Thread(target = c.run) + t.start() + # threads.push(c) + +for thread in threads: + thread.join() \ No newline at end of file diff --git a/main.py b/main.py new file mode 100755 index 0000000..eb8ddaa --- /dev/null +++ b/main.py @@ -0,0 +1,110 @@ +import src.web as web +import src.utils as utils +import src.modules as modules +from sys import argv + +webserv = web.webserv() +moduleMaster = modules.moduleMaster() + + +def main(): + + if not utils.pathExists('data'): + utils.makeDir('data') + + if not utils.pathExists('data/creds.json'): + if input("No credentials file was found, \nwould you like to create one? (Y/n): ").lower() in ["yes", "y", ""]: + utils.writeFile('data/creds.json', utils.genDefaultAccounts()) + + if webserv.secure and ( not utils.pathExists('data/ssl.crt') or not utils.pathExists('data/ssl.key') ): + if input("No ssl key/cert was found, \nwould you like to create them? (Y/n): ").lower() in ["yes", "y", ""]: + + if not utils.pathExists('data/ssl.key'): + utils.genKey(utils.getRoot('data/')) + + if not utils.pathExists('data/ssl.crt'): + utils.genCert(utils.getRoot('data/')) + + moduleMaster.addModules(webserv) + webserv.init() + moduleMaster.initModules(webserv) + webserv.start() + moduleMaster.runModules() + + # for m in modules: + # m.module.main() + +def printHelp(): + print(""" + Modulator usage: + + -h -? --help - Print this help information + -v --verbose - Print verbose information, default: false + -u --unsecure - Use http instead of https, default: false + -p --port - Set port of the webserver, default: 80 or 44 + -h --host - Set host of the webserver, default: 0.0.0.0 + + --defaultTab - Set the default tab on visit, default: 'main' + --title - Set the title of the html pages, default: 'Modulator' + + Examples: + + $ python3 ./main.py + $ python3 ./main.py -vo 127.0.0.1 + $ python3 ./main.py -p 12345 -h 192.168.0.123 + """) + +if __name__ == '__main__': + + i = 1 + + while i < len(argv): + arg = argv[i] + sargs = list(arg) + if sargs[0] == '-' and sargs[1] == '-': + match arg: + case '--help': + printHelp() + exit() + case '--verbose': + webserv.verbose = True + i+=1; continue + case '--unsecure': + webserv.secure = False + if webserv.port == 443: + webserv.port = 80 + i+=1; continue + case '--port': + webserv.port = int(argv[i+1]) + i+=2; continue + case '--host': + webserv.host = str(argv[i+1]) + i+=2; continue + case '--defaultTab': + webserv.defaultTab = str(argv[i+1]) + i+=2; continue + case '--title': + webserv.title = str(argv[i+1]) + i+=2; continue + elif sargs[0] == '-': + for sarg in sargs: + match sarg: + case 'h' | '?': + printHelp() + exit() + case 'v': + webserv.verbose = True + case 'u': + webserv.secure = False + if webserv.port == 443: + webserv.port = 80 + case 'p': + webserv.port = int(argv[i+1]) + i+=1; continue + case 'o': + webserv.host = str(argv[i+1]) + i+=1; continue + + i += 1 + + main() diff --git a/modules/main/Dashboard.html b/modules/main/Dashboard.html new file mode 100755 index 0000000..ca8e801 --- /dev/null +++ b/modules/main/Dashboard.html @@ -0,0 +1,19 @@ + + +
+
+ + \ No newline at end of file diff --git a/modules/main/adminSettings.html b/modules/main/adminSettings.html new file mode 100755 index 0000000..8bcd8a5 --- /dev/null +++ b/modules/main/adminSettings.html @@ -0,0 +1,248 @@ +
+

User Settings

+

Users

+ + + + + + + + + + + +
UsernameCreatedPass UpdatedGroupsManage
+

Sessions

+ + + + + + + + + + + +
UsernameAddressPathExpiresManage
+ +
+ \ No newline at end of file diff --git a/modules/main/main.py b/modules/main/main.py new file mode 100755 index 0000000..aa6a990 --- /dev/null +++ b/modules/main/main.py @@ -0,0 +1,206 @@ +import libs.scanutils as scanutils +mm = None + +def dashboardMetrics(ac): + ac.send('Scanner-Metrics', { + "scanCount": scanutils.countScannedIps() + }) + +def init(moduleMaster): + global mm + mm = moduleMaster + + mm.addPageEventListener('/main/dashboard', dashboardMetrics) + + # User settings + mm.addAuthEventListener('logout', logout) + mm.addAuthEventListener('unauth', unauth) + + mm.addAuthEventListener('passwordChangeRequest', changePassword) + + # Admin settings + mm.addAuthEventListener('addUserRequest', addUser) + mm.addAuthEventListener('disconnectAllSessions', disconnectAllSessions) + mm.addAuthEventListener('changeGroupsRequest', changeGroups) + mm.addAuthEventListener('deleteUserRequest', deleteUser) + # mm.addAuthEventListener('login', disconnectAllSessions) + + mm.addPageEventListener('/main/User', loadSessions) + mm.addPageEventListener('/main/Admin', loadSessionsAdmin) + + + +def main(): + pass + + + +def logout(ac, data): + mm.unauth(ac) + + + +def unauth(ac, data): + removeClient = mm.getAuthClientByID(data['data']) + if removeClient == None: + return + if removeClient.user != ac.user and not mm.userInGroup(ac, "Admins"): + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + mm.unauth(removeClient) + mm.sendPopupSuccess(ac.rawClient, "Success", "Client removed!") + if(ac.currentPage == "/main/Admin" and mm.userInGroup(ac, "Admins")): + loadSessionsAdmin(ac) + else: + loadSessions(ac) + + + +def loadSessions(ac): + obj = [] + for client in mm.authServer.clients: + if client.user != ac.user: + continue + obj.append({ + 'username': client.username, + 'address': client.rawClient.address, + 'currentPage': client.currentPage, + 'clientid': client.rawClient.clientid, + 'timeout': client.timeout + }) + # obj.append(client.session) + ac.send('sessions', obj) + + + +def changePassword(ac, data): + # If the account is not an admin, and the username is the same, and the password is correct => Change password + # If the account is not an admin, and the username is the same, and the password not correct and => Incorrect Password + # If the account is not an admin, and the username is not the same => Access denied + # If the account is an admin, and the username is the same, and the password is correct => Change password + # If the account is an admin, and the username is the same, and the password is not correct => Incorrect Password + # If the account is an admin, and the username is not the same => Change password + + isAdmin = mm.userInGroup(ac, 'Admins') + correctName = ac.user.id == data['data']['id'] + + + if isAdmin and correctName and not 'old' in data['data']: + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + + if isAdmin or correctName: + if not isAdmin and ac.user.sha256passwordhash != data['data']['old']: + mm.sendPopupError(ac.rawClient, "Error", "Incorrect Password") + return + elif isAdmin and correctName and ac.user.sha256passwordhash != data['data']['old']: + mm.sendPopupError(ac.rawClient, "Error", "Incorrect Password") + return + else: + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + user = mm.getUserById(data['data']['id']) + if user == None: + mm.sendPopupError(ac.rawClient, "Error", "Invalid id") + return + + mm.setUserPassword(user, data['data']['new']) + mm.sendPopupSuccess(ac.rawClient, "Success", "Password updated!") + + if isAdmin: + loadSessionsAdmin(ac) + + + +def loadSessionsAdmin(ac): + if not mm.userInGroup(ac, 'Admins'): + return + + obj = { + 'users': [], + 'sessions': [] + } + for client in mm.authServer.clients: + obj['sessions'].append({ + 'username': client.username, + 'address': client.rawClient.address, + 'currentPage': client.currentPage, + 'clientid': client.rawClient.clientid, + 'timeout': client.timeout + }) + for user in mm.authServer.users: + obj['users'].append({ + 'username': user.username, + 'permGroups': user.permGroups, + 'id': user.id, + 'created': user.created, + 'passwordUpdated': user.passwordUpdated + }) + ac.send('sessions', obj) + + + +def addUser(ac, data): + if not mm.userInGroup(ac, 'Admins'): + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + mm.addUser( + data['data']['username'], + data['data']['groups'], + data['data']['password']) + loadSessionsAdmin(ac) + + + +def disconnectAllSessions(ac, data): + if not mm.userInGroup(ac, 'Admins'): + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + user = mm.getUserById(data['data']['id']) + + for client in mm.authServer.clients: + if client.user == user: + mm.unauth(client) + loadSessionsAdmin(ac) + + + +def changeGroups(ac, data): + if not mm.userInGroup(ac, 'Admins'): + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + user = mm.getUserById(data['data']['id']) + if user == None: + mm.sendPopupError(ac.rawClient, "Error", "Invalid id") + return + if user == ac.user: + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + mm.setUserGroups(user, data['data']['groups']) + mm.sendPopupSuccess(ac.rawClient, "Success", "Groups updated!") + loadSessionsAdmin(ac) + + + +def deleteUser(ac, data): + if not mm.userInGroup(ac, 'Admins'): + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + user = mm.getUserById(data['data']['id']) + if user == None: + mm.sendPopupError(ac.rawClient, "Error", "Invalid id") + return + if user == ac.user: + mm.sendPopupError(ac.rawClient, "Error", "You are not authorised") + return + + mm.deleteUser(user) + mm.sendPopupSuccess(ac.rawClient, "Success", "User deleted!") + loadSessionsAdmin(ac) \ No newline at end of file diff --git a/modules/main/module.json b/modules/main/module.json new file mode 100755 index 0000000..d828bfa --- /dev/null +++ b/modules/main/module.json @@ -0,0 +1,38 @@ +{ + "name": "main", + "creators": ["ASTATIN3"], + "version": "1.0", + "entrypoint": "modules/main/main.py", + "tabs": [ + { + "name": "main", + "defaultPage": "dashboard", + "pages": [ + { + "type": "page", + "name": "dashboard", + "requiredPermGroup": "", + "location": "modules/main/Dashboard.html" + }, + { + "type": "folder", + "name": "Settings", + "pages": [ + { + "type": "page", + "name": "User", + "requiredPermGroup": "", + "location": "modules/main/userSettings.html" + }, + { + "type": "page", + "name": "Admin", + "requiredPermGroup": "Admins", + "location": "modules/main/adminSettings.html" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/modules/main/userSettings.html b/modules/main/userSettings.html new file mode 100755 index 0000000..9cf6c49 --- /dev/null +++ b/modules/main/userSettings.html @@ -0,0 +1,105 @@ +
+

User Settings

+
+

Sessions

+ + + + + + + + + + + +
UsernameAddressPathExpiresManage
+ + +
+ \ No newline at end of file diff --git a/modules/scan/main.py b/modules/scan/main.py new file mode 100755 index 0000000..15e6134 --- /dev/null +++ b/modules/scan/main.py @@ -0,0 +1,46 @@ +import libs.scanner as scan +import time + +mm = None + + +def loadSettings(ac): + ac.send('Scanner-Settings', mm.vars['Scanner-Settings']) + + +def setSettings(ac, data): + mm.vars['Scanner-Settings'] = data['data'] + + +def startScanner(ac, data): + scan.start(mm.vars['Scanner-Settings']) + + +def stopScanner(ac, data): + scan.stop() + + + +def init(moduleMaster): + global mm + mm = moduleMaster + + mm.vars['Scanner-Settings'] = { + "range": [[0,0,0,0], [255,255,255,255]], + "numJobs": 50, + "maxPingTimeout": 3, + "output": "./data/scan.txt" + } + + mm.addPageEventListener('Scanner-LoadSettings', loadSettings) + + mm.addAuthEventListener('Scanner-StartScanner', startScanner) + mm.addAuthEventListener('Scanner-StopScanner', stopScanner) + +def main(): + while True: + if scan.processStarted(): + print("eee") + # print(scan.getStdout()) + # print("eee") + time.sleep(1) \ No newline at end of file diff --git a/modules/scan/module.json b/modules/scan/module.json new file mode 100755 index 0000000..6edda6e --- /dev/null +++ b/modules/scan/module.json @@ -0,0 +1,20 @@ +{ + "name": "Scan", + "creators": ["ASTATIN3"], + "version": "1.0", + "entrypoint": "modules/scan/main.py", + "tabs": [ + { + "name": "Scan", + "defaultPage": "Scan", + "pages": [ + { + "type": "page", + "name": "Scan", + "requiredPermGroup": "", + "location": "modules/scan/scan.html" + } + ] + } + ] +} \ No newline at end of file diff --git a/modules/scan/scan.html b/modules/scan/scan.html new file mode 100755 index 0000000..e695c4e --- /dev/null +++ b/modules/scan/scan.html @@ -0,0 +1,23 @@ + +
+

This is a very simple example module!

+ + +
+ + \ No newline at end of file diff --git a/paused.conf b/paused.conf new file mode 100644 index 0000000..62b2b0c --- /dev/null +++ b/paused.conf @@ -0,0 +1,150 @@ + +# resume information +resume-index = 275723 +seed = 11690600974265531384 +rate = 1000 +shard = 1/1 +nocapture = servername + +output-filename = ./data/scan-1713225964108.txt +output-format = grepable + +adapter-ip = 192.168.0.241 +# TARGET SELECTION (IP, PORTS, EXCLUDES) +ports = 1,3-4,6-7,9,13,17,19-26,30,32-33,37,42-43,49,53,70,79-85,88-90,99-100,106,109-111,113,119,125,135,139,143-144,146,161,163,179,199,211-212,222,254-256,259,264,280,301,306,311,340,366,389,406-407,416-417,425,427,443-445,458,464-465,481,497,500,512-515,524,541,543-545,548,554-555,563,587,593,616-617,625,631,636,646,648,666-668,683,687,691,700,705,711,714,720,722,726,749,765,777,783,787,800-801,808,843,873,880,888,898,900-903,911-912,981,987,990,992-993,995,999-1002,1007,1009-1011,1021-1100,1102,1104-1108,1110-1114,1117,1119,1121-1124,1126,1130-1132,1137-1138,1141,1145,1147-1149,1151-1152,1154,1163-1166,1169,1174-1175,1183,1185-1187,1192,1198-1199,1201,1213,1216-1218,1233-1234,1236,1244,1247-1248,1259,1271-1272,1277,1287,1296,1300-1301,1309-1311,1322,1328,1334,1352,1417,1433-1434,1443,1455,1461,1494,1500-1501,1503,1521,1524,1533,1556,1580,1583,1594,1600,1641,1658,1666,1687-1688,1700,1717-1721,1723,1755,1761,1782-1783,1801,1805,1812,1839-1840,1862-1864,1875,1900,1914,1935,1947,1971-1972,1974,1984,1998-2010,2013,2020-2022,2030,2033-2035,2038,2040-2043,2045-2049,2065,2068,2099-2100,2103,2105-2107,2111,2119,2121,2126,2135,2144,2160-2161,2170,2179,2190-2191,2196,2200,2222,2251,2260,2288,2301,2323,2366,2381-2383,2393-2394,2399,2401,2492,2500,2522,2525,2557,2601-2602,2604-2605,2607-2608,2638,2701-2702,2710,2717-2718,2725,2800,2809,2811,2869,2875,2909-2910,2920,2967-2968,2998,3000-3001,3003,3005-3007,3011,3013,3017,3030-3031,3052,3071,3077,3128,3168,3211,3221,3260-3261,3268-3269,3283,3300-3301,3306,3322-3325,3333,3351,3367,3369-3372,3389-3390,3404,3476,3493,3517,3527,3546,3551,3580,3659,3689-3690,3703,3737,3766,3784,3800-3801,3809,3814,3826-3828,3851,3869,3871,3878,3880,3889,3905,3914,3918,3920,3945,3971,3986,3995,3998,4000-4006,4045,4111,4125-4126,4129,4224,4242,4279,4321,4343,4443-4446,4449,4550,4567,4662,4848,4899-4900,4998,5000-5004,5009,5030,5033,5050-5051,5054,5060-5061,5080,5087,5100-5102,5120,5190,5200,5214,5221-5222,5225-5226,5269,5280,5298,5357,5405,5414,5431-5432,5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678-5679,5718,5730,5800-5802,5810-5811,5815,5822,5825,5850,5859,5862,5877,5900-5904,5906-5907,5910-5911,5915,5922,5925,5950,5952,5959-5963,5987-5989,5998-6007,6009,6025,6059,6100-6101,6106,6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565-6567,6580,6646,6666-6669,6689,6692,6699,6779,6788-6789,6792,6839,6881,6901,6969,7000-7002,7004,7007,7019,7025,7070,7100,7103,7106,7200-7201,7402,7435,7443,7496,7512,7625,7627,7676,7741,7777-7778,7800,7911,7920-7921,7937-7938,7999-8002,8007-8011,8021-8022,8031,8042,8045,8080-8090,8093,8099-8100,8180-8181,8192-8194,8200,8222,8254,8290-8292,8300,8333,8383,8400,8402,8443,8500,8600,8649,8651-8652,8654,8701,8800,8873,8888,8899,8994,9000-9003,9009-9011,9040,9050,9071,9080-9081,9090-9091,9099-9103,9110-9111,9200,9207,9220,9290,9415,9418,9485,9500,9502-9503,9535,9575,9593-9595,9618,9666,9876-9878,9898,9900,9917,9929,9943-9944,9968,9998-10004,10009-10010,10012,10024-10025,10082,10180,10215,10243,10566,10616-10617,10621,10626,10628-10629,10778,11110-11111,11967,12000,12174,12265,12345,13456,13722,13782-13783,14000,14238,14441-14442,15000,15002-15004,15660,15742,16000-16001,16012,16016,16018,16080,16113,16992-16993,17877,17988,18040,18101,18988,19101,19283,19315,19350,19780,19801,19842,20000,20005,20031,20221-20222,20828,21571,22939,23502,24444,24800,25734-25735,26214,27000,27352-27353,27355-27356,27715,28201,30000,30718,30951,31038,31337,32768-32785,33354,33899,34571-34573,35500,38292,40193,40911,41511,42510,44176,44442-44443,44501,45100,48080,49152-49161,49163,49165,49167,49175-49176,49400,49999-50003,50006,50300,50389,50500,50636,50800,51103,51493,52673,52822,52848,52869,54045,54328,55055-55056,55555,55600,56737-56738,57294,57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,65129,65389 +range = 1.0.0.0-4.53.200.255 +range = 4.53.202.0-5.152.178.255 +range = 5.152.180.0-5.255.255.255 +range = 7.0.0.0-8.12.161.255 +range = 8.12.165.0-8.14.83.255 +range = 8.14.88.0-8.14.144.255 +range = 8.14.148.0-8.17.249.255 +range = 8.17.253.0-9.255.255.255 +range = 11.0.0.0-20.255.255.255 +range = 23.0.0.0-23.26.255.255 +range = 23.28.0.0-23.231.127.255 +range = 23.232.0.0-23.255.255.255 +range = 24.16.0.0-24.87.255.255 +range = 24.89.0.0-24.111.255.255 +range = 24.112.128.0-24.131.255.255 +range = 24.132.3.0-24.187.255.255 +range = 24.192.0.0-37.72.171.255 +range = 37.72.174.0-38.72.199.255 +range = 38.72.204.0-50.93.191.255 +range = 50.93.198.0-50.115.127.255 +range = 50.115.144.0-50.116.255.255 +range = 50.117.128.0-50.118.127.255 +range = 50.119.0.0-63.141.221.255 +range = 63.141.223.0-64.62.252.255 +range = 64.62.254.0-64.92.95.255 +range = 64.92.128.0-64.145.78.255 +range = 64.145.80.0/23 +range = 64.145.84.0-64.158.145.255 +range = 64.158.148.0-65.49.23.255 +range = 65.49.25.0-65.49.92.255 +range = 65.49.94.0-65.162.191.255 +range = 65.162.196.0-66.79.159.255 +range = 66.79.192.0-66.160.190.255 +range = 66.160.192.0-68.68.95.255 +range = 68.68.112.0-69.46.63.255 +range = 69.46.96.0-69.176.79.255 +range = 69.176.96.0-72.13.79.255 +range = 72.13.96.0-72.52.75.255 +range = 72.52.77.0-74.82.42.255 +range = 74.82.44.0-74.82.159.255 +range = 74.82.192.0-74.114.87.255 +range = 74.114.92.0-74.114.255.255 +range = 74.115.1.0/24 +range = 74.115.3.0/24 +range = 74.115.5.0-74.122.99.255 +range = 74.122.104.0-75.126.255.255 +range = 75.127.1.0-100.63.255.255 +range = 100.128.0.0-103.251.90.255 +range = 103.251.92.0-108.171.31.255 +range = 108.171.33.0-108.171.41.255 +range = 108.171.43.0-108.171.51.255 +range = 108.171.53.0-108.171.61.255 +range = 108.171.63.0-118.193.77.255 +range = 118.193.80.0-126.255.255.255 +range = 128.0.0.0-130.93.15.255 +range = 130.93.18.0-131.214.255.255 +range = 131.216.0.0-134.3.255.255 +range = 134.5.0.0-135.255.255.255 +range = 136.1.0.0-142.110.255.255 +range = 142.112.0.0-142.251.255.255 +range = 142.253.0.0-146.82.55.92 +range = 146.82.55.94-149.54.135.255 +range = 149.54.144.0/21 +range = 149.54.160.0-153.10.255.255 +range = 153.12.0.0-165.159.255.255 +range = 165.161.0.0-166.87.255.255 +range = 166.89.0.0-169.253.255.255 +range = 169.255.0.0-172.15.255.255 +range = 172.32.0.0-172.251.255.255 +range = 172.253.0.0-173.245.63.255 +range = 173.245.96.0-173.245.193.255 +range = 173.245.196.0-173.245.219.255 +range = 173.245.224.0-173.252.191.255 +range = 173.253.0.0-178.18.15.255 +range = 178.18.20.0-178.18.25.255 +range = 178.18.30.0-183.182.21.255 +range = 183.182.23.0-191.255.255.255 +range = 192.0.1.0/24 +range = 192.0.3.0-192.12.18.255 +range = 192.12.20.0-192.31.42.255 +range = 192.31.44.0-192.41.207.255 +range = 192.41.209.0-192.43.242.255 +range = 192.43.244.0-192.54.248.255 +range = 192.54.250.0-192.88.98.255 +range = 192.88.100.0-192.92.113.255 +range = 192.92.115.0-192.155.159.255 +range = 192.155.192.0-192.167.255.255 +range = 192.169.0.0-192.176.255.255 +range = 192.178.0.0-192.185.255.255 +range = 192.186.64.0-192.249.63.255 +range = 192.249.80.0-192.250.239.255 +range = 192.251.0.0-194.77.40.241 +range = 194.77.40.243-194.77.40.245 +range = 194.77.40.247-194.110.213.255 +range = 194.110.215.0-198.12.119.255 +range = 198.12.123.0-198.17.255.255 +range = 198.20.0.0-198.51.99.255 +range = 198.51.101.0-198.144.239.255 +range = 198.145.0.0-199.33.119.255 +range = 199.33.121.0-199.33.123.255 +range = 199.33.128.0-199.48.146.255 +range = 199.48.148.0-199.68.195.255 +range = 199.68.200.0-199.127.239.255 +range = 199.127.248.0-199.187.167.255 +range = 199.187.172.0-199.188.237.255 +range = 199.188.240.0-199.255.207.255 +range = 199.255.209.0-203.0.112.255 +range = 203.0.114.0-203.12.5.255 +range = 203.12.7.0-204.13.63.255 +range = 204.13.72.0-204.16.191.255 +range = 204.16.200.0-204.19.237.255 +range = 204.19.239.0-204.74.207.255 +range = 204.74.224.0-205.159.188.255 +range = 205.159.190.0-205.163.255.255 +range = 205.164.64.0-205.209.127.255 +range = 205.209.192.0-206.108.51.255 +range = 206.108.54.0-206.165.3.255 +range = 206.165.5.0-208.77.39.255 +range = 208.77.48.0-208.80.3.255 +range = 208.80.8.0-208.123.222.255 +range = 208.123.224.0-209.51.184.255 +range = 209.51.186.0-209.54.47.255 +range = 209.54.64.0-209.107.191.255 +range = 209.107.194.0-209.107.209.255 +range = 209.107.211.0/24 +range = 209.107.213.0-211.156.109.255 +range = 211.156.112.0-216.83.32.255 +range = 216.83.50.0/24 +range = 216.83.64.0-216.151.182.255 +range = 216.151.184.0-216.151.189.255 +range = 216.151.192.0-216.172.127.255 +range = 216.172.160.0-216.185.35.255 +range = 216.185.37.0-216.218.232.255 +range = 216.218.234.0-216.224.111.255 +range = 216.224.128.0-239.255.255.255 + diff --git a/src/auth.py b/src/auth.py new file mode 100755 index 0000000..68626e5 --- /dev/null +++ b/src/auth.py @@ -0,0 +1,192 @@ +import os +import base64 +import json +from hashlib import sha256 +from flask import Flask, render_template, Response +from flask import request, redirect, url_for, make_response + +import src.packets as packets +import src.utils as utils + +class authUser: + def __init__(self): + self.username = None + self.permGroups = [] + self.id = None + self.sha256passwordhash = None + self.passwordUpdated = None + self.created = None + +class authClient: + def __init__(self): + self.username = None + self.session = utils.randID(32) + self.currentPage = "/login" + self.user = None + + self.timeout = utils.getUnixTime() + (6 * 60 * 60 * 1000) + self.loginTime = utils.getUnixTime() + self.lastReauth = utils.getUnixTime() + + self.rawClient = None + + def send(self, type, data): + self.rawClient.send(type, data) + +class authServer: + def __init__(self, webserv): + self.rawServer = None + self.app = None + self.clients = [] + self.users = [] + + self.webserv = webserv + + self.pageListeners = [] + + self.reloadUsers() + self.rawServer = webserv.rawServer + self.initRawServer() + + def login(self, c, data): + if c.clientid != data['cid']: + c.send('error', 'invalidLoginRequest') + return + + if int(data['data']['salt']) > (utils.getUnixTime() + 5000): + c.send('error', 'invalidLoginRequest') + return + + logins = json.loads(utils.readFile(utils.getRoot('data/')+'creds.json')) + isValid = False + validAcc = None + for acc in self.users: + hash = utils.hash( + str(acc.username)+ + str(acc.sha256passwordhash)+ + str(data['data']['salt'])) + + if hash == str(data['data']['data']): + isValid = True + validAcc = acc + break + + if isValid: + if utils.getatribinarr(self.clients, 'rawClient', c): + c.send('error', 'prelogin') + return + + ac = authClient() + ac.username = validAcc.username + ac.user = validAcc + ac.rawClient = c + + self.clients.append(ac) + + c.send('loginSuccess', { + 'username': ac.username, + 'permGroups': ac.user.permGroups, + 'session': ac.session, + 'redir': f'/{self.webserv.defaultTab}/{self.webserv.defaultPage}', + 'timeout': ac.timeout + }) + + return + else: + c.send('error', 'invalidLogin') + return + + def validAc(self, ac): + if ac == None: + return False + if not (ac in self.clients): + return False + if ac.rawClient.address != request.remote_addr: + return False + if utils.getUnixTime() > ac.timeout: + return False + + return True + + def reauth(self, c, data): + session = data['data']['session'] + + ac = utils.getatribinarr(self.clients, 'session', session) + + if not self.validAc(ac): + c.send('error', 'invalidLoginRequest') + return + + ac.rawClient = c + ac.lastReauth = utils.getUnixTime() + + ac.send('reauth', { + 'username': ac.username, + 'id': ac.user.id, + 'permGroups': ac.user.permGroups, + 'created': ac.user.created, + 'passwordUpdated': ac.user.passwordUpdated, + 'timeout': ac.timeout + }) + + for pageListener in self.pageListeners: + if pageListener['page'] == ac.currentPage: + pageListener['func'](ac) + + def cookieLogin(self, request): + session = request.cookies.get('session') + if session == None: + return None + + ac = utils.getatribinarr(self.clients, 'session', session) + + if not self.validAc(ac): + return False + + ac.currentPage = request.path + + return True + + def validPermGroup(self, group, request): + session = request.cookies.get('session') + if session == None: + return False, None + + ac = utils.getatribinarr(self.clients, 'session', session) + + if not self.validAc(ac): + return False, None + if (group != "") and not (group in ac.user.permGroups): + return False, None + return True, ac.user.permGroups + + # def validPermGroupfromSession(self, group, request): + + + # def logout(self, ac): + # if not self.validAc(ac): + # return False + # self.clients.remove(ac) + # return True + + def unauth(self, ac): + self.clients.remove(ac) + + def initRawServer(self): + self.rawServer.addEventListener('login', self.login) + self.rawServer.addEventListener('reauth', self.reauth) + + def reloadUsers(self): + data = json.loads(utils.readFile(utils.getRoot('data/')+'creds.json')) + + self.users = [] + + for acc in data: + user = authUser() + user.username = acc['username'] + user.id = acc['id'] + user.sha256passwordhash = acc['sha256passwordhash'] + user.permGroups = acc['permGroups'] + user.created = acc['created'] + user.passwordUpdated = acc['passwordUpdated'] + self.users.append(user) \ No newline at end of file diff --git a/src/jsonpack.py b/src/jsonpack.py new file mode 100755 index 0000000..4840b57 --- /dev/null +++ b/src/jsonpack.py @@ -0,0 +1,273 @@ +# Copyright (c) 2013, Rodrigo González, Sapienlab All Rights Reserved. +# Available via MIT LICENSE. See https://github.com/roro89/jsonpack/blob/master/LICENSE.md for details. + +TOKEN_TRUE = -1 +TOKEN_FALSE = -2 +TOKEN_NULL = -3 +TOKEN_EMPTY_STRING = -4 +TOKEN_UNDEFINED = -5 + +def pack(json): + json = json if isinstance(json, str) else json + dictionary = { + 'strings': [], + 'integers': [], + 'floats': [] + } + + def recursiveAstBuilder(item): + if item is None: + return { + 'type': 'null', + 'index': TOKEN_NULL + } + if item == '': + return { + 'type': '', + 'index': TOKEN_UNDEFINED + } + if isinstance(item, list): + ast = ['@'] + for i in item: + ast.append(recursiveAstBuilder(i)) + return ast + if isinstance(item, dict): + ast = ['$'] + for key, value in item.items(): + ast.append(recursiveAstBuilder(key)) + ast.append(recursiveAstBuilder(value)) + return ast + if item == '': + return { + 'type': 'empty', + 'index': TOKEN_EMPTY_STRING + } + if type(item) == type(True): + return { + 'type': 'boolean', + 'index': TOKEN_TRUE if item else TOKEN_FALSE + } + if isinstance(item, str): + index = dictionary['strings'].index(item) if item in dictionary['strings'] else -1 + if index == -1: + dictionary['strings'].append((item)) + index = len(dictionary['strings']) - 1 + return { + 'type': 'strings', + 'index': index + } + if isinstance(item, int): + index = dictionary['integers'].index(item) if item in dictionary['integers'] else -1 + if index == -1: + dictionary['integers'].append(_base10To36(item)) + index = len(dictionary['integers']) - 1 + return { + 'type': 'integers', + 'index': index + } + if isinstance(item, float): + index = dictionary['floats'].index(item) if item in dictionary['floats'] else -1 + if index == -1: + dictionary['floats'].append(item) + index = len(dictionary['floats']) - 1 + return { + 'type': 'floats', + 'index': index + } + raise TypeError('Unexpected argument of type ' + str(type(item))) + + def recursiveParser(item): + if isinstance(item, list): + packed = item[0] + for i in item[1:]: + packed += recursiveParser(i) + '|' + return (packed[:-1] if packed[-1] == '|' else packed) + ']' + type = item['type'] + index = item['index'] + if type == 'strings': + return _base10To36(index) + if type == 'integers': + return _base10To36(stringLength + index) + if type == 'floats': + return _base10To36(stringLength + integerLength + index) + if type == 'boolean': + return str(index) + if type == 'null': + return str(TOKEN_NULL) + if type == '': + return str(TOKEN_UNDEFINED) + if type == 'empty': + return str(TOKEN_EMPTY_STRING) + raise TypeError('The item is alien!') + + ast = recursiveAstBuilder(json) + + stringLength = len(dictionary['strings']) + integerLength = len(dictionary['integers']) + floatLength = len(dictionary['floats']) + packed = '|'.join(dictionary['strings']) + packed += '^' + '|'.join(dictionary['integers']) + dictionary['floats'] = [str(n) for n in dictionary['floats']] + packed += '^' + '|'.join(dictionary['floats']) + packed += '^' + recursiveParser(ast) + + return packed + +def unpack(packed): + rawBuffers = packed.split('^') + dictionary = [] + buffer = rawBuffers[0] + if buffer != '': + buffer = buffer.split('|') + for i in buffer: + dictionary.append(_decode(i)) + buffer = rawBuffers[1] + if buffer != '': + buffer = buffer.split('|') + for i in buffer: + dictionary.append(_base36To10(i)) + buffer = rawBuffers[2] + if buffer != '': + buffer = buffer.split('|') + for i in buffer: + dictionary.append(float(i)) + tokens = [] + number36 = '' + for i in rawBuffers[3]: + if i in ['|', '$', '@', ']']: + if number36: + tokens.append(_base36To10(number36)) + number36 = '' + if i != '|': + tokens.append(i) + else: + number36 += i + tokensLength = len(tokens) + tokensIndex = 0 + + def recursiveUnpackerParser(): + nonlocal tokensIndex + # Maybe '$' (object) or '@' (array) + type = tokens[tokensIndex] + tokensIndex += 1 + # Parse an array + if type == '@': + node = [] + while tokensIndex < tokensLength: + value = tokens[tokensIndex] + if value == ']': + return node + if value == '@' or value == '$': + node.append(recursiveUnpackerParser()) + else: + if value == TOKEN_TRUE: + node.append(True) + elif value == TOKEN_FALSE: + node.append(False) + elif value == TOKEN_NULL: + node.append(None) + elif value == TOKEN_UNDEFINED: + node.append() + elif value == TOKEN_EMPTY_STRING: + node.append('') + else: + node.append(dictionary[value]) + tokensIndex += 1 + return node + # Parse an object + if type == '$': + node = {} + while tokensIndex < tokensLength: + key = tokens[tokensIndex] + if key == ']': + return node + if key == TOKEN_EMPTY_STRING: + key = '' + else: + key = dictionary[key] + tokensIndex += 1 + value = tokens[tokensIndex] + if value == '@' or value == '$': + node[key] = recursiveUnpackerParser() + else: + if value == TOKEN_TRUE: + node[key] = True + elif value == TOKEN_FALSE: + node[key] = False + elif value == TOKEN_NULL: + node[key] = None + elif value == TOKEN_UNDEFINED: + node[key] = None + elif value == TOKEN_EMPTY_STRING: + node[key] = '' + else: + node[key] = dictionary[value] + tokensIndex += 1 + return node + raise TypeError('Bad token ' + str(type) + ' isn\'t a type') + + return recursiveUnpackerParser() + +def _indexOfDictionary(dictionary, value): + if isinstance(value, bool): + return TOKEN_TRUE if value else TOKEN_FALSE + if value is None: + return TOKEN_NULL + if value == '': + return TOKEN_UNDEFINED + if value == '': + return TOKEN_EMPTY_STRING + if isinstance(value, str): + value = _encode(value) + index = dictionary['strings'].index(value) if value in dictionary['strings'] else -1 + if index == -1: + dictionary['strings'].append(value) + index = len(dictionary['strings']) - 1 + if type(value) not in [str, int]: + raise Error('The type is not a JSON type') + if isinstance(value, str): + value = _encode(value) + elif isinstance(value, int) and value % 1 == 0: + value = _base10To36(value) + value = _encode(value) if isinstance(value, str) else _base10To36(value) + index = dictionary[type(value)].index(value) if value in dictionary[type(value)] else -1 + if index == -1: + dictionary[type(value)].append(value) + index = len(dictionary[type(value)]) - 1 + return '+' + str(index) if type(value) == 'number' else index + +def _encode(string): + if not isinstance(string, str): + return string + return string.replace(' ', '+').replace('+', '%2B').replace('|', '%7C').replace('^', '%5E').replace('%', '%25') + +def _decode(string): + if not isinstance(string, str): + return string + return string.replace('+', ' ').replace('%2B', '+').replace('%7C', '|').replace('%5E', '^').replace('%25', '%') + +def _base10To36(number): + if not isinstance(number, (int, float)): + raise TypeError('number must be an integer') + is_negative = number < 0 + number = abs(number) + + alphabet, base36 = ['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', ''] + + while number: + number, i = divmod(number, 36) + base36 = alphabet[i] + base36 + if is_negative: + base36 = '-' + base36 + + return base36 or alphabet[0] + + +def _base36To10(number): + return int(number, 36) + +def _indexOf(array, obj, start=0): + for i in range(start, len(array)): + if array[i] == obj: + return i + return -1 \ No newline at end of file diff --git a/src/modules.py b/src/modules.py new file mode 100755 index 0000000..843464d --- /dev/null +++ b/src/modules.py @@ -0,0 +1,280 @@ +import json +import importlib +import sys +import multiprocessing as mupr + +import src.web as web +import src.utils as utils + +class module(): + def __init__(self): + self.name = None + self.module = None + self.proc = None + self.rootdir = None + self.tabs = [] + + def add(self): + spec = importlib.util.spec_from_file_location(self.name, utils.getRoot(self.entrypoint)) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + self.module = module + + def init(self, moduleMaster): + self.module.init(moduleMaster) + self.proc = mupr.Process(target=self.module.main) + + def run(self): + self.proc.start() + + def stop(self): + self.proc.stop() + + + +class moduleMaster(): + def __init__(self): + self.modules = [] + + self.webserv = None + self.app = None + self.rawServer = None + self.authServer = None + self.defaultPage = "" + self.vars = {} + + # self.addRawEventListener('test1', test1) + + def addModules(self, webserv): + self.webserv = webserv + + mdirs = utils.listSubdirs(utils.getRoot('modules/')) + + for mname in mdirs: + mjson = json.loads(open(utils.getRoot(f'modules/{mname}/module.json')).read()) + m = module() + m.name = mjson['name'] + m.entrypoint = mjson['entrypoint'] + + for tab in mjson['tabs']: + mtab = utils.getatribinarr(self.webserv.webtabs, 'name', tab['name']) + + if mtab == None: + mtab = web.webtab() + mtab.name = tab['name'] + m.tabs.append(mtab) + + def recursiveAdder(objs): + tmpPages = [] + for obj in objs: + if obj['type'] == 'folder': + folder = web.webpagefolder() + folder.name = obj['name'] + tmpTmpPages = recursiveAdder(obj['pages']) + for tmpobj in tmpTmpPages: + folder.pages.append(tmpobj) + tmpPages.append(folder) + else: + mpage = web.webpage() + mpage.name = obj['name'] + mpage.requiredPermGroup = obj['requiredPermGroup'] + mpage.location = obj['location'] + tmpPages.append(mpage) + return tmpPages + + tmpPages = recursiveAdder(tab['pages']) + + for obj in tmpPages: + mtab.pages.append(obj) + + mtab.defaultPage = tab['defaultPage'] + + self.webserv.webtabs.append(mtab) + + m.add() + self.modules.append(m) + + # for tab in webserv.webtabs: + # tab.compileHtml('User') + + def initModules(self, webserv): + self.webserv = webserv + self.app = webserv.app + self.rawServer = webserv.rawServer + self.authServer = webserv.authServer + + self.defaultPage = f'/{webserv.defaultTab}/{webserv.defaultPage}' + + for module in self.modules: + module.init(self) + + def runModules(self): + for module in self.modules: + module.run() + + + + + def reloadUsers(self): + self.authServer.reloadUsers() + + def editUser(self, user, varname, value): + path = utils.getRoot('data/')+'creds.json' + logins = json.loads(utils.readFile(path)) + for userdata in logins: + if userdata['username'] == user.username: + userdata[varname] = value + + utils.writeFile(path, json.dumps(logins, sort_keys=True, indent=2)) + + def setUserPassword(self, user, hash): + for ac in self.authServer.clients: + if ac.user == user: + self.unauth(ac) + self.editUser(user, 'sha256passwordhash', hash) + self.editUser(user, 'passwordUpdated', utils.getUnixTime()) + self.authServer.reloadUsers() + + def setUserGroups(self, user, groups): + for ac in self.authServer.clients: + if ac.user == user: + self.unauth(ac) + self.editUser(user, 'permGroups', groups) + self.authServer.reloadUsers() + + def addUser(self, user, groups, hash): + path = utils.getRoot('data/')+'creds.json' + time = utils.getUnixTime() + logins = json.loads(utils.readFile(path)) + logins.append({ + 'username': user, + 'permGroups': groups, + 'created': time, + 'id': utils.randID(16), + 'passwordUpdated': time, + 'sha256passwordhash': hash + }) + utils.writeFile(path, json.dumps(logins, sort_keys=True, indent=2)) + self.authServer.reloadUsers() + + def deleteUser(self, user): + path = utils.getRoot('data/')+'creds.json' + time = utils.getUnixTime() + logins = json.loads(utils.readFile(path)) + for login in logins: + if login['id'] == user.id: + logins.remove(login) + utils.writeFile(path, json.dumps(logins, sort_keys=True, indent=2)) + self.authServer.reloadUsers() + + def userInGroup(self, ac, group): + if not self.authServer.validAc(ac): + return False + if (group != "") and not (group in ac.user.permGroups): + return False + return True + + + + def getUserByName(self, name): + returnArr = [] + for user in self.authServer.users: + if user.username == name: + returnArr.append(user) + return returnArr + + def getUserById(self, id): + return utils.getatribinarr(self.authServer.users, 'id', id) + + + + + + def getRawClients(self): + return self.rawServer.clients + + def getAuthClients(self): + return self.authServer.clients + + def addRawEventListener(self, eventName, func): + self.rawServer.eventListeners.append({ + 'type': eventName, + 'func': func + }) + + def addAuthEventListener(self, eventName, func): + def tmpfunc(c, data): + if not c in self.rawServer.clients: + return + ac = utils.getatribinarr(self.authServer.clients, 'rawClient', c) + if ac == None: + return + if not self.authServer.validAc(ac): + return + + func(ac, data) + + self.rawServer.addEventListener(eventName, tmpfunc) + + def getRawClientByID(self, ID): + return utils.getatribinarr(self.rawServer.clients, 'clientid', ID) + + def getAuthClientByID(self, ID): + c = utils.getatribinarr(self.rawServer.clients, 'clientid', ID) + if c == None: + return None + return utils.getatribinarr(self.authServer.clients, 'rawClient', c) + + def addPageEventListener(self, page, func): + self.authServer.pageListeners.append({ + 'page': page, + 'func': func + }) + + + + def getVar(self, varName): + return self.vars[varname] + + def setVar(self, varName, val): + self.vars[varName] = val + + + def unauth(self, ac): + ac.send('redir', { + "location": "/" + }) + self.authServer.unauth(ac) + + + def sendPopupInfo(self, c, title, msg): + c.send('popupInfo', { + 'title': title, + 'msg': msg + }) + + def sendPopupSuccess(self, c, title, msg): + c.send('popupSuccess', { + 'title': title, + 'msg': msg + }) + + def sendPopupWarning(self, c, title, msg): + c.send('popupWarning', { + 'title': title, + 'msg': msg + }) + + def sendPopupError(self, c, title, msg): + c.send('popupError', { + 'title': title, + 'msg': msg + }) + + def sendPopupColor(self, c, title, msg, color, isDark): + c.send('popupColor', { + 'title': title, + 'msg': msg, + 'color': color, + 'isDark': isDark + }) \ No newline at end of file diff --git a/src/packets.py b/src/packets.py new file mode 100755 index 0000000..8eecf1f --- /dev/null +++ b/src/packets.py @@ -0,0 +1,113 @@ +import os +import base64 +from hashlib import sha256 +from flask import Flask, render_template, Response +from flask import request, redirect, url_for, make_response + +import src.jsonpack as jsonpack +import src.utils as utils + +import queue + +class rawClient: + def __init__(self, rawServer): + self.clientid = utils.randID(32) + self.messages = queue.Queue() + self.rawServer = rawServer + self.address = None + def send(self, type, msg): + self.rawServer.sendClient(self, jsonpack.pack({ + 'type': type, + 'data': msg, + 'cid': self.clientid + })) + +#Credit to https://github.com/MaxHalford/flask-sse-no-deps +class rawServer: + + def __init__(self, webserv): + self.eventListeners = [] + self.clients = [] + self.webserv = webserv + self.app = webserv.app + # self.app = app + + def listen(self): + c = rawClient(self) + self.clients.append(c) + return self.clients[-1] + + def broadcast(self, msg): + # We go in reverse order because we might have to delete an element, which will shift the + # indices backward + ssedata = format_sse(msg) + for i in reversed(range(len(clients))): + try: + self.clients[i].messages.put_nowait(ssedata) + except queue.Full: + del self.clients[i] + + def sendClient(self, c, msg): + if c not in self.clients: + return + ssedata = format_sse(msg) + c.messages.put_nowait(ssedata) + + def clientByCID(self, cid): + for c in self.clients: + if c.clientid == cid: + return c + return None + + def addEventListener(self, eventName, func): + self.eventListeners.append({ + 'type': eventName, + 'func': func + }) + +def format_sse(data: str, event=None) -> str: + #Formats a string and an event name in order to follow the event stream convention. + msg = f'data: {data}\n\n' + if event is not None: + msg = f'event: {event}\n{msg}' + return msg + + +def startRawListener(webserv): + server = rawServer(webserv) + # app.rawServer = server + + @webserv.app.route('/listen', methods=['GET', 'POST']) + def listen(): + + if request.method == 'GET': + + c = server.listen() # returns a queue.Queue + c.address = request.remote_addr + c.send('clidata', { + 'cid': c.clientid + }) + + def stream(): + while True: + msg = c.messages.get() # blocks until a new message arrives + yield msg + + return Response(stream(), mimetype='text/event-stream') + if request.method == 'POST': + + data = jsonpack.unpack(request.data.decode("utf-8")) + + if data['cid'] == None: + return {}, 400 + c = utils.getatribinarr(server.clients, 'clientid', data['cid']) + if c == None: + return {}, 400 + + for event in server.eventListeners: + if event['type'] == data['type']: + event['func'](c, data) + + return {}, 200 + + return server \ No newline at end of file diff --git a/src/utils.py b/src/utils.py new file mode 100755 index 0000000..fe5180f --- /dev/null +++ b/src/utils.py @@ -0,0 +1,132 @@ +import os +import json +import string +import random +from hashlib import sha256 +from datetime import datetime + +from sys import platform + +import subprocess + +def getRoot(path): + rootdir = os.getcwd() + f'/{path}' + + if platform in ['nt', 'win32', 'win64']: + rootdir = rootdir.split(':')[1].replace('\\', '/') + + return rootdir + +def pathExists(path): + return os.path.exists(path) + +def makeDir(path): + if not os.path.exists(path): + os.makedirs(path) + +def listSubdirs(folder): + if os.path.exists(folder): + return os.listdir(folder) + else: + return [] + +def writeFile(path, data): + if not os.path.exists(path): + with open(path, mode='a'): pass + with open(path, 'w') as f: + f.write(data) + +def readFile(path): + if not os.path.exists(path): + return '' + try: + with open(path) as f: + return f.read() + except: + return '' + +def delFile(path): + if os.path.exists(path): + os.remove(path) + +def getUnixTime(): + return round((datetime.utcnow() - datetime(1970, 1, 1)).total_seconds() * 1000) + +def hash(data): + return sha256(data.encode('utf-8')).hexdigest().upper() + +def getatribinarr(arr, atribname, atrib): + for i in range(0,len(arr),1): + if getattr(arr[i], atribname) == atrib: + return arr[i] + return None + +def randID(length): + letters = string.hexdigits + return ''.join(random.choice(letters) for i in range(length)) + +def genDefaultAccounts(): + userPassword = randID(16) + adminPassword = randID(16) + + print('#################################################') + print('New Credentials - THESE ONLY WILL BE PRINTED ONCE') + print('########') + print('Username: User') + print(f'Password: {userPassword}') + print('########') + print('Username: Admin') + print(f'Password: {adminPassword}') + print('#################################################') + + time = getUnixTime() + + return json.dumps( + [ + { + 'username': 'User', + 'permGroups': [ + 'Users' + ], + 'id': randID(16), + 'created': time, + 'passwordUpdated': time, + 'sha256passwordhash': hash(userPassword) + }, + { + 'username': 'Admin', + 'permGroups': [ + 'Users', + 'Admins' + ], + 'id': randID(16), + 'created': time, + 'passwordUpdated': time, + 'sha256passwordhash': hash(adminPassword) + } + ], sort_keys=True, indent=2) + +def genKey(path): + subprocess.run(['openssl', 'genrsa', '-out', f'{path}ssl.key', '2048']) + +def genCert(path): + writeFile(f'{path}/ssl.cnf', +"""[req] +default_bits = 2048 +prompt = no +default_md = sha256 +encrypt_key = no +distinguished_name = dn + +[dn] +C = ID +O = Local Digital Cert Authority +OU = www.ca.local +CN = Self-Signed Root CA +""") + + subprocess.run(['openssl', 'req', '-new', '-key', f'{path}ssl.key', '-out', f'{path}ssl.csr', '-config', f'{path}ssl.cnf']) + subprocess.run(['openssl', 'x509', '-req', '-days', '36500', '-in', f'{path}ssl.csr', '-signkey', f'{path}ssl.key', '-out', f'{path}ssl.crt']) + + delFile(f'{path}ssl.cnf') + delFile(f'{path}ssl.csr') \ No newline at end of file diff --git a/src/web.py b/src/web.py new file mode 100755 index 0000000..0a9a1ed --- /dev/null +++ b/src/web.py @@ -0,0 +1,187 @@ +import os +import src.utils as utils +import multiprocessing as mupr + +from flask import Flask, render_template, Response +from flask import request, redirect, url_for, make_response + +import src.jsonpack as jsonpack +import src.packets as packets +import src.auth as auth + +webroot = utils.getRoot('html/') + +app = Flask(__name__, + static_url_path=webroot, + static_folder=webroot, + template_folder=webroot) + +class webtab(): + def __init__(self): + self.name = None + self.pages = [] + self.defaultPage = '' + self.html = '' + + def compileHtml(self, permGroups): + html = '' + for page in self.pages: + html += page.compileHtml(self.name, permGroups) + return html + + def addPage(self, page): + self.pages.append(page) + +class webpagefolder(): + def __init__(self): + self.name = None + self.pages = [] + + def compileHtml(self, tabname, permGroups): + html = '
' + self.name + '
    ' + for page in self.pages: + html += page.compileHtml(tabname, permGroups) + html += '
' + return html + +class webpage(): + def __init__(self): + self.name = None + self.requiredPermGroup = '' + self.location = None + + def compileHtml(self, tabname, permGroups): + html = '' +\ + self.name + else: + html += f'>{self.name}' + return html + '' + +@app.route('/') +def index(): + isValid = app.webserv.authServer.cookieLogin(request) + if not isValid: + return redirect("/login", code=302) + else: + return redirect(f'/{app.webserv.defaultTab}/{app.webserv.defaultPage}', code=302) + +@app.route('/login') +def loginPage(): + isValid = app.webserv.authServer.cookieLogin(request) + if isValid: + return redirect(f'/{app.webserv.defaultTab}/{app.webserv.defaultPage}', code=302) + + return make_response(open(f'{webroot}nav.html', 'r').read() + .replace('', open(f'{webroot}login.html', 'r').read()) + .replace('', 'Login') + .replace('', app.webserv.title) + .replace('', '/login')) + +def recursivePageFinder(pagename, objs): + returnVal = None + for obj in objs: + if isinstance(obj, webpagefolder): + tmp = recursivePageFinder(pagename, obj.pages) + if tmp != None: + returnVal = tmp + else: + if obj.name == pagename: + returnVal = obj + return returnVal + +@app.route('//') +def page(tabname, pagename): + + isValid = app.webserv.authServer.cookieLogin(request) + if not isValid: + return redirect("/login", code=302) + + try: + + tab = utils.getatribinarr(app.webserv.webtabs, 'name', tabname) + page = recursivePageFinder(pagename, tab.pages) + + # print(page.requiredPermGroup) + + isValid, permGroups = app.webserv.authServer.validPermGroup(page.requiredPermGroup, request) + + if not isValid: + return redirect(f'/{tab.name}/{tab.defaultPage}', code=302) + + return make_response(open(utils.getRoot('html/nav.html'), 'r').read() + .replace('', open(utils.getRoot(page.location), 'r').read()) + .replace('', app.webserv.tabHtml) + .replace('', tab.compileHtml(permGroups)) + .replace('', app.webserv.title) + .replace('', f'/{app.webserv.defaultTab}/{app.webserv.defaultPage}')) + except: + return redirect("/", code=302) + +@app.route('/src/') +def src(file): + return app.send_static_file(f'src/{file}') + +@app.errorhandler(404) +def err404(err): + return redirect("/", code=302) + + +class webserv(): + def __init__(self): + self.title = 'Polyboard' + self.port = 443 + self.host = '0.0.0.0' + self.verbose = False + self.secure = True + self.tabHtml = '' + self.webtabs = [] + self.defaultTab = 'main' + self.defaultPage = '' + + self.app = None + + def init(self): + if not self.verbose: + import logging + log = logging.getLogger('werkzeug') + log.setLevel(logging.ERROR) + + if self.secure: + dataroot = utils.getRoot("data/") + sslcontext = (f'{dataroot}ssl.crt', f'{dataroot}ssl.key') + else: + sslcontext = None + + def tabHtml(path, name): + return f'{name}' + + for tab in self.webtabs: + if tab.name == self.defaultTab: + self.tabHtml = tabHtml(f'/{tab.name}/{tab.defaultPage}', tab.name) + self.tabHtml + self.defaultPage = tab.defaultPage + else: + self.tabHtml += tabHtml(f'/{tab.name}/{tab.defaultPage}', tab.name) + + app.webserv = self + self.app = app + self.rawServer = packets.startRawListener(self) + self.authServer = auth.authServer(self) + self.proc = mupr.Process(target=app.run, kwargs=dict(debug=self.verbose, port=self.port, host=self.host, ssl_context=sslcontext)) + + + def start(self): + self.proc.start() + + # return self.rawServer + + def stop(self): + self.proc.terminate() + + # def sendfatal(self, err): + # self.rawServer.broadcast(jsonpack.pack({ + # 'type': 'error', + # 'severity': 'fatal', + # 'error': err + # })) \ No newline at end of file