Пишем клиент для Голос в связке с CMS Joomla
Да, вы угадали, на связи @captain. У меня есть один проект, которому скоро исполнится уже год. Это альтернативный веб-клиент Голоса. Сначала я за него взялся с огоньком, но потом поостыл - ребенок родился, я несколько отошел от голоса. Вернулся к нему в начале осени, но потом переключился на торговую площадку https://golos.world и клиент как-то заглох. Сразу скажу, что это не убийца https://golos.io или GoldVoice. Это просто мое прочтение того, как должен выглядеть удобный мне сайт. Но нас интересует именно код, программные решения. Именно о них я и расскажу в серии своих статей. И надеюсь, что их кульминацией таки будет запуск клиента.
Разработка ведется на PHP, JS (и jQuery) и HTML(Bootstrap). Для каркаса сайта я использую Joomla, но это совершенно не обязательный элемент. К ней будет привязана только авторизация и система меню. Итогом будет не только веб клиент в сети Интернет, но и локальный клиент, который не будет зависеть от каких-либо серверов, а сможет запускаться с компьютера (хоть с флешки) локально.
До чего-то я дошел сам в процессе разработки, что-то подсмотрел у других, что-то выпытал в чатах.
Фигура первая. Подготовка и начало работы.
Нам нужно будет подключить к сайту библиотеку JS API Golos. Взять ее можно тут: https://github.com/GolosChain/golos-js
Также понадобится jQuery (да, я старомоден), хотя можно и без этого обойтись. Например, так:
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
И подключим Bootstrap 3
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
Еще раз повторюсь - можете подключать это к пустой html странице, можете к расширению для какого-то фреймворка или CMS, особой разницы нет. Итак, у нас все готово для начала работы.
Фигура вторая. Авторизация, хранение данных об авторизации, регистрация.
В данном случае у нас будет немного специфическое для Joomla решение. Но, в целом, это можно применить и для любой другой CMS, если вы умеете добавлять пользователей программно.
Делаем простую форму входа:
<form action="/index.php?option=com_greg&task=save" method="post" id="adminForm" class="form-validate col-sm-10 col-sm-offset-1">
<div class="form-group1">
<label for="login" style="color: white;">Логин GOLOS<span style="color: red;">*</span> </label>
<div class="input-group">
<div class="input-group-addon">@</div>
<input type="text" class="form-control required" id="login" name="login" onblur="checkLogin(this.value);" required="required">
</div>
</div>
</div>
<div class="form-group1">
<label for="key" style="color: white;">Постинг ключ</label> <span style="color: red;">*</span>
<input type="password" class="form-control required" id="key" name="key" placeholder="Начинается с 5" required="required">
</div>
<br>
<div class="center" style="text-align: center;">
<input type="hidden" name="ok" id="ok" value="false">
<input type="button" class="btn btn-primary" value="Войти" onclick="if(!storeKeyLocally()){return false;};this.form.submit();">
</div>
</form>
Посмотреть на pastebin
В эту форму пользователь должен ввести свой логин и приватный постинг ключ. Как видите, тут вызывается JS функция storeKeyLocally()
перед отправкой формы. Она нужна для проверки ключа пользователя и сохранения его в localStorage
браузера. А при вводе логина он проверяется функцией checkLogin(this.value);
Вот эти функции
function checkLogin(login)
{
golos.api.getAccounts([login], function(err, response){
if(response == '')
{
document.getElementById('login').value = '';
return false;
}
return true;
});
}
function storeKeyLocally()
{
var login = document.getElementById("login").value;
var key = document.getElementById("key").value;
if(key && login)
{
localStorage.setItem(login, sjcl.encrypt(login, key));
localStorage.setItem('login', login);
return true;
}
else
{
return false;
}
}
Посмотреть на pastebin
В функции storeKeyLocally
мы используем библиотеку шифрования, она подключается вот так:
<script src="https://cdnjs.cloudflare.com/ajax/libs/sjcl/1.0.7/sjcl.min.js" type="text/javascript"></script>
В этой функции мы сохраняем логин. А также мы сохраняем приватный ключ, зашифрованный логином пользователя.
После отправки формы она обрабатывается на сервере. Нам нужно будет занести пользователя в БД и сохранить хэш от его пароля. Это зависит конкретно от вашего фреймворка. Для Joomla это будет вот такой код в контроллере вашего компонента регистрации:
$app = JFactory::getApplication();
$filter = JFilterInput::getInstance();
$username = $filter->clean( $app->input->getUsername('login', '') );
$password = $app->input->getVar('key');
$email = $username . '@golos.world'; // так как email у нас нет
$db = JFactory::getDBO();
$query = "select count(*) from `#__users` where email = '$email'";
$result = $db->setQuery($query);
$n = $db->loadResult();
if($n > 0) // пользователь существует
{
$credentials = array( 'username'=> $username, 'password'=> $password );
//В этом массиве параметры авторизации! в данном случае это установка запоминания пользователя
$options = array( 'remember'=>true );
//выполняем авторизацию
if( JFactory::getApplication()->login( $credentials, $options )){
$url = JRoute::_( '/' );
JControllerLegacy::setRedirect( $url, '');
return true;
}
else
{
JError::raiseWarning('', 'Неверно указаны данные для входа');
return false;
}
}
//добавляем пользователя
$data = array();
$data['name'] = $username;
$data['username'] = $username;
$data['email'] = $email;
$data['email1'] = $email;
$data['password'] = $password;
$data['password1'] = $password;
$data['password2'] = $password;
$data['password_clear'] = $password;
$data['sendEmail'] = 0;
$activation = $this->registerUser($data);
if($activation)
{
$query = "update `#__users` set block = 0, activation = '' where email = '$email'";
$result = $db->setQuery($query);
$result = $db->execute();
$query = "select * from `#__users` where email = '$email'";
$result = $db->setQuery($query);
$user = $db->loadObject();
$credentials = array( 'username' => $username, 'password' => $password );
$options = array( 'remember' => true );
if( JFactory::getApplication()->login( $credentials, $options )){
$url = JRoute::_( '/' );
JControllerLegacy::setRedirect( $url, '');
return true;
}
}
else
{
$message = 'Проблемы при входе...';
JFactory::getApplication()->enqueueMessage($message, 'error');
return false;
}
Посмотреть на pastebin
Для тех кто использует Joomla. Здесь использована функция registerUser, которая во многом повторяет соответствующую функцию компонента com_users, но из нее вырезана отправка активации пользователю и т.п.
Нужно отметить и еще один важный момент. На данном этапе, мы сознательно не используем login.api голоса. Все же доступ стороннего приложения к активному ключу это значительный риск. Это значит, что если пользователь сменил ключи, то для авторизации ему нужно будет обновить ключ. То есть, в клиенте нужно предусмотреть вход со старым постинг-ключом и замену его на новый.
Ну вот и все пока что, мы научились авторизовывать и регистрировать пользователя на нашем сайте. При этом мы не храним его постинг ключ, он хранится локально в браузере пользователя.
И немного пиара. @captain это делегат голоса. Вот его делегатский пост https://golos.io/@captain/post-delegata-captain/
@captain много чего делает для голоса и много чего еще сделает. Поэтому не поленитесь и проголосуйте за него тут https://golos.io/~witnesses или тут https://goldvoice.club/witnesses/