Use some of Eloquent's features to make life easier.

This commit is contained in:
flash 2018-02-11 13:57:01 +01:00
parent de56e9ede8
commit 8d90699f40
7 changed files with 128 additions and 30 deletions

View file

@ -29,7 +29,7 @@ class Application extends ApplicationBase
* Session instance.
* @var \Misuzu\Users\Session
*/
public $session = null;
private $session = null;
/**
* Constructor, called by ApplicationBase::start() which also passes the arguments through.
@ -51,13 +51,29 @@ class Application extends ApplicationBase
public function startSession(int $user_id, string $session_key): void
{
$session = Session::where('session_key', $session_key)->where('user_id', $user_id)->first();
$session = Session::where('session_key', $session_key)
->where('user_id', $user_id)
->first();
if ($session !== null) {
$this->session = $session;
if ($session->hasExpired()) {
$session->delete();
} else {
$this->setSession($session);
}
}
}
public function getSession(): Session
{
return $this->session;
}
public function setSession(Session $session): void
{
$this->session = $session;
}
/**
* Sets up the database module.
*/

View file

@ -29,30 +29,31 @@ class AuthController extends Controller
$password = $_POST['password'] ?? '';
try {
$user = User::where('username', $username)->firstOrFail();
$user = User::where('username', $username)->orWhere('email', $username)->firstOrFail();
} catch (ModelNotFoundException $e) {
return ['error' => 'Invalid username or password!'];
}
if (!password_verify($password, $user->password)) {
if (!$user->validatePassword($password)) {
return ['error' => 'Invalid username or password!'];
}
$session = new Session;
$session->user_id = $user->user_id;
$session->session_ip = IP::unpack(IP::remote());
$session->session_ip = IP::remote();
$session->user_agent = 'Misuzu Testing 1';
$session->expires_on = Carbon::now()->addMonth();
$session->session_key = bin2hex(random_bytes(32));
$session->save();
Application::getInstance()->session = $session;
Application::getInstance()->setSession($session);
$this->setCookie('uid', $session->user_id, 604800);
$this->setCookie('sid', $session->session_key, 604800);
// Temporary key generation for chat login.
// Should eventually be replaced with a callback login system.
// Also uses different cookies since $httponly is required to be false for these.
$user->last_ip = IP::remote();
$user->user_chat_key = bin2hex(random_bytes(16));
$user->save();
@ -79,6 +80,10 @@ class AuthController extends Controller
{
$ipAddr = IP::unpack($ipAddr ?? IP::remote());
if ($ipAddr === IP::unpack('127.0.0.1') || $ipAddr === IP::unpack('::1')) {
return false;
}
if (User::withTrashed()->where('register_ip', $ipAddr)->orWhere('last_ip', $ipAddr)->count()) {
return true;
}
@ -157,14 +162,7 @@ class AuthController extends Controller
return ['error' => 'Your password is considered too weak!'];
}
$user = new User;
$user->username = $username;
$user->password = password_hash($password, PASSWORD_ARGON2I);
$user->email = $email;
$user->register_ip = IP::unpack(IP::remote());
$user->last_ip = IP::unpack(IP::remote());
$user->user_country = get_country_code(IP::remote());
$user->save();
User::createUser($username, $password, $email);
return ['error' => 'Welcome to Flashii! You may now log in.', 'next' => '/auth/login'];
}

View file

@ -2,10 +2,27 @@
namespace Misuzu\Users;
use Misuzu\Model;
use Misuzu\Net\IP;
class Session extends Model
{
protected $primaryKey = 'session_id';
protected $dates = ['expires_on'];
public function getSessionIpAttribute(string $ipAddress): string
{
return IP::pack($ipAddress);
}
public function setSessionIpAttribute(string $ipAddress): void
{
$this->attributes['session_ip'] = IP::unpack($ipAddress);
}
public function hasExpired(): bool
{
return $this->expires_on->isPast();
}
public function user()
{

View file

@ -3,13 +3,71 @@ namespace Misuzu\Users;
use Illuminate\Database\Eloquent\SoftDeletes;
use Misuzu\Model;
use Misuzu\Net\IP;
class User extends Model
{
use SoftDeletes;
private const PASSWORD_HASH_ALGO = PASSWORD_ARGON2I;
protected $primaryKey = 'user_id';
public static function createUser(
string $username,
string $password,
string $email,
?string $ipAddress = null
): User {
$ipAddress = $ipAddress ?? IP::remote();
$user = new User;
$user->username = $username;
$user->password = $password;
$user->email = $email;
$user->register_ip = $ipAddress;
$user->last_ip = $ipAddress;
$user->user_country = get_country_code($ipAddress);
$user->save();
return $user;
}
public function getRegisterIpAttribute(string $ipAddress): string
{
return IP::pack($ipAddress);
}
public function setRegisterIpAttribute(string $ipAddress): void
{
$this->attributes['register_ip'] = IP::unpack($ipAddress);
}
public function getLastIpAttribute(string $ipAddress): string
{
return IP::pack($ipAddress);
}
public function setLastIpAttribute(string $ipAddress): void
{
$this->attributes['last_ip'] = IP::unpack($ipAddress);
}
public function setPasswordAttribute(string $password): void
{
$this->attributes['password'] = password_hash($password, self::PASSWORD_HASH_ALGO);
}
public function validatePassword(string $password): bool
{
if (password_needs_rehash($this->password, self::PASSWORD_HASH_ALGO)) {
$this->password = $password;
$this->save();
}
return password_verify($password, $this->password);
}
public function sessions()
{
return $this->hasMany(Session::class, 'user_id');

View file

@ -3,12 +3,14 @@
{% set banner_classes = 'banner--insane landing__banner' %}
{% block banner_content %}
<h1 style="align-self: center; text-align: left; flex-grow: 1; padding-left: 2em">Well, this is embarrassing...</h1>
{% endblock %}
{% block content %}
<div class="platform" style="text-align: left;">
<p>Long story short, almost nothing is ready and going live now (or within the next week) will just lead to greater disappointment. I set up a <a href="https://twitter.com/flashiinet" class="container__footer-link" target="_blank" rel="noreferrer noopener">Twitter</a> again on which I'll eventually inform when the site goes in public beta.</p>
<p>I offer my sincerest apologies for not being able to live up to the hype I've created (twice, even) but understand that this decision will make for a less rushed end product and less coping with hurried code in the future.</p>
<div class="landing__inner">
<div class="landing__buttons">
<a href="/auth/register" class="landing__button">register</a>
<a href="/auth/login" class="landing__button">login</a>
</div>
<div class="landing__text">
<p>Registration soon, but not now.</p>
<p>Keep an eye on <a href="https://twitter.com/flashiinet" class="container__footer-link" target="_blank" rel="noreferrer noopener">Twitter</a>!</p>
</div>
</div>
{% endblock %}

5
views/nova/macros.twig Normal file
View file

@ -0,0 +1,5 @@
{% macro link(url, content, class) %}
{% spaceless %}
<a href="{{ url }}" {% if '://' in url %} target="_blank" rel="noreferrer noopener"{% endif %} {% if class is defined %}class="{{ class }}"{% endif %}>{{ content|raw }}</a>
{% endspaceless %}
{% endmacro %}

View file

@ -1,3 +1,5 @@
{% from '@nova/macros.twig' import link %}
<!doctype html>
<html>
<head>
@ -21,7 +23,7 @@
{% endif %}
</div>
<a class="header__user" href="{{ app.session is not null ? '/users/' ~ app.session.user_id : '/auth/login' }}">
<div class="header__username">{{ app.session is not null ? app.session.user.first.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>
</a>
</div>
@ -41,15 +43,15 @@
<div class="container__footer">
<div class="container__footer-copyright">
<a href="https://flash.moe" class="container__footer-link">flash.moe 2013-{{ ''|date('Y') }}</a> |
<a href="https://github.com/flashwave/misuzu/tree/{{ git_branch() }}" class="container__footer-link">{{ git_branch() }}</a>#<a href="https://github.com/flashwave/misuzu/commit/{{ git_hash(true) }}" class="container__footer-link">{{ git_hash() }}</a>
{{ link('https://flash.moe', 'flash.moe 2013-' ~ ''|date('Y'), 'container__footer-link') }} |
{{ link('https://github.com/flashwave/misuzu/tree/' ~ git_branch(), git_branch(), 'container__footer-link') }}#{{ link('https://github.com/flashwave/misuzu/commit/' ~ git_hash(true), git_hash(), 'container__footer-link') }}
</div>
<div class="container__footer-links">
<a href="#" class="container__footer-link">Terms of Service</a>
<a href="#" class="container__footer-link">Rules</a>
<a href="#" class="container__footer-link">Contact</a>
<a href="#" class="container__footer-link">Status</a>
<a href="https://twitter.com/flashiinet" class="container__footer-link" target="_blank" rel="noreferrer noopener">@flashiinet</a>
{{ link('#', 'Terms of Service', 'container__footer-link') }}
{{ link('#', 'Rules', 'container__footer-link') }}
{{ link('#', 'Contact', 'container__footer-link') }}
{{ link('#', 'Status', 'container__footer-link') }}
{{ link('https://twitter.com/flashiinet', '@flashiinet', 'container__footer-link') }}
</div>
</div>
</div>