Что-то давно я ничего сюда не писал, все никак не было времени. Итак, цель была поставлена написать что-нибудь не сложное, но полезное в рамках изучения технологий. То с чем можно будет податься хотя бы в джуны. Начало этой статьи лежит тут , после чего можно заглянуть в эту статью, где расписано как безопасно запустить rest-сервер от root. В итоге я пришел к тому, что решил отказаться от собственной базы данных в пользу firebase, о чем написал в этой статье. Все прошло вполне себе гладко за счет функционального стиля. Т.е. фактически мне пришлось всего лишь изменить функцию, возвращающую данные из базы и не важно что SQL база вдруг стала NoSQL. Также в рамках безопасности было применено шифрование паролей от email в firebase, об основных принципах можно почитать здесь.
Возвращаясь к разработке, была у меня цель выучить какой-нибудь полезный фреймворк на javascript. Я пошерстил вакансии и наиболее популяерные фреймворки и обратил внимания на два: Angular и ReactJS. Выбор же мой пал именно на последний. Почему это так: у нас в компании есть проект на Angular (в общем-то его фактически повесили на меня, но я им не занимаюсь. это согласовано). Так вот это очень глючный проект. Понятное дело, что проблема не в фреймворке, а в том кто его использовал (это уже стало дурной концепцией вешать на меня проекты фактически без документации. мол, вот тебе исходники — разбирайся как хочешь. по-крайней мере это уже третий, но предыдущими двумя мне приходится заниматься). Так вот посмотрев на эти глюки Angular мне явно не симпатизировал. К тому же, ReactJS это чистый view-фреймворк, что меня более чем устраивало. Хорошим плюсом было еще и возможность написать приложение на React Native под мобильный девайс (на будущее). Ну а учитывая наличие огромного числа библиотек для фоновых задач, смысл использования фреймворка для фона я пока не усмотрел. Была идея хватануть сразу связку React-Redux, но на тот момент это было сложной задачей, так что начал с малого — React + Store в компонентах + EventEmitter для связки Store между собой и с фоновыми функциями. Вышло интересно.
Исходники проекта есть на github (возможно я и стану его дорабатывать, но пока я свою цель выполнил, изучив React, EventEmitter, отточив работу с firebase, rest-запросами. бонусом научился работать с github).
Сам же проект можно глянуть тут: https://vpn.sergdudko.tk зайдя под тестовым пользователем или попросив у меня логин и пароль для теста. Для того, чтобы у вас была адекватная возможность доработки проекта (по желанию), исходники в чистом виде, в том числе не скомпилированный babel-ем view на reactjs.
Интересности, которые были решены в рамках проекта:
- Если сделать блок в центре экрана, при этом для мобильных устройств сделать трансформ (CSS) для этого блока, то он занимает 100% экрана мобильного девайса, что на мой взляд почти гениальное решение оптимизации под мобильные девайсы.
- Если нужно заблокировать страничку на время выполнения асинхронного запроса, нужно создать блок с индексом z (CSS) выше основного. Делать этот блок видимым при отправке запроса и невидимым, при получении ответа. Получается некое подобие загрузки. Выглядит красиво, конечно это только картинка. Т.е. технически нужно предусмотреть все же, что этот блок не выведется и пользователь продолжит тыркать кнопочки.
- Для того чтобы текст на кнопках не выделялся (и не только кнопках), в CSS есть классное свойство user-select: none c префиксом типа браузера, т.к. оно не стандартное. Получается подобие реальной кнопки.
- Ну и конечно порадовал сам React, для одностраничных приложений это, на мой взгляд, почти идеальное решение. Захотелось переписать на него половину рабочих проектов (т.е. если вы взглянете на мои извороты для препроводительной ведомости, то все поймете)
- В качестве уже какой-то наркомании, придумал как перезагружать страничку с http на https методом javascript:
1 2 3 4 5 6 7 |
var tenyears = new Date(new Date().getTime() + 10 * 365 * 24 * 60 * 60 * 1000); document.cookie = "SSL=true; path=/; expires=" + tenyears.toUTCString() + ";secure"; if(getCookie("SSL") != "true"){ this.location = "https://"+this.location.hostname; } |
Ну и немного о настройках Firebase:
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "rules": { ".read": false, ".write": false, "$uid":{ ".read": "((auth.uid == $uid) && (auth.token.email_verified == true))", ".write": "((auth.uid == $uid) && (auth.email != 'testuser@sergdudko.tk') && (auth.token.email_verified == true))" }, ".indexOn": ["adminmail", "server"] } } |
Пара скриншотов:
Дабы не переписывать по сто раз одно и тоже, приведу документацию с Github:
Surname Web Panel (dwpanel)
Приложение для работы (развертывание и обслуживание) с openvpn на CentOS 7.x сервере.
Пример можно посмотреть на сайте проекта.
Для пользователя testuser@sergdudko.tk запись в FIREBASE ограничена настройками базы данных.
Пакетная установка
rpm —import https://vpn.sergdudko.tk/releases/RPM-GPG-KEY-SERGDUDKOTK
rpm -ivh https://vpn.sergdudko.tk/releases/dwpanel-2.5.0-2.noarch.rpm
rpm —import https://raw.githubusercontent.com/namedudko/dwpanel/master/releases/RPM-GPG-KEY-SERGDUDKOTK
rpm -ivh https://raw.githubusercontent.com/namedudko/dwpanel/master/releases/dwpanel-2.5.0-2.noarch.rpm
Ручная установка
Обязательные пакеты: php (5 или 7), php-mcrypt, curl, zip, openvpn, easy-rsa (версия 2, есть в ../install)
Рекомендуемые пакеты: firewalld
- Очистить каталог /etc/openvpn/:
1 2 |
rm -rf /etc/openvpn/* |
- Создать каталоги:
1 2 3 |
mkdir -p /etc/openvpn/scripts/ mkdir -p /var/dwpanel/ |
- Скопировать файлы:
1 2 3 4 5 |
cp -R .../backend/scripts/* /etc/openvpn/scripts/ cp -R .../frontend/* /var/dwpanel/ cp .../backend/bin/dwpanel /usr/bin/dwpanel cp .../backend/unit/dwpanel-server.service /etc/systemd/system/dwpanel-server.service |
- Запустить внутренний сервер приложения:
1 2 3 4 |
systemctl daemon-reload systemctl start dwpanel-server systemctl enable dwpanel-server |
- Настроить firewalld. Порт 999 должен быть открыт только для localhost, т.к. на нем крутится внутренний сервер от root. Порты 1700-1954 для 255 VPN серверов (13.0.0.0 — 13.254.0.0). Порт 443 для внешнего web-сервера.
1 2 3 4 5 6 7 |
firewall-cmd --zone=trusted --add-interface=lo firewall-cmd --zone=public --add-interface=eth0 firewall-cmd --permanent --zone=public --add-port=443/tcp firewall-cmd --permanent --zone=public --add-port=1700-1954/tcp firewall-cmd --permanent --zone=trusted --add-port=999/tcp firewall-cmd --reload |
- Настроить ваш веб-сервер на папку /var/dwpanel
Работа с консолью через команду dwpanel. Обязательные аргументы (порядок не важен) для dwpanel
Добавление/Удаление сервера:
1 2 3 4 |
build:server server:1(численный номер сервера) com:add или remove(добавить или удалить соответственно) |
Добавление/Удаление сертификатов клиента:
1 2 3 4 5 6 |
build:client server:1(численный номер сервера) com:add или remove(добавить или удалить соответственно) client:1(численный номер клиентского сертификата) email:test@sergdudko.tk(клиентское мыло, можно не указывать при удалении) |
Отправка сертификатов на email:
1 2 3 4 5 |
send:toemail server:1(численный номер сервера) client:1(численный номер клиентского сертификата) email:test@sergdudko.tk(клиентское мыло) |
Настройка подключения к FIREBASE
1 2 3 4 5 6 7 |
-settings db_key:token(токен проекта firebase) db_projectname:projectname(имя проекта firebase) db_user:user(пользователь БД) db_pass:password(пароль пользователя БД) encoding:Europe/Minsk(таймзона) |
Работа с внутренним/внешним веб-сервером. Обязательные аргументы (порядок не важен) для json:
type: POST format: RAW Content-Type: application/json url: https://адрес_вашего_сайта/core-web-ctrl.php Запросы аналогично для dwpanel.
Для работы внешнего веб-сервера скопировать настроить ваш веб-сервер на папку /var/dwpanel/
Создание сервера OpenVPN:
1 2 3 4 5 6 7 8 9 |
{ "build":"server", "com":"add", "server":"0", "auth":{ "username":"user", "password":"password" } } |
Удаление сервера OpenVPN:
1 2 3 4 5 6 7 8 9 |
{ "build":"server", "com":"remove", "server":"0", "auth":{ "username":"user", "password":"password" } } |
Создание сертификатов клиента:
1 2 3 4 5 6 7 8 9 10 11 |
{ "build":"client", "com":"add", "server":"0", "email":"admin@sergdudko.tk", "client":"1", "auth":{ "username":"user", "password":"password" } } |
Удаление сертификатов клиента:
1 2 3 4 5 6 7 8 9 10 |
{ "build":"client", "com":"remove", "server":"0", "client":"1", "auth":{ "username":"user", "password":"password" } } |
Отправка сертификатов на email:
1 2 3 4 5 6 7 8 9 10 |
{ "send":"toemail", "email":"admin@sergdudko.tk", "server":"0", "client":"1", "auth":{ "username":"user", "password":"password" } } |
ТОЛЬКО ДЛЯ ОТЛАДКИ
создание и удаление сервера
1 2 3 |
php /etc/openvpn/scripts/build_server.php --args -add 1 php /etc/openvpn/scripts/build_server.php --args -remove 1 |
создание и удаление сертификатов клиента
1 2 3 |
php /etc/openvpn/scripts/build_client.php --args -add 1 1 test@email.by php /etc/openvpn/scripts/build_client.php --args -remove 1 1 test@email.by |
отправка сертификатов клиента на email
1 2 |
php /etc/openvpn/scripts/cert_send_toemail.php --args 1 1 test@sergdudko.tk |
UPDATE
version 2.1.0
- В запросах изменилась авторизация
1 2 3 4 5 |
"auth":{ "username":"user", "password":"password" } |
1 2 3 |
user - md5 имени пользователя БД password - md5 пароля пользователя БД |
- При запросе пароля на электронную почту теперь используется шифрование, пароль в базе хранится в зашифрованном виде. Ключевое слово для декриптора состоит из учетных данных пользователя, при смене пароля к БД — пароли к email перестанут дешифроваться.
- Получение статуса сервера запросом:
1 2 3 4 5 6 7 8 9 |
{ "status":{ "server":"0" }, "auth":{ "username":"user", "password":"password" } } |
1 2 |
где 0 - номер сервера. |
- Реализована панель управления на javascript (фреймворк react), требует https для работы с бэкэндом (работа с базой данных доступна и в http режиме).
Панель управления поддерживает:
- авторизацию пользователя в firebase по учетным данным
- создание настроек сервера в базе данных
- редактирование настроек сервера в базе данных
- удаление настроек сервера в базе данных (ВНИМАНИЕ: при удалении весь пуль сдвигается и потребуется пересоздание всех серверов с id равному или выше, чем удаляемый)
- создание и редактирование настроек email для отправки сертификатов
- создание VPN-сервера (запрос к бэкэнду)
- удаление VPN-сервера (запрос к бэкэнду)
- создание клиентского сертификата (запрос к бэкэнду)
- удаление клиентского сертификата (запрос к бэкэнду)
- отправка клиентского сертификата на email (запрос к бэкэнду)
- получение статуса VPN-сервера (запрос к бэкэнду)
version 2.1.1
- Доработана верстка:
- увеличен размер уведомлений для мобильных девайсов
- увеличен размер слоя блокировки (при запросах) до 100% на мобильных девайсах
- Добавлена регистрация пользователя при новой установке:
- пользователь по умолчанию «testuser@sergdudko.tk«
- пароль по умолчанию «password»
- Доработана смена имени пользователя и пароля json-запросом, теперь пароль летает в зашифрованном виде.
- Отныне в сборке будет присутствовать RPM-пакет и GPG-ключ
version 2.2.0
- Немного доработана верстка
- В форму регистрации теперь автоматически подставляется адрес хоста
- Добавлена папка install с скриптами установки (протестировано на чистой сборке CentOS-7-x86_64-Minimal-1611.iso)
- В проект добавлен easy-rsa 2.2.2 (т.к. из стандартного репозитория устанавливается easy-rsa 3, поддержку которого пока не реализовал)
- Добавлено настройка selinux
- Добавлена настройка firewalld
- Добавлена ТЕСТОВАЯ настройка httpd на 443 порт на папку /var/dwpanel
- Реализован диалог с пользователем перед установкой (какие системные компоненты трогать, какие нет)
version 2.5.0
- Клиентская часть переписана под react 16.2.0
- Код клиентской части переписан с ES5 на ES6
- Обновлены внешние библиотеки клиентской части