Browse Source

Create template based on SSO code

master
Skylar Ittner 2 years ago
commit
16cbf2a5f1

+ 4
- 0
.gitignore View File

@@ -0,0 +1,4 @@
1
+vendor
2
+settings.php
3
+nbproject/private
4
+database_model.mwb.bak

+ 62
- 0
action.php View File

@@ -0,0 +1,62 @@
1
+<?php
2
+
3
+/**
4
+ * Make things happen when buttons are pressed and forms submitted.
5
+ */
6
+use LdapTools\LdapManager;
7
+use LdapTools\Object\LdapObjectType;
8
+
9
+require_once __DIR__ . "/required.php";
10
+
11
+dieifnotloggedin();
12
+
13
+require_once __DIR__ . "/lib/login.php";
14
+require_once __DIR__ . "/lib/worst_passwords.php";
15
+
16
+function returnToSender($msg, $arg = "") {
17
+    global $VARS;
18
+    if ($arg == "") {
19
+        header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=" . $msg);
20
+    } else {
21
+        header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg&arg=$arg");
22
+    }
23
+    die();
24
+}
25
+
26
+switch ($VARS['action']) {
27
+    case "signout":
28
+        session_destroy();
29
+        header('Location: index.php');
30
+        die("Logged out.");
31
+    case "chpasswd":
32
+        if ($_SESSION['password'] == $VARS['oldpass']) {
33
+            if ($VARS['newpass'] == $VARS['conpass']) {
34
+                $passrank = checkWorst500List($VARS['newpass']);
35
+                if ($passrank !== FALSE) {
36
+                    returnToSender("password_500", $passrank);
37
+                }
38
+                if (strlen($VARS['newpass']) < MIN_PASSWORD_LENGTH) {
39
+                    returnToSender("weak_password");
40
+                }
41
+
42
+                $database->update('accounts', ['password' => encryptPassword($VARS['newpass'])], ['uid' => $_SESSION['uid']]);
43
+                $_SESSION['password'] = $VARS['newpass'];
44
+                returnToSender("password_updated");
45
+            } else {
46
+                returnToSender("new_password_mismatch");
47
+            }
48
+        } else {
49
+            returnToSender("old_password_mismatch");
50
+        }
51
+        break;
52
+    case "add2fa":
53
+        if (is_empty($VARS['secret'])) {
54
+            returnToSender("invalid_parameters");
55
+        }
56
+        $database->update('accounts', ['authsecret' => $VARS['secret']], ['uid' => $_SESSION['uid']]);
57
+        returnToSender("2fa_enabled");
58
+    case "rm2fa":
59
+        $database->update('accounts', ['authsecret' => ""], ['uid' => $_SESSION['uid']]);
60
+        returnToSender("2fa_removed");
61
+        break;
62
+}

+ 128
- 0
app.php View File

@@ -0,0 +1,128 @@
1
+<?php
2
+require_once __DIR__ . "/required.php";
3
+
4
+if ($_SESSION['loggedin'] != true) {
5
+    header('Location: index.php');
6
+    die("Session expired.  Log in again to continue.");
7
+}
8
+
9
+require_once __DIR__ . "/pages.php";
10
+
11
+$pageid = "home";
12
+if (!is_empty($_GET['page'])) {
13
+    $pg = strtolower($_GET['page']);
14
+    $pg = preg_replace('/[^0-9a-z_]/', "", $pg);
15
+    if (array_key_exists($pg, PAGES) && file_exists(__DIR__ . "/pages/" . $pg . ".php")) {
16
+        $pageid = $pg;
17
+    } else {
18
+        $pageid = "404";
19
+    }
20
+}
21
+?>
22
+<!DOCTYPE html>
23
+<html>
24
+    <head>
25
+        <meta charset="UTF-8">
26
+        <meta http-equiv="X-UA-Compatible" content="IE=edge">
27
+        <meta name="viewport" contgreent="width=device-width, initial-scale=1">
28
+
29
+        <title><?php echo SITE_TITLE; ?></title>
30
+
31
+        <link href="static/css/bootstrap.min.css" rel="stylesheet">
32
+        <link href="static/css/font-awesome.min.css" rel="stylesheet">
33
+        <link href="static/css/app.css" rel="stylesheet">
34
+    </head>
35
+    <body>
36
+        <div class="container">
37
+            <div class="row">
38
+                <div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4">
39
+                    <img class="img-responsive banner-image" src="static/img/banner.png" />
40
+                </div>
41
+            </div>
42
+            <nav class="navbar navbar-inverse">
43
+                <div class="container-fluid">
44
+                    <div class="navbar-header">
45
+                        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
46
+                            <span class="sr-only">Toggle navigation</span>
47
+                            <span class="icon-bar"></span>
48
+                            <span class="icon-bar"></span>
49
+                            <span class="icon-bar"></span>
50
+                        </button>
51
+                        <a class="navbar-brand" href="app.php?page=home">
52
+                            <?php
53
+                            // add breadcrumb-y thing
54
+                            //lang("home");
55
+                            //echo " <i class=\"fa fa-caret-right\"></i> ";
56
+                            lang(PAGES[$pageid]['title']);
57
+                            ?>
58
+                        </a>
59
+                    </div>
60
+
61
+                    <div class="collapse navbar-collapse" id="navbar-collapse">
62
+                        <ul class="nav navbar-nav">
63
+                        </ul>
64
+                        <ul class="nav navbar-nav navbar-right">
65
+                            <li class="dropdown">
66
+                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-gears fa-fw"></i> <?php lang("options") ?> <span class="caret"></span></a>
67
+                                <ul class="dropdown-menu" role="menu">
68
+                                    <li><a href="app.php?page=security"><i class="fa fa-lock fa-fw"></i> <?php lang("account security") ?></a></li>
69
+                                    <li class="divider"></li>
70
+                                    <li><a href="action.php?action=signout"><i class="fa fa-sign-out fa-fw"></i> <?php lang("sign out") ?></a></li>
71
+                                </ul>
72
+                            </li>
73
+                        </ul>
74
+                    </div>
75
+                </div>
76
+            </nav>
77
+            <?php
78
+            // Alert messages
79
+            if (!is_empty($_GET['msg']) && array_key_exists($_GET['msg'], MESSAGES)) {
80
+                // optional string generation argument
81
+                if (is_empty($_GET['arg'])) {
82
+                    $alertmsg = lang(MESSAGES[$_GET['msg']]['string'], false);
83
+                } else {
84
+                    $alertmsg = lang2(MESSAGES[$_GET['msg']]['string'], ["arg" => $_GET['arg']], false);
85
+                }
86
+                $alerttype = MESSAGES[$_GET['msg']]['type'];
87
+                $alerticon = "square-o";
88
+                switch (MESSAGES[$_GET['msg']]['type']) {
89
+                    case "danger":
90
+                        $alerticon = "times";
91
+                        break;
92
+                    case "warning":
93
+                        $alerticon = "exclamation-triangle";
94
+                        break;
95
+                    case "info":
96
+                        $alerticon = "info-circle";
97
+                        break;
98
+                    case "success":
99
+                        $alerticon = "check";
100
+                        break;
101
+                }
102
+                echo <<<END
103
+            <div class="row">
104
+                <div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4">
105
+                    <div class="alert alert-dismissible alert-$alerttype">
106
+                        <button type="button" class="close">&times;</button>
107
+                        <i class="fa fa-$alerticon"></i> $alertmsg
108
+                    </div>
109
+                </div>
110
+            </div>
111
+END;
112
+            }
113
+            ?>
114
+            <div>
115
+                <?php
116
+                include_once __DIR__ . '/pages/' . $pageid . ".php";
117
+                ?>
118
+            </div>
119
+            <div class="footer">
120
+                <?php echo LICENSE_TEXT; ?><br />
121
+                Copyright &copy; <?php echo date('Y'); ?> <?php echo COPYRIGHT_NAME; ?>
122
+            </div>
123
+        </div>
124
+        <script src="static/js/jquery-3.2.1.min.js"></script>
125
+        <script src="static/js/bootstrap.min.js"></script>
126
+        <script src="static/js/app.js"></script>
127
+    </body>
128
+</html>

+ 16
- 0
composer.json View File

@@ -0,0 +1,16 @@
1
+{
2
+    "name": "netsyms/web-app-template",
3
+    "description": "Simple framework for rapid webapp development",
4
+    "type": "project",
5
+    "require": {
6
+        "catfan/medoo": "^1.2",
7
+        "spomky-labs/otphp": "^8.3"
8
+    },
9
+    "license": "MIT",
10
+    "authors": [
11
+        {
12
+            "name": "Skylar Ittner",
13
+            "email": "admin@netsyms.com"
14
+        }
15
+    ]
16
+}

+ 461
- 0
composer.lock View File

@@ -0,0 +1,461 @@
1
+{
2
+    "_readme": [
3
+        "This file locks the dependencies of your project to a known state",
4
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
+        "This file is @generated automatically"
6
+    ],
7
+    "content-hash": "51c1672b4dea32e60865b4c0cd9ff8e1",
8
+    "packages": [
9
+        {
10
+            "name": "beberlei/assert",
11
+            "version": "v2.7.4",
12
+            "source": {
13
+                "type": "git",
14
+                "url": "https://github.com/beberlei/assert.git",
15
+                "reference": "3ee3bc468a3ce4bbfc3d74f53c6cdb5242d39d1a"
16
+            },
17
+            "dist": {
18
+                "type": "zip",
19
+                "url": "https://api.github.com/repos/beberlei/assert/zipball/3ee3bc468a3ce4bbfc3d74f53c6cdb5242d39d1a",
20
+                "reference": "3ee3bc468a3ce4bbfc3d74f53c6cdb5242d39d1a",
21
+                "shasum": ""
22
+            },
23
+            "require": {
24
+                "ext-mbstring": "*",
25
+                "php": ">=5.3"
26
+            },
27
+            "require-dev": {
28
+                "friendsofphp/php-cs-fixer": "^2.1.1",
29
+                "phpunit/phpunit": "^4|^5"
30
+            },
31
+            "type": "library",
32
+            "autoload": {
33
+                "psr-4": {
34
+                    "Assert\\": "lib/Assert"
35
+                },
36
+                "files": [
37
+                    "lib/Assert/functions.php"
38
+                ]
39
+            },
40
+            "notification-url": "https://packagist.org/downloads/",
41
+            "license": [
42
+                "BSD-2-Clause"
43
+            ],
44
+            "authors": [
45
+                {
46
+                    "name": "Benjamin Eberlei",
47
+                    "email": "kontakt@beberlei.de",
48
+                    "role": "Lead Developer"
49
+                },
50
+                {
51
+                    "name": "Richard Quadling",
52
+                    "email": "rquadling@gmail.com",
53
+                    "role": "Collaborator"
54
+                }
55
+            ],
56
+            "description": "Thin assertion library for input validation in business models.",
57
+            "keywords": [
58
+                "assert",
59
+                "assertion",
60
+                "validation"
61
+            ],
62
+            "time": "2017-03-14T18:06:52+00:00"
63
+        },
64
+        {
65
+            "name": "catfan/medoo",
66
+            "version": "v1.2.1",
67
+            "source": {
68
+                "type": "git",
69
+                "url": "https://github.com/catfan/Medoo.git",
70
+                "reference": "b5a788c90c44db0f978512c890cb6962af4685e8"
71
+            },
72
+            "dist": {
73
+                "type": "zip",
74
+                "url": "https://api.github.com/repos/catfan/Medoo/zipball/b5a788c90c44db0f978512c890cb6962af4685e8",
75
+                "reference": "b5a788c90c44db0f978512c890cb6962af4685e8",
76
+                "shasum": ""
77
+            },
78
+            "require": {
79
+                "ext-pdo": "*",
80
+                "php": ">=5.4"
81
+            },
82
+            "suggest": {
83
+                "ext-pdo_dblib": "For MSSQL or Sybase databases on Linux/UNIX platform",
84
+                "ext-pdo_mysql": "For MySQL or MariaDB databases",
85
+                "ext-pdo_oci": "For Oracle databases",
86
+                "ext-pdo_pqsql": "For PostgreSQL databases",
87
+                "ext-pdo_sqlite": "For SQLite databases",
88
+                "ext-pdo_sqlsrv": "For MSSQL databases on Windows platform"
89
+            },
90
+            "type": "framework",
91
+            "autoload": {
92
+                "psr-4": {
93
+                    "Medoo\\": "/src"
94
+                }
95
+            },
96
+            "notification-url": "https://packagist.org/downloads/",
97
+            "license": [
98
+                "MIT"
99
+            ],
100
+            "authors": [
101
+                {
102
+                    "name": "Angel Lai",
103
+                    "email": "angel@catfan.me"
104
+                }
105
+            ],
106
+            "description": "The Lightest PHP database framework to accelerate development",
107
+            "homepage": "http://medoo.in",
108
+            "keywords": [
109
+                "database",
110
+                "lightweight",
111
+                "mssql",
112
+                "mysql",
113
+                "php framework",
114
+                "sql",
115
+                "sqlite"
116
+            ],
117
+            "time": "2017-02-17T16:05:35+00:00"
118
+        },
119
+        {
120
+            "name": "christian-riesen/base32",
121
+            "version": "1.3.1",
122
+            "source": {
123
+                "type": "git",
124
+                "url": "https://github.com/ChristianRiesen/base32.git",
125
+                "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa"
126
+            },
127
+            "dist": {
128
+                "type": "zip",
129
+                "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa",
130
+                "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa",
131
+                "shasum": ""
132
+            },
133
+            "require": {
134
+                "php": ">=5.3.0"
135
+            },
136
+            "require-dev": {
137
+                "phpunit/phpunit": "4.*",
138
+                "satooshi/php-coveralls": "0.*"
139
+            },
140
+            "type": "library",
141
+            "extra": {
142
+                "branch-alias": {
143
+                    "dev-master": "1.1.x-dev"
144
+                }
145
+            },
146
+            "autoload": {
147
+                "psr-4": {
148
+                    "Base32\\": "src/"
149
+                }
150
+            },
151
+            "notification-url": "https://packagist.org/downloads/",
152
+            "license": [
153
+                "MIT"
154
+            ],
155
+            "authors": [
156
+                {
157
+                    "name": "Christian Riesen",
158
+                    "email": "chris.riesen@gmail.com",
159
+                    "homepage": "http://christianriesen.com",
160
+                    "role": "Developer"
161
+                }
162
+            ],
163
+            "description": "Base32 encoder/decoder according to RFC 4648",
164
+            "homepage": "https://github.com/ChristianRiesen/base32",
165
+            "keywords": [
166
+                "base32",
167
+                "decode",
168
+                "encode",
169
+                "rfc4648"
170
+            ],
171
+            "time": "2016-05-05T11:49:03+00:00"
172
+        },
173
+        {
174
+            "name": "paragonie/random_compat",
175
+            "version": "v2.0.10",
176
+            "source": {
177
+                "type": "git",
178
+                "url": "https://github.com/paragonie/random_compat.git",
179
+                "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
180
+            },
181
+            "dist": {
182
+                "type": "zip",
183
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
184
+                "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
185
+                "shasum": ""
186
+            },
187
+            "require": {
188
+                "php": ">=5.2.0"
189
+            },
190
+            "require-dev": {
191
+                "phpunit/phpunit": "4.*|5.*"
192
+            },
193
+            "suggest": {
194
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
195
+            },
196
+            "type": "library",
197
+            "autoload": {
198
+                "files": [
199
+                    "lib/random.php"
200
+                ]
201
+            },
202
+            "notification-url": "https://packagist.org/downloads/",
203
+            "license": [
204
+                "MIT"
205
+            ],
206
+            "authors": [
207
+                {
208
+                    "name": "Paragon Initiative Enterprises",
209
+                    "email": "security@paragonie.com",
210
+                    "homepage": "https://paragonie.com"
211
+                }
212
+            ],
213
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
214
+            "keywords": [
215
+                "csprng",
216
+                "pseudorandom",
217
+                "random"
218
+            ],
219
+            "time": "2017-03-13T16:27:32+00:00"
220
+        },
221
+        {
222
+            "name": "spomky-labs/otphp",
223
+            "version": "v8.3.0",
224
+            "source": {
225
+                "type": "git",
226
+                "url": "https://github.com/Spomky-Labs/otphp.git",
227
+                "reference": "8c90e16ba48fe7c306832611e22c5bad2d663a98"
228
+            },
229
+            "dist": {
230
+                "type": "zip",
231
+                "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/8c90e16ba48fe7c306832611e22c5bad2d663a98",
232
+                "reference": "8c90e16ba48fe7c306832611e22c5bad2d663a98",
233
+                "shasum": ""
234
+            },
235
+            "require": {
236
+                "beberlei/assert": "^2.4",
237
+                "christian-riesen/base32": "^1.1",
238
+                "paragonie/random_compat": "^2.0",
239
+                "php": "^5.5|^7.0",
240
+                "symfony/polyfill-mbstring": "^1.1",
241
+                "symfony/polyfill-php56": "^1.1"
242
+            },
243
+            "require-dev": {
244
+                "phpunit/phpunit": "~4.0|^5.0",
245
+                "satooshi/php-coveralls": "^1.0"
246
+            },
247
+            "type": "library",
248
+            "extra": {
249
+                "branch-alias": {
250
+                    "dev-master": "8.2.x-dev"
251
+                }
252
+            },
253
+            "autoload": {
254
+                "psr-4": {
255
+                    "OTPHP\\": "src/"
256
+                }
257
+            },
258
+            "notification-url": "https://packagist.org/downloads/",
259
+            "license": [
260
+                "MIT"
261
+            ],
262
+            "authors": [
263
+                {
264
+                    "name": "Florent Morselli",
265
+                    "homepage": "https://github.com/Spomky"
266
+                },
267
+                {
268
+                    "name": "All contributors",
269
+                    "homepage": "https://github.com/Spomky-Labs/otphp/contributors"
270
+                }
271
+            ],
272
+            "description": "A PHP library for generating one time passwords according to RFC 4226 (HOTP Algorithm) and the RFC 6238 (TOTP Algorithm) and compatible with Google Authenticator",
273
+            "homepage": "https://github.com/Spomky-Labs/otphp",
274
+            "keywords": [
275
+                "FreeOTP",
276
+                "RFC 4226",
277
+                "RFC 6238",
278
+                "google authenticator",
279
+                "hotp",
280
+                "otp",
281
+                "totp"
282
+            ],
283
+            "time": "2016-12-08T10:46:02+00:00"
284
+        },
285
+        {
286
+            "name": "symfony/polyfill-mbstring",
287
+            "version": "v1.3.0",
288
+            "source": {
289
+                "type": "git",
290
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
291
+                "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
292
+            },
293
+            "dist": {
294
+                "type": "zip",
295
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
296
+                "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
297
+                "shasum": ""
298
+            },
299
+            "require": {
300
+                "php": ">=5.3.3"
301
+            },
302
+            "suggest": {
303
+                "ext-mbstring": "For best performance"
304
+            },
305
+            "type": "library",
306
+            "extra": {
307
+                "branch-alias": {
308
+                    "dev-master": "1.3-dev"
309
+                }
310
+            },
311
+            "autoload": {
312
+                "psr-4": {
313
+                    "Symfony\\Polyfill\\Mbstring\\": ""
314
+                },
315
+                "files": [
316
+                    "bootstrap.php"
317
+                ]
318
+            },
319
+            "notification-url": "https://packagist.org/downloads/",
320
+            "license": [
321
+                "MIT"
322
+            ],
323
+            "authors": [
324
+                {
325
+                    "name": "Nicolas Grekas",
326
+                    "email": "p@tchwork.com"
327
+                },
328
+                {
329
+                    "name": "Symfony Community",
330
+                    "homepage": "https://symfony.com/contributors"
331
+                }
332
+            ],
333
+            "description": "Symfony polyfill for the Mbstring extension",
334
+            "homepage": "https://symfony.com",
335
+            "keywords": [
336
+                "compatibility",
337
+                "mbstring",
338
+                "polyfill",
339
+                "portable",
340
+                "shim"
341
+            ],
342
+            "time": "2016-11-14T01:06:16+00:00"
343
+        },
344
+        {
345
+            "name": "symfony/polyfill-php56",
346
+            "version": "v1.3.0",
347
+            "source": {
348
+                "type": "git",
349
+                "url": "https://github.com/symfony/polyfill-php56.git",
350
+                "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c"
351
+            },
352
+            "dist": {
353
+                "type": "zip",
354
+                "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/1dd42b9b89556f18092f3d1ada22cb05ac85383c",
355
+                "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c",
356
+                "shasum": ""
357
+            },
358
+            "require": {
359
+                "php": ">=5.3.3",
360
+                "symfony/polyfill-util": "~1.0"
361
+            },
362
+            "type": "library",
363
+            "extra": {
364
+                "branch-alias": {
365
+                    "dev-master": "1.3-dev"
366
+                }
367
+            },
368
+            "autoload": {
369
+                "psr-4": {
370
+                    "Symfony\\Polyfill\\Php56\\": ""
371
+                },
372
+                "files": [
373
+                    "bootstrap.php"
374
+                ]
375
+            },
376
+            "notification-url": "https://packagist.org/downloads/",
377
+            "license": [
378
+                "MIT"
379
+            ],
380
+            "authors": [
381
+                {
382
+                    "name": "Nicolas Grekas",
383
+                    "email": "p@tchwork.com"
384
+                },
385
+                {
386
+                    "name": "Symfony Community",
387
+                    "homepage": "https://symfony.com/contributors"
388
+                }
389
+            ],
390
+            "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
391
+            "homepage": "https://symfony.com",
392
+            "keywords": [
393
+                "compatibility",
394
+                "polyfill",
395
+                "portable",
396
+                "shim"
397
+            ],
398
+            "time": "2016-11-14T01:06:16+00:00"
399
+        },
400
+        {
401
+            "name": "symfony/polyfill-util",
402
+            "version": "v1.3.0",
403
+            "source": {
404
+                "type": "git",
405
+                "url": "https://github.com/symfony/polyfill-util.git",
406
+                "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb"
407
+            },
408
+            "dist": {
409
+                "type": "zip",
410
+                "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/746bce0fca664ac0a575e465f65c6643faddf7fb",
411
+                "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb",
412
+                "shasum": ""
413
+            },
414
+            "require": {
415
+                "php": ">=5.3.3"
416
+            },
417
+            "type": "library",
418
+            "extra": {
419
+                "branch-alias": {
420
+                    "dev-master": "1.3-dev"
421
+                }
422
+            },
423
+            "autoload": {
424
+                "psr-4": {
425
+                    "Symfony\\Polyfill\\Util\\": ""
426
+                }
427
+            },
428
+            "notification-url": "https://packagist.org/downloads/",
429
+            "license": [
430
+                "MIT"
431
+            ],
432
+            "authors": [
433
+                {
434
+                    "name": "Nicolas Grekas",
435
+                    "email": "p@tchwork.com"
436
+                },
437
+                {
438
+                    "name": "Symfony Community",
439
+                    "homepage": "https://symfony.com/contributors"
440
+                }
441
+            ],
442
+            "description": "Symfony utilities for portability of PHP codes",
443
+            "homepage": "https://symfony.com",
444
+            "keywords": [
445
+                "compat",
446
+                "compatibility",
447
+                "polyfill",
448
+                "shim"
449
+            ],
450
+            "time": "2016-11-14T01:06:16+00:00"
451
+        }
452
+    ],
453
+    "packages-dev": [],
454
+    "aliases": [],
455
+    "minimum-stability": "stable",
456
+    "stability-flags": [],
457
+    "prefer-stable": false,
458
+    "prefer-lowest": false,
459
+    "platform": [],
460
+    "platform-dev": []
461
+}

BIN
database_model.mwb View File


+ 117
- 0
index.php View File

@@ -0,0 +1,117 @@
1
+<?php
2
+require_once __DIR__ . "/required.php";
3
+
4
+require_once __DIR__ . "/lib/login.php";
5
+
6
+/* Authenticate user */
7
+$userpass_ok = false;
8
+$multiauth = false;
9
+if ($VARS['progress'] == "1") {
10
+    if (authenticate_user($VARS['username'], $VARS['password'])) {
11
+        switch (get_account_status($VARS['username'])) {
12
+            case "LOCKED_OR_DISABLED":
13
+                $alert = lang("account locked", false);
14
+                break;
15
+            case "TERMINATED":
16
+                $alert = lang("account terminated", false);
17
+                break;
18
+            case "CHANGE_PASSWORD":
19
+                $alert = lang("password expired", false);
20
+            case "NORMAL":
21
+                $userpass_ok = true;
22
+                break;
23
+            case "ALERT_ON_ACCESS":
24
+                sendLoginAlertEmail($VARS['username']);
25
+                $userpass_ok = true;
26
+                break;
27
+        }
28
+        if ($userpass_ok) {
29
+            if (userHasTOTP($VARS['username'])) {
30
+                $multiauth = true;
31
+            } else {
32
+                doLoginUser($VARS['username'], $VARS['password']);
33
+                header('Location: app.php');
34
+                die("Logged in, go to app.php");
35
+            }
36
+        }
37
+    } else {
38
+        $alert = lang("login incorrect", false);
39
+    }
40
+} else if ($VARS['progress'] == "2") {
41
+    if (verifyTOTP($VARS['username'], $VARS['authcode'])) {
42
+        doLoginUser($VARS['username'], $VARS['password']);
43
+        header('Location: app.php');
44
+        die("Logged in, go to app.php");
45
+    } else {
46
+        $alert = lang("2fa incorrect", false);
47
+    }
48
+}
49
+?>
50
+<!DOCTYPE html>
51
+<html>
52
+    <head>
53
+        <meta charset="UTF-8">
54
+        <meta http-equiv="X-UA-Compatible" content="IE=edge">
55
+        <meta name="viewport" contgreent="width=device-width, initial-scale=1">
56
+
57
+        <title><?php echo SITE_TITLE; ?></title>
58
+
59
+        <link href="static/css/bootstrap.min.css" rel="stylesheet">
60
+        <link href="static/css/app.css" rel="stylesheet">
61
+    </head>
62
+    <body>
63
+        <div class="container">
64
+            <div class="row">
65
+                <div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4">
66
+                    <div>
67
+                        <img class="img-responsive banner-image" src="static/img/banner.png" />
68
+                    </div>
69
+                    <div class="panel panel-primary">
70
+                        <div class="panel-heading">
71
+                            <h3 class="panel-title"><?php lang("sign in"); ?></h3>
72
+                        </div>
73
+                        <div class="panel-body">
74
+                            <form action="" method="POST">
75
+                                <?php
76
+                                if (!is_empty($alert)) {
77
+                                    ?>
78
+                                    <div class="alert alert-danger">
79
+                                        <?php echo $alert; ?>
80
+                                    </div>
81
+                                    <?php
82
+                                }
83
+
84
+                                if ($multiauth != true) {
85
+                                    ?>
86
+                                    <input type="text" class="form-control" name="username" placeholder="<?php lang("username"); ?>" required="required" autofocus /><br />
87
+                                    <input type="password" class="form-control" name="password" placeholder="<?php lang("password"); ?>" required="required" /><br />
88
+                                    <input type="hidden" name="progress" value="1" />
89
+                                    <?php
90
+                                } else if ($multiauth) {
91
+                                    ?>
92
+                                    <div class="alert alert-info">
93
+                                        <?php lang("2fa prompt"); ?>
94
+                                    </div>
95
+                                    <input type="text" class="form-control" name="authcode" placeholder="<?php lang("authcode"); ?>" required="required" autofocus /><br />
96
+                                    <input type="hidden" name="progress" value="2" />
97
+                                    <input type="hidden" name="username" value="<?php echo $VARS['username']; ?>" />
98
+                                    <?php
99
+                                }
100
+                                ?>
101
+                                <button type="submit" class="btn btn-primary">
102
+                                    <?php lang("continue"); ?>
103
+                                </button>
104
+                            </form>
105
+                        </div>
106
+                    </div>
107
+                </div>
108
+            </div>
109
+            <div class="footer">
110
+                <?php echo LICENSE_TEXT; ?><br />
111
+                Copyright &copy; <?php echo date('Y'); ?> <?php echo COPYRIGHT_NAME; ?>
112
+            </div>
113
+        </div>
114
+        <script src="static/js/jquery-3.2.1.min.js"></script>
115
+        <script src="static/js/bootstrap.min.js"></script>
116
+    </body>
117
+</html>

+ 42
- 0
lang/en_us.php View File

@@ -0,0 +1,42 @@
1
+<?php
2
+
3
+define("STRINGS", [
4
+    "sign in" => "Sign In",
5
+    "username" => "Username",
6
+    "password" => "Password",
7
+    "continue" => "Continue",
8
+    "authcode" => "Authentication code",
9
+    "2fa prompt" => "Enter the six-digit code from your mobile authenticator app.",
10
+    "2fa incorrect" => "Authentication code incorrect.",
11
+    "login incorrect" => "Login incorrect.",
12
+    "account locked" => "This account has been disabled. Contact technical support.",
13
+    "password expired" => "You must change your password before continuing.",
14
+    "account terminated" => "Account terminated.  Access denied.",
15
+    "account state error" => "Your account state is not stable.  Log out, restart your browser, and try again.",
16
+    "password on 500 list" => "The given password is ranked number {arg} out of the 500 most common passwords.  Try a different one.",
17
+    "welcome user" => "Welcome, {user}!",
18
+    "change password" => "Change password",
19
+    "security options" => "Security options",
20
+    "account security" => "Account security",
21
+    "sign out" => "Sign out",
22
+    "settings" => "Settings",
23
+    "options" => "Options",
24
+    "404 error" => "404 Error",
25
+    "page not found" => "Page not found.",
26
+    "current password incorrect" => "The current password is incorrect.  Try again.",
27
+    "new password mismatch" => "The new passwords did not match.  Try again.",
28
+    "weak password" => "Password does not meet requirements.",
29
+    "password updated" => "Password updated successfully.",
30
+    "setup 2fa" => "Setup 2-factor authentication",
31
+    "2fa removed" => "2-factor authentication disabled.",
32
+    "2fa enabled" => "2-factor authentication activated.",
33
+    "remove 2fa" => "Disable 2-factor authentication",
34
+    "2fa explained" => "2-factor authentication adds more security to your account. You'll need an app such as Google Authenticator on your smartphone. When you have the app installed, you can enable 2-factor authentication by clicking the button below and scanning a QR code with the app. Whenever you sign in in the future, you'll need to input a six-digit code from your phone into the login page when prompted. You can disable 2-factor authentication from this page if you change your mind.",
35
+    "2fa active" => "2-factor authentication is active on your account.  To remove 2fa, reset your authentication secret, or change to a new security device, click the button below.",
36
+    "enable 2fa" => "Enable 2-factor authentication",
37
+    "scan 2fa qrcode" => "Scan the QR Code with the authenticator app, or enter the secret key manually.",
38
+    "confirm 2fa" => "Finish setup",
39
+    "invalid parameters" => "Invalid request parameters.",
40
+    "ldap server error" => "The LDAP server returned an error: {arg}",
41
+    "home" => "Home",
42
+]);

+ 44
- 0
lang/messages.php View File

@@ -0,0 +1,44 @@
1
+<?php
2
+
3
+define("MESSAGES", [
4
+    "old_password_mismatch" => [
5
+        "string" => "current password incorrect",
6
+        "type" => "danger"
7
+    ],
8
+    "new_password_mismatch" => [
9
+        "string" => "new password mismatch",
10
+        "type" => "danger"
11
+    ],
12
+    "weak_password" => [
13
+        "string" => "weak password",
14
+        "type" => "danger"
15
+    ],
16
+    "password_updated" => [
17
+        "string" => "password updated",
18
+        "type" => "success"
19
+    ],
20
+    "2fa_removed" => [
21
+        "string" => "2fa removed",
22
+        "type" => "success"
23
+    ],
24
+    "2fa_enabled" => [
25
+        "string" => "2fa enabled",
26
+        "type" => "success"
27
+    ],
28
+    "invalid_parameters" => [
29
+        "string" => "invalid parameters",
30
+        "type" => "danger"
31
+    ],
32
+    "password_500" => [
33
+        "string" => "password on 500 list",
34
+        "type" => "danger"
35
+    ],
36
+    "account_state_error" => [
37
+        "string" => "account state error",
38
+        "type" => "danger"
39
+    ],
40
+    "404_error" => [
41
+        "string" => "page not found",
42
+        "type" => "info"
43
+    ]
44
+]);

+ 302
- 0
lib/login.php View File

@@ -0,0 +1,302 @@
1
+<?php
2
+
3
+/**
4
+ * Authentication and account functions
5
+ */
6
+use Base32\Base32;
7
+use OTPHP\TOTP;
8
+use LdapTools\LdapManager;
9
+use LdapTools\Connection\ADResponseCodes;
10
+
11
+////////////////////////////////////////////////////////////////////////////////
12
+//                           Account handling                                 //
13
+////////////////////////////////////////////////////////////////////////////////
14
+
15
+/**
16
+ * Add a user to the system.  /!\ Assumes input is OK /!\
17
+ * @param string $username Username, saved in lowercase.
18
+ * @param string $password Password, will be hashed before saving.
19
+ * @param string $realname User's real legal name
20
+ * @param string $email User's email address.
21
+ * @return int The new user's ID number in the database.
22
+ */
23
+function adduser($username, $password, $realname, $email = null, $phone1 = "", $phone2 = "") {
24
+    global $database;
25
+    $database->debug()->insert('accounts', [
26
+        'username' => strtolower($username),
27
+        'password' => (is_null($password) ? null : encryptPassword($password)),
28
+        'realname' => $realname,
29
+        'email' => $email,
30
+        'phone1' => $phone1,
31
+        'phone2' => $phone2,
32
+        'acctstatus' => 1
33
+    ]);
34
+
35
+    return $database->id();
36
+}
37
+
38
+/**
39
+ * Get where a user's account actually is.
40
+ * @param string $username
41
+ * @return string "LDAP", "LOCAL", "LDAP_ONLY", or "NONE".
42
+ */
43
+function account_location($username, $password) {
44
+    global $database;
45
+    $user_exists = user_exists($username);
46
+    if (!$user_exists && !LDAP_ENABLED) {
47
+        return false;
48
+    }
49
+    if ($user_exists) {
50
+        $userinfo = $database->select('accounts', ['password'], ['username' => $username])[0];
51
+        // if password empty, it's an LDAP user
52
+        if (is_empty($userinfo['password']) && LDAP_ENABLED) {
53
+            return "LDAP";
54
+        } else if (is_empty($userinfo['password']) && !LDAP_ENABLED) {
55
+            return "NONE";
56
+        } else {
57
+            return "LOCAL";
58
+        }
59
+    } else {
60
+        if (user_exists_ldap($username, $password)) {
61
+            return "LDAP_ONLY";
62
+        } else {
63
+            return "NONE";
64
+        }
65
+    }
66
+}
67
+
68
+/**
69
+ * Checks the given credentials against the database.
70
+ * @param string $username
71
+ * @param string $password
72
+ * @return boolean True if OK, else false
73
+ */
74
+function authenticate_user($username, $password) {
75
+    global $database;
76
+    global $ldap_config;
77
+    if (is_empty($username) || is_empty($password)) {
78
+        return false;
79
+    }
80
+    $loc = account_location($username, $password);
81
+    if ($loc == "NONE") {
82
+        return false;
83
+    } else if ($loc == "LOCAL") {
84
+        $hash = $database->select('accounts', ['password'], ['username' => $username, "LIMIT" => 1])[0]['password'];
85
+        return (comparePassword($password, $hash));
86
+    } else if ($loc == "LDAP") {
87
+        return authenticate_user_ldap($username, $password);
88
+    } else if ($loc == "LDAP_ONLY") {
89
+        if (authenticate_user_ldap($username, $password) === TRUE) {
90
+            try {
91
+                $user = (new LdapManager($ldap_config))->getRepository('user')->findOneByUsername($username);
92
+                var_dump($user);
93
+                adduser($user->getUsername(), null, $user->getName(), ($user->hasEmailAddress() ? $user->getEmailAddress() : null));
94
+                return true;
95
+            } catch (Exception $e) {
96
+                sendError("LDAP error: " . $e->getMessage());
97
+            }
98
+        } else {
99
+            return false;
100
+        }
101
+    } else {
102
+        return false;
103
+    }
104
+}
105
+
106
+/**
107
+ * Check if a username exists in the local database.
108
+ * @param String $username
109
+ */
110
+function user_exists($username) {
111
+    global $database;
112
+    return $database->has('accounts', ['username' => $username, "LIMIT" => QUERY_LIMIT]);
113
+}
114
+
115
+/**
116
+ * Get the account status: NORMAL, TERMINATED, LOCKED_OR_DISABLED,
117
+ * CHANGE_PASSWORD, or ALERT_ON_ACCESS
118
+ * @global $database $database
119
+ * @param string $username
120
+ * @return string
121
+ */
122
+function get_account_status($username) {
123
+    global $database;
124
+    $loc = account_location($username);
125
+    if ($loc == "LOCAL") {
126
+        $statuscode = $database->select('accounts', [
127
+                    '[>]acctstatus' => [
128
+                        'acctstatus' => 'statusid'
129
+                    ]
130
+                        ], [
131
+                    'accounts.acctstatus',
132
+                    'acctstatus.statuscode'
133
+                        ], [
134
+                    'username' => $username,
135
+                    "LIMIT" => 1
136
+                        ]
137
+                )[0]['statuscode'];
138
+        return $statuscode;
139
+    } else if ($loc == "LDAP") {
140
+        // TODO: Read actual account status from AD servers
141
+        return "NORMAL";
142
+    } else {
143
+        // account isn't setup properly
144
+        return "LOCKED_OR_DISABLED";
145
+    }
146
+}
147
+
148
+////////////////////////////////////////////////////////////////////////////////
149
+//                              Login handling                                //
150
+////////////////////////////////////////////////////////////////////////////////
151
+
152
+/**
153
+ * Setup $_SESSION values to log in a user
154
+ * @param string $username
155
+ */
156
+function doLoginUser($username, $password) {
157
+    global $database;
158
+    $userinfo = $database->select('accounts', ['email', 'uid', 'realname'], ['username' => $username])[0];
159
+    $_SESSION['username'] = $username;
160
+    $_SESSION['uid'] = $userinfo['uid'];
161
+    $_SESSION['email'] = $userinfo['email'];
162
+    $_SESSION['realname'] = $userinfo['realname'];
163
+    $_SESSION['password'] = $password; // needed for things like EWS
164
+    $_SESSION['loggedin'] = true;
165
+}
166
+
167
+/**
168
+ * Send an alert email to the system admin
169
+ * 
170
+ * Used when an account with the status ALERT_ON_ACCESS logs in
171
+ * @param String $username the account username
172
+ */
173
+function sendLoginAlertEmail($username) {
174
+    // TODO: add email code
175
+}
176
+
177
+////////////////////////////////////////////////////////////////////////////////
178
+//                              LDAP handling                                 //
179
+////////////////////////////////////////////////////////////////////////////////
180
+
181
+/**
182
+ * Checks the given credentials against the LDAP server.
183
+ * @param string $username
184
+ * @param string $password
185
+ * @return mixed True if OK, else false or the error code from the server
186
+ */
187
+function authenticate_user_ldap($username, $password) {
188
+    global $ldap_config;
189
+    if (is_empty($username) || is_empty($password)) {
190
+        return false;
191
+    }
192
+    $ldapManager = new LdapManager($ldap_config);
193
+    $msg = "";
194
+    $code = 0;
195
+    if ($ldapManager->authenticate($username, $password, $msg, $code)) {
196
+        return true;
197
+    } else {
198
+        return $code;
199
+    }
200
+}
201
+
202
+/**
203
+ * Check if a username exists on the LDAP server.
204
+ * @global type $ldap_config
205
+ * @param type $username
206
+ * @return boolean true if yes, else false
207
+ */
208
+function user_exists_ldap($username, $password) {
209
+    global $ldap_config;
210
+    $ldap = new LdapManager($ldap_config);
211
+    if (!$ldap->authenticate($username, $password, $message, $code)) {
212
+        switch ($code) {
213
+            case ADResponseCodes::ACCOUNT_INVALID:
214
+                return false;
215
+            case ADResponseCodes::ACCOUNT_CREDENTIALS_INVALID:
216
+                return true;
217
+            case ADResponseCodes::ACCOUNT_RESTRICTIONS:
218
+                return true;
219
+            case ADResponseCodes::ACCOUNT_RESTRICTIONS_TIME:
220
+                return true;
221
+            case ADResponseCodes::ACCOUNT_RESTRICTIONS_DEVICE:
222
+                return true;
223
+            case ADResponseCodes::ACCOUNT_PASSWORD_EXPIRED:
224
+                return true;
225
+            case ADResponseCodes::ACCOUNT_DISABLED:
226
+                return true;
227
+            case ADResponseCodes::ACCOUNT_CONTEXT_IDS:
228
+                return true;
229
+            case ADResponseCodes::ACCOUNT_EXPIRED:
230
+                return false;
231
+            case ADResponseCodes::ACCOUNT_PASSWORD_MUST_CHANGE:
232
+                return true;
233
+            case ADResponseCodes::ACCOUNT_LOCKED:
234
+                return true;
235
+            default:
236
+                return false;
237
+        }
238
+    }
239
+    return true;
240
+}
241
+
242
+////////////////////////////////////////////////////////////////////////////////
243
+//                          2-factor authentication                           //
244
+////////////////////////////////////////////////////////////////////////////////
245
+
246
+/**
247
+ * Check if a user has TOTP setup
248
+ * @global $database $database
249
+ * @param string $username
250
+ * @return boolean true if TOTP secret exists, else false
251
+ */
252
+function userHasTOTP($username) {
253
+    global $database;
254
+    $secret = $database->select('accounts', 'authsecret', ['username' => $username])[0];
255
+    if (is_empty($secret)) {
256
+        return false;
257
+    }
258
+    return true;
259
+}
260
+
261
+/**
262
+ * Generate a TOTP secret for the given user.
263
+ * @param string $username
264
+ * @return string OTP provisioning URI (for generating a QR code)
265
+ */
266
+function newTOTP($username) {
267
+    global $database;
268
+    $secret = random_bytes(20);
269
+    $encoded_secret = Base32::encode($secret);
270
+    $userdata = $database->select('accounts', ['email', 'authsecret', 'realname'], ['username' => $username])[0];
271
+    $totp = new TOTP((is_null($userdata['email']) ? $userdata['realname'] : $userdata['email']), $encoded_secret);
272
+    $totp->setIssuer(SYSTEM_NAME);
273
+    return $totp->getProvisioningUri();
274
+}
275
+
276
+/**
277
+ * Save a TOTP secret for the user.
278
+ * @global $database $database
279
+ * @param string $username
280
+ * @param string $secret
281
+ */
282
+function saveTOTP($username, $secret) {
283
+    global $database;
284
+    $database->update('accounts', ['authsecret' => $secret], ['username' => $username]);
285
+}
286
+
287
+/**
288
+ * Verify a TOTP multiauth code
289
+ * @global $database
290
+ * @param string $username
291
+ * @param int $code
292
+ * @return boolean true if it's legit, else false
293
+ */
294
+function verifyTOTP($username, $code) {
295
+    global $database;
296
+    $userdata = $database->select('accounts', ['email', 'authsecret'], ['username' => $username])[0];
297
+    if (is_empty($userdata['authsecret'])) {
298
+        return false;
299
+    }
300
+    $totp = new TOTP(null, $userdata['authsecret']);
301
+    return $totp->verify($code);
302
+}

+ 522
- 0
lib/worst_passwords.php View File

@@ -0,0 +1,522 @@
1
+<?php
2
+/*
3
+ * 500 most common passwords, to be used in stopping idiots from having really bad passwords.
4
+ * Source: https://github.com/danielmiessler/SecLists/blob/master/Passwords/500-worst-passwords.txt
5
+ */
6
+
7
+
8
+/**
9
+ * Checks a given password against the list of the 500 most common passwords.
10
+ * @param string $search the password to check
11
+ * @return false if not found, the password ranking if found
12
+ */
13
+function checkWorst500List($search) {
14
+    $worst_password_list = [
15
+        "123456",
16
+        "password",
17
+        "12345678",
18
+        "1234",
19
+        "pussy",
20
+        "12345",
21
+        "dragon",
22
+        "qwerty",
23
+        "696969",
24
+        "mustang",
25
+        "letmein",
26
+        "baseball",
27
+        "master",
28
+        "michael",
29
+        "football",
30
+        "shadow",
31
+        "monkey",
32
+        "abc123",
33
+        "pass",
34
+        "fuckme",
35
+        "6969",
36
+        "jordan",
37
+        "harley",
38
+        "ranger",
39
+        "iwantu",
40
+        "jennifer",
41
+        "hunter",
42
+        "fuck",
43
+        "2000",
44
+        "test",
45
+        "batman",
46
+        "trustno1",
47
+        "thomas",
48
+        "tigger",
49
+        "robert",
50
+        "access",
51
+        "love",
52
+        "buster",
53
+        "1234567",
54
+        "soccer",
55
+        "hockey",
56
+        "killer",
57
+        "george",
58
+        "sexy",
59
+        "andrew",
60
+        "charlie",
61
+        "superman",
62
+        "asshole",
63
+        "fuckyou",
64
+        "dallas",
65
+        "jessica",
66
+        "panties",
67
+        "pepper",
68
+        "1111",
69
+        "austin",
70
+        "william",
71
+        "daniel",
72
+        "golfer",
73
+        "summer",
74
+        "heather",
75
+        "hammer",
76
+        "yankees",
77
+        "joshua",
78
+        "maggie",
79
+        "biteme",
80
+        "enter",
81
+        "ashley",
82
+        "thunder",
83
+        "cowboy",
84
+        "silver",
85
+        "richard",
86
+        "fucker",
87
+        "orange",
88
+        "merlin",
89
+        "michelle",
90
+        "corvette",
91
+        "bigdog",
92
+        "cheese",
93
+        "matthew",
94
+        "121212",
95
+        "patrick",
96
+        "martin",
97
+        "freedom",
98
+        "ginger",
99
+        "blowjob",
100
+        "nicole",
101
+        "sparky",
102
+        "yellow",
103
+        "camaro",
104
+        "secret",
105
+        "dick",
106
+        "falcon",
107
+        "taylor",
108
+        "111111",
109
+        "131313",
110
+        "123123",
111
+        "bitch",
112
+        "hello",
113
+        "scooter",
114
+        "please",
115
+        "porsche",
116
+        "guitar",
117
+        "chelsea",
118
+        "black",
119
+        "diamond",
120
+        "nascar",
121
+        "jackson",
122
+        "cameron",
123
+        "654321",
124
+        "computer",
125
+        "amanda",
126
+        "wizard",
127
+        "xxxxxxxx",
128
+        "money",
129
+        "phoenix",
130
+        "mickey",
131
+        "bailey",
132
+        "knight",
133
+        "iceman",
134
+        "tigers",
135
+        "purple",
136
+        "andrea",
137
+        "horny",
138
+        "dakota",
139
+        "aaaaaa",
140
+        "player",
141
+        "sunshine",
142
+        "morgan",
143
+        "starwars",
144
+        "boomer",
145
+        "cowboys",
146
+        "edward",
147
+        "charles",
148
+        "girls",
149
+        "booboo",
150
+        "coffee",
151
+        "xxxxxx",
152
+        "bulldog",
153
+        "ncc1701",
154
+        "rabbit",
155
+        "peanut",
156
+        "john",
157
+        "johnny",
158
+        "gandalf",
159
+        "spanky",
160
+        "winter",
161
+        "brandy",
162
+        "compaq",
163
+        "carlos",
164
+        "tennis",
165
+        "james",
166
+        "mike",
167
+        "brandon",
168
+        "fender",
169
+        "anthony",
170
+        "blowme",
171
+        "ferrari",
172
+        "cookie",
173
+        "chicken",
174
+        "maverick",
175
+        "chicago",
176
+        "joseph",
177
+        "diablo",
178
+        "sexsex",
179
+        "hardcore",
180
+        "666666",
181
+        "willie",
182
+        "welcome",
183
+        "chris",
184
+        "panther",
185
+        "yamaha",
186
+        "justin",
187
+        "banana",
188
+        "driver",
189
+        "marine",
190
+        "angels",
191
+        "fishing",
192
+        "david",
193
+        "maddog",
194
+        "hooters",
195
+        "wilson",
196
+        "butthead",
197
+        "dennis",
198
+        "fucking",
199
+        "captain",
200
+        "bigdick",
201
+        "chester",
202
+        "smokey",
203
+        "xavier",
204
+        "steven",
205
+        "viking",
206
+        "snoopy",
207
+        "blue",
208
+        "eagles",
209
+        "winner",
210
+        "samantha",
211
+        "house",
212
+        "miller",
213
+        "flower",
214
+        "jack",
215
+        "firebird",
216
+        "butter",
217
+        "united",
218
+        "turtle",
219
+        "steelers",
220
+        "tiffany",
221
+        "zxcvbn",
222
+        "tomcat",
223
+        "golf",
224
+        "bond007",
225
+        "bear",
226
+        "tiger",
227
+        "doctor",
228
+        "gateway",
229
+        "gators",
230
+        "angel",
231
+        "junior",
232
+        "thx1138",
233
+        "porno",
234
+        "badboy",
235
+        "debbie",
236
+        "spider",
237
+        "melissa",
238
+        "booger",
239
+        "1212",
240
+        "flyers",
241
+        "fish",
242
+        "porn",
243
+        "matrix",
244
+        "teens",
245
+        "scooby",
246
+        "jason",
247
+        "walter",
248
+        "cumshot",
249
+        "boston",
250
+        "braves",
251
+        "yankee",
252
+        "lover",
253
+        "barney",
254
+        "victor",
255
+        "tucker",
256
+        "princess",
257
+        "mercedes",
258
+        "5150",
259
+        "doggie",
260
+        "zzzzzz",
261
+        "gunner",
262
+        "horney",
263
+        "bubba",
264
+        "2112",
265
+        "fred",
266
+        "johnson",
267
+        "xxxxx",
268
+        "tits",
269
+        "member",
270
+        "boobs",
271
+        "donald",
272
+        "bigdaddy",
273
+        "bronco",
274
+        "penis",
275
+        "voyager",
276
+        "rangers",
277
+        "birdie",
278
+        "trouble",
279
+        "white",
280
+        "topgun",
281
+        "bigtits",
282
+        "bitches",
283
+        "green",
284
+        "super",
285
+        "qazwsx",
286
+        "magic",
287
+        "lakers",
288
+        "rachel",
289
+        "slayer",
290
+        "scott",
291
+        "2222",
292
+        "asdf",
293
+        "video",
294
+        "london",
295
+        "7777",
296
+        "marlboro",
297
+        "srinivas",
298
+        "internet",
299
+        "action",
300
+        "carter",
301
+        "jasper",
302
+        "monster",
303
+        "teresa",
304
+        "jeremy",
305
+        "11111111",
306
+        "bill",
307
+        "crystal",
308
+        "peter",
309
+        "pussies",
310
+        "cock",
311
+        "beer",
312
+        "rocket",
313
+        "theman",
314
+        "oliver",
315
+        "prince",
316
+        "beach",
317
+        "amateur",
318
+        "7777777",
319
+        "muffin",
320
+        "redsox",
321
+        "star",
322
+        "testing",
323
+        "shannon",
324
+        "murphy",
325
+        "frank",
326
+        "hannah",
327
+        "dave",
328
+        "eagle1",
329
+        "11111",
330
+        "mother",
331
+        "nathan",
332
+        "raiders",
333
+        "steve",
334
+        "forever",
335
+        "angela",
336
+        "viper",
337
+        "ou812",
338
+        "jake",
339
+        "lovers",
340
+        "suckit",
341
+        "gregory",
342
+        "buddy",
343
+        "whatever",
344
+        "young",
345
+        "nicholas",
346
+        "lucky",
347
+        "helpme",
348
+        "jackie",
349
+        "monica",
350
+        "midnight",
351
+        "college",
352
+        "baby",
353
+        "cunt",
354
+        "brian",
355
+        "mark",
356
+        "startrek",
357
+        "sierra",
358
+        "leather",
359
+        "232323",
360
+        "4444",
361
+        "beavis",
362
+        "bigcock",
363
+        "happy",
364
+        "sophie",
365
+        "ladies",
366
+        "naughty",
367
+        "giants",
368
+        "booty",
369
+        "blonde",
370
+        "fucked",
371
+        "golden",
372
+        "0",
373
+        "fire",
374
+        "sandra",
375
+        "pookie",
376
+        "packers",
377
+        "einstein",
378
+        "dolphins",
379
+        "chevy",
380
+        "winston",
381
+        "warrior",
382
+        "sammy",
383
+        "slut",
384
+        "8675309",
385
+        "zxcvbnm",
386
+        "nipples",
387
+        "power",
388
+        "victoria",
389
+        "asdfgh",
390
+        "vagina",
391
+        "toyota",
392
+        "travis",
393
+        "hotdog",
394
+        "paris",
395
+        "rock",
396
+        "xxxx",
397
+        "extreme",
398
+        "redskins",
399
+        "erotic",
400
+        "dirty",
401
+        "ford",
402
+        "freddy",
403
+        "arsenal",
404
+        "access14",
405
+        "wolf",
406
+        "nipple",
407
+        "iloveyou",
408
+        "alex",
409
+        "florida",
410
+        "eric",
411
+        "legend",
412
+        "movie",
413
+        "success",
414
+        "rosebud",
415
+        "jaguar",
416
+        "great",
417
+        "cool",
418
+        "cooper",
419
+        "1313",
420
+        "scorpio",
421
+        "mountain",
422
+        "madison",
423
+        "987654",
424
+        "brazil",
425
+        "lauren",
426
+        "japan",
427
+        "naked",
428
+        "squirt",
429
+        "stars",
430
+        "apple",
431
+        "alexis",
432
+        "aaaa",
433
+        "bonnie",
434
+        "peaches",
435
+        "jasmine",
436
+        "kevin",
437
+        "matt",
438
+        "qwertyui",
439
+        "danielle",
440
+        "beaver",
441
+        "4321",
442
+        "4128",
443
+        "runner",
444
+        "swimming",
445
+        "dolphin",
446
+        "gordon",
447
+        "casper",
448
+        "stupid",
449
+        "shit",
450
+        "saturn",
451
+        "gemini",
452
+        "apples",
453
+        "august",
454
+        "3333",
455
+        "canada",
456
+        "blazer",
457
+        "cumming",
458
+        "hunting",
459
+        "kitty",
460
+        "rainbow",
461
+        "112233",
462
+        "arthur",
463
+        "cream",
464
+        "calvin",
465
+        "shaved",
466
+        "surfer",
467
+        "samson",
468
+        "kelly",
469
+        "paul",
470
+        "mine",
471
+        "king",
472
+        "racing",
473
+        "5555",
474
+        "eagle",
475
+        "hentai",
476
+        "newyork",
477
+        "little",
478
+        "redwings",
479
+        "smith",
480
+        "sticky",
481
+        "cocacola",
482
+        "animal",
483
+        "broncos",
484
+        "private",
485
+        "skippy",
486
+        "marvin",
487
+        "blondes",
488
+        "enjoy",
489
+        "girl",
490
+        "apollo",
491
+        "parker",
492
+        "qwert",
493
+        "time",
494
+        "sydney",
495
+        "women",
496
+        "voodoo",
497
+        "magnum",
498
+        "juice",
499
+        "abgrtyu",
500
+        "777777",
501
+        "dreams",
502
+        "maxwell",
503
+        "music",
504
+        "rush2112",
505
+        "russia",
506
+        "scorpion",
507
+        "rebecca",
508
+        "tester",
509
+        "mistress",
510
+        "phantom",
511
+        "billy",
512
+        "6666",
513
+        "albert"
514
+    ];
515
+    
516
+    $index = array_search($search, $worst_password_list);
517
+    if ($index === FALSE) {
518
+        return false;
519
+    } else {
520
+        return $index + 1;
521
+    }
522
+}

+ 8
- 0
nbproject/project.properties View File

@@ -0,0 +1,8 @@
1
+auxiliary.org-netbeans-modules-html-editor-lib.default-html-public-id=-//W3C//DTD HTML 4.01 Transitional//EN
2
+include.path=${php.global.include.path}
3
+php.version=PHP_70
4
+source.encoding=UTF-8
5
+src.dir=.
6
+tags.asp=false
7
+tags.short=false
8
+web.root=.

+ 9
- 0
nbproject/project.xml View File

@@ -0,0 +1,9 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project xmlns="http://www.netbeans.org/ns/project/1">
3
+    <type>org.netbeans.modules.php.project</type>
4
+    <configuration>
5
+        <data xmlns="http://www.netbeans.org/ns/php-project/1">
6
+            <name>WebAppTemplate</name>
7
+        </data>
8
+    </configuration>
9
+</project>

+ 11
- 0
pages.php View File

@@ -0,0 +1,11 @@
1
+<?php
2
+
3
+// List of pages and metadata
4
+define("PAGES", [
5
+    "home" => [
6
+        "title" => "home"
7
+    ],
8
+    "404" => [
9
+        "title" => "404 error"
10
+    ]
11
+]);

+ 5
- 0
pages/404.php View File

@@ -0,0 +1,5 @@
1
+<div class="row">
2
+    <div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4">
3
+        <div class="alert alert-warning"><b><?php lang("404 error");?></b><br /> <?php lang("page not found"); ?></div>
4
+    </div>
5
+</div>

+ 1
- 0
pages/home.php View File

@@ -0,0 +1 @@
1
+<h1>Hello World</h1>

+ 226
- 0
required.php View File

@@ -0,0 +1,226 @@
1
+<?php
2
+
3
+/**
4
+ * This file contains global settings and utility functions.
5
+ */
6
+ob_start(); // allow sending headers after content
7
+// Unicode, solves almost all stupid encoding problems
8
+header('Content-Type: text/html; charset=utf-8');
9
+
10
+// l33t $ecurity h4x
11
+header('X-Content-Type-Options: nosniff');
12
+header('X-XSS-Protection: 1; mode=block');
13
+header('X-Powered-By: Late-night coding frenzies (plz send caffeine, thx)');
14
+$session_length = 60 * 60; // 1 hour
15
+session_set_cookie_params($session_length, "/", null, false, true);
16
+
17
+session_start(); // stick some cookies in it
18
+//
19
+// Composer
20
+require __DIR__ . '/vendor/autoload.php';
21
+
22
+// Settings file
23
+require __DIR__ . '/settings.php';
24
+// List of alert messages
25
+require __DIR__ . '/lang/messages.php';
26
+// text strings (i18n)
27
+require __DIR__ . '/lang/' . LANGUAGE . ".php";
28
+
29
+/**
30
+ * Kill off the running process and spit out an error message
31
+ * @param string $error error message
32
+ */
33
+function sendError($error) {
34
+    die("<!DOCTYPE html><html><head><title>Error</title></head><body><h1 style='color: red; font-family: sans-serif; font-size:100%;'>" . htmlspecialchars($error) . "</h1></body></html>");
35
+}
36
+
37
+date_default_timezone_set(TIMEZONE);
38
+
39
+// Database settings
40
+// Also inits database and stuff
41
+use Medoo\Medoo;
42
+
43
+$database;
44
+try {
45
+    $database = new Medoo([
46
+        'database_type' => DB_TYPE,
47
+        'database_name' => DB_NAME,
48
+        'server' => DB_SERVER,
49
+        'username' => DB_USER,
50
+        'password' => DB_PASS,
51
+        'charset' => DB_CHARSET
52
+    ]);
53
+} catch (Exception $ex) {
54
+    //header('HTTP/1.1 500 Internal Server Error');
55
+    sendError("Database error.  Try again later.  $ex");
56
+}
57
+
58
+
59
+if (!DEBUG) {
60
+    error_reporting(0);
61
+} else {
62
+    error_reporting(E_ALL);
63
+    ini_set('display_errors', 'On');
64
+}
65
+
66
+
67
+$VARS;
68
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
69
+    $VARS = $_POST;
70
+    define("GET", false);
71
+} else {
72
+    $VARS = $_GET;
73
+    define("GET", true);
74
+}
75
+
76
+/**
77
+ * Checks if a string or whatever is empty.
78
+ * @param $str The thingy to check
79
+ * @return boolean True if it's empty or whatever.
80
+ */
81
+function is_empty($str) {
82
+    return (is_null($str) || !isset($str) || $str == '');
83
+}
84
+
85
+/**
86
+ * I18N string getter.  If the key doesn't exist, outputs the key itself.
87
+ * @param string $key I18N string key
88
+ * @param boolean $echo whether to echo the result or return it (default echo)
89
+ */
90
+function lang($key, $echo = true) {
91
+    if (array_key_exists($key, STRINGS)) {
92
+        $str = STRINGS[$key];
93
+    } else {
94
+        $str = $key;
95
+    }
96
+
97
+    if ($echo) {
98
+        echo $str;
99
+    } else {
100
+        return $str;
101
+    }
102
+}
103
+
104
+/**
105
+ * I18N string getter (with builder).    If the key doesn't exist, outputs the key itself.
106
+ * @param string $key I18N string key
107
+ * @param array $replace key-value array of replacements.
108
+ * If the string value is "hello {abc}" and you give ["abc" => "123"], the
109
+ * result will be "hello 123".
110
+ * @param boolean $echo whether to echo the result or return it (default echo)
111
+ */
112
+function lang2($key, $replace, $echo = true) {
113
+    if (array_key_exists($key, STRINGS)) {
114
+        $str = STRINGS[$key];
115
+    } else {
116
+        $str = $key;
117
+    }
118
+
119
+    foreach ($replace as $find => $repl) {
120
+        $str = str_replace("{" . $find . "}", $repl, $str);
121
+    }
122
+
123
+    if ($echo) {
124
+        echo $str;
125
+    } else {
126
+        return $str;
127
+    }
128
+}
129
+
130
+/**
131
+ * Checks if an email address is valid.
132
+ * @param string $email Email to check
133
+ * @return boolean True if email passes validation, else false.
134
+ */
135
+function isValidEmail($email) {
136
+    return filter_var($email, FILTER_VALIDATE_EMAIL);
137
+}
138
+
139
+
140
+/**
141
+ * Hashes the given plaintext password
142
+ * @param String $password
143
+ * @return String the hash, using bcrypt
144
+ */
145
+function encryptPassword($password) {
146
+    return password_hash($password, PASSWORD_BCRYPT);
147
+}
148
+
149
+/**
150
+ * Securely verify a password and its hash
151
+ * @param String $password
152
+ * @param String $hash the hash to compare to
153
+ * @return boolean True if password OK, else false
154
+ */
155
+function comparePassword($password, $hash) {
156
+    return password_verify($password, $hash);
157
+}
158
+
159
+function dieifnotloggedin() {
160
+    if ($_SESSION['loggedin'] != true) {
161
+        sendError("Session expired.  Please log out and log in again.");
162
+    }
163
+}
164
+
165
+/**
166
+ * Check if the previous database action had a problem.
167
+ * @param array $specials int=>string array with special response messages for SQL errors
168
+ */
169
+function checkDBError($specials = []) {
170
+    global $database;
171
+    $errors = $database->error();
172
+    if (!is_null($errors[1])) {
173
+        foreach ($specials as $code => $text) {
174
+            if ($errors[1] == $code) {
175
+                sendError($text);
176
+            }
177
+        }
178
+        sendError("A database error occurred:<br /><code>" . $errors[2] . "</code>");
179
+    }
180
+}
181
+
182
+/*
183
+ * http://stackoverflow.com/a/20075147/2534036
184
+ */
185
+if (!function_exists('base_url')) {
186
+
187
+    function base_url($atRoot = FALSE, $atCore = FALSE, $parse = FALSE) {
188
+        if (isset($_SERVER['HTTP_HOST'])) {
189
+            $http = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
190
+            $hostname = $_SERVER['HTTP_HOST'];
191
+            $dir = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
192
+
193
+            $core = preg_split('@/@', str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath(dirname(__FILE__))), NULL, PREG_SPLIT_NO_EMPTY);
194
+            $core = $core[0];
195
+
196
+            $tmplt = $atRoot ? ($atCore ? "%s://%s/%s/" : "%s://%s/") : ($atCore ? "%s://%s/%s/" : "%s://%s%s");
197
+            $end = $atRoot ? ($atCore ? $core : $hostname) : ($atCore ? $core : $dir);
198
+            $base_url = sprintf($tmplt, $http, $hostname, $end);
199
+        } else
200
+            $base_url = 'http://localhost/';
201
+
202
+        if ($parse) {
203
+            $base_url = parse_url($base_url);
204
+            if (isset($base_url['path']))
205
+                if ($base_url['path'] == '/')
206
+                    $base_url['path'] = '';
207
+        }
208
+
209
+        return $base_url;
210
+    }
211
+
212
+}
213
+
214
+function redirectToPageId($id, $args, $dontdie) {
215
+    header('Location: ' . URL . '?id=' . $id . $args);
216
+    if (is_null($dontdie)) {
217
+        die("Please go to " . URL . '?id=' . $id . $args);
218
+    }
219
+}
220
+
221
+function redirectIfNotLoggedIn() {
222
+    if ($_SESSION['loggedin'] !== TRUE) {
223
+        header('Location: ' . URL . '/login.php');
224
+        die();
225
+    }
226
+}

+ 47
- 0
settings.template.php View File

@@ -0,0 +1,47 @@
1
+<?php
2
+
3
+// Whether to show debugging data in output.
4
+// DO NOT SET TO TRUE IN PRODUCTION!!!
5
+define("DEBUG", false);
6
+
7
+// Database connection settings
8
+// See http://medoo.in/api/new for info
9
+define("DB_TYPE", "mysql");
10
+define("DB_NAME", "app");
11
+define("DB_SERVER", "localhost");
12
+define("DB_USER", "app");
13
+define("DB_PASS", "");
14
+define("DB_CHARSET", "utf8");
15
+
16
+define("SITE_TITLE", "Web App Template");
17
+
18
+// Used to identify the system in OTP and other places
19
+define("SYSTEM_NAME", "Web App Template");
20
+
21
+// For supported values, see http://php.net/manual/en/timezones.php
22
+define("TIMEZONE", "America/Denver");
23
+
24
+// Base URL for site links.
25
+define('URL', 'http://localhost:8000/');
26
+
27
+// See lang folder for language options
28
+define('LANGUAGE', "en_us");
29
+
30
+// Minimum length for new passwords
31
+// The system checks new passwords against the 500 worst passwords and rejects
32
+// any matches.
33
+// If you want to have additional password requirements, go edit action.php.
34
+// However, all that does is encourage people to use the infamous 
35
+// "post-it password manager".  See also https://xkcd.com/936/ and
36
+// http://stackoverflow.com/a/34166252/2534036 for reasons why forcing passwords
37
+// like CaPs45$% is not actually a great idea.
38
+// Encourage users to use 2-factor auth whenever possible.
39
+define("MIN_PASSWORD_LENGTH", 8);
40
+
41
+//////////////////////////////////////////////////////////////
42
+//  /!\       Warning: Changing these values may       /!\  //
43
+//  /!\  violate the terms of your license agreement!  /!\  //
44
+//////////////////////////////////////////////////////////////
45
+define("LICENSE_TEXT", "<b>Free Software: MIT License</b>");
46
+define("COPYRIGHT_NAME", "Netsyms Technologies");
47
+//////////////////////////////////////////////////////////////

+ 13
- 0
static/css/app.css View File

@@ -0,0 +1,13 @@
1
+.banner-image {
2
+    max-height: 100px;
3
+    margin: 2em auto;
4
+}
5
+
6
+.navbar-brand {
7
+    font-size: 110%;
8
+}
9
+
10
+.footer {
11
+    margin-top: 10em;
12
+    text-align: center;
13
+}

+ 11
- 0
static/css/bootstrap.min.css
File diff suppressed because it is too large
View File


+ 2337
- 0
static/css/font-awesome.css
File diff suppressed because it is too large
View File


+ 4
- 0
static/css/font-awesome.min.css
File diff suppressed because it is too large
View File


BIN
static/fonts/FontAwesome.otf View File


BIN
static/fonts/fontawesome-webfont.eot View File


+ 2671
- 0
static/fonts/fontawesome-webfont.svg
File diff suppressed because it is too large
View File


BIN
static/fonts/fontawesome-webfont.ttf View File


BIN
static/fonts/fontawesome-webfont.woff View File


BIN
static/fonts/fontawesome-webfont.woff2 View File


+ 7
- 0
static/js/app.js View File

@@ -0,0 +1,7 @@
1
+
2
+$(document).ready(function () {
3
+    /* Fade out alerts */
4
+    $(".alert .close").click(function (e) {
5
+        $(this).parent().fadeOut('slow');
6
+    });
7
+});

+ 7
- 0
static/js/bootstrap.min.js
File diff suppressed because it is too large
View File


+ 4
- 0
static/js/jquery-3.2.1.min.js
File diff suppressed because it is too large
View File


Loading…
Cancel
Save