You say 'a step backwards', I say 'modern web development'.

This commit is contained in:
flash 2018-03-14 02:39:02 +01:00
parent f57b58b212
commit 7a160c1e3e
15 changed files with 114 additions and 198 deletions

View file

@ -11,7 +11,6 @@
"ext-bcmath": "*", "ext-bcmath": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"twig/twig": "~2.4", "twig/twig": "~2.4",
"phroute/phroute": "~2.1",
"nesbot/carbon": "~1.22", "nesbot/carbon": "~1.22",
"illuminate/database": "~5.5", "illuminate/database": "~5.5",
"illuminate/filesystem": "~5.5", "illuminate/filesystem": "~5.5",

46
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "ad8d5aadca5a1f854d58dd82131f701a", "content-hash": "bfc5b8cbdbf22514c4b51ae1af8c333b",
"packages": [ "packages": [
{ {
"name": "composer/ca-bundle", "name": "composer/ca-bundle",
@ -1148,50 +1148,6 @@
], ],
"time": "2018-03-10T10:10:14+00:00" "time": "2018-03-10T10:10:14+00:00"
}, },
{
"name": "phroute/phroute",
"version": "v2.1.0",
"source": {
"type": "git",
"url": "https://github.com/mrjgreen/phroute.git",
"reference": "dbe2b986f9ee1dd33dc956fcc35d1fa22e8e196c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mrjgreen/phroute/zipball/dbe2b986f9ee1dd33dc956fcc35d1fa22e8e196c",
"reference": "dbe2b986f9ee1dd33dc956fcc35d1fa22e8e196c",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "*",
"satooshi/php-coveralls": "dev-master"
},
"type": "library",
"autoload": {
"psr-4": {
"Phroute\\Phroute\\": "src/Phroute"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Joe Green",
"email": "joe.green.0991@gmail.com"
}
],
"description": "Fast, fully featured restful request router for PHP",
"keywords": [
"router",
"routing"
],
"time": "2015-07-22T20:46:43+00:00"
},
{ {
"name": "psr/container", "name": "psr/container",
"version": "1.0.0", "version": "1.0.0",

View file

@ -8,3 +8,13 @@ $app = Application::start(
IO\Directory::exists(__DIR__ . '/vendor/phpunit/phpunit') IO\Directory::exists(__DIR__ . '/vendor/phpunit/phpunit')
); );
$app->startDatabase(); $app->startDatabase();
if (PHP_SAPI !== 'cli') {
if (isset($_COOKIE['msz_uid'], $_COOKIE['msz_sid'])) {
$app->startSession((int)$_COOKIE['msz_uid'], $_COOKIE['msz_sid']);
}
//ob_start('ob_gzhandler');
$app->startTemplating();
}

View file

@ -1,6 +1,4 @@
<?php <?php
namespace Misuzu\Controllers;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Misuzu\Application; use Misuzu\Application;
@ -9,9 +7,9 @@ use Misuzu\Net\IP;
use Misuzu\Users\User; use Misuzu\Users\User;
use Misuzu\Users\Session; use Misuzu\Users\Session;
class AuthController extends Controller require_once __DIR__ . '/../misuzu.php';
{
private const USERNAME_VALIDATION_ERRORS = [ $username_validation_errors = [
'trim' => 'Your username may not start or end with spaces!', 'trim' => 'Your username may not start or end with spaces!',
'short' => "Your username is too short, it has to be at least " . User::USERNAME_MIN_LENGTH . " characters!", 'short' => "Your username is too short, it has to be at least " . User::USERNAME_MIN_LENGTH . " characters!",
'long' => "Your username is too long, it can't be longer than " . User::USERNAME_MAX_LENGTH . " characters!", 'long' => "Your username is too long, it can't be longer than " . User::USERNAME_MAX_LENGTH . " characters!",
@ -20,21 +18,38 @@ class AuthController extends Controller
'spacing' => 'Please use either underscores or spaces, not both!', 'spacing' => 'Please use either underscores or spaces, not both!',
]; ];
public function login() $mode = $_GET['m'] ?? 'login';
{ $app->templating->var('auth_mode', $mode);
$app = Application::getInstance();
switch ($mode) {
case 'logout':
if ($app->getSession() === null) {
echo "You aren't logged in.";
} else {
echo "You've been logged out.";
set_cookie_m('uid', '', -3600);
set_cookie_m('sid', '', -3600);
$app->getSession()->delete();
$app->setSession(null);
}
echo '<meta http-equiv="refresh" content="1; url=/">';
break;
case 'login':
if ($app->getSession() !== null) { if ($app->getSession() !== null) {
return '<meta http-equiv="refresh" content="0; url=/">'; echo '<meta http-equiv="refresh" content="0; url=/">';
break;
} }
if ($_SERVER['REQUEST_METHOD'] === 'GET') { if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$twig = $app->templating; echo $app->templating->render('auth.login');
return $twig->render('auth.login'); break;
} }
if (!isset($_POST['username'], $_POST['password'])) { if (!isset($_POST['username'], $_POST['password'])) {
return ['error' => "You didn't fill all the forms!"]; echo json_encode_m(['error' => "You didn't fill all the forms!"]);
break;
} }
$username = $_POST['username'] ?? ''; $username = $_POST['username'] ?? '';
@ -43,17 +58,19 @@ class AuthController extends Controller
try { try {
$user = User::where('username', $username)->orWhere('email', $username)->firstOrFail(); $user = User::where('username', $username)->orWhere('email', $username)->firstOrFail();
} catch (ModelNotFoundException $e) { } catch (ModelNotFoundException $e) {
return ['error' => 'Invalid username or password!']; echo json_encode_m(['error' => 'Invalid username or password!']);
break;
} }
if (!$user->validatePassword($password)) { if (!$user->validatePassword($password)) {
return ['error' => 'Invalid username or password!']; echo json_encode_m(['error' => 'Invalid username or password!']);
break;
} }
$session = Session::createSession($user, 'Misuzu T1'); $session = Session::createSession($user, 'Misuzu T2');
$app->setSession($session); $app->setSession($session);
$this->setCookie('uid', $session->user_id, 604800); set_cookie_m('uid', $session->user_id, 604800);
$this->setCookie('sid', $session->session_key, 604800); set_cookie_m('sid', $session->session_key, 604800);
// Temporary key generation for chat login. // Temporary key generation for chat login.
// Should eventually be replaced with a callback login system. // Should eventually be replaced with a callback login system.
@ -65,42 +82,30 @@ class AuthController extends Controller
setcookie('msz_tmp_id', $user->user_id, time() + 604800, '/', '.flashii.net'); setcookie('msz_tmp_id', $user->user_id, time() + 604800, '/', '.flashii.net');
setcookie('msz_tmp_key', $user->user_chat_key, time() + 604800, '/', '.flashii.net'); setcookie('msz_tmp_key', $user->user_chat_key, time() + 604800, '/', '.flashii.net');
return ['error' => 'You are now logged in!', 'next' => '/']; echo json_encode_m(['error' => 'You are now logged in!', 'next' => '/']);
} break;
private function setCookie(string $name, string $value, int $expires): void
{
setcookie(
"msz_{$name}",
$value,
time() + $expires,
'/',
'',
!empty($_SERVER['HTTPS']),
true
);
}
public function register()
{
$app = Application::getInstance();
$prevent_registration = $app->config->get('Auth', 'prevent_registration', 'bool', false);
case 'register':
if ($app->getSession() !== null) { if ($app->getSession() !== null) {
return '<meta http-equiv="refresh" content="0; url=/">'; return '<meta http-equiv="refresh" content="0; url=/">';
} }
$prevent_registration = $app->config->get('Auth', 'prevent_registration', 'bool', false);
if ($_SERVER['REQUEST_METHOD'] === 'GET') { if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$app->templating->var('prevent_registration', $prevent_registration); $app->templating->var('prevent_registration', $prevent_registration);
return $app->templating->render('auth.register'); echo $app->templating->render('auth.register');
break;
} }
if ($prevent_registration) { if ($prevent_registration) {
return ['error' => 'Registration is not allowed on this instance.']; echo json_encode_m(['error' => 'Registration is not allowed on this instance.']);
break;
} }
if (!isset($_POST['username'], $_POST['password'], $_POST['email'])) { if (!isset($_POST['username'], $_POST['password'], $_POST['email'])) {
return ['error' => "You didn't fill all the forms!"]; echo json_encode_m(['error' => "You didn't fill all the forms!"]);
break;
} }
$username = $_POST['username'] ?? ''; $username = $_POST['username'] ?? '';
@ -109,55 +114,42 @@ class AuthController extends Controller
$email = $_POST['email'] ?? ''; $email = $_POST['email'] ?? '';
if ($username_validate !== '') { if ($username_validate !== '') {
return ['error' => self::USERNAME_VALIDATION_ERRORS[$username_validate]]; echo json_encode_m(['error' => $username_validation_errors[$username_validate]]);
break;
} }
try { try {
$existing = User::where('username', $username)->firstOrFail(); $existing = User::where('username', $username)->firstOrFail();
if ($existing->user_id > 0) { if ($existing->user_id > 0) {
return ['error' => 'This username is already taken!']; echo json_encode_m(['error' => 'This username is already taken!']);
break;
} }
} catch (ModelNotFoundException $e) { } catch (ModelNotFoundException $e) {
} }
if (!filter_var($email, FILTER_VALIDATE_EMAIL) || !check_mx_record($email)) { if (!filter_var($email, FILTER_VALIDATE_EMAIL) || !check_mx_record($email)) {
return ['error' => 'The e-mail address you entered is invalid!']; echo json_encode_m(['error' => 'The e-mail address you entered is invalid!']);
break;
} }
try { try {
$existing = User::where('email', $email)->firstOrFail(); $existing = User::where('email', $email)->firstOrFail();
if ($existing->user_id > 0) { if ($existing->user_id > 0) {
return ['error' => 'This e-mail address has already been used!']; echo json_encode_m(['error' => 'This e-mail address has already been used!']);
break;
} }
} catch (ModelNotFoundException $e) { } catch (ModelNotFoundException $e) {
} }
if (password_entropy($password) < 32) { if (password_entropy($password) < 32) {
return ['error' => 'Your password is considered too weak!']; echo json_encode_m(['error' => 'Your password is too weak!']);
break;
} }
User::createUser($username, $password, $email); User::createUser($username, $password, $email);
return ['error' => 'Welcome to Flashii! You may now log in.', 'next' => '/auth/login']; echo json_encode_m(['error' => 'Welcome to Flashii! You may now log in.', 'next' => '/auth.php?m=login']);
} break;
public function logout()
{
$app = Application::getInstance();
$session = $app->getSession();
if ($session === null) {
echo "You aren't logged in.";
} else {
echo "You've been logged out.";
$this->setCookie('uid', '', -3600);
$this->setCookie('sid', '', -3600);
$session->delete();
$app->setSession(null);
}
return '<meta http-equiv="refresh" content="1; url=/">';
}
} }

View file

@ -1,24 +1,4 @@
<?php <?php
namespace Misuzu;
use Phroute\Phroute\Dispatcher;
require_once __DIR__ . '/../misuzu.php'; require_once __DIR__ . '/../misuzu.php';
//ob_start('ob_gzhandler'); echo $app->templating->render('home.landing');
$app = Application::getInstance();
if (isset($_COOKIE['msz_uid'], $_COOKIE['msz_sid'])) {
$app->startSession((int)$_COOKIE['msz_uid'], $_COOKIE['msz_sid']);
}
$app->startRouter();
$app->startTemplating();
include __DIR__ . '/../routes.php';
echo (new Dispatcher($app->router->getData()))->dispatch(
$_SERVER['REQUEST_METHOD'],
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
);

9
public/profile.php Normal file
View file

@ -0,0 +1,9 @@
<?php
use Misuzu\Users\User;
require_once __DIR__ . '/../misuzu.php';
$user_id = (int)$_GET['u'];
$app->templating->vars(['profile' => User::findOrFail($user_id)]);
echo $app->templating->render('user.view');

View file

@ -3,7 +3,6 @@ namespace Misuzu;
use Misuzu\Config\ConfigManager; use Misuzu\Config\ConfigManager;
use Misuzu\Users\Session; use Misuzu\Users\Session;
use Phroute\Phroute\RouteCollector;
use UnexpectedValueException; use UnexpectedValueException;
use InvalidArgumentException; use InvalidArgumentException;
@ -124,7 +123,6 @@ class Application extends ApplicationBase
$twig->addFunction('byte_symbol'); $twig->addFunction('byte_symbol');
$twig->addFunction('session_id'); $twig->addFunction('session_id');
$twig->addFunction('config', [$this->config, 'get']); $twig->addFunction('config', [$this->config, 'get']);
$twig->addFunction('route', [$this->router, 'route']);
$twig->addFunction('git_hash', [Application::class, 'gitCommitHash']); $twig->addFunction('git_hash', [Application::class, 'gitCommitHash']);
$twig->addFunction('git_branch', [Application::class, 'gitBranch']); $twig->addFunction('git_branch', [Application::class, 'gitBranch']);
@ -132,16 +130,4 @@ class Application extends ApplicationBase
$twig->addPath('nova', __DIR__ . '/../views/nova'); $twig->addPath('nova', __DIR__ . '/../views/nova');
} }
/**
* Sets up the router module.
*/
public function startRouter(): void
{
if ($this->hasRouter) {
throw new UnexpectedValueException('Router module has already been started.');
}
$this->addModule('router', new RouteCollector);
}
} }

View file

@ -1,6 +0,0 @@
<?php
namespace Misuzu\Controllers;
abstract class Controller
{
}

View file

@ -1,16 +0,0 @@
<?php
namespace Misuzu\Controllers;
use Misuzu\Application;
use Misuzu\Database;
class HomeController extends Controller
{
public function index(): string
{
$app = Application::getInstance();
$twig = $app->templating;
return $twig->render('home.landing');
}
}

View file

@ -1,16 +0,0 @@
<?php
namespace Misuzu\Controllers;
use Misuzu\Application;
use Misuzu\Users\User;
class UserController extends Controller
{
public function view(int $userId): string
{
$app = Application::getInstance();
$twig = $app->templating;
$twig->vars(['profile' => User::findOrFail($userId)]);
return $twig->render('user.view');
}
}

View file

@ -16,6 +16,28 @@ if (!function_exists('ends_with')) {
} }
} }
function json_encode_m($obj): string
{
if (!headers_sent()) {
header('Content-Type: application/json; charset=utf-8');
}
return json_encode($obj);
}
function set_cookie_m(string $name, string $value, int $expires): void
{
setcookie(
"msz_{$name}",
$value,
time() + $expires,
'/',
'',
!empty($_SERVER['HTTPS']),
true
);
}
function password_entropy(string $password): int function password_entropy(string $password): int
{ {
return count(count_chars(utf8_decode($password), 1)) * log(256, 2); return count(count_chars(utf8_decode($password), 1)) * log(256, 2);

View file

@ -9,7 +9,7 @@
{% block content %} {% block content %}
<div class="platform form" id="auth-form"> <div class="platform form" id="auth-form">
<div> <div>
<a href="{{ route('auth.register') }}"><button class="button" type="button">Click here if you don't have an account yet</button></a> <a href="/auth.php?m=register"><button class="button" type="button">Click here if you don't have an account yet</button></a>
</div> </div>
<div> <div>
<input class="form__text" type="text" name="username" placeholder="Username"> <input class="form__text" type="text" name="username" placeholder="Username">

View file

@ -37,7 +37,7 @@
function authfSubmit() function authfSubmit()
{ {
authHttp.open('POST', location.pathname, true); authHttp.open('POST', location.pathname + '?m={{ auth_mode }}', true);
authHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); authHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
authHttp.send(authfForms()); authHttp.send(authfForms());
} }

View file

@ -6,8 +6,8 @@
<div class="landing__inner"> <div class="landing__inner">
{% if app.session is null %} {% if app.session is null %}
<div class="landing__buttons"> <div class="landing__buttons">
<a href="{{ route('auth.register') }}" class="landing__button">register</a> <a href="/auth.php?m=register" class="landing__button">register</a>
<a href="{{ route('auth.login') }}" class="landing__button">login</a> <a href="/auth.php?m=login" class="landing__button">login</a>
</div> </div>
<div class="landing__text"> <div class="landing__text">
<p>Keep an eye on <a href="https://twitter.com/flashiinet" class="container__footer-link" target="_blank" rel="noreferrer noopener">Twitter</a>!</p> <p>Keep an eye on <a href="https://twitter.com/flashiinet" class="container__footer-link" target="_blank" rel="noreferrer noopener">Twitter</a>!</p>

View file

@ -16,13 +16,13 @@
<nav class="header"> <nav class="header">
<div class="header__inner"> <div class="header__inner">
<div class="header__navigation"> <div class="header__navigation">
<a class="header__entry fa-home" href="/">home</a> {# for whatever backwards reason {{ route('main.index') }} doesn't do anything here #} <a class="header__entry fa-home" href="/">home</a>
<a class="header__entry fa-comments" href="https://chat.flashii.net">chat</a> <a class="header__entry fa-comments" href="https://chat.flashii.net">chat</a>
{% if app.session is not null %} {% if app.session is not null %}
<a class="header__entry fa-sign-out" href="{{ route('auth.logout') }}">logout</a> <a class="header__entry fa-sign-out" href="/auth.php?m=logout">logout</a>
{% endif %} {% endif %}
</div> </div>
<a class="header__user" href="{{ app.session is not null ? route('users.view', [app.session.user_id]) : route('auth.register') }}"> <a class="header__user" href="{{ app.session is not null ? '/profile.php?u=' ~ app.session.user_id : '/auth.php?m=login' }}">
<div class="header__username">{{ app.session is not null ? app.session.user.username : 'login' }}</div> <div class="header__username">{{ app.session is not null ? app.session.user.username : 'login' }}</div>
<div class="header__avatar" style="background-image: url('https://static.flash.moe/images/{{ app.session is not null ? 'discord-logo' : 'nova-none' }}.png')"></div> <div class="header__avatar" style="background-image: url('https://static.flash.moe/images/{{ app.session is not null ? 'discord-logo' : 'nova-none' }}.png')"></div>
</a> </a>