mirror of
https://github.com/openvk/openvk
synced 2024-12-23 00:51:03 +03:00
Merge branch 'master' into similartovk
This commit is contained in:
commit
47626b91c7
21 changed files with 490 additions and 34 deletions
204
Email/verify-email.eml.latte
Executable file
204
Email/verify-email.eml.latte
Executable file
|
@ -0,0 +1,204 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Подтверждение Email</title>
|
||||
<link rel="stylesheet" href="foundation.css" />
|
||||
<style>
|
||||
.container {
|
||||
border-top: 5px solid pink;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table class="body" data-made-with-foundation="">
|
||||
<tr>
|
||||
<td class="float-center" align="center" valign="top">
|
||||
<center>
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="container">
|
||||
<tr>
|
||||
<td>
|
||||
<table class="row header">
|
||||
<tr>
|
||||
<th class="small-12 large-12 columns first last">
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h4 class="text-center">Подтверждение Email</h4>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="row">
|
||||
<tr>
|
||||
<th class="small-12 large-12 columns first last">
|
||||
<table class="row">
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<img src="pictures/lock.jpeg" align="center" class="float-center" width=128 height=128 />
|
||||
</center>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr/>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="text-left">
|
||||
Здравствуйте, {$name}! Вы вероятно зарегистрировались на одном из инстансов OpenVK. Чтобы ваш аккаунт активировался, необходимо подтвердить Email.
|
||||
</p>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="button large expand success">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/regFinish?key={rawurlencode($key)}" align="center" class="float-center">Подтвердить Email!</a>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="text-left">
|
||||
Если кнопка не работает, вы можете попробовать скопировать и вставить эту ссылку в адресную строку вашего веб-обозревателя:
|
||||
</p>
|
||||
|
||||
<table class="callout">
|
||||
<tr>
|
||||
<th class="callout-inner primary">
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}" style="color: #000; text-decoration: none;">
|
||||
http://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="text-left">
|
||||
Обратите внимание на то, что эту ссылку нельзя:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Передавать другим людям (даже друзьям, питомцам, соседам, любимым девушкам)</li>
|
||||
<li>Использовать, если прошло более двух дней с её генерации</li>
|
||||
</ul>
|
||||
|
||||
<table class="callout">
|
||||
<tr>
|
||||
<th class="callout-inner alert">
|
||||
<p>
|
||||
Ещё раз <b>обратите внимание</b> на то, что данную ссылку или письмо <b>ни в коем случае нельзя</b> передавать другим людям! Даже если они представляются службой поддержки.<br/>
|
||||
Это письмо предназначено исключительно для одноразового, <b>непосредственного</b> использования владельцем аккаунта.
|
||||
</p>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="text-right">
|
||||
С уважением, овк-тян.
|
||||
</p>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr/>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="text-left">
|
||||
<small>
|
||||
Вы получили это письмо так как кто-то или вы зарегистрировались на инстансе OpenVK. Это не рассылка и от неё нельзя отписаться. Если вы всё равно хотите перестать получать подобные письма, деактивируйте ваш аккаунт.
|
||||
</small>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -48,7 +48,7 @@ ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/ext
|
|||
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
||||
```
|
||||
|
||||
4. Import `install/init-static-db.sql` to **same database** you installed Chandler to
|
||||
4. Import `install/init-static-db.sql` to **same database** you installed Chandler to and import all sqls from `install/sqls` to **same database**
|
||||
5. Import `install/init-event-db.sql` to **separate database**
|
||||
6. Copy `openvk-example.yml` to `openvk.yml` and change options
|
||||
7. Run `composer install` in OpenVK directory
|
||||
|
@ -75,7 +75,7 @@ You may reach out to us via:
|
|||
|
||||
* [Bug-tracker](https://github.com/openvk/openvk/projects/1)
|
||||
* [Ticketing system](https://openvk.su/support?act=new)
|
||||
* Telegram chat: Go to [our channel](https://t.me/openvkch) and open discussion in our channel menu.
|
||||
* Telegram chat: Go to [our channel](https://t.me/openvkenglish) and open discussion in our channel menu.
|
||||
* [Reddit](https://www.reddit.com/r/openvk/)
|
||||
* [Discussions](https://github.com/openvk/openvk/discussions)
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/ext
|
|||
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
||||
```
|
||||
|
||||
4. Импортируйте `install/init-static-db.sql` в **ту же базу данных**, в которую вы установили Chandler
|
||||
4. Импортируйте `install/init-static-db.sql` в **ту же базу данных**, в которую вы установили Chandler, и импортируйте все SQL файлы из папки `install/sqls` в **ту же базу данных**
|
||||
5. Импортируйте `install/init-event-db.sql` в **отдельную базу данных**
|
||||
6. Скопируйте `openvk-example.yml` в `openvk.yml` и измените параметры
|
||||
7. Запустите `composer install` в директории OpenVK
|
||||
|
|
10
Web/Models/Entities/EmailVerification.php
Executable file
10
Web/Models/Entities/EmailVerification.php
Executable file
|
@ -0,0 +1,10 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Entities;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
|
||||
class EmailVerification extends PasswordReset
|
||||
{
|
||||
protected $tableName = "email_verifications";
|
||||
}
|
|
@ -34,12 +34,15 @@ class PasswordReset extends RowModel
|
|||
*/
|
||||
function isNew(): bool
|
||||
{
|
||||
return $this->getRecord()->timestamp > (time() - 301);
|
||||
return $this->getRecord()->timestamp > (time() - (5 * MINUTE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Token is valid only for 3 days.
|
||||
*/
|
||||
function isStillValid(): bool
|
||||
{
|
||||
return $this->getRecord()->timestamp > (time() - 172801);
|
||||
return $this->getRecord()->timestamp > (time() - (3 * DAY));
|
||||
}
|
||||
|
||||
function verify(string $token): bool
|
||||
|
|
|
@ -850,10 +850,10 @@ class User extends RowModel
|
|||
|
||||
function isDeleted(): bool
|
||||
{
|
||||
if ($this->getRecord()->deleted == 1)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
if ($this->getRecord()->deleted == 1)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -883,5 +883,11 @@ class User extends RowModel
|
|||
return $this->getRecord()->website;
|
||||
}
|
||||
|
||||
// ты устрица
|
||||
function isActivated(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->activated;
|
||||
}
|
||||
|
||||
use Traits\TSubscribable;
|
||||
}
|
||||
|
|
33
Web/Models/Repositories/Verifications.php
Executable file
33
Web/Models/Repositories/Verifications.php
Executable file
|
@ -0,0 +1,33 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Entities\EmailVerification;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class Verifications
|
||||
{
|
||||
private $context;
|
||||
private $verifications;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->context = DatabaseConnection::i()->getContext();
|
||||
$this->verifications = $this->context->table("email_verifications");
|
||||
}
|
||||
|
||||
function toEmailVerification(?ActiveRow $ar): ?EmailVerification
|
||||
{
|
||||
return is_null($ar) ? NULL : new EmailVerification($ar);
|
||||
}
|
||||
|
||||
function getByToken(string $token): ?EmailVerification
|
||||
{
|
||||
return $this->toEmailVerification($this->verifications->where("key", $token)->fetch());
|
||||
}
|
||||
|
||||
function getLatestByUser(User $user): ?EmailVerification
|
||||
{
|
||||
return $this->toEmailVerification($this->verifications->where("profile", $user->getId())->order("timestamp DESC")->fetch());
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use Chandler\Session\Session;
|
|||
final class AboutPresenter extends OpenVKPresenter
|
||||
{
|
||||
protected $banTolerant = true;
|
||||
protected $activationTolerant = true;
|
||||
|
||||
function renderIndex(): void
|
||||
{
|
||||
|
|
|
@ -3,9 +3,11 @@ namespace openvk\Web\Presenters;
|
|||
use openvk\Web\Models\Entities\IP;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Entities\PasswordReset;
|
||||
use openvk\Web\Models\Entities\EmailVerification;
|
||||
use openvk\Web\Models\Repositories\IPs;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\Repositories\Restores;
|
||||
use openvk\Web\Models\Repositories\Verifications;
|
||||
use openvk\Web\Util\Validator;
|
||||
use Chandler\Session\Session;
|
||||
use Chandler\Security\User as ChandlerUser;
|
||||
|
@ -16,19 +18,22 @@ use lfkeitel\phptotp\{Base32, Totp};
|
|||
final class AuthPresenter extends OpenVKPresenter
|
||||
{
|
||||
protected $banTolerant = true;
|
||||
protected $activationTolerant = true;
|
||||
|
||||
private $authenticator;
|
||||
private $db;
|
||||
private $users;
|
||||
private $restores;
|
||||
private $verifications;
|
||||
|
||||
function __construct(Users $users, Restores $restores)
|
||||
function __construct(Users $users, Restores $restores, Verifications $verifications)
|
||||
{
|
||||
$this->authenticator = Authenticator::i();
|
||||
$this->db = DatabaseConnection::i()->getContext();
|
||||
|
||||
$this->users = $users;
|
||||
$this->restores = $restores;
|
||||
$this->verifications = $verifications;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
@ -96,6 +101,7 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
$user->setSince(date("Y-m-d H:i:s"));
|
||||
$user->setRegistering_Ip(CONNECTING_IP);
|
||||
$user->setBirthday(strtotime($this->postParam("birthday")));
|
||||
$user->setActivated((int) !OPENVK_ROOT_CONF['openvk']['preferences']['security']['requireEmail']);
|
||||
$user->save();
|
||||
|
||||
if(!is_null($referer)) {
|
||||
|
@ -103,6 +109,18 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
$referer->toggleSubscription($user);
|
||||
}
|
||||
|
||||
if (OPENVK_ROOT_CONF['openvk']['preferences']['security']['requireEmail']) {
|
||||
$verification = new EmailVerification;
|
||||
$verification->setProfile($user->getId());
|
||||
$verification->save();
|
||||
|
||||
$params = [
|
||||
"key" => $verification->getKey(),
|
||||
"name" => $user->getCanonicalName(),
|
||||
];
|
||||
$this->sendmail($user->getEmail(), "verify-email", $params); #Vulnerability possible
|
||||
}
|
||||
|
||||
$this->authenticator->authenticate($chUser->getId());
|
||||
$this->redirect("/id" . $user->getId(), static::REDIRECT_TEMPORARY);
|
||||
}
|
||||
|
@ -253,4 +271,48 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
$this->flashFail("succ", tr("information_-1"), tr("password_reset_email_sent"));
|
||||
}
|
||||
}
|
||||
|
||||
function renderResendEmail(): void
|
||||
{
|
||||
if(!is_null($this->user) && $this->user->identity->isActivated())
|
||||
$this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$user = $this->user->identity;
|
||||
if(!$user || $user->isDeleted() || $user->isActivated())
|
||||
$this->flashFail("err", tr("error"), tr("email_error"));
|
||||
|
||||
$request = $this->verifications->getLatestByUser($user);
|
||||
if(!is_null($request) && $request->isNew())
|
||||
$this->flashFail("err", tr("forbidden"), tr("email_rate_limit_error"));
|
||||
|
||||
$verification = new EmailVerification;
|
||||
$verification->setProfile($user->getId());
|
||||
$verification->save();
|
||||
|
||||
$params = [
|
||||
"key" => $verification->getKey(),
|
||||
"name" => $user->getCanonicalName(),
|
||||
];
|
||||
$this->sendmail($user->getEmail(), "verify-email", $params); #Vulnerability possible
|
||||
|
||||
$this->flashFail("succ", tr("information_-1"), tr("email_sent"));
|
||||
}
|
||||
}
|
||||
|
||||
function renderVerifyEmail(): void
|
||||
{
|
||||
$request = $this->verifications->getByToken(str_replace(" ", "+", $this->queryParam("key")));
|
||||
if(!$request || !$request->isStillValid()) {
|
||||
$this->flash("err", tr("token_manipulation_error"), tr("token_manipulation_error_comment"));
|
||||
$this->redirect("/");
|
||||
} else {
|
||||
$user = $request->getUser();
|
||||
$user->setActivated(1);
|
||||
$user->save();
|
||||
|
||||
$this->flash("success", tr("email_verify_success"));
|
||||
$this->redirect("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use WhichBrowser;
|
|||
abstract class OpenVKPresenter extends SimplePresenter
|
||||
{
|
||||
protected $banTolerant = false;
|
||||
protected $activationTolerant = false;
|
||||
protected $errorTemplate = "@error";
|
||||
protected $user = NULL;
|
||||
|
||||
|
@ -212,6 +213,27 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
$this->template->userTainted = $user->isTainted();
|
||||
|
||||
if($this->user->identity->isDeleted()) {
|
||||
/*
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⠶⠶⣶⠶⠶⠶⠶⠶⠶⠶⠶⠶⢶⠶⠶⠶⠤⠤⠤⠤⣄⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠊⠀⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒⠀⠀⠀⠀⠤⢤⣤⣄⠉⠉⠛⠛⠷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⣰⠟⠀⠀⠀⠀⠀⠐⠋⢑⣤⣶⣶⣤⡢⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣄⡂⠀⠀⠶⢄⠙⢷⣤⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⣸⡿⠚⠉⡀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⢢⠀⠀⡀⣰⣿⣿⣿⣿⣦⡀⠀⠀⠡⡀⢹⡆⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⢀⣴⠏⠀⣀⣀⣀⡤⢤⣄⣠⣿⣿⣿⣿⣻⣿⣿⣷⠀⢋⣾⠈⠙⣶⠒⢿⣿⣿⣿⣿⡿⠟⠃⠀⡀⠡⠼⣧⡀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⢀⣴⣿⢃⡴⢊⢽⣶⣤⣀⠀⠊⠉⠉⡛⢿⣿⣿⣿⠿⠋⢀⡀⠁⠀⠀⢸⣁⣀⣉⣉⣉⡉⠀⠩⡡⠀⣩⣦⠀⠈⠻⣦⡀⠀⠀⠀⠀
|
||||
⠀⢠⡟⢡⠇⡞⢀⠆⠀⢻⣿⣿⣷⣄⠀⢀⠈⠂⠈⢁⡤⠚⡟⠉⠀⣀⣀⠀⠈⠳⣍⠓⢆⢀⡠⢀⣨⣴⣿⣿⡏⢀⡆⠀⢸⡇⠀⠀⠀⠀
|
||||
⠀⣾⠁⢸⠀⠀⢸⠀⠀⠀⠹⣿⣿⣿⣿⣶⣬⣦⣤⡈⠀⠀⠇⠀⠛⠉⣩⣤⣤⣤⣿⣤⣤⣴⣾⣿⣿⣿⣿⣿⣧⠞⠀⠀⢸⡇⠀⠀⠀⠀
|
||||
⠀⢹⣆⠸⠀⠀⢸⠀⠀⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣟⣛⠛⠛⣛⡛⠛⠛⣛⣋⡉⠉⣡⠶⢾⣿⣿⣿⣿⣿⣿⡇⠀⠀⢀⣾⠃⠀⠀⠀⠀
|
||||
⠀⠀⠻⣆⡀⠀⠈⢂⠀⠀⠀⠠⡈⢻⣿⣿⣿⣿⡟⠁⠈⢧⡼⠉⠙⣆⡞⠁⠈⢹⣴⠃⠀⢸⣿⣿⣿⣿⣿⣿⠃⠀⡆⣾⠃⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠈⢻⣇⠀⠀⠀⠀⠀⠀⢡⠀⠹⣿⣿⣿⣷⡀⠀⣸⡇⠀⠀⣿⠁⠀⠀⠘⣿⠀⠀⠘⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠹⣇⠀⠠⠀⠀⠀⠀⠡⠐⢬⡻⣿⣿⣿⣿⣿⣷⣶⣶⣿⣦⣤⣤⣤⣿⣦⣶⣿⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠹⣧⡀⠡⡀⠀⠀⠀⠑⠄⠙⢎⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⢿⡇⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠈⠳⣤⡐⡄⠀⠀⠀⠈⠂⠀⠱⣌⠻⣿⣿⣿⣿⣿⣿⣿⠿⣿⠟⢻⡏⢻⣿⣿⣿⣿⣿⣿⣿⠀⢸⡇⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢮⣦⡀⠂⠀⢀⠀⠀⠈⠳⣈⠻⣿⣿⣿⡇⠘⡄⢸⠀⠀⣇⠀⣻⣿⣿⣿⣿⣿⡏⠀⠸⡇⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢶⣤⣄⡑⠄⠀⠀⠈⠑⠢⠙⠻⢷⣶⣵⣞⣑⣒⣋⣉⣁⣻⣿⠿⠟⠱⠃⡸⠀⣧⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⣷⣄⡀⠐⠢⣄⣀⡀⠀⠉⠉⠉⠉⠛⠙⠭⠭⠄⠒⠈⠀⠐⠁⢀⣿⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠷⢦⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣒⡠⠄⣠⡾⠃⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠷⠶⣦⣤⣭⣤⣬⣭⣭⣴⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
*/
|
||||
Authenticator::i()->logout();
|
||||
Session::i()->set("_su", NULL);
|
||||
$this->flashFail("err", tr("error"), tr("profile_not_found"));
|
||||
|
@ -228,6 +250,17 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
exit;
|
||||
}
|
||||
|
||||
// ето для емейл уже надо (и по хорошему надо бы избавится от повторяющегося кода мда)
|
||||
if(!$this->user->identity->isActivated() && !$this->activationTolerant) {
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@email.xml", [
|
||||
"thisUser" => $this->user->identity,
|
||||
"csrfToken" => $GLOBALS["csrfToken"],
|
||||
"isTimezoned" => Session::i()->get("_timezoneOffset"),
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($this->user->identity->onlineStatus() == 0) {
|
||||
$this->user->identity->setOnline(time());
|
||||
$this->user->identity->save();
|
||||
|
|
19
Web/Presenters/templates/@email.xml
Executable file
19
Web/Presenters/templates/@email.xml
Executable file
|
@ -0,0 +1,19 @@
|
|||
{extends "@layout.xml"}
|
||||
{block title}{_ec_header}{/block}
|
||||
|
||||
{block header}
|
||||
{_ec_header}
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<div class="border-block center">
|
||||
<h4>{_ec_title}</h4>
|
||||
<p>{tr("ec_1", htmlentities($thisUser->getCanonicalName()))|noescape}<br/></p>
|
||||
<p>{_ec_2}</p>
|
||||
<p>
|
||||
<form action="/reg/resend" method="post">
|
||||
<input type="submit" class="button" value="{_ec_resend}">
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
{/block}
|
|
@ -100,7 +100,7 @@
|
|||
<div id="xhead" class="dm"></div>
|
||||
<div class="page_header {if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}page_custom_header{/if}">
|
||||
<a href="/" class="home_button {if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}home_button_custom{/if}" title="{$instance_name}">{$instance_name}</a>
|
||||
<div n:if="isset($thisUser) ? !$thisUser->isBanned() : true" class="header_navigation">
|
||||
<div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation">
|
||||
{ifset $thisUser}
|
||||
<div class="link">
|
||||
<a href="/">{_header_home}</a>
|
||||
|
@ -142,7 +142,7 @@
|
|||
<div class="sidebar">
|
||||
<div class="navigation">
|
||||
{ifset $thisUser}
|
||||
{if !$thisUser->isBanned()}
|
||||
{if !$thisUser->isBanned() XOR !$thisUser->isActivated()}
|
||||
<a href="/edit" class="link edit-button">{_edit_button}</a>
|
||||
<a href="{$thisUser->getURL()}" class="link">{_my_page}</a>
|
||||
<a href="/friends{$thisUser->getId()}" class="link">{_my_friends}
|
||||
|
@ -189,6 +189,8 @@
|
|||
<a n:if="OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['enable'] && $thisUser->getLeftMenuItemStatus('poster')" href="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['link']}" >
|
||||
<img src="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['src']}" alt="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['caption']}" class="psa-poster" style="max-width: 100%; margin-top: 50px;" />
|
||||
</a>
|
||||
{elseif !$thisUser->isActivated()}
|
||||
<a href="/logout?hash={urlencode($csrfToken)}" class="link">{_menu_logout}</a>
|
||||
{else}
|
||||
<a href="/support" class="link">{_menu_support}
|
||||
{if $ticketAnsweredCount > 0}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{block wrap}
|
||||
<div class="page_wrap">
|
||||
<div n:ifset="tabs" class="tabs">
|
||||
<div n:ifset="tabs" n:ifcontent class="tabs">
|
||||
{include tabs}
|
||||
</div>
|
||||
|
||||
|
@ -30,12 +30,12 @@
|
|||
{ifset infotable}
|
||||
{include infotable, x => $dat}
|
||||
{else}
|
||||
<a href="{include link, x => $dat}">
|
||||
<b>
|
||||
{include name, x => $dat}
|
||||
</b>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="{include link, x => $dat}">
|
||||
<b>
|
||||
{include name, x => $dat}
|
||||
</b>
|
||||
</a>
|
||||
<br/>
|
||||
{include description, x => $dat}
|
||||
{/ifset}
|
||||
</td>
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
{block tabs}
|
||||
{if !is_null($thisUser) && $user->getId() === $thisUser->getId()}
|
||||
<div {if !$admin}id="activetabs"{/if} class="tab">
|
||||
<a {if !$admin}id="act_tab_a"{/if} href="/groups{$user->getId()}">
|
||||
<div n:attr='id => ($admin ? false : "activetabs")' class="tab">
|
||||
<a n:attr='id => ($admin ? false : "act_tab_a")' href="/groups{$user->getId()}">
|
||||
{_groups}
|
||||
</a>
|
||||
</div>
|
||||
<div {if $admin}id="activetabs"{/if} class="tab">
|
||||
<a {if $admin}id="act_tab_a"{/if} href="/groups{$user->getId()}?act=managed">
|
||||
<div n:attr='id => (!$admin ? false : "activetabs")' class="tab">
|
||||
<a n:attr='id => (!$admin ? false : "act_tab_a")' href="/groups{$user->getId()}?act=managed">
|
||||
{_managed}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -51,15 +51,15 @@
|
|||
<img src="{$x->getAvatarUrl()}" width="75" alt="Фотография группы" />
|
||||
{/block}
|
||||
|
||||
{block infotable}
|
||||
{block infoTable}
|
||||
<table id="basicInfo" class="ugc-table group_info" cellspacing="0" cellpadding="0" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="label"><span class="nobold">Название: </span></td>
|
||||
<td class="label"><span class="nobold">{_name}: </span></td>
|
||||
<td class="data"><a href="{$x->getURL()}">{$x->getName()}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label"><span class="nobold">Размер:</span></td>
|
||||
<td class="label"><span class="nobold">{_size}:</span></td>
|
||||
<td class="data"><a href="/club{$x->getId()}/followers">{tr("participants", $x->getFollowersCount())}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -89,9 +89,31 @@
|
|||
<input type="hidden" name="act" value="rem" />
|
||||
<input type="hidden" name="id" value="{$x->getId()}" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input style="text-transform: lowercase; border-bottom: none; width: 140px;" type="submit" id="profile_link" value="{_"leave_community"}" />
|
||||
<input style="width: 140px; text-transform: lowercase;" type="submit" id="profile_link" value="{_leave_community}" />
|
||||
</form>
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
{block bottom}
|
||||
{if !is_null($thisUser) && $user->getId() === $thisUser->getId()}
|
||||
<div class="groups_options">
|
||||
<div id="gp_container" style="width: 200px; margin-right: 40px;">
|
||||
<h4>{_open_new_group}</h4>
|
||||
<span>{_open_group_desc}</span>
|
||||
<form action="/groups_create">
|
||||
<button class="button">{_create_group}</button>
|
||||
</form>
|
||||
</div>
|
||||
<div id="gp_container" style="width: 344px;">
|
||||
<h4>{_search_group}</h4>
|
||||
<span>{_search_group_desc}</span>
|
||||
<form action="/search">
|
||||
<input name="type" type="hidden" value="groups">
|
||||
<input name="query" class="header_search_input" value="" style="background: none; width: 155px; padding-left: 3px;">
|
||||
<button class="button">{_search_by_groups}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ services:
|
|||
- openvk\Web\Models\Repositories\Tickets
|
||||
- openvk\Web\Models\Repositories\Messages
|
||||
- openvk\Web\Models\Repositories\Restores
|
||||
- openvk\Web\Models\Repositories\Verifications
|
||||
- openvk\Web\Models\Repositories\Notifications
|
||||
- openvk\Web\Models\Repositories\TicketComments
|
||||
- openvk\Web\Models\Repositories\IPs
|
||||
|
|
|
@ -59,6 +59,10 @@ routes:
|
|||
handler: "Auth->restore"
|
||||
- url: "/restore/internal-finish"
|
||||
handler: "Auth->finishRestoringPassword"
|
||||
- url: "/reg/resend"
|
||||
handler: "Auth->resendEmail"
|
||||
- url: "/regFinish"
|
||||
handler: "Auth->verifyEmail"
|
||||
- url: "/setSID/{slug}"
|
||||
handler: "Auth->su"
|
||||
- url: "/settings"
|
||||
|
|
|
@ -1855,11 +1855,11 @@ body.scrolled .toTop:hover {
|
|||
|
||||
.container_gray .content:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.group_info {
|
||||
padding: 0 0 0 5px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.group_info .label {
|
||||
width: auto !important;
|
||||
|
@ -1876,3 +1876,13 @@ table td[width="120"] {
|
|||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.border-block {
|
||||
box-shadow: inset 0px 0 0px 1px #b6bfca, inset 0px 0 0px 10px #d8dfe7;
|
||||
width: 300px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: 0 auto;
|
||||
}
|
|
@ -231,7 +231,7 @@ return (function() {
|
|||
if(is_dir($gitDir = OPENVK_ROOT . "/.git") && $showCommitHash)
|
||||
$ver = trim(`git --git-dir="$gitDir" log --pretty="%h" -n1 HEAD` ?? "Unknown version") . "-nightly";
|
||||
else
|
||||
$ver = "Build 15";
|
||||
$ver = "Public Technical Preview 3";
|
||||
|
||||
// Unix time constants
|
||||
define('MINUTE', 60);
|
||||
|
|
9
install/sqls/00018-email-verification.sql
Normal file
9
install/sqls/00018-email-verification.sql
Normal file
|
@ -0,0 +1,9 @@
|
|||
ALTER TABLE `profiles` ADD `activated` tinyint(3) NULL DEFAULT '1' AFTER `2fa_secret`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `email_verifications` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`profile` bigint(20) unsigned NOT NULL,
|
||||
`key` char(64) COLLATE utf8mb4_general_nopad_ci NOT NULL,
|
||||
`timestamp` bigint(20) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_nopad_ci;
|
|
@ -35,6 +35,13 @@
|
|||
"password_reset_error" = "An unexpected error occurred while resetting the password.";
|
||||
"password_reset_rate_limit_error" = "You can't do it that often, sorry.";
|
||||
|
||||
"email_sent" = "Mail has been successfully sent.";
|
||||
"email_sent_desc" = "If your email addess exists, you will receive instructions.";
|
||||
"email_error" = "An unexpected error occurred while sending the email.";
|
||||
"email_rate_limit_error" = "You can't do it that often, sorry.";
|
||||
|
||||
"email_verify_success" = "Your Email has been verified. Have a great time!";
|
||||
|
||||
"registration_disabled_info" = "Registration has been disabled by the system administrator. If possible, ask for an invitation from your friend, if he is registered on this site.";
|
||||
"registration_closed" = "Registration is closed.";
|
||||
"invites_you_to" = "<strong>$1</strong> invites you to $2";
|
||||
|
@ -216,6 +223,7 @@
|
|||
"subscriptions" = "Subscriptions";
|
||||
"join_community" = "Join community";
|
||||
"leave_community" = "Leave community";
|
||||
"check_community" = "View community";
|
||||
"min_6_community" = "Name of the group must have more that 6 characters";
|
||||
"participants" = "Participants";
|
||||
"groups" = "Groups";
|
||||
|
@ -233,6 +241,7 @@
|
|||
"only_administrators" = "Only administrators";
|
||||
"website" = "Website";
|
||||
"managed" = "Managed";
|
||||
"size" = "Size";
|
||||
|
||||
"administrators_one" = "$1 administrator";
|
||||
"administrators_other" = "$1 administrators";
|
||||
|
@ -265,6 +274,10 @@
|
|||
"groups_one" = "$1 group";
|
||||
"groups_other" = "$1 groups";
|
||||
|
||||
"groups_list_zero" = "You are not a participant in any group";
|
||||
"groups_list_one" = "You are participating in one group";
|
||||
"groups_list_other" = "You are a participant of $1 groups";
|
||||
|
||||
"meetings_zero" = "No meetings";
|
||||
"meetings_one" = "$1 meeting";
|
||||
"meetings_other" = "$1 meetings";
|
||||
|
@ -655,6 +668,14 @@
|
|||
"banned_2" = "And the reason for this is simple: <b>$1</b>. Unfortunately, this time we had to block you forever.";
|
||||
"banned_3" = "You can still <a href=\"/support?act=new\">write to the support</a> if you think there was an error or <a href=\"/logout?hash=$1\">logout</a>.";
|
||||
|
||||
/* Registration confirm */
|
||||
|
||||
"ec_header" = "Registration confirmation";
|
||||
"ec_title" = "Thanks!";
|
||||
"ec_1" = "<b>$1</b>, your registration is almost done. In a few minutes you should receive an mail with a link to confirm your email address.";
|
||||
"ec_2" = "If for some reason you don't get the mail, check your spam folder. If you don't find the email there, you can resend it.";
|
||||
"ec_resend" = "Resend mail";
|
||||
|
||||
/* Discussions */
|
||||
|
||||
"discussions" = "Discussions";
|
||||
|
|
|
@ -36,6 +36,13 @@
|
|||
"password_reset_error" = "Непредвиденная ошибка при сбросе пароля.";
|
||||
"password_reset_rate_limit_error" = "Нельзя делать это так часто, извините.";
|
||||
|
||||
"email_sent" = "Письмо было успешно отправлено.";
|
||||
"email_sent_desc" = "Если ваш электронный адрес существует, вы получите письмо.";
|
||||
"email_error" = "Непредвиденная ошибка при отправке письма.";
|
||||
"email_rate_limit_error" = "Нельзя делать это так часто, извините.";
|
||||
|
||||
"email_verify_success" = "Ваш Email был подтверждён. Приятного времяпрепровождения!";
|
||||
|
||||
"registration_disabled_info" = "Регистрация отключена системным администратором. При возможности попросите приглашение у вашего знакомого, если он зарегистрирован на этом сайте.";
|
||||
"registration_closed" = "Регистрация закрыта.";
|
||||
"invites_you_to" = "<strong>$1</strong> приглашает вас в $2";
|
||||
|
@ -243,6 +250,7 @@
|
|||
"only_administrators" = "Только администраторы";
|
||||
"website" = "Сайт";
|
||||
"managed" = "Управляемые";
|
||||
"size" = "Размер";
|
||||
|
||||
"administrators_one" = "$1 администратор";
|
||||
"administrators_few" = "$1 администратора";
|
||||
|
@ -695,6 +703,14 @@
|
|||
"banned_2" = "А причина этому проста: <b>$1</b>. К сожалению, на этот раз нам пришлось заблокировать вас навсегда.";
|
||||
"banned_3" = "Вы всё ещё можете <a href=\"/support?act=new\">написать в службу поддержки</a>, если считаете что произошла ошибка или <a href=\"/logout?hash=$1\">выйти</a>.";
|
||||
|
||||
/* Registration confirm */
|
||||
|
||||
"ec_header" = "Подтверждение регистрации";
|
||||
"ec_title" = "Спасибо!";
|
||||
"ec_1" = "<b>$1</b>, ваша регистрация почти закончена. В течении нескольких минут на ваш адрес E-mail должно прийти письмо с ссылкой для подтверждения вашего адреса почты.";
|
||||
"ec_2" = "Если по каким-то причинам вам не пришло письмо, то проверьте папку Спам. Если письма не окажется и там, то вы можете переотправить письмо.";
|
||||
"ec_resend" = "Переотправить письмо";
|
||||
|
||||
/* Discussions */
|
||||
|
||||
"discussions" = "Обсуждения";
|
||||
|
|
Loading…
Reference in a new issue