├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── docker ├── installer │ └── Dockerfile └── php │ └── Dockerfile ├── mdash-caddy ├── background.jpg ├── dashboard │ ├── add │ │ ├── add.api.php │ │ ├── index.php │ │ └── script.js │ ├── delete │ │ ├── delete.api.php │ │ └── index.php │ ├── edit │ │ ├── edit.api.php │ │ ├── index.php │ │ └── script.js │ ├── index.php │ ├── script.js │ └── style.css ├── functions.js ├── functions.php ├── header.php ├── index.php ├── login.api.php ├── old-background.jpg ├── script.js ├── settings │ ├── custom-config │ │ ├── index.php │ │ ├── script.js │ │ ├── style.css │ │ └── submit.api.php │ ├── header.php │ ├── index.php │ ├── logout.php │ ├── modules │ │ ├── edit │ │ │ ├── edit.api.php │ │ │ ├── index.php │ │ │ ├── log.api.php │ │ │ └── script.js │ │ └── index.php │ ├── script.js │ ├── settings-home.css │ ├── style.css │ ├── system-info │ │ ├── index.php │ │ ├── info.api.php │ │ ├── script.js │ │ └── style.css │ ├── tokens │ │ ├── delete │ │ │ ├── delete.api.php │ │ │ ├── index.php │ │ │ └── style.css │ │ └── index.php │ └── users │ │ ├── add │ │ ├── add.api.php │ │ ├── index.php │ │ └── script.js │ │ ├── delete │ │ ├── delete.api.php │ │ ├── index.php │ │ └── style.css │ │ ├── edit │ │ ├── edit.api.php │ │ ├── index.php │ │ └── script.js │ │ └── index.php ├── style.css └── welcome │ ├── index.php │ ├── script.js │ └── welcome.api.php ├── mdash-root ├── build-caddy.sh ├── build-caddyfile.php ├── config.json ├── mdash.version └── reset-db.php ├── setup.php └── terminal.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beans-are-gross/mdash/267116bef24d9b6d62ae8ade84309dd33cd993ce/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mDash 2 | Reverse proxy made easy. 3 | 4 | A web GUI controller for Caddy that automatically gives you an SSL certificate. 5 | 6 | ![](https://github.com/beans-are-gross/mdash-photos/blob/main/Welcome-2-Apps.png?raw=true) 7 | ![](https://github.com/beans-are-gross/mdash-photos/blob/main/Settings-Home.png?raw=true) 8 | 9 | ## Features 10 | 1. Reverse proxy with a free SSL certificate from Caddy. 11 | 2. Easy to use UI, with a dashboard. 12 | 3. Multiple users can use the same mDash server. 13 | 4. You can share "apps" with other users, giving them view, or view and edit access. (Only the owner of an app can delete it.) 14 | 5. You can give users "admin" rights to allow them to delete users and bad or old login tokens. 15 | 16 | ## Docker Command Line 17 | ``` 18 | docker volume create mdash-root 19 | docker volume create mdash-php 20 | docker volume create mdash-caddyfile 21 | docker network create mdash --subnet 172.220.0.0/24 22 | 23 | docker run -d --name mdash-mysql --restart unless-stopped --network mdash --ip 172.220.0.5 -e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD= mysql 24 | docker run -d --name mdash-installer --network mdash -v mdash-root:/mdash/ -v mdash-php:/var/www/ -v mdash-caddyfile:/etc/caddy/ -e DB_PASS= beansaregross/mdash 25 | ``` 26 | 27 | > [!IMPORTANT] 28 | > Wait until the "mdash-installer" container exits with a status code of 143 to continue. 29 | > If the status is not 143, please check the logs. 30 | 31 | ``` 32 | docker run -d --name mdash-php --restart unless-stopped --network mdash --ip 172.220.0.10 -p 9000:9000 -v mdash-root:/mdash/ -v mdash-php:/var/www/ beansaregross/mdash-php 33 | docker run -d --name mdash-caddy --network mdash --restart unless-stopped -p 80:80 -p 443:443 -p 8080:8080 -v mdash-root:/mdash/ -v mdash-php:/var/www/ -v mdash-caddyfile:/etc/caddy/ caddy 34 | ``` 35 | 36 | ## Docker Compose 37 | ### Create Volumes 38 | ``` 39 | docker volume create mdash-root 40 | docker volume create mdash-php 41 | docker volume create mdash-caddyfile 42 | docker network create mdash --subnet 172.220.0.0/24 43 | ``` 44 | 45 | ### Compose 46 | ``` 47 | name: mdash 48 | services: 49 | mysql: 50 | container_name: mdash-mysql 51 | networks: 52 | mdash: 53 | ipv4_address: 172.220.0.5 54 | ports: 55 | - 3306:3306 56 | environment: 57 | - MYSQL_ROOT_HOST=% 58 | - MYSQL_ROOT_PASSWORD= 59 | image: mysql 60 | restart: unless-stopped 61 | mdash-php: 62 | container_name: mdash-php 63 | networks: 64 | mdash: 65 | ipv4_address: 172.220.0.10 66 | ports: 67 | - 9000:9000 68 | volumes: 69 | - mdash-root:/mdash/ 70 | - mdash-php:/var/www/ 71 | image: beansaregross/mdash-php 72 | restart: unless-stopped 73 | caddy: 74 | container_name: mdash-caddy 75 | networks: 76 | - mdash 77 | ports: 78 | - 80:80 79 | - 443:443 80 | - 8080:8080 81 | volumes: 82 | - mdash-root:/mdash/ 83 | - mdash-php:/var/www/ 84 | - mdash-caddyfile:/etc/caddy/ 85 | image: caddy 86 | restart: unless-stopped 87 | networks: 88 | mdash: 89 | external: true 90 | name: mdash 91 | volumes: 92 | mdash-root: 93 | external: true 94 | name: mdash-root 95 | mdash-php: 96 | external: true 97 | name: mdash-php 98 | mdash-caddyfile: 99 | external: true 100 | name: mdash-caddyfile 101 | ``` 102 | 103 | ### One Time Container 104 | This container adds the files to the volumes for the other containers to use. 105 | ``` 106 | docker run -d --name mdash-installer --restart unless-stopped --network mdash -v mdash-root:/mdash/ -v mdash-php:/var/www/ -v mdash-caddyfile:/etc/caddy/ -e DB_PASS= beansaregross/mdash 107 | ``` 108 | 109 | > [!IMPORTANT] 110 | > Wait until the "mdash-installer" container exits with a status code of 143 to continue. 111 | > If the status is not 143, please check the logs. 112 | > 113 | > Then, restart the compose to update the files in Caddy. 114 | 115 | ## Server Install 116 | Please view [terminal.md](https://github.com/beans-are-gross/mdash/blob/main/terminal.md) 117 | 118 | The new background photo used is by [Kalen Emsley on Unsplash](https://unsplash.com/photos/green-mountain-across-body-of-water-Bkci_8qcdvQ?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash). 119 | -------------------------------------------------------------------------------- /docker/installer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | 3 | RUN apt-get update && apt-get install git php-fpm php-mysql -y 4 | RUN mkdir /mdash-installer 5 | 6 | WORKDIR /mdash-installer/ 7 | 8 | RUN git clone https://github.com/beans-are-gross/mdash 9 | 10 | WORKDIR /mdash-installer/mdash/ 11 | 12 | CMD ["php", "setup.php", "docker=true"] -------------------------------------------------------------------------------- /docker/php/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:fpm 2 | RUN docker-php-ext-install mysqli -------------------------------------------------------------------------------- /mdash-caddy/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beans-are-gross/mdash/267116bef24d9b6d62ae8ade84309dd33cd993ce/mdash-caddy/background.jpg -------------------------------------------------------------------------------- /mdash-caddy/dashboard/add/add.api.php: -------------------------------------------------------------------------------- 1 | "Failed to verify that the app is not a duplicate."]); 36 | } 37 | 38 | mysqli_stmt_bind_result($stmt, $appCount); 39 | mysqli_stmt_fetch($stmt); 40 | mysqli_stmt_close($stmt); 41 | 42 | if ($appCount !== 0) { 43 | echo json_encode(["error" => "An app with the same name or external URL already exists."]); 44 | exit; 45 | } 46 | 47 | $sharing = $data["sharing"]; 48 | $sharingEncrypted = [$accountIdEncrypted => encryptData("edit")]; 49 | $sharing = explode(",", $sharing); 50 | foreach ($sharing as $user) { 51 | if (empty($user)) 52 | continue; 53 | 54 | $user = explode("=", $user); 55 | $sharingEncrypted[encryptData($user[0])] = encryptData($user[1]); 56 | } 57 | $sharingEncrypted = encryptData(json_encode($sharingEncrypted)); 58 | 59 | //insert the data into the database 60 | $sql = "INSERT INTO `apps` (`name`, `int_url`, `int_url_ssl`, `ext_url`, `icon`, `sharing`, `owner`) VALUES (?, ?, ?, ?, ?, ?, ?);"; 61 | $stmt = mysqli_stmt_init($dbConn); 62 | mysqli_stmt_prepare($stmt, $sql); 63 | mysqli_stmt_bind_param($stmt, "sssssss", $name, $intUrl, $intUrlSsl, $extUrl, $icon, $sharingEncrypted, $accountIdEncrypted); 64 | $appQuery = mysqli_stmt_execute($stmt); 65 | 66 | //close the connection 67 | mysqli_stmt_close($stmt); 68 | mysqli_close($dbConn); 69 | 70 | if (!$appQuery) { 71 | echo json_encode(["error" => "Failed to add the app to the database: " . mysqli_stmt_error($stmt)]); 72 | } else { 73 | //call the build Caddyfile script 74 | $buildCaddyfile = json_decode(shell_exec("php /mdash/build-caddyfile.php"), true); 75 | if (!isset($buildCaddyfile["status"])) { 76 | echo json_encode(["error" => "Failed to build Caddyfile."]); 77 | } else { 78 | echo json_encode(["success" => true]); 79 | } 80 | exit; 81 | } 82 | } else { 83 | echo json_encode(["error" => "Required information is missing."]); 84 | exit; 85 | } -------------------------------------------------------------------------------- /mdash-caddy/dashboard/add/index.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 |
10 |
11 |

Add an App

12 | 13 |
14 | 15 |
16 | 17 |

Leave internal URL blank if you only need a link.

18 | 19 |
20 | 21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 |
29 | 30 |
31 | 32 |
33 | 34 | 40 |
41 | 42 | 43 | 44 |

Sharing

45 | 46 | "; 66 | echo "

$nickname

"; 67 | echo ""; 72 | echo ""; 73 | echo "
"; 74 | } 75 | 76 | if (mysqli_stmt_num_rows($stmt) == 0) { 77 | echo "

There are no other users to share this app with.

"; 78 | } 79 | 80 | //close the connection 81 | mysqli_stmt_close($stmt); 82 | mysqli_close($dbConn); 83 | ?> 84 | 85 |
86 | 87 | 88 |
89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /mdash-caddy/dashboard/add/script.js: -------------------------------------------------------------------------------- 1 | addHoverAnimation("name", "name-field"); 2 | addHoverAnimation("int-url", "int-url-field"); 3 | addHoverAnimation("ext-url", "ext-url-field"); 4 | addHoverAnimation("icon", "icon-field"); 5 | 6 | var userIds = []; 7 | 8 | document.getElementById("add-form").addEventListener("submit", (e) => { 9 | e.preventDefault(); 10 | 11 | let submit = document.getElementById("add-form-submit"); 12 | submit.innerHTML = "
Add App"; 13 | submit.disabled = true; 14 | submit.style.cursor = "not-allowed"; 15 | 16 | let name = document.getElementById("name").value; 17 | let intUrl = document.getElementById("int-url").value; 18 | let intUrlSsl = document.getElementById("int-url-ssl").checked; 19 | let extUrl = document.getElementById("ext-url").value; 20 | let icon = document.getElementById("icon").value; 21 | 22 | if (name.trim() !== "") { 23 | let httpsRegex = /^https?:\/\//gm; 24 | 25 | if (!httpsRegex.test(extUrl)) { 26 | if (icon.trim() !== "") { 27 | //get all of the shared users 28 | let sharing = ""; 29 | userIds.forEach((id) => { 30 | let sharingValue = document.getElementById("sharing-" + id).value; 31 | sharing += id + "=" + sharingValue + ","; 32 | }); 33 | 34 | //get the mdash-token cookie to pass to the api 35 | let cookies = document.cookie; 36 | cookies = cookies.split(";"); 37 | let mdashToken = cookies.find((c) => 38 | c.trim().startsWith("mdash-token=") 39 | ); 40 | mdashToken = mdashToken.split("=")[1]; 41 | 42 | fetch("add.api.php", { 43 | method: "POST", 44 | credentials: "same-origin", 45 | body: JSON.stringify({ 46 | name: name, 47 | intUrl: intUrl, 48 | intUrlSsl: intUrlSsl, 49 | extUrl: extUrl, 50 | icon: icon, 51 | sharing: sharing, 52 | }), 53 | headers: { 54 | "Content-type": "application/json; charset=UTF-8", 55 | Cookie: "mdash-token=" + mdashToken, 56 | }, 57 | }) 58 | .then((response) => response.json()) 59 | .then((json) => { 60 | if (json["success"]) { 61 | window.location.href = "/dashboard/"; 62 | } else if (json["error"] !== undefined) { 63 | showError("Error", json["error"], 5000); 64 | } else { 65 | showError("Invald Response", JSON.stringify(json), 5000); 66 | } 67 | }); 68 | } else { 69 | showError("Icon", "Please enter an icon name.", 5000); 70 | } 71 | } else { 72 | showError("External URL", "Do not enter http:// or https://.", 5000); 73 | } 74 | } else { 75 | showError("Name", "Please enter a name.", 5000); 76 | } 77 | 78 | submit.innerHTML = "Add App"; 79 | submit.disabled = false; 80 | submit.style.cursor = "pointer"; 81 | }); 82 | -------------------------------------------------------------------------------- /mdash-caddy/dashboard/delete/delete.api.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Delete an App

16 | 17 |
18 | This app does not exist.

"; 39 | exit; 40 | } 41 | 42 | //check if the user is the owner 43 | if (decryptData($owner) !== $accountInfo[0]) { 44 | echo "

Only the owner can delete this app.

"; 45 | exit; 46 | } 47 | 48 | //display the app as it would be on the dashboard 49 | $name = decryptData($name); 50 | $icon = decryptData($icon); 51 | 52 | echo "
"; 53 | 54 | echo ""; 55 | echo "

$name

"; 56 | 57 | echo "
"; 58 | ?> 59 |
60 | 61 | 62 |

Are you sure you want to delete this app? This action cannot be undone.

63 |
64 | 65 | 66 |
67 |
68 |
69 | 70 | 71 | -------------------------------------------------------------------------------- /mdash-caddy/dashboard/edit/edit.api.php: -------------------------------------------------------------------------------- 1 | "Failed to verify that the app is not a duplicate."]); 38 | } 39 | 40 | mysqli_stmt_bind_result($stmt, $appId); 41 | 42 | $appExists = false; 43 | while (mysqli_stmt_fetch($stmt)) { 44 | if ($appExists) 45 | break; 46 | $appExists = $appId == $id ? true : false; 47 | } 48 | 49 | if (!$appExists) { 50 | echo json_encode(["error" => "The app you are trying to edit does not exist."]); 51 | exit; 52 | } 53 | 54 | mysqli_stmt_close($stmt); 55 | 56 | $sharing = $data["sharing"]; 57 | $sharing = explode(",", $sharing); 58 | $sharingEncrypted = [encryptData($accountInfo[0]) => encryptData("edit")]; 59 | 60 | foreach ($sharing as $user) { 61 | if (empty($user)) 62 | continue; 63 | 64 | $user = explode("=", $user); 65 | $sharingEncrypted[encryptData($user[0])] = encryptData($user[1]); 66 | } 67 | $sharingEncrypted = encryptData(json_encode($sharingEncrypted)); 68 | 69 | //check if the user has edit access 70 | $sql = "SELECT `sharing` FROM `apps` WHERE `id` = ?;"; 71 | $stmt = mysqli_stmt_init($dbConn); 72 | mysqli_stmt_prepare($stmt, $sql); 73 | mysqli_stmt_bind_param($stmt, "s", $id); 74 | $appExecute = mysqli_stmt_execute($stmt); 75 | 76 | if (!$appExecute) { 77 | die("Failed to execute app query: " . mysqli_error($dbConn)); 78 | } 79 | 80 | mysqli_stmt_bind_result($stmt, $sharingSql); 81 | mysqli_stmt_fetch($stmt); 82 | 83 | $sharingCheck = json_decode(decryptData($sharingSql), true); 84 | if (decryptData($sharingCheck[$accountId]) !== "edit") { 85 | echo json_encode(["error" => "You dot have access to edit this file."]); 86 | exit; 87 | } 88 | 89 | //update the data in the database 90 | $sql = "UPDATE `apps` SET `name` = ?, `int_url` = ?, `int_url_ssl` = ?, `ext_url` = ?, `icon` = ?, `sharing` = ? WHERE `id` = ?;"; 91 | $stmt = mysqli_stmt_init($dbConn); 92 | mysqli_stmt_prepare($stmt, $sql); 93 | mysqli_stmt_bind_param($stmt, "sssssss", $name, $intUrl, $intUrlSsl, $extUrl, $icon, $sharingEncrypted, $id); 94 | $appUpdate = mysqli_stmt_execute($stmt); 95 | 96 | //close the connection 97 | mysqli_stmt_close($stmt); 98 | mysqli_close($dbConn); 99 | 100 | if (!$appUpdate) { 101 | echo json_encode(["error" => "Failed to edit the app in the database: " . mysqli_stmt_error($stmt)]); 102 | } else { 103 | //call the build Caddyfile script 104 | $buildCaddyfile = json_decode(shell_exec("php /mdash/build-caddyfile.php"), true); 105 | if (!isset($buildCaddyfile["status"])) { 106 | echo json_encode(["error" => "Failed to build Caddyfile."]); 107 | } else { 108 | echo json_encode(["success" => true]); 109 | } 110 | exit; 111 | } 112 | } else { 113 | echo json_encode(["error" => "Required information is missing."]); 114 | exit; 115 | } -------------------------------------------------------------------------------- /mdash-caddy/dashboard/edit/index.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Edit an App

16 | 17 | This app does not exist.

"; 38 | exit; 39 | } 40 | 41 | //check if the user has edit access 42 | $sharing = json_decode(decryptData($sharing), true); 43 | if (decryptData($sharing[$accountIdEncrypted]) !== "edit") { 44 | echo "

You don't have access to edit this app.

"; 45 | exit; 46 | } 47 | 48 | //display the app as it would be on the dashboard 49 | $name = decryptData($name); 50 | $intUrl = decryptData($intUrl); 51 | $intUrl = $intUrl == "---" ? "" : $intUrl; 52 | $intUrlSsl = decryptData($intUrlSsl) ? "checked" : ""; 53 | $extUrl = decryptData($extUrl); 54 | $icon = decryptData($icon); 55 | 56 | echo "
"; 57 | 58 | echo ""; 59 | echo "

$name

"; 60 | 61 | echo "
"; 62 | 63 | mysqli_stmt_close($stmt); 64 | ?> 65 | 66 |
67 |

Name

68 | 69 |
70 | 71 |

Leave internal URL blank if you only need a link.

72 | 73 |
74 |

Internal URL

75 | 76 |
77 |
78 | > 79 | 80 |
81 |
82 | 83 |
84 |

External URL

85 | 86 |
87 | 88 |
89 | 91 | 97 |
98 | 99 | 100 | 101 | 102 | 103 |

Sharing

104 | 105 | "; 127 | echo "

$nickname

"; 128 | echo ""; 140 | echo ""; 141 | echo "
"; 142 | } 143 | 144 | if (mysqli_stmt_num_rows($stmt) == 0) { 145 | echo "

There are no other users to share this app with.

"; 146 | } 147 | 148 | //close the connection 149 | mysqli_stmt_close($stmt); 150 | mysqli_close($dbConn); 151 | ?> 152 | 153 |
154 | 155 | 156 |
157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /mdash-caddy/dashboard/edit/script.js: -------------------------------------------------------------------------------- 1 | addHoverAnimation("name", "name-field"); 2 | addHoverAnimation("int-url", "int-url-field"); 3 | addHoverAnimation("ext-url", "ext-url-field"); 4 | addHoverAnimation("icon", "icon-field"); 5 | 6 | var userIds = []; 7 | 8 | document.getElementById("edit-form").addEventListener("submit", (e) => { 9 | e.preventDefault(); 10 | 11 | let submit = document.getElementById("edit-form-submit"); 12 | submit.innerHTML = "
Update App"; 13 | submit.disabled = true; 14 | submit.style.cursor = "not-allowed"; 15 | 16 | let name = document.getElementById("name").value; 17 | let intUrl = document.getElementById("int-url").value; 18 | let intUrlSsl = document.getElementById("int-url-ssl").checked; 19 | let extUrl = document.getElementById("ext-url").value; 20 | let icon = document.getElementById("icon").value; 21 | let id = document.getElementById("id").value; 22 | 23 | if (name.trim() !== "") { 24 | let httpsRegex = /^https?:\/\//gm; 25 | 26 | if (!httpsRegex.test(extUrl)) { 27 | if (icon.trim() !== "") { 28 | //get all of the shared users 29 | let sharing = ""; 30 | userIds.forEach((id) => { 31 | let sharingValue = document.getElementById("sharing-" + id).value; 32 | sharing += id + "=" + sharingValue + ","; 33 | }); 34 | 35 | //get the mdash-token cookie to pass to the api 36 | let cookies = document.cookie; 37 | cookies = cookies.split(";"); 38 | let mdashToken = cookies.find((c) => 39 | c.trim().startsWith("mdash-token=") 40 | ); 41 | mdashToken = mdashToken.split("=")[1]; 42 | 43 | fetch("edit.api.php", { 44 | method: "POST", 45 | credentials: "same-origin", 46 | body: JSON.stringify({ 47 | name: name, 48 | intUrl: intUrl, 49 | intUrlSsl: intUrlSsl, 50 | extUrl: extUrl, 51 | icon: icon, 52 | id: id, 53 | sharing: sharing, 54 | }), 55 | headers: { 56 | "Content-type": "application/json; charset=UTF-8", 57 | Cookie: "mdash-token=" + mdashToken, 58 | }, 59 | }) 60 | .then((response) => response.json()) 61 | .then((json) => { 62 | if (json["success"]) { 63 | window.location.href = "/dashboard/"; 64 | } else if (json["error"] !== undefined) { 65 | showError("Error", json["error"], 5000); 66 | } else { 67 | showError("Invald Response", JSON.stringify(json), 5000); 68 | } 69 | }); 70 | } else { 71 | showError("Icon", "Please enter an icon name.", 5000); 72 | } 73 | } else { 74 | showError("External URL", "Do not enter http:// or https://.", 5000); 75 | } 76 | } else { 77 | showError("Name", "Please enter a name.", 5000); 78 | } 79 | 80 | submit.innerHTML = "Update App"; 81 | submit.disabled = false; 82 | submit.style.cursor = "pointer"; 83 | }); 84 | -------------------------------------------------------------------------------- /mdash-caddy/dashboard/index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 |
22 |
23 |
24 |

Welcome

25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 | "; 65 | 66 | echo "edit"; 67 | echo ""; 68 | echo "

$name

"; 69 | 70 | echo ""; 71 | 72 | echo "
"; 73 | } 74 | 75 | //check if they dont have any apps, if so, show a message 76 | if (!$userHasOneApp) { 77 | //the
closes the app grid div 78 | echo "

You don't have any apps.

"; 79 | } 80 | 81 | //close the connection 82 | mysqli_stmt_close($stmt); 83 | mysqli_close($dbConn); 84 | ?> 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /mdash-caddy/dashboard/script.js: -------------------------------------------------------------------------------- 1 | var totalIconsPerRow = Math.floor(window.innerWidth / 350); 2 | var totalIconsPerRowCss = ""; 3 | 4 | for(var i = 0; i < totalIconsPerRow; i++){ 5 | totalIconsPerRowCss += " auto"; 6 | } 7 | 8 | document.getElementById("app-grid").style.gridTemplateColumns = totalIconsPerRowCss; 9 | 10 | function addAppFeatures(id, extUrl) { 11 | //when the box is clicked, go to this website 12 | document.getElementById('app-' + id).addEventListener('mouseup', ()=>{ 13 | window.location.href = 'https://' + extUrl; 14 | }); 15 | 16 | //when the box is hovered over, show the edit button 17 | document.getElementById('app-' + id).addEventListener('mouseover', ()=>{ 18 | document.getElementById('app-edit-' + id).style.display = "block"; 19 | document.getElementById('app-edit-' + id).style.animation = "show .25s forwards"; 20 | }); 21 | 22 | document.getElementById('app-' + id).addEventListener('mouseleave', ()=>{ 23 | document.getElementById('app-edit-' + id).style.animation = "hide .25s forwards"; 24 | setTimeout(() => { 25 | document.getElementById('app-edit-' + id).style.display = "none"; 26 | }, 250); 27 | }); 28 | 29 | document.getElementById('app-edit-' + id).style.opacity = 0; 30 | setTimeout(() => { 31 | document.getElementById('app-edit-' + id).style.display = "none"; 32 | document.getElementById('app-edit-' + id).style.opacity = 1; 33 | }, 250); 34 | } 35 | 36 | // document.getElementById('darken').style.display = "none"; 37 | 38 | // window.addEventListener("load", () => { 39 | // document.getElementById("darken").style.animation = "show .5s forwards"; 40 | // document.getElementById('darken').style.display = "flex"; 41 | 42 | // document.getElementById("loader-container").style.animation = "hide .5s forwards"; 43 | // setTimeout(() => { 44 | // document.getElementById("loader-container").outerHTML = ""; 45 | // }, 500); 46 | // }); -------------------------------------------------------------------------------- /mdash-caddy/dashboard/style.css: -------------------------------------------------------------------------------- 1 | #app-grid { 2 | display: grid; 3 | } 4 | 5 | .app{ 6 | width: 300px; 7 | height: 100px; 8 | 9 | margin: 10px; 10 | 11 | background-color: rgba(128, 128, 128, 0.5); 12 | backdrop-filter: blur(10px); 13 | 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | 18 | cursor: pointer; 19 | 20 | border: 2px solid rgba(255, 255, 255, 0.1); 21 | border-radius: 15px; 22 | 23 | transition: .25s; 24 | } 25 | 26 | .app:hover { 27 | background-color: rgba(128, 128, 128, 0.6); 28 | border-color: rgba(255, 255, 255, 0.2); 29 | 30 | transform: scale(1.05, 1.05); 31 | } 32 | 33 | .app-edit { 34 | position: absolute; 35 | top: 5px; 36 | right: 5px; 37 | 38 | background-color: rgba(128, 128, 128, 0.5); 39 | 40 | border-radius: 5px; 41 | border-top-right-radius: 10px; 42 | 43 | padding: 5px; 44 | margin: 0; 45 | } 46 | 47 | .app img { 48 | width: 75px; 49 | height: 75px; 50 | 51 | margin-right: 25px; 52 | } -------------------------------------------------------------------------------- /mdash-caddy/functions.js: -------------------------------------------------------------------------------- 1 | //for making the outer field expand when the input element is clicked 2 | function addHoverAnimation(field, container) { 3 | field = document.getElementById(field); 4 | container = document.getElementById(container); 5 | 6 | field.addEventListener("focus", () => { 7 | container.style.animation = "hoverShow .5s forwards"; 8 | }); 9 | 10 | field.addEventListener("blur", () => { 11 | container.style.animation = "hoverHide .5s forwards"; 12 | }); 13 | } 14 | 15 | function addButtonBorderAnimation(button) { 16 | button = document.getElementById(button); 17 | 18 | button.addEventListener("mouseover", () => { 19 | button.style.animation = "hoverShow .5s forwards"; 20 | }); 21 | 22 | button.addEventListener("mouseout", () => { 23 | button.style.animation = "hoverHide .5s forwards"; 24 | }); 25 | } 26 | 27 | //for revealing passwords with the eyeball button 28 | function addReveal(button, field) { 29 | button = document.getElementById(button); 30 | field = document.getElementById(field); 31 | button.addEventListener("click", () => { 32 | if (field.type == "text") { 33 | field.type = "password"; 34 | button.innerHTML = 35 | ' visibility '; 36 | } else if (field.type == "password") { 37 | field.type = "text"; 38 | button.innerHTML = 39 | ' visibility_off '; 40 | } 41 | }); 42 | } 43 | 44 | function showError(header, message, disappear){ 45 | document.getElementById("error-container").style.display = "flex"; 46 | document.getElementById("error-container").style.animation = "showPopup .5s forwards"; 47 | document.getElementById("error-header").textContent = header; 48 | document.getElementById("error-message").innerHTML = message; 49 | 50 | if(disappear !== 0){ 51 | setTimeout(() => { 52 | document.getElementById("error-container").style.animation = "hidePopup .5s forwards"; 53 | setTimeout(() => { 54 | document.getElementById("error-container").style.display = "none"; 55 | }, 500); 56 | }, disappear); 57 | } 58 | } -------------------------------------------------------------------------------- /mdash-caddy/functions.php: -------------------------------------------------------------------------------- 1 | $expiresSql)) { 73 | //check if the token equals the database (double check) 74 | $tokenSql = decryptData($idSql); 75 | 76 | if ($token === $tokenSql) { 77 | //check if the ip matches 78 | if (!empty($_SERVER['HTTP_CLIENT_IP'])) { 79 | $ip = $_SERVER['HTTP_CLIENT_IP']; 80 | } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 81 | $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; 82 | } else { 83 | $ip = $_SERVER['REMOTE_ADDR']; 84 | } 85 | 86 | $ipSql = decryptData($ipSql); 87 | 88 | if ($ip === $ipSql) { 89 | //if all pass, then pull the users nickname 90 | $accountId = decryptData($accountIdSql); 91 | 92 | mysqli_stmt_close($stmt); 93 | $sql = "SELECT nickname FROM accounts WHERE id = ?;"; 94 | $stmt = mysqli_stmt_init($dbConn); 95 | mysqli_stmt_prepare($stmt, $sql); 96 | mysqli_stmt_bind_param($stmt, "s", $accountId); 97 | $userQuery = mysqli_stmt_execute($stmt); 98 | 99 | if (!$userQuery) { 100 | die("Failed to execute user query."); 101 | } 102 | 103 | mysqli_stmt_bind_result($stmt, $accountNickname); 104 | 105 | if (!mysqli_stmt_fetch($stmt)) { 106 | //the user was not found 107 | mysqli_stmt_close($stmt); 108 | mysqli_close($dbConn); 109 | 110 | return "no-user"; 111 | } 112 | 113 | mysqli_stmt_close($stmt); 114 | mysqli_close($dbConn); 115 | 116 | return [$accountId, $accountNickname]; 117 | } else { 118 | //the ip was bad 119 | return "bad-ip"; 120 | } 121 | 122 | } else { 123 | //the token was bad 124 | return "bad-token"; 125 | } 126 | } else { 127 | //the token was expired 128 | return "token-expired"; 129 | } 130 | } else { 131 | //the token was not found in the database 132 | return "token-404"; 133 | } 134 | } else { 135 | //the token cookie was not set 136 | return "token-400"; 137 | } 138 | } 139 | 140 | function verifyAdmin($id) 141 | { 142 | //connect to the database 143 | $config = json_decode(file_get_contents("/mdash/config.json"), true); 144 | $dbInfo = $config["dbData"]; 145 | 146 | $dbHost = $dbInfo["dbHost"]; 147 | $dbUser = $dbInfo["dbUser"]; 148 | $dbPass = decryptData($dbInfo["dbPass"]); 149 | $dbDatabase = $dbInfo["dbDatabase"]; 150 | 151 | $dbConn = mysqli_connect($dbHost, $dbUser, $dbPass, $dbDatabase); 152 | 153 | if (!$dbConn) { 154 | die("Failed to connect to the database: " . mysqli_connect_error()); 155 | } 156 | unset($config); 157 | 158 | //check if the user is an admin 159 | $sql = "SELECT `admin` FROM `accounts` WHERE `id` = ?;"; 160 | $stmt = mysqli_stmt_init($dbConn); 161 | mysqli_stmt_prepare($stmt, $sql); 162 | mysqli_stmt_bind_param($stmt, "s", $id); 163 | $checkExecute = mysqli_stmt_execute($stmt); 164 | 165 | if (!$checkExecute) { 166 | die("Failed to execute the SQL statement: " . mysqli_stmt_error($stmt)); 167 | } 168 | 169 | mysqli_stmt_bind_result($stmt, $admin); 170 | mysqli_stmt_fetch($stmt); 171 | 172 | $admin = decryptData($admin); 173 | 174 | mysqli_stmt_close($stmt); 175 | mysqli_close($dbConn); 176 | 177 | return $admin; 178 | } -------------------------------------------------------------------------------- /mdash-caddy/header.php: -------------------------------------------------------------------------------- 1 | 42 | 43 | 44 | 45 | 46 | 47 | mDash 48 | 50 | 51 | 52 | 53 | 54 | 55 |
56 | error 57 |
58 |

Error

59 |

Message

60 |
61 |
62 | 63 | "; 64 | } 65 | ?> -------------------------------------------------------------------------------- /mdash-caddy/index.php: -------------------------------------------------------------------------------- 1 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 64 | 65 | 66 | 67 |
68 | error 69 |
70 |

Error

71 |

Message

72 |
73 |
74 |
75 |
76 |
77 |

Hi there

78 |

Enter your info to login

79 |
80 | 81 |
82 |

83 | 84 |
85 | 86 | 91 |
92 |

93 | 94 | 95 |
96 |
97 |
98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /mdash-caddy/login.api.php: -------------------------------------------------------------------------------- 1 | "Failed to execute user query."]); 56 | exit; 57 | } 58 | 59 | mysqli_stmt_bind_result($stmt, $idSql, $passwordSql); 60 | 61 | if (mysqli_stmt_fetch($stmt)) { 62 | if (password_verify($password, $passwordSql)) { 63 | $tokenUnhashed = substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil(32 / strlen($x)))), 1, 32); 64 | $token = openssl_encrypt( 65 | $tokenUnhashed, 66 | $encryptionInfo["cipher"], 67 | $encryptionInfo["key"], 68 | $encryptionInfo["options"], 69 | $encryptionInfo["iv"] 70 | ); 71 | $id = openssl_encrypt( 72 | $idSql, 73 | $encryptionInfo["cipher"], 74 | $encryptionInfo["key"], 75 | $encryptionInfo["options"], 76 | $encryptionInfo["iv"] 77 | ); 78 | 79 | if (!empty($_SERVER['HTTP_CLIENT_IP'])) { 80 | $ip = $_SERVER['HTTP_CLIENT_IP']; 81 | } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 82 | $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; 83 | } else { 84 | $ip = $_SERVER['REMOTE_ADDR']; 85 | } 86 | $ip = openssl_encrypt( 87 | $ip, 88 | $encryptionInfo["cipher"], 89 | $encryptionInfo["key"], 90 | $encryptionInfo["options"], 91 | $encryptionInfo["iv"] 92 | ); 93 | 94 | $expiresUnhashed = time() + 2592000; 95 | $expires = openssl_encrypt( 96 | $expiresUnhashed, 97 | $encryptionInfo["cipher"], 98 | $encryptionInfo["key"], 99 | $encryptionInfo["options"], 100 | $encryptionInfo["iv"] 101 | ); 102 | 103 | mysqli_stmt_close($stmt); 104 | 105 | $sql = "INSERT INTO tokens (`id`, `account_id`, `ip`, `expires`) VALUES(?, ?, ?, ?);"; 106 | $stmt = mysqli_stmt_init($dbConn); 107 | mysqli_stmt_prepare($stmt, $sql); 108 | mysqli_stmt_bind_param($stmt, "ssss", $token, $id, $ip, $expires); 109 | $tokenQuery = mysqli_stmt_execute($stmt); 110 | 111 | if (!$tokenQuery) { 112 | echo json_encode(["error" => "Failed to create token query."]); 113 | } else { 114 | setcookie("mdash-token", $tokenUnhashed, $expiresUnhashed, "/"); 115 | echo json_encode(["correct" => true]); 116 | } 117 | 118 | exit; 119 | } else { 120 | echo json_encode(["correct" => false]); 121 | exit; 122 | } 123 | } else { 124 | echo json_encode(["correct" => false]); 125 | exit; 126 | } 127 | } else { 128 | //all required data was not provided 129 | echo json_encode(["error" => "Required information is missing."]); 130 | exit; 131 | } -------------------------------------------------------------------------------- /mdash-caddy/old-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beans-are-gross/mdash/267116bef24d9b6d62ae8ade84309dd33cd993ce/mdash-caddy/old-background.jpg -------------------------------------------------------------------------------- /mdash-caddy/script.js: -------------------------------------------------------------------------------- 1 | addHoverAnimation("login-username", "login-form-username-field"); 2 | addHoverAnimation("login-password", "login-form-password-field"); 3 | addReveal("login-password-reveal", "login-password"); 4 | 5 | document.getElementById("login-form").addEventListener("submit", (e) => { 6 | e.preventDefault(); 7 | 8 | let username = document.getElementById("login-username").value; 9 | let password = document.getElementById("login-password").value; 10 | 11 | if (username.trim() === "") { 12 | showError("Error", "Please fill in your username.", 5000); 13 | return; 14 | } 15 | 16 | if (password.trim() === "") { 17 | showError("Error", "Please fill in your password.", 5000); 18 | return; 19 | } 20 | 21 | fetch("login.api.php", { 22 | method: "POST", 23 | body: JSON.stringify({ 24 | username: username, 25 | password: password, 26 | }), 27 | headers: { 28 | "Content-type": "application/json; charset=UTF-8", 29 | }, 30 | }) 31 | .then((response) => response.json()) 32 | .then((json) => { 33 | if(json["error"] !== undefined){ 34 | showError("Error", $json["error"], 5000); 35 | } else if (json["correct"]) { 36 | window.location.href = "/dashboard/"; 37 | } else if (!json["correct"]) { 38 | showError("Error", "Incorrect username or password.", 5000); 39 | } else { 40 | showError("Invald Response", JSON.stringify(json), 5000); 41 | } 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /mdash-caddy/settings/custom-config/index.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 10 |
11 |
12 |
13 | settings_alert 14 |

Config Error

15 |
16 |

Caddy reported an error with your custom config.
17 | 18 |

19 |
20 | 21 |
22 |
23 |
24 |
25 |
26 | Error"; 29 | echo "

You do not have access to this page.

"; 30 | echo "
"; 31 | exit; 32 | } 33 | ?> 34 | 35 | 36 | 37 |

Custom Config

38 |

Please make sure to use the proper formatting.
How to use a Caddyfile 40 |

41 | 42 |
43 | 48 | 49 |
50 | 51 | 52 |
53 |
54 | -------------------------------------------------------------------------------- /mdash-caddy/settings/custom-config/script.js: -------------------------------------------------------------------------------- 1 | function closeInfoPopup(){ 2 | document.getElementById("info-container").style.animation = 3 | "infoHidePopup .5s forwards"; 4 | setTimeout(() => { 5 | document.getElementById("info-container").style.display = "none"; 6 | }, 500); 7 | } 8 | 9 | document.getElementById("config-form").addEventListener("submit", (e) => { 10 | e.preventDefault(); 11 | 12 | var customConfig = document.getElementById("custom-config-textarea").value; 13 | 14 | //get the mdash-token cookie to pass to the api 15 | let cookies = document.cookie; 16 | cookies = cookies.split(";"); 17 | let mdashToken = cookies.find((c) => 18 | c.trim().startsWith("mdash-token=") 19 | ); 20 | mdashToken = mdashToken.split("=")[1]; 21 | 22 | fetch("submit.api.php", { 23 | method: "POST", 24 | credentials: "same-origin", 25 | body: JSON.stringify({ 26 | customConfig: customConfig, 27 | }), 28 | headers: { 29 | "Content-type": "application/json; charset=UTF-8", 30 | Cookie: "mdash-token=" + mdashToken, 31 | }, 32 | }) 33 | .then((response) => response.json()) 34 | .then((json) => { 35 | if (json["success"]) { 36 | window.location.href = "/settings/"; 37 | } else if (json["error"] !== undefined) { 38 | document.getElementById("info-container").style.display = "flex"; 39 | document.getElementById("info-container").style.animation = 40 | "infoShowPopup .5s forwards"; 41 | 42 | document.getElementById("custom-config-log").innerHTML = json["error"]; 43 | } else { 44 | showError("Invald Response", JSON.stringify(json), 5000); 45 | } 46 | }); 47 | }); -------------------------------------------------------------------------------- /mdash-caddy/settings/custom-config/style.css: -------------------------------------------------------------------------------- 1 | #custom-config-textarea{ 2 | margin-top: 20px; 3 | color: black; 4 | text-align: left; 5 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/custom-config/submit.api.php: -------------------------------------------------------------------------------- 1 | "You do not have permission to complete this task."]); 12 | exit; 13 | } 14 | 15 | //get the post data from javascript fetch 16 | $payload = file_get_contents("php://input"); 17 | $data = json_decode($payload, true); 18 | 19 | if (isset($data["customConfig"])) { 20 | $customConfig = strip_tags($data["customConfig"]); 21 | $customConfigLog = "/mdash/custom-config.log"; 22 | $customCaddyfile = "/mdash/custom.caddyfile"; 23 | 24 | if (file_exists($customCaddyfile)) { 25 | shell_exec("rm $customCaddyfile"); 26 | } 27 | 28 | if (file_exists($customConfigLog)) { 29 | shell_exec("> $customConfigLog"); 30 | } 31 | 32 | shell_exec("touch $customCaddyfile"); 33 | shell_exec("echo '$customConfig' >> $customCaddyfile"); 34 | exec("cd /mdash/ && caddy validate --config $customCaddyfile >> custom-config.log 2>&1 ", $output, $code); 35 | 36 | if ($code !== 0) { 37 | shell_exec("rm $customCaddyfile"); 38 | $customConfigErrors = nl2br(file_get_contents($customConfigLog)); 39 | echo json_encode(["error" => $customConfigErrors]); 40 | exit; 41 | } else { 42 | $buildCaddyfile = json_decode(shell_exec("php /mdash/build-caddyfile.php"), true); 43 | if (!isset($buildCaddyfile["status"])) { 44 | echo json_encode(["error" => "Failed to build Caddyfile."]); 45 | } else { 46 | echo json_encode(["success" => true]); 47 | } 48 | exit; 49 | } 50 | } else { 51 | echo json_encode(["error" => "Required information is missing."]); 52 | exit; 53 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/header.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |

Settings

6 |

Version 7 | 11 |

12 | Update to $latestVersion"; 21 | } 22 | ?> 23 |
24 |
25 | 26 | 27 | 29 | 30 | 31 | 32 | 34 | 35 | 54 |
55 |
56 |
-------------------------------------------------------------------------------- /mdash-caddy/settings/index.php: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 11 |
12 | 13 |
14 | 31 | 32 |

Your info

33 | 34 |
35 |

Nickname

36 |

37 |
38 | 39 |
40 |

Username

41 |

42 |
43 |
44 | 45 |
46 | 54 | 62 | 70 | 78 | 79 |
80 |
81 | 82 | 83 | -------------------------------------------------------------------------------- /mdash-caddy/settings/logout.php: -------------------------------------------------------------------------------- 1 | "You do not have permission to complete this task."]); 12 | exit; 13 | } 14 | 15 | //get the post data from javascript fetch 16 | $payload = file_get_contents("php://input"); 17 | $data = json_decode($payload, true); 18 | 19 | if (isset($data["modules"])) { 20 | $sql = "DELETE FROM `modules`;"; 21 | $stmt = mysqli_stmt_init($dbConn); 22 | mysqli_stmt_prepare($stmt, $sql); 23 | $moduleQuery = mysqli_stmt_execute($stmt); 24 | if (!$moduleQuery) { 25 | echo json_encode(["error" => "Failed to empty module database: " . mysqli_stmt_error($stmt)]); 26 | exit; 27 | } 28 | mysqli_stmt_close($stmt); 29 | 30 | $command = "cd /mdash/ && ./build-caddy.sh"; 31 | 32 | $modules = $data["modules"]; 33 | $modules = explode(",", $modules); 34 | foreach ($modules as $module) { 35 | if (empty($module)) 36 | continue; 37 | 38 | $module = encryptData($module); 39 | 40 | $sql = "INSERT INTO `modules` (`url`) VALUES (?);"; 41 | $stmt = mysqli_stmt_init($dbConn); 42 | mysqli_stmt_prepare($stmt, $sql); 43 | mysqli_stmt_bind_param($stmt, "s", $module); 44 | $moduleQuery = mysqli_stmt_execute($stmt); 45 | if (!$moduleQuery) { 46 | echo json_encode(["error" => "Failed to add module: " . mysqli_stmt_error($stmt)]); 47 | exit; 48 | } 49 | mysqli_stmt_close($stmt); 50 | 51 | $command .= " $module"; 52 | } 53 | 54 | exec($command, $output, $code); 55 | 56 | if ($code != 0) { 57 | echo json_encode(["error" => "xcaddy failed to build, returned $code
Check /mdash/build-caddy.log for error info."]); 58 | } 59 | 60 | echo json_encode(["success" => true]); 61 | } else { 62 | echo json_encode(["error" => "Required information is missing."]); 63 | exit; 64 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/modules/edit/index.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 10 |
11 |
12 |
13 | restart_alt 14 |

Rebooting

15 |
16 |

This will take a few minutes.
17 | 18 |
19 | 20 | 21 |

22 |
23 |
24 |
25 |
26 | Error"; 29 | echo "

You do not have access to this page.

"; 30 | echo "
"; 31 | exit; 32 | } 33 | ?> 34 |

Edit Modules

35 | Editing modules is not supported on Docker.

"; 38 | exit; 39 | } 40 | ?> 41 |

Do not put http:// or https:// in the link.

42 |
43 |
44 |
45 | 46 | 47 | addLink('$url')"; 60 | } 61 | ?> 62 |
63 | 64 | 65 |
66 |
67 |
68 |
69 | -------------------------------------------------------------------------------- /mdash-caddy/settings/modules/edit/log.api.php: -------------------------------------------------------------------------------- 1 | { 2 | addLink(""); 3 | }); 4 | 5 | var linkIds = []; 6 | var id = 0; 7 | 8 | function addLink(value) { 9 | id++; 10 | 11 | let formField = document.createElement("div"); 12 | formField.setAttribute("class", "form-field"); 13 | formField.setAttribute("id", "module-field-" + id); 14 | 15 | let input = document.createElement("input"); 16 | input.setAttribute("type", "text"); 17 | input.setAttribute("id", "module-" + id); 18 | input.setAttribute("placeholder", "Module " + id + " URL"); 19 | input.setAttribute("value", value); 20 | 21 | let inputIcon = document.createElement("button"); 22 | inputIcon.setAttribute("class", "input-small-icon"); 23 | inputIcon.setAttribute("onclick", "deleteLink(" + id + ");"); 24 | inputIcon.innerHTML = "delete"; 25 | 26 | formField.appendChild(input); 27 | formField.appendChild(inputIcon); 28 | document.getElementById("module-fields").appendChild(formField); 29 | 30 | linkIds.push(id); 31 | } 32 | 33 | function deleteLink(id) { 34 | document.getElementById("module-field-" + id).outerHTML = ""; 35 | linkIds = linkIds.filter((linkId) => linkId !== id); 36 | } 37 | 38 | function updateInfoPopup(){ 39 | let cookies = document.cookie; 40 | cookies = cookies.split(";"); 41 | let mdashToken = cookies.find((c) => c.trim().startsWith("mdash-token=")); 42 | mdashToken = mdashToken.split("=")[1]; 43 | 44 | fetch("log.api.php", { 45 | headers: { 46 | "Content-type": "application/json; charset=UTF-8", 47 | Cookie: "mdash-token=" + mdashToken, 48 | }, 49 | }) 50 | .then((response) => response.text()) 51 | .then((log) => { 52 | let modulesLog = document.getElementById("modules-log"); 53 | modulesLog.innerHTML = log; 54 | 55 | if(document.getElementById("auto-scroll").checked){ 56 | modulesLog.scrollTop = modulesLog.scrollHeight; 57 | } 58 | 59 | log = log.split("
"); 60 | if(log[log.length - 2] == "mDash: Success!"){ 61 | window.location.href = "/settings/modules/"; 62 | } 63 | }); 64 | } 65 | 66 | document.getElementById("modules-form").addEventListener("submit", (e) => { 67 | e.preventDefault(); 68 | 69 | document.getElementById("info-container").style.display = "flex"; 70 | document.getElementById("info-container").style.animation = 71 | "infoShowPopup .5s forwards"; 72 | 73 | setInterval(updateInfoPopup, 1000); 74 | 75 | let submit = document.getElementById("modules-form-submit"); 76 | submit.innerHTML = "
Update Modules"; 77 | submit.disabled = true; 78 | submit.style.cursor = "not-allowed"; 79 | 80 | let stop = false; 81 | 82 | let modules = ""; 83 | linkIds.forEach((module) => { 84 | let moduleUrl = document.getElementById("module-" + module).value; 85 | if (moduleUrl.trim() == "" || module == null) { 86 | return; 87 | } else { 88 | let httpsRegex = /^https?:\/\//gm; 89 | 90 | if (httpsRegex.test(moduleUrl)) { 91 | showError( 92 | "Module " + module + " URL", 93 | "Do not enter http:// or https://.", 94 | 5000 95 | ); 96 | stop = true; 97 | } else { 98 | modules += moduleUrl + ","; 99 | } 100 | } 101 | }); 102 | 103 | if(stop == true) { 104 | submit.innerHTML = "Update Modules"; 105 | submit.disabled = false; 106 | submit.style.cursor = "pointer"; 107 | 108 | return; 109 | } 110 | 111 | //get the mdash-token cookie to pass to the api 112 | let cookies = document.cookie; 113 | cookies = cookies.split(";"); 114 | let mdashToken = cookies.find((c) => c.trim().startsWith("mdash-token=")); 115 | mdashToken = mdashToken.split("=")[1]; 116 | 117 | fetch("edit.api.php", { 118 | method: "POST", 119 | body: JSON.stringify({ 120 | modules: modules, 121 | }), 122 | headers: { 123 | "Content-type": "application/json; charset=UTF-8", 124 | Cookie: "mdash-token=" + mdashToken, 125 | }, 126 | }) 127 | .then((response) => response.json()) 128 | .then((json) => { 129 | if (json["success"]) { 130 | window.location.href = "/settings/modules/"; 131 | } else if (json["error"] !== undefined) { 132 | document.getElementById("info-container").style.animation = 133 | "infoHidePopup .5s forwards"; 134 | setTimeout(() => { 135 | document.getElementById("info-container").style.display = "none"; 136 | 137 | showError("Error", json["error"], 5000); 138 | }, 500); 139 | } else { 140 | document.getElementById("info-container").style.animation = 141 | "infoHidePopup .5s forwards"; 142 | setTimeout(() => { 143 | document.getElementById("info-container").style.display = "none"; 144 | 145 | showError("Invald Response", JSON.stringify(json), 5000); 146 | }, 500); 147 | } 148 | }); 149 | 150 | submit.innerHTML = "Update Modules"; 151 | submit.disabled = false; 152 | submit.style.cursor = "pointer"; 153 | }); 154 | -------------------------------------------------------------------------------- /mdash-caddy/settings/modules/index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 |
14 |
15 |

Modules

16 |

17 |
18 | 19 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | document.getElementById('skip').selected = true;"; 35 | } else { 36 | $modules = shell_exec("caddy list-modules --versions"); 37 | } 38 | } else { 39 | $modules = shell_exec("caddy list-modules --versions"); 40 | } 41 | $modules = explode("\n", $modules); 42 | $stats = ""; 43 | foreach ($modules as $module) { 44 | if (str_contains($module, ":")) { 45 | $stats .= "$module
"; 46 | continue; 47 | } 48 | 49 | $moduleInfo = explode(" ", $module); 50 | 51 | if (empty($moduleInfo[0]) && empty($moduleInfo[1])) { 52 | continue; 53 | } 54 | 55 | echo ""; 56 | echo ""; 57 | echo ""; 58 | echo ""; 59 | } 60 | 61 | echo ""; 62 | ?> 63 | 64 |
ModuleVersion
$moduleInfo[0] $moduleInfo[1]
65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /mdash-caddy/settings/script.js: -------------------------------------------------------------------------------- 1 | var totalIconsPerRow = Math.floor(document.getElementById("settings-home").offsetWidth / 210); 2 | var totalIconsPerRowCss = ""; 3 | 4 | for(var i = 0; i < totalIconsPerRow; i++){ 5 | totalIconsPerRowCss += " auto"; 6 | } 7 | 8 | document.getElementById("settings-home").style.gridTemplateColumns = totalIconsPerRowCss; -------------------------------------------------------------------------------- /mdash-caddy/settings/settings-home.css: -------------------------------------------------------------------------------- 1 | #settings-home { 2 | display: grid; 3 | justify-content: center; 4 | width: 100%; 5 | } 6 | 7 | .settings-home-button div .material-symbols-rounded{ 8 | font-size: 100px; 9 | margin: 0; 10 | } 11 | 12 | .settings-home-button div h2, 13 | .settings-home-button div p{ 14 | margin: 0; 15 | } 16 | 17 | .settings-home-button{ 18 | display: flex; 19 | align-items: normal; 20 | justify-content: center; 21 | width: 200px; 22 | height: 200px; 23 | border-radius: 10px; 24 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/style.css: -------------------------------------------------------------------------------- 1 | table { 2 | background: rgba(128, 128, 128, 0.5); 3 | backdrop-filter: blur(10px); 4 | 5 | padding: 10px; 6 | 7 | border-radius: 15px; 8 | 9 | display: block; 10 | max-height: 50vh; 11 | overflow: scroll; 12 | } 13 | 14 | th, 15 | td { 16 | padding-left: 5px; 17 | padding-right: 5px; 18 | } 19 | 20 | .darken { 21 | width: 85vw; 22 | position: absolute; 23 | top: 0; 24 | right: 0; 25 | } 26 | 27 | .settings-nav { 28 | background-color: #28282B; 29 | display: flex; 30 | justify-content: center; 31 | width: 15vw; 32 | max-width: 15vw; 33 | height: 100vh; 34 | position: absolute; 35 | top: 0; 36 | left: 0; 37 | } 38 | 39 | .settings-header { 40 | background-color: #1D1D20; 41 | width: 15vw; 42 | padding: 20px 0 20px 0; 43 | } 44 | 45 | .settings-nav-buttons button{ 46 | width: 15vw; 47 | border: none; 48 | border-radius: 0px; 49 | padding: 0; 50 | margin: 0; 51 | background-color: #28282B; 52 | } 53 | 54 | .settings-nav-buttons button:hover { 55 | background-color: #3A3A41; 56 | } 57 | 58 | #info-container { 59 | position: fixed; 60 | top: 50%; 61 | left: 50%; 62 | transform: translate(-50%, -50%); 63 | } 64 | 65 | @keyframes infoShowPopup { 66 | 0% { 67 | opacity: 0; 68 | top: -60px; 69 | } 70 | 100% { 71 | opacity: 1; 72 | top: 50%; 73 | } 74 | } 75 | 76 | @keyframes infoHidePopup { 77 | 0% { 78 | opacity: 1; 79 | top: 50%; 80 | } 81 | 100% { 82 | opacity: 0; 83 | top: -60px; 84 | } 85 | } 86 | 87 | .log{ 88 | margin: 0; 89 | margin-top: 10px; 90 | padding: 10px; 91 | display: inline-block; 92 | text-align: left; 93 | height: 50vh; 94 | width: 75vw; 95 | overflow: scroll; 96 | flex-direction: column-reverse; 97 | background-color: rgba(0, 0, 0, .2); 98 | border-radius: 10px; 99 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/system-info/index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 9 | 10 |
11 |
12 |
13 | hard_drive 14 |

Storage

15 |

GB

16 |

Free

17 | 18 |
19 |

GB

20 |

GB

21 |
22 |
23 | 24 |
25 | memory 26 |

Memory

27 |

MB

28 |

Available

29 | 30 |
31 |

MB

32 |

MB

33 |
34 |
35 | 36 |
37 | schedule 38 |

Server Time

39 |

40 |

41 |

42 |
43 | 44 |
45 | power 46 |

Up Since

47 |

48 |

49 |
50 | 51 |
52 | lan 53 |

Network

54 |

55 |

56 |
57 |
58 | 59 |
60 | -------------------------------------------------------------------------------- /mdash-caddy/settings/system-info/info.api.php: -------------------------------------------------------------------------------- 1 | "You do not have permission to complete this task."]); 11 | exit; 12 | } 13 | 14 | 15 | // storage 16 | $bytesToGb = 1000000000; 17 | 18 | $totalSpace = round(disk_total_space("/") / $bytesToGb, 2); 19 | $freeSpace = round(disk_free_space("/") / $bytesToGb, 2); 20 | $usedSpace = round($totalSpace - $freeSpace, 2); 21 | 22 | // memory 23 | $memory = explode("\n", shell_exec("free -m"))[1]; 24 | $memory = array_values(array_filter(explode(" ", $memory))); 25 | $totalMemory = $memory[1]; 26 | $usedMemory = $memory[2]; 27 | $availableMemory = $memory[6]; 28 | 29 | // server time 30 | $timezone = date_default_timezone_get(); 31 | $serverTime = date("G:i:s"); 32 | $serverDate = date("M d, o"); 33 | 34 | // uptime 35 | $upSince = date("M d, o", strtotime(shell_exec("uptime -s"))); 36 | $uptime = str_replace("up ", "", shell_exec("uptime -p")); 37 | 38 | // network 39 | $ipAddr = shell_exec("hostname -i"); 40 | $hostname = shell_exec("hostname"); 41 | 42 | $returnArray = [ 43 | "total-space" => $totalSpace, 44 | "free-space" => $freeSpace, 45 | "used-space" => $usedSpace, 46 | "total-memory" => $totalMemory, 47 | "used-memory" => $usedMemory, 48 | "available-memory" => $availableMemory, 49 | "timezone" => $timezone, 50 | "server-time" => $serverTime, 51 | "server-date" => $serverDate, 52 | "up-since" => $upSince, 53 | "uptime" => $uptime, 54 | "ip-addr" => $ipAddr, 55 | "hostname" => $hostname, 56 | ]; 57 | 58 | echo json_encode($returnArray); -------------------------------------------------------------------------------- /mdash-caddy/settings/system-info/script.js: -------------------------------------------------------------------------------- 1 | var totalIconsPerRow = Math.floor( 2 | document.getElementById("darken").offsetWidth / 200 3 | ); 4 | var totalIconsPerRowCss = ""; 5 | 6 | for (var i = 0; i < totalIconsPerRow; i++){ 7 | totalIconsPerRowCss += " auto"; 8 | } 9 | 10 | document.getElementById("system-info-grid").style.gridTemplateColumns = 11 | totalIconsPerRowCss; 12 | 13 | var idArray = [ 14 | "total-space", 15 | "free-space", 16 | "used-space", 17 | "storage", 18 | "total-memory", 19 | "used-memory", 20 | "available-memory", 21 | "memory", 22 | "timezone", 23 | "server-time", 24 | "server-date", 25 | "up-since", 26 | "uptime", 27 | "ip-addr", 28 | "hostname", 29 | ]; 30 | 31 | function updateInfo() { 32 | fetch("./info.api.php") 33 | .then((res) => res.json()) 34 | .then((json) => { 35 | idArray.forEach((id) => { 36 | if(id == "storage"){ 37 | let progress = document.getElementById("storage"); 38 | progress.value = json["used-space"]; 39 | progress.max = json["total-space"]; 40 | } else if(id == "memory") { 41 | let progress = document.getElementById("memory"); 42 | progress.value = json["used-memory"]; 43 | progress.max = json["total-memory"]; 44 | } else { 45 | let textContent = document.getElementById(id).textContent; 46 | document.getElementById(id).textContent = json[id]; 47 | } 48 | }); 49 | }); 50 | } 51 | 52 | updateInfo(); 53 | setInterval(updateInfo, 1000); -------------------------------------------------------------------------------- /mdash-caddy/settings/system-info/style.css: -------------------------------------------------------------------------------- 1 | .right{ 2 | text-align: right; 3 | } 4 | 5 | .right-special{ 6 | display: flex; 7 | align-items: center; 8 | justify-content: right; 9 | } 10 | 11 | #system-info-grid { 12 | display: grid; 13 | } 14 | 15 | .system-info-widget { 16 | width: max-content; 17 | padding: 10px; 18 | margin: 10px; 19 | width: 175px; 20 | height: 175px; 21 | background-color: rgba(128, 128, 128, 0.5); 22 | backdrop-filter: blur(10px); 23 | color: white; 24 | border-radius: 10px; 25 | border: 2px solid rgba(255, 255, 255, 0.1); 26 | } 27 | 28 | .system-info-widget h2{ 29 | margin: 0; 30 | text-align: left; 31 | } 32 | 33 | .system-info-widget p, 34 | .system-info-widget .material-symbols-rounded { 35 | text-align: left; 36 | margin: 0; 37 | } 38 | 39 | .system-info-widget div{ 40 | display: flex; 41 | align-items: center; 42 | justify-content: space-between; 43 | } 44 | 45 | progress{ 46 | border-radius: 100px; 47 | width: 100%; 48 | } 49 | 50 | progress::-moz-progress-bar, 51 | progress::-webkit-progress-bar { 52 | background-color: #7953A9; 53 | border-radius: 100px; 54 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/tokens/delete/delete.api.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 |
17 |
18 |

Delete a Token

19 | 20 |
21 | You do not have access to this page.

"; 29 | echo "
"; 30 | exit; 31 | } 32 | 33 | //pull the token information 34 | $sql = "SELECT `account_id`, `expires` FROM `tokens` WHERE `id` = ?;"; 35 | $stmt = mysqli_stmt_init($dbConn); 36 | mysqli_stmt_prepare($stmt, $sql); 37 | mysqli_stmt_bind_param($stmt, "s", $idDecrypted); 38 | $tokenExecute = mysqli_stmt_execute($stmt); 39 | 40 | if (!$tokenExecute) { 41 | die("Failed to execute token query: " . mysqli_error($dbConn)); 42 | } 43 | 44 | mysqli_stmt_bind_result($stmt, $tokenAccountId, $expires); 45 | mysqli_stmt_fetch($stmt); 46 | 47 | if (is_null($tokenAccountId)) { 48 | echo "
"; 49 | echo "

This token does not exist.

"; 50 | echo "
"; 51 | echo "
"; 52 | exit; 53 | } 54 | 55 | $tokenAccountId = decryptData($tokenAccountId); 56 | $expires = date("M j, o g:i:s a", decryptData($expires)); 57 | 58 | mysqli_stmt_close($stmt); 59 | 60 | //pull the user information 61 | $sql = "SELECT `nickname` FROM `accounts` WHERE `id` = ?;"; 62 | $stmt = mysqli_stmt_init($dbConn); 63 | mysqli_stmt_prepare($stmt, $sql); 64 | mysqli_stmt_bind_param($stmt, "s", $tokenAccountId); 65 | $tokenExecute = mysqli_stmt_execute($stmt); 66 | 67 | if (!$tokenExecute) { 68 | die("Failed to execute token query: " . mysqli_error($dbConn)); 69 | } 70 | 71 | mysqli_stmt_bind_result($stmt, $nickname); 72 | mysqli_stmt_fetch($stmt); 73 | 74 | $nickname = !empty($nickname) ? decryptData($nickname) : "Deleted User"; 75 | 76 | echo "
"; 77 | echo "

$nickname

"; 78 | echo "

$expires

"; 79 | echo "
"; 80 | 81 | mysqli_stmt_close($stmt); 82 | mysqli_close($dbConn); 83 | } 84 | ?> 85 |
86 | 87 | 88 |

Are you sure you want to delete this token? This action cannot be undone, and will immediately log out 89 | the user.

90 |
91 | 92 | 93 |
94 |
95 |
96 | 97 | 98 | -------------------------------------------------------------------------------- /mdash-caddy/settings/tokens/delete/style.css: -------------------------------------------------------------------------------- 1 | .token-info { 2 | background-color: rgba(128, 128, 128, 0.5); 3 | backdrop-filter: blur(10px); 4 | 5 | padding: 10px; 6 | border-radius: 15px; 7 | border: 2px solid rgba(255, 255, 255, 0.1); 8 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/tokens/index.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 |
21 |
22 | Error"; 25 | echo "

You do not have access to this page.

"; 26 | echo "
"; 27 | exit; 28 | } 29 | ?> 30 |

Tokens

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | "; 83 | echo ""; 84 | echo ""; 85 | echo ""; 91 | echo ""; 92 | } 93 | 94 | mysqli_stmt_close($stmt); 95 | mysqli_close($dbConn); 96 | ?> 97 | 98 | 99 |
NicknameExpires
$nickname $currentToken$expires"; 86 | echo "
"; 87 | echo ""; 88 | echo ""; 89 | echo "
"; 90 | echo "
100 |
101 |
102 | 103 | 104 | -------------------------------------------------------------------------------- /mdash-caddy/settings/users/add/add.api.php: -------------------------------------------------------------------------------- 1 | "You do not have permission to complete this task."]); 9 | exit; 10 | } 11 | 12 | header("Content-Type: application/json"); 13 | 14 | //get the post data from javascript fetch 15 | $payload = file_get_contents("php://input"); 16 | $data = json_decode($payload, true); 17 | 18 | if (isset($data["nickname"]) && isset($data["username"]) && isset($data["password"]) && isset($data["admin"])) { 19 | //encrypt the data 20 | $nickname = encryptData($data["nickname"]); 21 | $username = encryptData($data["username"]); 22 | $password = password_hash($data["password"], PASSWORD_BCRYPT); 23 | $admin = encryptData($data["admin"]); 24 | 25 | //check if the app already exists 26 | $sql = "SELECT COUNT(*) FROM `accounts` WHERE `username` = ?;"; 27 | $stmt = mysqli_stmt_init($dbConn); 28 | mysqli_stmt_prepare($stmt, $sql); 29 | mysqli_stmt_bind_param($stmt, "s", $username); 30 | $appCheck = mysqli_stmt_execute($stmt); 31 | 32 | if (!$appCheck) { 33 | echo json_encode(["error" => "Failed to verify that the user is not a duplicate."]); 34 | } 35 | 36 | mysqli_stmt_bind_result($stmt, $appCount); 37 | mysqli_stmt_fetch($stmt); 38 | mysqli_stmt_close($stmt); 39 | 40 | if ($appCount !== 0) { 41 | echo json_encode(["error" => "A user with the same username already exists."]); 42 | exit; 43 | } 44 | 45 | //insert the data into the database 46 | $sql = "INSERT INTO accounts (nickname, username, password, admin) VALUES (?, ?, ?, ?)"; 47 | $stmt = mysqli_stmt_init($dbConn); 48 | mysqli_stmt_prepare($stmt, $sql); 49 | mysqli_stmt_bind_param($stmt, "ssss", $nickname, $username, $password, $admin); 50 | $addUserExecute = mysqli_stmt_execute($stmt); 51 | 52 | if (!$addUserExecute) { 53 | echo json_encode(["error" => "Failed to add the user to the database: " . mysqli_stmt_error($stmt)]); 54 | } else { 55 | echo json_encode(["success" => true]); 56 | } 57 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/users/add/index.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 22 |
23 |
24 |
25 | Error"; 28 | echo "

You do not have access to this page.

"; 29 | echo "
"; 30 | exit; 31 | } 32 | ?> 33 |

Add a User

34 |
35 | 36 |
37 | 38 |
39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 | 47 |
48 | 49 | 54 |
55 | 56 |
57 | 58 | 63 |
64 | 65 |
66 | 67 | 68 |
69 |
70 |
71 |
72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /mdash-caddy/settings/users/add/script.js: -------------------------------------------------------------------------------- 1 | addHoverAnimation("nickname", "nickname-field"); 2 | addHoverAnimation("username", "username-field"); 3 | addHoverAnimation("password", "password-field"); 4 | addHoverAnimation("password-verify", "password-verify-field"); 5 | 6 | addReveal("password-reveal", "password"); 7 | addReveal("password-verify-reveal", "password-verify"); 8 | 9 | document.getElementById("add-form").addEventListener("submit", (e) => { 10 | e.preventDefault(); 11 | 12 | let nickname = document.getElementById("nickname").value; 13 | let username = document.getElementById("username").value; 14 | let password = document.getElementById("password").value; 15 | let passwordVerify = document.getElementById("password-verify").value; 16 | 17 | if (nickname.trim() === "") { 18 | showError("Nickname", "Please enter a nickname.", 5000); 19 | return; 20 | } 21 | 22 | if (username.trim() === "") { 23 | showError("Username", "Please enter a username.", 5000); 24 | return; 25 | } 26 | 27 | if (password.trim() === "") { 28 | showError("Password", "Please enter a password.", 5000); 29 | return; 30 | } 31 | 32 | if (passwordVerify.trim() === "") { 33 | showError("Password Verify", "Please enter a password again.", 5000); 34 | return; 35 | } 36 | 37 | if (password !== passwordVerify) { 38 | showError("Passwords", "The passwords do not match.", 5000); 39 | return; 40 | } 41 | 42 | let admin = document.getElementById("admin").checked; 43 | 44 | //get the mdash-token cookie to pass to the api 45 | let cookies = document.cookie; 46 | cookies = cookies.split(";"); 47 | let mdashToken = cookies.find((c) => c.trim().startsWith("mdash-token=")); 48 | mdashToken = mdashToken.split("=")[1]; 49 | 50 | fetch("add.api.php", { 51 | method: "POST", 52 | body: JSON.stringify({ 53 | nickname: nickname, 54 | username: username, 55 | password: password, 56 | admin: admin, 57 | }), 58 | headers: { 59 | "Content-type": "application/json; charset=UTF-8", 60 | "Cookie": "mdash-token=" + mdashToken, 61 | }, 62 | }) 63 | .then((response) => response.json()) 64 | .then((json) => { 65 | if (json["success"]) { 66 | window.location.href = "/settings/users"; 67 | } else if (json["error"] !== undefined) { 68 | showError("Error", json["error"], 5000); 69 | } else { 70 | showError("Invald Response", JSON.stringify(json), 5000); 71 | } 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /mdash-caddy/settings/users/delete/delete.api.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 |
17 |
18 |

Delete a User

19 | 20 |
21 | You do not have access to this page.

"; 28 | echo "
"; 29 | exit; 30 | } 31 | 32 | //pull the app info 33 | $sql = "SELECT `nickname`, `username` FROM `accounts` WHERE `id` = ?;"; 34 | $stmt = mysqli_stmt_init($dbConn); 35 | mysqli_stmt_prepare($stmt, $sql); 36 | mysqli_stmt_bind_param($stmt, "s", $idDecrypted); 37 | $userExecute = mysqli_stmt_execute($stmt); 38 | 39 | if (!$userExecute) { 40 | die("Failed to execute app query: " . mysqli_error($dbConn)); 41 | } 42 | 43 | mysqli_stmt_bind_result($stmt, $nickname, $username); 44 | mysqli_stmt_fetch($stmt); 45 | 46 | //check to see if the app exists, or if the user has access 47 | if (is_null($nickname)) { 48 | echo "

This user does not exist.

"; 49 | exit; 50 | } 51 | 52 | //display the app as it would be on the dashboard 53 | $nickname = decryptData($nickname); 54 | $username = decryptData($username); 55 | 56 | echo ""; 60 | ?> 61 |
62 | 63 | 64 |

Are you sure you want to delete this user? This action cannot be undone.

65 |
66 | 67 | 68 |
69 |
70 |
71 | 72 | 73 | -------------------------------------------------------------------------------- /mdash-caddy/settings/users/delete/style.css: -------------------------------------------------------------------------------- 1 | .user-info { 2 | background-color: rgba(128, 128, 128, 0.5); 3 | backdrop-filter: blur(10px); 4 | 5 | padding: 10px; 6 | border-radius: 15px; 7 | border: 2px solid rgba(255, 255, 255, 0.1); 8 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/users/edit/edit.api.php: -------------------------------------------------------------------------------- 1 | "You do not have permission to complete this task."]); 12 | exit; 13 | } 14 | 15 | //get the post data from javascript fetch 16 | $payload = file_get_contents("php://input"); 17 | $data = json_decode($payload, true); 18 | 19 | if (isset($data["nickname"]) && isset($data["username"]) && isset($data["password"]) && isset($data["admin"]) && isset($data["id"])) { 20 | $accountId = encryptData($accountInfo[0]); 21 | 22 | //encrypt the other data 23 | $nickname = encryptData($data["nickname"]); 24 | $username = encryptData($data["username"]); 25 | $admin = encryptData($data["admin"]); 26 | 27 | //decrypt the id 28 | $id = decryptData($data["id"]); 29 | 30 | //check if the app already exists 31 | $sql = "SELECT `id` FROM `accounts` WHERE `username` = ?;"; 32 | $stmt = mysqli_stmt_init($dbConn); 33 | mysqli_stmt_prepare($stmt, $sql); 34 | mysqli_stmt_bind_param($stmt, "s", $username); 35 | $userCheck = mysqli_stmt_execute($stmt); 36 | 37 | if (!$userCheck) { 38 | echo json_encode(["error" => "Failed to verify that the user is not a duplicate."]); 39 | } 40 | 41 | mysqli_stmt_bind_result($stmt, $userId); 42 | 43 | $userExists = false; 44 | while (mysqli_stmt_fetch($stmt)) { 45 | if ($userExists) 46 | break; 47 | $userExists = $userId == $id ? false : true; 48 | } 49 | 50 | if ($userExists) { 51 | echo json_encode(["error" => "A user with the same username already exists."]); 52 | exit; 53 | } 54 | 55 | if (!empty(trim($data["password"], " "))) { 56 | $password = password_hash($data["password"], PASSWORD_BCRYPT); 57 | 58 | //update the data in the database 59 | $sql = "UPDATE `accounts` SET `nickname` = ?, `username` = ?, `password` = ?, `admin` = ? WHERE `id` = ?;"; 60 | $stmt = mysqli_stmt_init($dbConn); 61 | mysqli_stmt_prepare($stmt, $sql); 62 | mysqli_stmt_bind_param($stmt, "sssss", $nickname, $username, $password, $admin, $id); 63 | $updateUserExecute = mysqli_stmt_execute($stmt); 64 | } else { 65 | //update the data in the database 66 | $sql = "UPDATE `accounts` SET `nickname` = ?, `username` = ?, `admin` = ? WHERE `id` = ?;"; 67 | $stmt = mysqli_stmt_init($dbConn); 68 | mysqli_stmt_prepare($stmt, $sql); 69 | mysqli_stmt_bind_param($stmt, "ssss", $nickname, $username, $admin, $id); 70 | $updateUserExecute = mysqli_stmt_execute($stmt); 71 | } 72 | 73 | //close the connection 74 | mysqli_stmt_close($stmt); 75 | mysqli_close($dbConn); 76 | 77 | if (!$updateUserExecute) { 78 | echo json_encode(["error" => "Failed to edit the user to the database: " . mysqli_stmt_error($stmt)]); 79 | } else { 80 | echo json_encode(["success" => true]); 81 | exit; 82 | } 83 | } else { 84 | echo json_encode(["error" => "Required information is missing."]); 85 | exit; 86 | } -------------------------------------------------------------------------------- /mdash-caddy/settings/users/edit/index.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 |
19 |
20 |
21 | Error"; 24 | echo "

You do not have access to this page.

"; 25 | echo "
"; 26 | exit; 27 | } 28 | 29 | $id = strip_tags($_GET["id"]); 30 | $idDecrypted = decryptData($id); 31 | 32 | //pull the user information 33 | $sql = "SELECT `nickname`, `username`, `admin` FROM `accounts` WHERE `id`=?;"; 34 | $stmt = mysqli_stmt_init($dbConn); 35 | mysqli_stmt_prepare($stmt, $sql); 36 | mysqli_stmt_bind_param($stmt, "s", $idDecrypted); 37 | $userExecute = mysqli_stmt_execute($stmt); 38 | 39 | if (!$userExecute) { 40 | die("Failed to execute user query: " . mysqli_error($dbConn)); 41 | } 42 | 43 | mysqli_stmt_bind_result($stmt, $nickname, $username, $admin); 44 | mysqli_stmt_fetch($stmt); 45 | mysqli_stmt_close($stmt); 46 | 47 | $nickname = decryptData($nickname); 48 | $username = decryptData($username); 49 | $admin = decryptData($admin) ? "checked" : ""; 50 | ?> 51 |

Edit a User

52 | 53 | 54 | 55 |
56 |

Nickname

57 | 58 |
59 | 60 |
61 |

Username

62 | 63 |
64 |
65 | > 66 | 67 |
68 |
69 | 70 |

You do not need to fill the password fields out if you do not want to give the user 71 | a new one.

72 | 73 |
74 | 75 | 80 |
81 | 82 |
83 | 84 | 89 |
90 | 91 |
92 | 93 | 94 |
95 |
96 |
97 |
98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /mdash-caddy/settings/users/edit/script.js: -------------------------------------------------------------------------------- 1 | addHoverAnimation("nickname", "nickname-field"); 2 | addHoverAnimation("username", "username-field"); 3 | addHoverAnimation("password", "password-field"); 4 | addHoverAnimation("password-verify", "password-verify-field"); 5 | 6 | addReveal("password-reveal", "password"); 7 | addReveal("password-verify-reveal", "password-verify"); 8 | 9 | document.getElementById("add-form").addEventListener("submit", (e) => { 10 | e.preventDefault(); 11 | 12 | let id = document.getElementById("id").value; 13 | 14 | let nickname = document.getElementById("nickname").value; 15 | let username = document.getElementById("username").value; 16 | let password = document.getElementById("password").value; 17 | let passwordVerify = document.getElementById("password-verify").value; 18 | 19 | if (nickname.trim() === "") { 20 | showError("Nickname", "Please enter a nickname.", 5000); 21 | return; 22 | } 23 | 24 | if (username.trim() === "") { 25 | showError("Userame", "Please enter a username.", 5000); 26 | return; 27 | } 28 | 29 | //if the first password field is not empty 30 | if (password.trim() != "") { 31 | //if the second password field is empty 32 | if (passwordVerify.trim() === "") { 33 | showError("Password Verify", "Please enter a password again.", 5000); 34 | return; 35 | } else { 36 | if (password !== passwordVerify) { 37 | showError("Passwords", "Your passwords do not match.", 5000); 38 | return; 39 | } 40 | } 41 | } 42 | 43 | let admin = document.getElementById("admin").checked; 44 | 45 | //get the mdash-token cookie to pass to the api 46 | let cookies = document.cookie; 47 | cookies = cookies.split(";"); 48 | let mdashToken = cookies.find((c) => c.trim().startsWith("mdash-token=")); 49 | mdashToken = mdashToken.split("=")[1]; 50 | 51 | fetch("edit.api.php", { 52 | method: "POST", 53 | body: JSON.stringify({ 54 | nickname: nickname, 55 | username: username, 56 | password: password, 57 | admin: admin, 58 | id: id, 59 | }), 60 | headers: { 61 | "Content-type": "application/json; charset=UTF-8", 62 | "Cookie": "mdash-token=" + mdashToken, 63 | }, 64 | }) 65 | .then((response) => response.json()) 66 | .then((json) => { 67 | if (json["success"]) { 68 | window.location.href = "/settings/users"; 69 | } else if (json["error"] !== undefined) { 70 | showError("Error", json["error"], 5000); 71 | } else { 72 | showError("Invald Response", JSON.stringify(json), 5000); 73 | } 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /mdash-caddy/settings/users/index.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 |
21 |
22 | Error"; 25 | echo "

You do not have access to this page.

"; 26 | echo "
"; 27 | exit; 28 | } 29 | ?> 30 |

Users

31 |
32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | "; 64 | echo ""; 65 | echo ""; 66 | echo ""; 70 | echo ""; 71 | } 72 | 73 | mysqli_stmt_close($stmt); 74 | mysqli_close($dbConn); 75 | ?> 76 | 77 | 78 |
NicknameUsername
$nickname$username"; 67 | echo ""; 68 | echo ""; 69 | echo "
79 |
80 |
81 | 82 | 83 | -------------------------------------------------------------------------------- /mdash-caddy/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400&display=swap"); 2 | 3 | * { 4 | font-family: "Poppins", sans-serif; 5 | color: white; 6 | text-align: center; 7 | } 8 | 9 | body { 10 | width: 100vw; 11 | min-height: 100vh; 12 | 13 | background-image: url("/background.jpg"); 14 | background-repeat: no-repeat; 15 | background-size: cover; 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | margin: 0; 20 | } 21 | 22 | .darken { 23 | width: 100vw; 24 | min-height: 100vh; 25 | background-color: rgba(0, 0, 0, 0.7); 26 | display: flex; 27 | align-items: center; 28 | justify-content: center; 29 | } 30 | 31 | #container { 32 | width: 100%; 33 | min-height: 100vh; 34 | display: flex; 35 | flex-direction: column; 36 | justify-content: center; 37 | } 38 | 39 | .secondary { 40 | margin: 0px; 41 | color: #a9a9a9; 42 | } 43 | 44 | form { 45 | width: 100vw; 46 | display: flex; 47 | flex-direction: column; 48 | align-items: center; 49 | justify-content: center; 50 | } 51 | 52 | @keyframes hoverShow { 53 | 0% { 54 | transform: scale(1, 1); 55 | } 56 | 100% { 57 | transform: scale(1.05, 1.05); 58 | } 59 | } 60 | 61 | @keyframes hoverHide { 62 | 0% { 63 | transform: scale(1.05, 1.05); 64 | } 65 | 100% { 66 | transform: scale(1, 1); 67 | } 68 | } 69 | 70 | @keyframes show { 71 | 0% { 72 | opacity: 0; 73 | } 74 | 100% { 75 | opacity: 1; 76 | } 77 | } 78 | 79 | @keyframes hide { 80 | 0% { 81 | opacity: 1; 82 | } 83 | 100% { 84 | opacity: 0; 85 | } 86 | } 87 | 88 | .form-field { 89 | display: flex; 90 | align-items: center; 91 | justify-content: center; 92 | width: 300px; 93 | height: 30px; 94 | padding: 10px; 95 | margin: 10px; 96 | background-color: rgba(128, 128, 128, 0.5); 97 | backdrop-filter: blur(10px); 98 | color: white; 99 | border-radius: 30px; 100 | border: 2px solid rgba(255, 255, 255, 0.1); 101 | text-align: left; 102 | } 103 | 104 | .form-field-double { 105 | width: 300px; 106 | height: 70px; 107 | padding: 10px; 108 | margin: 10px; 109 | background-color: rgba(128, 128, 128, 0.5); 110 | backdrop-filter: blur(10px); 111 | color: white; 112 | border-radius: 30px; 113 | border: 2px solid rgba(255, 255, 255, 0.1); 114 | text-align: left; 115 | } 116 | 117 | .splitter { 118 | width: 100%; 119 | height: 1px; 120 | background-color: rgba(255, 255, 255, 0.1); 121 | margin-top: 5px; 122 | margin-bottom: 5px; 123 | } 124 | 125 | .form-field input, 126 | .form-field-double input[type="text"] { 127 | width: 100%; 128 | height: 30px; 129 | background-color: transparent; 130 | border: none; 131 | outline: none; 132 | text-align: left; 133 | } 134 | 135 | select { 136 | color: black; 137 | margin-left: 5px; 138 | } 139 | 140 | option { 141 | color: black; 142 | } 143 | 144 | .form-field-double input[type="checkbox"] { 145 | height: 100%; 146 | } 147 | 148 | .form-field-double label { 149 | font-size: 13px; 150 | } 151 | 152 | .form-field input::placeholder, 153 | .form-field-double input::placeholder { 154 | color: white; 155 | opacity: 1; /* Firefox */ 156 | } 157 | 158 | .form-field input::-ms-input-placeholder, 159 | .form-field-double input::-ms-input-placeholder { 160 | /* Edge 12 -18 */ 161 | color: white; 162 | } 163 | 164 | .input-small { 165 | width: 250px; 166 | } 167 | 168 | .input-small-icon { 169 | width: 25px; 170 | height: 25px; 171 | background-color: transparent; 172 | border-top-right-radius: 100px; 173 | border-bottom-right-radius: 100px; 174 | border: none; 175 | outline: none; 176 | text-align: left; 177 | cursor: pointer; 178 | position: absolute; 179 | top: 0; 180 | right: 0; 181 | } 182 | 183 | .error { 184 | margin: 0; 185 | padding: 0; 186 | color: red; 187 | 188 | display: flex; 189 | align-items: center; 190 | } 191 | 192 | .error-icon { 193 | color: red; 194 | margin-right: 5px; 195 | } 196 | 197 | button { 198 | display: flex; 199 | align-items: center; 200 | justify-content: center; 201 | width: max-content; 202 | height: 30px; 203 | padding: 10px; 204 | margin: 10px; 205 | background-color: rgba(128, 128, 128, 0.5); 206 | backdrop-filter: blur(10px); 207 | color: white; 208 | border-radius: 100px; 209 | border: 2px solid rgba(255, 255, 255, 0.1); 210 | text-align: left; 211 | cursor: pointer; 212 | } 213 | 214 | button .material-symbols-rounded { 215 | margin-right: 5px; 216 | } 217 | 218 | .form-secondary { 219 | position: absolute; 220 | top: 50%; 221 | right: 10px; 222 | 223 | padding: 0; 224 | margin: 0; 225 | 226 | font-size: 10px; 227 | 228 | line-height: 0; 229 | } 230 | 231 | .center { 232 | display: flex; 233 | align-items: center; 234 | justify-content: center; 235 | } 236 | 237 | /* Loading animation */ 238 | .loader { 239 | width: 50px; 240 | aspect-ratio: 1; 241 | display: grid; 242 | } 243 | .loader::before, 244 | .loader::after { 245 | content: ""; 246 | grid-area: 1/1; 247 | --c: no-repeat radial-gradient(farthest-side, #25b09b 92%, #0000); 248 | background: var(--c) 50% 0, var(--c) 50% 100%, var(--c) 100% 50%, 249 | var(--c) 0 50%; 250 | background-size: 12px 12px; 251 | animation: l12 1s infinite; 252 | } 253 | .loader::before { 254 | margin: 4px; 255 | filter: hue-rotate(45deg); 256 | background-size: 8px 8px; 257 | animation-timing-function: linear; 258 | } 259 | 260 | @keyframes l12 { 261 | 100% { 262 | transform: rotate(0.5turn); 263 | } 264 | } 265 | 266 | #loader-container { 267 | display: flex; 268 | align-items: center; 269 | justify-content: center; 270 | 271 | height: 100vh; 272 | width: 100vw; 273 | 274 | background-color: black; 275 | 276 | position: fixed; 277 | top: 0; 278 | left: 0; 279 | } 280 | 281 | .small { 282 | transform: scale(0.25, 0.25); 283 | } 284 | 285 | #error-container, 286 | #info-container { 287 | position: fixed; 288 | top: -60px; 289 | left: 50%; 290 | transform: translate(-50%); 291 | 292 | width: max-content; 293 | height: max-content; 294 | 295 | background-color: rgba(128, 128, 128, 0.5); 296 | backdrop-filter: blur(10px); 297 | 298 | border-radius: 10px; 299 | border: 2px solid rgba(255, 255, 255, 0.1); 300 | 301 | display: none; 302 | align-items: center; 303 | justify-content: center; 304 | 305 | padding: 10px; 306 | 307 | color: white; 308 | 309 | z-index: 10; 310 | } 311 | 312 | @keyframes showPopup { 313 | 0% { 314 | opacity: 0; 315 | top: -60px; 316 | } 317 | 100% { 318 | opacity: 1; 319 | top: 10px; 320 | } 321 | } 322 | 323 | @keyframes hidePopup { 324 | 0% { 325 | opacity: 1; 326 | top: 10px; 327 | } 328 | 100% { 329 | opacity: 0; 330 | top: -60px; 331 | } 332 | } 333 | 334 | #error-container .material-symbols-rounded, 335 | #info-container .material-symbols-rounded { 336 | border-radius: 100px; 337 | 338 | font-size: 50px; 339 | color: white; 340 | } 341 | 342 | #error-container .material-symbols-rounded{ 343 | background-color: #ff6961; 344 | } 345 | 346 | #error-container div { 347 | margin-left: 20px; 348 | } 349 | 350 | #error-header, 351 | #error-message { 352 | margin: 0; 353 | } -------------------------------------------------------------------------------- /mdash-caddy/welcome/index.php: -------------------------------------------------------------------------------- 1 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | mDash 52 | 53 | 55 | 56 | 57 | 58 |
59 | error 60 |
61 |

Error

62 |

Message

63 |
64 |
65 |
66 |
67 |
68 |

Welcome to mDash

69 |

Just one step to begin.

70 |
71 | 72 |
73 | 74 |
75 | 76 |
77 | 78 |
79 | 80 | 85 |
86 | 87 |
88 | 89 | 94 |
95 | 96 | 97 |
98 |
99 |
100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /mdash-caddy/welcome/script.js: -------------------------------------------------------------------------------- 1 | addHoverAnimation("nickname", "nickname-field"); 2 | addHoverAnimation("username", "username-field"); 3 | addHoverAnimation("password", "password-field"); 4 | addHoverAnimation("password-verify", "password-verify-field"); 5 | 6 | addReveal("password-reveal", "password"); 7 | addReveal("password-verify-reveal", "password-verify"); 8 | 9 | document.getElementById("welcome-form").addEventListener("submit", (e) => { 10 | e.preventDefault(); 11 | 12 | let nickname = document.getElementById("nickname").value; 13 | let username = document.getElementById("username").value; 14 | let password = document.getElementById("password").value; 15 | let passwordVerify = document.getElementById("password-verify").value; 16 | 17 | if (nickname.trim() === "") { 18 | showError("Nickname", "Please enter a nickname.", 5000); 19 | return; 20 | } 21 | 22 | if (username.trim() === "") { 23 | showError("Username", "Please enter a username.", 5000); 24 | return; 25 | } 26 | 27 | if (password.trim() === "") { 28 | showError("Password", "Please enter a password.", 5000); 29 | return; 30 | } 31 | 32 | if (passwordVerify.trim() === "") { 33 | showError("Password Verify", "Please enter a password again.", 5000); 34 | return; 35 | } 36 | 37 | if (password !== passwordVerify) { 38 | showError("Passwords", "The passwords do not match.", 5000); 39 | return; 40 | } 41 | 42 | fetch("welcome.api.php", { 43 | method: "POST", 44 | body: JSON.stringify({ 45 | nickname: nickname, 46 | username: username, 47 | password: password, 48 | }), 49 | headers: { 50 | "Content-type": "application/json; charset=UTF-8", 51 | }, 52 | }) 53 | .then((response) => response.json()) 54 | .then((json) => { 55 | if (json["success"]) { 56 | window.location.href = "/"; 57 | } else { 58 | showError("Invald Response", JSON.stringify(json), 5000); 59 | } 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /mdash-caddy/welcome/welcome.api.php: -------------------------------------------------------------------------------- 1 | "Failed to connect to the database: " . mysqli_connect_error()]); 68 | } 69 | 70 | $admin = openssl_encrypt( 71 | true, 72 | $encryptionInfo["cipher"], 73 | $encryptionInfo["key"], 74 | $encryptionInfo["options"], 75 | $encryptionInfo["iv"] 76 | ); 77 | 78 | $sql = "INSERT INTO accounts (nickname, username, password, admin) VALUES (?, ?, ?, ?)"; 79 | $stmt = mysqli_stmt_init($dbConn); 80 | mysqli_stmt_prepare($stmt, $sql); 81 | mysqli_stmt_bind_param($stmt, "ssss", $encryptedNickname, $encryptedUsername, $hashedPassword, $admin); 82 | $addUserExecute = mysqli_stmt_execute($stmt); 83 | 84 | if (!$addUserExecute) { 85 | echo json_encode(["error" => "Failed to add the user to the database: " . mysqli_stmt_error($stmt)]); 86 | } else { 87 | header("Content-Type: application/json"); 88 | echo json_encode(["success" => true]); 89 | exit; 90 | } 91 | } -------------------------------------------------------------------------------- /mdash-root/build-caddy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | go=$(which go) 4 | 5 | export PATH="$PATH:$go" 6 | 7 | modules="" 8 | 9 | while [[ $# -gt 0 ]]; do 10 | module="$1" 11 | modules+=" --with $module" 12 | shift 13 | done 14 | 15 | cd /mdash/ 16 | 17 | xcaddy build $modules > build-caddy.log 2>&1 18 | exit_code=$? 19 | 20 | sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy >> build-caddy.log 2>&1 21 | sudo mv ./caddy /usr/bin/caddy.custom >> build-caddy.log 2>&1 22 | sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10 >> build-caddy.log 2>&1 23 | sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50 >> build-caddy.log 2>&1 24 | sudo systemctl restart caddy >> build-caddy.log 2>&1 25 | 26 | echo "mDash: Success!" >> build-caddy.log 2>&1 27 | 28 | exit $exit_code -------------------------------------------------------------------------------- /mdash-root/build-caddyfile.php: -------------------------------------------------------------------------------- 1 | "ok"]); -------------------------------------------------------------------------------- /mdash-root/config.json: -------------------------------------------------------------------------------- 1 | {"encryption":{"cipher":"aes-256-ctr","key":"nzBxtdjm28JvLZw1YMQcVDCIPSKUXpTe","options":0,"iv":2933823398667304},"dbData":{"dbHost":"127.0.0.1","dbUser":"mdash_php","dbPass":"a7GWngvVkSY84LsX6N5SE57GOgnSd6qcFRXzyc+vf0A=","dbDatabase":"mdash"}} -------------------------------------------------------------------------------- /mdash-root/mdash.version: -------------------------------------------------------------------------------- 1 | 1.1 -------------------------------------------------------------------------------- /mdash-root/reset-db.php: -------------------------------------------------------------------------------- 1 | '."); 36 | } 37 | 38 | blueResponse("Connecting to the mDash database."); 39 | 40 | $config = json_decode(file_get_contents("/mdash/config.json"), true); 41 | $dbHost = $dbInfo["dbHost"]; 42 | 43 | $dbConn = mysqli_connect($dbHost, "root", $_GET["db_pass"]); 44 | 45 | if (!$dbConn) { 46 | redResponse("Failed to connect to the mDash database."); 47 | } else { 48 | greenResponse("Connected to the mDash database successfully."); 49 | } 50 | 51 | blueResponse("Deleting the mDash database."); 52 | 53 | $deleteDbQuery = mysqli_query($dbConn, "DROP DATABASE mdash;"); 54 | 55 | if (!$deleteDbQuery) { 56 | redResponse("Failed to delete the mDash database. More info: " . mysqli_error($dbConn)); 57 | } else { 58 | greenResponse("Deleted the mDash database successfully."); 59 | } 60 | 61 | blueResponse("Deleting the mDash user."); 62 | 63 | $deleteUserQuery = mysqli_query($dbConn, "DROP USER 'mdash_php'@'127.0.0.1';"); 64 | 65 | if (!$deleteUserQuery) { 66 | redResponse("Failed to delete the mDash user. More info: " . mysqli_error($dbConn)); 67 | } else { 68 | greenResponse("Deleted the mDash user successfully."); 69 | } 70 | 71 | echo "\033[94mmDash Database Reset Script Complete\nThank you for using mDash. Farewell!\033[0m\n"; -------------------------------------------------------------------------------- /setup.php: -------------------------------------------------------------------------------- 1 | '."); 58 | } 59 | } 60 | } else { 61 | $dbPass = $_GET["db_pass"]; 62 | } 63 | 64 | function initQuestion() 65 | { 66 | echo "+==========================================+\n"; 67 | echo "| mDash Script |\n"; 68 | echo "| Please select what you would like to do: |\n"; 69 | echo "+==========================================+\n"; 70 | echo "| 1. Install |\n"; 71 | echo "| 2. Update |\n"; 72 | echo "+==========================================+\n"; 73 | $ask = readline("> "); 74 | if ($ask == 1) { 75 | system("clear"); 76 | 77 | echo "+============================================+\n"; 78 | echo "| mDash Install Script |\n"; 79 | echo "| Please enter your MySQL database password: |\n"; 80 | echo "+============================================+\n"; 81 | 82 | return false; 83 | } else if ($ask == 2) { 84 | system("clear"); 85 | 86 | echo "+============================================+\n"; 87 | echo "| mDash Update Script |\n"; 88 | echo "| Please enter your MySQL database password: |\n"; 89 | echo "+============================================+\n"; 90 | 91 | return true; 92 | } else { 93 | redResponse("Answer '$ask' is invalid."); 94 | initQuestion(); 95 | } 96 | } 97 | 98 | if (!$docker) { 99 | system("clear"); 100 | 101 | $update = initQuestion(); 102 | $dbPass = readline("> "); 103 | 104 | system("clear"); 105 | } else { 106 | $update = false; 107 | } 108 | 109 | // +============+ 110 | // | File Setup | 111 | // +============+ 112 | 113 | $pwd = str_replace("\n", "", shell_exec("pwd")); 114 | 115 | if ($update) { 116 | blueResponse("Moving mDash config file to root directory."); 117 | shell_exec("mv /mdash/config.json /mdash-config-copy.json"); 118 | greenResponse("Successfully moved mDash config file to root directory."); 119 | } 120 | 121 | blueResponse("Moving mDash root files to root directory."); 122 | if ($update) { 123 | shell_exec("rm -r /mdash/"); 124 | } 125 | shell_exec("mkdir /mdash/ && mv $pwd/mdash-root/* /mdash/"); 126 | greenResponse("Successfully moved mDash root files to root directory."); 127 | 128 | blueResponse("Moving mDash webpage files to /var/www/mdash/."); 129 | if ($update) { 130 | shell_exec("rm -r /var/www/mdash/"); 131 | } else { 132 | shell_exec("mkdir /var/www/"); 133 | } 134 | shell_exec("mkdir /var/www/mdash && mv $pwd/mdash-caddy/* /var/www/mdash/"); 135 | greenResponse("Successfully moved mDash webpage files to /var/www/mdash/."); 136 | 137 | blueResponse("Changing /mdash/ group to www-data."); 138 | shell_exec("chgrp -R www-data /mdash/"); 139 | greenResponse("Successfully changed group."); 140 | 141 | if (!$docker) { 142 | blueResponse("Changing /mdash/ group to www-data. (For modules)"); 143 | shell_exec("chgrp -R www-data /mdash/"); 144 | greenResponse("Successfully changed group."); 145 | 146 | blueResponse("Changing /mdash/ permission to 770. (For modules)"); 147 | shell_exec("chmod -R 770 /mdash/"); 148 | greenResponse("Successfully changed permissions."); 149 | 150 | blueResponse("Changing /var/www/ group to www-data. (For modules)"); 151 | shell_exec("chgrp -R www-data /var/www/"); 152 | greenResponse("Successfully changed group."); 153 | 154 | blueResponse("Changing /var/www/ permission to 770. (For modules)"); 155 | shell_exec("chmod -R 770 /var/www/"); 156 | greenResponse("Successfully changed permissions."); 157 | } 158 | 159 | // +===================================================+ 160 | // | Install and setup Caddy, xcaddy, go, and php-curl | 161 | // +===================================================+ 162 | 163 | if (!$docker) { 164 | blueResponse("Installing Caddy. This might take a minute to complete. (Please answer yes to the questions asked.)"); 165 | shell_exec("apt-get install debian-keyring debian-archive-keyring apt-transport-https curl -y"); 166 | shell_exec("curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg"); //caddy 167 | shell_exec("curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list"); //caddy 168 | shell_exec("curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg"); //xcaddy 169 | shell_exec("curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list"); //xcaddy 170 | shell_exec("apt-get update && apt-get install caddy xcaddy golang-go php-curl -y"); 171 | greenResponse("Successfully installed Caddy."); 172 | } 173 | 174 | if (!$update) { 175 | blueResponse("Seting up Caddy configuration."); 176 | if ($docker) { 177 | $caddyfile = ":8080 {\n" . 178 | " root * /var/www/mdash/\n" . 179 | " file_server\n" . 180 | " php_fastcgi 172.220.0.10:9000\n" . 181 | "}\n\n"; 182 | file_put_contents("/etc/caddy/Caddyfile", $caddyfile); 183 | } else { 184 | $caddyfile = ":8080 {\n" . 185 | " root * /var/www/mdash/\n" . 186 | " file_server\n" . 187 | " php_fastcgi unix//run/php/php-fpm.sock\n" . 188 | "}\n\n"; 189 | file_put_contents("/etc/caddy/Caddyfile", $caddyfile); 190 | } 191 | } 192 | 193 | shell_exec("cd /etc/caddy/ && caddy fmt --overwrite"); 194 | 195 | if (!$docker) { 196 | blueResponse("Giving PHP access to Caddyfile."); 197 | 198 | blueResponse("Changing Caddyfile owner to root and group to www-data."); 199 | shell_exec("chown root:www-data /etc/caddy/Caddyfile"); 200 | greenResponse("Successfully changed Caddyfile owner and group."); 201 | 202 | blueResponse("Changing Caddyfile access using chmod 660."); 203 | shell_exec("chmod 660 /etc/caddy/Caddyfile"); 204 | greenResponse("Successfully changed Caddyfile access."); 205 | 206 | shell_exec('systemctl reload caddy'); 207 | greenResponse("Set up Caddy configuration successfully."); 208 | 209 | $sudoPermissions = "www-data ALL=(ALL) NOPASSWD: /usr/bin/dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy, /usr/bin/mv ./caddy /usr/bin/caddy.custom, /usr/bin/update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10, /usr/bin/update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50, /usr/bin/systemctl restart caddy"; 210 | if (shell_exec("tail -n 1 /etc/sudoers") !== $sudoPermissions) { 211 | blueResponse("Updating sudoers file to give the caddy user moving permissions. (For modules)"); 212 | 213 | shell_exec("usermod -aG sudo www-data"); 214 | shell_exec("echo '$sudoPermissions' >> /etc/sudoers"); 215 | 216 | greenResponse("Successfully updated permissions."); 217 | } 218 | } 219 | 220 | // +================+ 221 | // | Setup database | 222 | // +================+ 223 | 224 | blueResponse("Connecting to database using the provided password."); 225 | $dbConn = mysqli_connect($dbHost, "root", $dbPass); 226 | if (!$dbConn) { 227 | redResponse("Failed to connect to database. Please make sure you have MySQL installed. More info: " . mysqli_connect_error()); 228 | } else { 229 | greenResponse("Connected to the database successfully."); 230 | } 231 | 232 | blueResponse("Creating the mDash database."); 233 | $createDb = mysqli_query($dbConn, "CREATE DATABASE IF NOT EXISTS `mdash`;"); 234 | if (!$createDb) { 235 | redResponse("Failed to create mDash database. More info: " . mysqli_error($dbConn)); 236 | } else { 237 | greenResponse("Created the mDash database successfully."); 238 | } 239 | 240 | blueResponse("Selecting the mDash database."); 241 | mysqli_select_db($dbConn, "mdash"); 242 | greenResponse("Selected the mDash database successfully."); 243 | 244 | blueResponse("Creating the user account table."); 245 | $createUserAccountTableQuery = mysqli_query($dbConn, "CREATE TABLE IF NOT EXISTS `mdash`.`accounts` ( `id` INT NOT NULL AUTO_INCREMENT , `nickname` VARCHAR(255) NOT NULL , `username` VARCHAR(255) NOT NULL , `password` VARCHAR(255) NOT NULL , `admin` VARCHAR(255) NOT NULL , PRIMARY KEY (`id`))"); 246 | if (!$createUserAccountTableQuery) { 247 | redResponse("Failed to create the user account table. More info: " . mysqli_error($dbConn)); 248 | } else { 249 | greenResponse("Created the user account table successfully."); 250 | } 251 | 252 | blueResponse("Creating the token table."); 253 | $createTokenTableQuery = mysqli_query($dbConn, "CREATE TABLE IF NOT EXISTS `mdash`.`tokens` ( `id` VARCHAR(255) NOT NULL , `account_id` VARCHAR(255) NOT NULL , `ip` VARCHAR(255) NOT NULL , `expires` VARCHAR(255) NOT NULL , PRIMARY KEY (`id`));"); 254 | if (!$createTokenTableQuery) { 255 | redResponse("Failed to create the token table. More info: " . mysqli_error($dbConn)); 256 | } else { 257 | greenResponse("Created the token table successfully."); 258 | } 259 | 260 | blueResponse("Creating the app table."); 261 | $createTokenTableQuery = mysqli_query($dbConn, "CREATE TABLE IF NOT EXISTS `mdash`.`apps` ( `id` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(255) NOT NULL , `int_url` VARCHAR(255) NOT NULL , `int_url_ssl` VARCHAR(255) NOT NULL , `ext_url` VARCHAR(255) NOT NULL , `icon` VARCHAR(255) NOT NULL , `sharing` VARCHAR(1000) NOT NULL , `owner` VARCHAR(1000) NOT NULL , PRIMARY KEY (`id`));"); 262 | if (!$createTokenTableQuery) { 263 | redResponse("Failed to create the app table. More info: " . mysqli_error($dbConn)); 264 | } else { 265 | greenResponse("Created the app table successfully."); 266 | } 267 | 268 | if (!$docker) { 269 | blueResponse("Creating the module table."); 270 | $createModuleTableQuery = mysqli_query($dbConn, "CREATE TABLE IF NOT EXISTS `mdash`.`modules` ( `id` INT NOT NULL AUTO_INCREMENT , `url` VARCHAR(10000) NOT NULL , PRIMARY KEY (`id`));"); 271 | if (!$createModuleTableQuery) { 272 | redResponse("Failed to create the module table. More info: " . mysqli_error($dbConn)); 273 | } else { 274 | greenResponse("Created the module table successfully."); 275 | } 276 | } 277 | 278 | if ($update) { 279 | if ($update) { 280 | blueResponse("Moving mDash config file to /mdash/ directory."); 281 | shell_exec("cp /mdash-config-copy.json /mdash/config.json"); 282 | greenResponse("Successfully moved mDash config file to /mdash/ directory."); 283 | } 284 | 285 | $ip = str_replace("\n", "", shell_exec("hostname -i")); 286 | echo "\033[94mmDash Update Script Complete\nEnjoy at: {$ip}:8080\033[0m\n"; 287 | exit; 288 | } 289 | 290 | blueResponse("Checking for an old mDash user."); 291 | $dbUser = "mdash_php"; 292 | $checkIfUserExistsQuery = mysqli_query($dbConn, "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '$dbUser');"); 293 | if (!$checkIfUserExistsQuery) { 294 | redResponse("Failed to check if an old mDash user existed. More info: " . mysqli_error($dbConn)); 295 | } else { 296 | if (mysqli_fetch_row($checkIfUserExistsQuery)[0] === "0") { 297 | greenResponse("No old mDash user found."); 298 | blueResponse("Creating the mDash user."); 299 | 300 | blueResponse("Generating the database password for mDash."); 301 | $dbGeneratedPass = substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil(32 / strlen($x)))), 1, 32); 302 | greenResponse("Generated the database password for mDash successfully."); 303 | 304 | $userIp = $docker ? "172.220.0.10" : "127.0.0.1"; 305 | 306 | $createUserQuery = mysqli_query($dbConn, "CREATE USER IF NOT EXISTS `mdash_php`@`$userIp` IDENTIFIED WITH caching_sha2_password BY '$dbGeneratedPass';"); 307 | 308 | if (!$createUserQuery) { 309 | redResponse("Failed to create mDash user. More info: " . mysqli_error($dbConn)); 310 | } else { 311 | greenResponse("Created the mDash user successfully."); 312 | 313 | blueResponse("Granting the mDash user the necessary privileges."); 314 | $grantUserQuery = mysqli_query($dbConn, "GRANT SELECT, INSERT, UPDATE, DELETE ON `mdash`.* TO `mdash_php`@`$userIp`;"); 315 | if (!$grantUserQuery) { 316 | redResponse("Failed to grant mDash user privileges. More info: " . mysqli_error($dbConn)); 317 | } else { 318 | greenResponse("Granted the mDash user the necessary privileges successfully."); 319 | } 320 | } 321 | } else { 322 | redResponse("An old mDash user was detected. The script has exited."); 323 | } 324 | 325 | mysqli_free_result($checkIfUserExistsQuery); 326 | } 327 | 328 | $configJson = []; 329 | 330 | blueResponse("Generating the cipher information."); 331 | $cipher = "aes-256-ctr"; 332 | $encryptionKey = substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil(32 / strlen($x)))), 1, 32); 333 | $options = 0; 334 | $iv = rand(1000000000000000, 9999999999999999); 335 | greenResponse("Generated the cipher information successfully."); 336 | 337 | blueResponse("Adding the cipher information to the config file."); 338 | $configJson["encryption"] = ["cipher" => $cipher, "key" => $encryptionKey, "options" => $options, "iv" => $iv]; 339 | greenResponse("Added the cipher information to the config file successfully."); 340 | 341 | blueResponse("Encrypting the mDash database password for the config file."); 342 | $encryptedDbPass = openssl_encrypt( 343 | $dbGeneratedPass, 344 | $cipher, 345 | $encryptionKey, 346 | $options, 347 | $iv 348 | ); 349 | if (!$encryptedDbPass) { 350 | redResponse("Failed to encrypt the mDash database password. More info: " . openssl_error_string()); 351 | } else { 352 | greenResponse("Encrypted the mDash database password for the config file successfully."); 353 | } 354 | 355 | blueResponse("Adding the encrypted mDash database password for the config file."); 356 | $configJson["dbData"] = ["dbHost" => $dbHost, "dbUser" => $dbUser, "dbPass" => $encryptedDbPass, "dbDatabase" => "mdash"]; 357 | greenResponse("Added the encrypted mDash database password for the config file successfully."); 358 | 359 | $config["docker"] = $docker; 360 | 361 | blueResponse("Generating the JSON for the config file."); 362 | $configJson = json_encode($configJson); 363 | greenResponse("Generated the JSON for the config file successfully."); 364 | 365 | blueResponse("Writing the JSON to the config file."); 366 | file_put_contents("/mdash/config.json", $configJson); 367 | greenResponse("Wrote the JSON to the config file successfully."); 368 | 369 | if ($docker) { 370 | echo "\033[94mmDash Setup Script Complete\033[0m\n"; 371 | exit(143); //Graceful termination (SIGTERM) 372 | } else { 373 | $ip = str_replace("\n", "", shell_exec("hostname -i")); 374 | echo "\033[94mmDash Setup Script Complete\nEnjoy at: {$ip}:8080\033[0m\n"; 375 | } 376 | -------------------------------------------------------------------------------- /terminal.md: -------------------------------------------------------------------------------- 1 | # Terminal Installation 2 | 3 | ## Step 1 - Install 4 | The following packages are required: 5 | 1. MySQL 6 | 2. Git 7 | 3. PHP-FPM 8 | 4. PHP-MySQL Plugin 9 | 10 | > [!NOTE] 11 | > You can use an existing MySQL installation on another server. 12 | 13 | ``` 14 | sudo apt update 15 | sudo apt install mysql-server git php-fpm php-mysql -y 16 | ``` 17 | 18 | ## Step 2 - Setup the Database 19 | > [!NOTE] 20 | > If you have an existing MySQL installation, you can skip these steps. 21 | 22 | ``` 23 | mysql 24 | ``` 25 | 26 | > [!IMPORTANT] 27 | > Dont forget to enter the new password you would like! 28 | 29 | ``` 30 | ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY ''; 31 | ``` 32 | 33 | ``` 34 | FLUSH PRIVILEGES; 35 | ``` 36 | 37 | ``` 38 | exit 39 | ``` 40 | 41 | ## Step 3 - Download mDash 42 | ``` 43 | git clone https://github.com/beans-are-gross/mdash 44 | cd mdash 45 | ``` 46 | 47 | ## Step 4 - Install mDash 48 | > [!NOTE] 49 | > If your MySQL database is not local, add "db_host=ip-address". 50 | ``` 51 | sudo php setup.php 52 | ``` 53 | --------------------------------------------------------------------------------