From 069a2115289913fdf7ea5ef3e82b4ecd2d687cf7 Mon Sep 17 00:00:00 2001 From: Bram Prieshof Date: Sun, 9 Jul 2023 02:03:41 +0200 Subject: [PATCH] inital commit --- .gitignore | 5 ++ composer.json | 17 +++++++ config.example.php | 8 +++ public/auth.php | 57 ++++++++++++++++++++++ public/css/style.css | 110 ++++++++++++++++++++++++++++++++++++++++++ public/favicon.ico | Bin 0 -> 32038 bytes public/index.php | 35 ++++++++++++++ public/js/app.js | 69 ++++++++++++++++++++++++++ public/js/favicon.ico | Bin 0 -> 32038 bytes 9 files changed, 301 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 config.example.php create mode 100644 public/auth.php create mode 100644 public/css/style.css create mode 100644 public/favicon.ico create mode 100644 public/index.php create mode 100644 public/js/app.js create mode 100644 public/js/favicon.ico diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b23222 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# ignore accidentally generated vendor directory and composer.lock file, just in case... +/vendor/ +/composer.lock +# Ignore personal config file +config.php \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..087f4ca --- /dev/null +++ b/composer.json @@ -0,0 +1,17 @@ +{ + "name": "brammp/basic-external-unifi-portal", + "description": "Basic Unifi Portal", + "type": "project", + "require": { + "art-of-wifi/unifi-api-client": "^1.1" + }, + "license": [ + "Unlicense" + ], + "authors": [ + { + "name": "brammp", + "email": "bram@bprieshof.nl" + } + ] +} diff --git a/config.example.php b/config.example.php new file mode 100644 index 0000000..d2cd571 --- /dev/null +++ b/config.example.php @@ -0,0 +1,8 @@ +:8443'); +define('controllerValidateSSL',false); +define('siteId','default'); +define('controllerVersion','7.4.156'); \ No newline at end of file diff --git a/public/auth.php b/public/auth.php new file mode 100644 index 0000000..00dd87b --- /dev/null +++ b/public/auth.php @@ -0,0 +1,57 @@ +login(); + + +// authorize_guest Params: DeviceMac ExpireTime(Minutes) UploadSpeedLimit DownloadSpeedLimit DataCap ApMac +//Send AuthRequest +$auth_result = $unifi_connection->authorize_guest($clientMac, '2000', $uploadSpeed, $downloadSpeed, null, $apMac); + +//Check if unsucsessfull +if ($auth_result == false) { + http_response_code(500); +} + +//provide feedback in json format +//error_log (json_encode($auth_result, JSON_PRETTY_PRINT)); diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..eee4ba1 --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,110 @@ +.loginPage { + padding: 8% 0 0; + margin: auto; + max-width: 600px + } + +.form { + position: relative; + z-index: 1; + background: #FFFFFF; + margin: 0 auto 100px; + padding: 45px; + text-align: center; + border-radius: 20px; + box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); +} +.form input { + border-radius: 5px; + outline: 0; + background: #f2f2f2; + width: 100%; + border: 0; + margin: 0 0 15px; + padding: 20px; + box-sizing: border-box; + font-size: 18px; +} +.button { + position: relative; + outline: 0; + background: #0081ff; + width: 100%; + border: 0; + padding: 15px; + color: #FFFFFF; + border-radius: 50px; + font-size: 20px; + -webkit-transition: all 0.3 ease; + transition: all 0.3 ease; + cursor: pointer; +} +.button:hover,.button:active,button:focus { + background: #0000ff; +} +.button:disabled { + background: gray; +} + +.buttonText { + color: #ffffff; + transition: all 0.2s; +} + +.buttonLoading .buttonText { + visibility: hidden; + opacity: 0; +} + +.buttonLoading::after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + border: 4px solid transparent; + border-top-color: #ffffff; + border-radius: 50%; + animation: button-loading-spinner 1s linear infinite; +} + +@keyframes button-loading-spinner { + from { + transform: rotate(0turn); + } + to { + transform: rotate(1turn); + } +} + +#responseMessage { + color: red; + font-weight: bold; +} + +body { + background: #090979; /* fallback for old browsers */ + background: rgb(9,9,121); + background: linear-gradient(90deg, rgba(0,129,255,100) 0%, rgba(9,9,121,1) 50%); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-family: Arial, Helvetica, sans-serif; + font-size: 18px; +} + +@media only screen and (max-width: 1000px), only screen and (max-device-width: 1000px){ + .button { + font-size: 40px; + } + .form input, body { + font-size: 35px; + } + .buttonLoading::after { + width: 40px; + height: 40px; + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..22f61482bd0a3aa492cc6f38e137486afcd175a6 GIT binary patch literal 32038 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 literal 0 HcmV?d00001 diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..604fa74 --- /dev/null +++ b/public/index.php @@ -0,0 +1,35 @@ + + + + +Portal + + + +
+ +

Welcome

+

Connecting to:" . htmlspecialchars(trim($_GET['ssid'])) ."

+

+ + + +
"; + } else { + // URL parameter does not exist + echo '

Something went wrong

'; + http_response_code(400); + } + ?> + + + diff --git a/public/js/app.js b/public/js/app.js new file mode 100644 index 0000000..27c4e48 --- /dev/null +++ b/public/js/app.js @@ -0,0 +1,69 @@ +// Retrieving the form data +var accesCode = document.getElementById("accesCode"); +var submitButton = document.getElementById("submitButton"); +var responseMessage = document.getElementById("responseMessage") +var redirectURL = document.getElementById("redirectURL").value +//var redirectURL = "https://Domain.tld/page" +var buttonLocked = false + +function submitFormAjax() { + if (buttonLocked === true){return}; + buttonLocked = true + responseMessage.innerHTML = "" + submitButton.classList.add("buttonLoading"); + if(accesCode == ""){ + responseMessage.innerHTML = "

Please enter your accesCode.

"; + return; + } + submitButton.disabled = true; + accesCode.disabled = true; + var xmlhttp = new XMLHttpRequest(); + + // Instantiating the request object + xmlhttp.open("POST", "auth.php", true); + // Defining event listener for readystatechange event + xmlhttp.onreadystatechange = function() { + console.log(this.readyState + " status:" + this.status) + if (this.readyState === 4 && this.status === 200) { + submitButton.classList.remove("buttonLoading"); + submitButton.style.backgroundColor = "green"; + document.getElementById("buttonText").innerHTML = "Connected" + accesCode.style.display = "none"; + window.setTimeout(redirectUser, 1500); + }else { + if (this.readyState === 4 && this.status === 403) { + responseMessage.innerHTML = "Acces code incorrect"; + enableButton() + } else if (this.readyState === 4) { + responseMessage.innerHTML = "Something went wrong"; + enableButton() + } + } + } + //console.log (document.getElementById("accesCode").value); + var params = "accesCode=" + encodeURIComponent(accesCode.value) + "&apMac=" + encodeURIComponent(document.getElementById("apMac").value) + "&clientMac=" + encodeURIComponent(document.getElementById("clientMac").value); + + //Setting headers + xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + + // Sending the request to the server + xmlhttp.send(params); +} + +function enableButton(){ + buttonLocked = false + submitButton.disabled = false; + accesCode.disabled = false; + submitButton.classList.remove("buttonLoading"); + accesCode.focus(); +} + +function inputEntry(){ + if(accesCode.value != "") + submitButton.disabled = false; + else + submitButton.disabled = true; +} +function redirectUser(){ + window.location.href = redirectURL +} \ No newline at end of file diff --git a/public/js/favicon.ico b/public/js/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..22f61482bd0a3aa492cc6f38e137486afcd175a6 GIT binary patch literal 32038 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 literal 0 HcmV?d00001