<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Криптовалютний підвал програміста</title><subtitle>Канал де я кидаю всякі криптовалютні темки, проги, баги і так далі.
Автор: @rostcraft</subtitle><author><name>Криптовалютний підвал програміста</name></author><id>https://teletype.in/atom/cryptopidval</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/cryptopidval?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/cryptopidval?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-22T08:37:49.319Z</updated><entry><id>cryptopidval:blum-drop-game</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/blum-drop-game?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Burp Suite ламає ігри або абузимо blum drop game</title><published>2024-07-05T16:17:57.923Z</published><updated>2024-07-05T16:18:12.394Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/10/89/1089a31b-9ca8-4659-8cd3-3913f681c6e9.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/67/46/67461b87-e46d-42ee-acdc-b869dc2c7303.png&quot;&gt;В blum якийсь час вже є drop game і я згадавши сьогодні про цю гру я вирішив її поламати.
(Через певні тести зроблені  мною в процесі написання цієї статті мене можливо забанять з Blum, раджу вам бути обережними якщо вам не байдуже на цей проект)</summary><content type="html">
  &lt;p id=&quot;8bc7&quot;&gt;В blum якийсь час вже є drop game і я згадавши сьогодні про цю гру я вирішив її поламати.&lt;br /&gt;(Через певні тести зроблені  мною в процесі написання цієї статті мене можливо забанять з Blum, раджу вам бути обережними якщо вам не байдуже на цей проект)&lt;/p&gt;
  &lt;h3 id=&quot;cE2r&quot;&gt;Як це роблять зазвичай&lt;/h3&gt;
  &lt;p id=&quot;cFB8&quot;&gt;Більшість людей запускають просто клікер і радіють життю, але в нашому підвалі клікери не те щоб вітаються(мені лінь їх кодити). &lt;/p&gt;
  &lt;h3 id=&quot;Uaor&quot;&gt;План&lt;/h3&gt;
  &lt;ol id=&quot;1BnT&quot;&gt;
    &lt;li id=&quot;KmQR&quot;&gt;Через Burp Suite перехопити запити зроблені Blum.&lt;/li&gt;
    &lt;li id=&quot;IdQZ&quot;&gt;Поміняти в запиті на зміну рахунку кількість поінтів.&lt;/li&gt;
    &lt;li id=&quot;sjkv&quot;&gt;Автоматизувати кидання таких запитів через скрипт.&lt;/li&gt;
    &lt;li id=&quot;PIMU&quot;&gt;Профіт&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h3 id=&quot;P0BP&quot;&gt;Виконання плану(або ж основна частина статті)&lt;/h3&gt;
  &lt;p id=&quot;ykUS&quot;&gt;Я вирішив перехоплювати запити з мобільного девайсу.&lt;br /&gt;Для цього треба додати сертифікат з Burp Suite на ваш девайс(так само як зазвичай, але можливо доведеться поміняти формат сертифікату для чого існує &lt;a href=&quot;https://www.openssh.com/&quot; target=&quot;_blank&quot;&gt;openssh&lt;/a&gt;).&lt;br /&gt;Також в самому Burp треба в налаштуваннях проксі додати ваш локальний айпі як доступний для використання(нижче скріншоти з тим як це робити).&lt;br /&gt;&lt;/p&gt;
  &lt;figure id=&quot;EdIB&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/67/46/67461b87-e46d-42ee-acdc-b869dc2c7303.png&quot; width=&quot;966&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;g8HD&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/39/5f/395f5c29-1fe6-49e1-9dea-dcd843e09db4.png&quot; width=&quot;1362&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;09E5&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/60/c4/60c4c5a3-16df-402f-a254-55456b1f9bd0.png&quot; width=&quot;759&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;bBdC&quot;&gt;Тепер перехопивши запити ми можемо помітити два цікавих для нас запити на адреси &lt;code&gt;game-domain.blum.codes/api/v1/game/play&lt;/code&gt; та &lt;code&gt;game-domain.blum.codes/api/v1/game/claim&lt;/code&gt;.&lt;br /&gt;Структура запитів максимально проста, перший запит має лише хедери авторизації і у відповідь ми отримуємо gameId.&lt;br /&gt;В другому надісланні данні складаються з цього самого gameId та поінтів.&lt;br /&gt;Таким чином ми можемо просто відправляти ці запити і вказувати потрібну кількість поінтів.&lt;/p&gt;
  &lt;p id=&quot;NGRi&quot;&gt;Ось невеличкий PoC(proof of concept) скрипт на rust який це робить.&lt;br /&gt;Цей скрипт схожий на скрипт зі &lt;a href=&quot;https://teletype.in/@cryptopidval/tonpokerwheel&quot; target=&quot;_blank&quot;&gt;статті про tonpoker wheel&lt;/a&gt;, частина речей пояснена трохи більш детально там.&lt;br /&gt;Для початку dependencies з Cargo.toml(версії бібліотек тут найновіші, не обов&amp;#x27;язково використовувати саме ці)&lt;/p&gt;
  &lt;pre id=&quot;ShAy&quot; data-lang=&quot;toml&quot;&gt;[dependencies]
rand = &amp;quot;0.8.5&amp;quot;
reqwest = { version = &amp;quot;0.12.5&amp;quot;, features = [&amp;quot;json&amp;quot;] }
serde = { version = &amp;quot;1.0.203&amp;quot;, features = [&amp;quot;derive&amp;quot;] }
tokio = { version = &amp;quot;1.38.0&amp;quot;, features = [&amp;quot;full&amp;quot;] }&lt;/pre&gt;
  &lt;pre id=&quot;oqfX&quot; data-lang=&quot;rust&quot;&gt;use rand::Rng;
use reqwest::header::HeaderMap;
use reqwest::{self, StatusCode};
use serde::{Deserialize, Serialize};
use std::time::Duration;&lt;/pre&gt;
  &lt;p id=&quot;YvVY&quot;&gt;Імпортуємо потрібні функції з бібліотек.&lt;/p&gt;
  &lt;pre id=&quot;f5Sk&quot; data-lang=&quot;rust&quot;&gt;#[derive(Serialize, Deserialize, Debug)]
struct GameClaimRequest {
    gameId: String,
    points: i32,
}

#[derive(Serialize, Deserialize, Debug)]
struct GamePlayResponse {
    gameId: String,
}&lt;/pre&gt;
  &lt;p id=&quot;RQCs&quot;&gt;Структури для нашого запиту на клейм та для відповіді на наш запит на початок гри.&lt;/p&gt;
  &lt;pre id=&quot;VADP&quot; data-lang=&quot;rust&quot;&gt;#[tokio::main]
async fn main() {
    let repeat_count = 1;
    let min_points = 350;
    let max_points = 450;
    let auth_token = &amp;quot;&amp;quot;;
    let wait_duration = Duration::from_secs(31);&lt;/pre&gt;
  &lt;p id=&quot;SOtb&quot;&gt;Початок основної функції, вказуємо кількість повторів, мінімальну кількість поінтів для рандмому і максимальну, токен авторизації, який можна взяти з burp suite і час очікування(blum наче як вимагає 30 секунд, ставимо 31 секунду для безпеки).&lt;br /&gt;&lt;/p&gt;
  &lt;figure id=&quot;LyUH&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5e/77/5e77a1d7-78e3-4561-888d-c539987039ad.png&quot; width=&quot;1065&quot; /&gt;
    &lt;figcaption&gt;Червоним закритий токен який і треба скопіювати&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;pre id=&quot;M2e0&quot; data-lang=&quot;rust&quot;&gt;let mut rng = rand::thread_rng();
let client = reqwest::Client::new();
let mut headers = HeaderMap::new();
headers.insert(
    &amp;quot;accept&amp;quot;,
    &amp;quot;application/json, text/plain, */*&amp;quot;.try_into().unwrap(),
);
headers.insert(
    &amp;quot;authorization&amp;quot;,
    format!(&amp;quot;Bearer {}&amp;quot;, auth_token).try_into().unwrap(),
);
headers.insert(&amp;quot;sec-fetch-site&amp;quot;, &amp;quot;same-site&amp;quot;.try_into().unwrap());
headers.insert(&amp;quot;accept-encoding&amp;quot;, &amp;quot;gzip, deflate, br&amp;quot;.try_into().unwrap());
headers.insert(&amp;quot;accept-language&amp;quot;, &amp;quot;en-GB,en;q=0.9&amp;quot;.try_into().unwrap());
headers.insert(&amp;quot;sec-fetch-mode&amp;quot;, &amp;quot;cors&amp;quot;.try_into().unwrap());
headers.insert(&amp;quot;origin&amp;quot;, &amp;quot;https://telegram.blum.codes&amp;quot;.try_into().unwrap());
headers.insert(
    &amp;quot;user-agent&amp;quot;,
    &amp;quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)&amp;quot;
        .try_into()
        .unwrap(),
);
headers.insert(&amp;quot;sec-fetch-dest&amp;quot;, &amp;quot;empty&amp;quot;.try_into().unwrap());&lt;/pre&gt;
  &lt;p id=&quot;V9FV&quot;&gt;Ініціалізуємо рандом, reqwest, і ставимо хедери(скопіювані з Burp Suite).&lt;br /&gt;Оскільки значення хедерів мають тип HeaderValue то ми можемо використати try_into щоб конвертувати значення в цей тип і unwrap який закінчує виконання помилкою якщо не виникає помилка конвертації.&lt;br /&gt;Почитати про try_into можна &lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/conversion/try_from_try_into.html&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt; або &lt;a href=&quot;https://doc.rust-lang.org/std/convert/trait.TryInto.html&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;.&lt;br /&gt;Про unwrap &lt;a href=&quot;https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#shortcuts-for-panic-on-error-unwrap-and-expect&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;.&lt;/p&gt;
  &lt;pre id=&quot;ZWaH&quot; data-lang=&quot;rust&quot;&gt;for _ in 0..repeat_count {
    let req = client
        .post(&amp;quot;https://game-domain.blum.codes/api/v1/game/play&amp;quot;)
        .headers(headers.clone())
        .send()
        .await
        .unwrap();&lt;/pre&gt;
  &lt;p id=&quot;uoab&quot;&gt;Починаємо цикл для використання наших тікетів.&lt;br /&gt;Запитуємо початок гри у сервера і отримуємо gameId.&lt;/p&gt;
  &lt;pre id=&quot;fJpv&quot; data-lang=&quot;rust&quot;&gt;let status = req.status();
match status {
    StatusCode::OK =&amp;gt; {
        let deserialized = req.json::&amp;lt;GamePlayResponse&amp;gt;().await;&lt;/pre&gt;
  &lt;p id=&quot;ljnw&quot;&gt;У випадку якщо статус запиту 200(OK) то десеріалізуємо відповідь на запит в нашу структуру.&lt;/p&gt;
  &lt;pre id=&quot;mcfc&quot; data-lang=&quot;rust&quot;&gt;match deserialized {
    Ok(deserialized) =&amp;gt; {
        println!(&amp;quot;Got game id: {}&amp;quot;, deserialized.gameId);
        println!(&amp;quot;Sleeping for {}ms&amp;quot;, wait_duration.as_millis());
        tokio::time::sleep(wait_duration).await;
        println!(&amp;quot;Finished sleeping&amp;quot;);
        let points = rng.gen_range(min_points..max_points);
        let params = GameClaimRequest {
gameId: deserialized.gameId,
            points,
        };
        println!(&amp;quot;Trying to claim {} points&amp;quot;, points);
        let response = client
            .post(&amp;quot;https://game-domain.blum.codes/api/v1/game/claim&amp;quot;)
            .headers(headers.clone())
            .json(&amp;amp;params)
            .send()
            .await
            .unwrap();
        println!(
                &amp;quot;Claim response status {}, {}&amp;quot;,
                response.status(),
                response.text().await.unwrap()
                )
    }
    Err(_) =&amp;gt; {
        println!(&amp;quot;Unable to deserialize&amp;quot;);
        println!(&amp;quot;Sleeping for {}ms&amp;quot;, wait_duration.as_millis());
        tokio::time::sleep(wait_duration).await;
        println!(&amp;quot;Finished sleeping&amp;quot;);
    }&lt;/pre&gt;
  &lt;p id=&quot;USZk&quot;&gt;Якщо десеріалізація успішна то чекаємо wait_duration і випадковим чином вибираємо кількість поінтів.&lt;br /&gt;Далі формуємо данні запиту через нашу структуру і відсилаємо наш запит на сервер.&lt;br /&gt;У випадку помилки десеріалізації просто чекаємо wait_duration.&lt;/p&gt;
  &lt;pre id=&quot;zNk7&quot; data-lang=&quot;rust&quot;&gt;_ =&amp;gt; {
    println!(&amp;quot;{}&amp;quot;, status);
    println!(
            &amp;quot;Sleeping for {}ms hoping it will work&amp;quot;,
            wait_duration.as_millis()
            );
    tokio::time::sleep(wait_duration).await;
    println!(&amp;quot;Finished sleeping&amp;quot;);
}&lt;/pre&gt;
  &lt;p id=&quot;cfuj&quot;&gt;Якщо відповідь на наш початковий запит була не 200(OK) то також чекаємо час очікування.&lt;/p&gt;
  &lt;figure id=&quot;HGfO&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fe/1d/fe1dc256-f918-438a-aab2-421739992219.png&quot; width=&quot;675&quot; /&gt;
    &lt;figcaption&gt;Приклад роботи програми&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;jQbX&quot;&gt;Весь код:&lt;/p&gt;
  &lt;pre id=&quot;rZK2&quot; data-lang=&quot;rust&quot;&gt;use rand::Rng;
use reqwest::header::HeaderMap;
use reqwest::{self, StatusCode};
use serde::{Deserialize, Serialize};
use std::time::Duration;

#[derive(Serialize, Deserialize, Debug)]
struct GameClaimRequest {
    gameId: String,
    points: i32,
}

#[derive(Serialize, Deserialize, Debug)]
struct GamePlayResponse {
    gameId: String,
}

#[tokio::main]
async fn main() {
    let repeat_count = 1;
    let min_points = 350;
    let max_points = 450;
    let auth_token = &amp;quot;&amp;quot;;
    let wait_duration = Duration::from_secs(31);

    let mut rng = rand::thread_rng();
    let client = reqwest::Client::new();
    let mut headers = HeaderMap::new();
    headers.insert(
        &amp;quot;accept&amp;quot;,
        &amp;quot;application/json, text/plain, */*&amp;quot;.try_into().unwrap(),
    );
    headers.insert(
        &amp;quot;authorization&amp;quot;,
        format!(&amp;quot;Bearer {}&amp;quot;, auth_token).try_into().unwrap(),
    );
    headers.insert(&amp;quot;sec-fetch-site&amp;quot;, &amp;quot;same-site&amp;quot;.try_into().unwrap());
    headers.insert(&amp;quot;accept-encoding&amp;quot;, &amp;quot;gzip, deflate, br&amp;quot;.try_into().unwrap());
    headers.insert(&amp;quot;accept-language&amp;quot;, &amp;quot;en-GB,en;q=0.9&amp;quot;.try_into().unwrap());
    headers.insert(&amp;quot;sec-fetch-mode&amp;quot;, &amp;quot;cors&amp;quot;.try_into().unwrap());
    headers.insert(&amp;quot;origin&amp;quot;, &amp;quot;https://telegram.blum.codes&amp;quot;.try_into().unwrap());
    headers.insert(
        &amp;quot;user-agent&amp;quot;,
        &amp;quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)&amp;quot;
            .try_into()
            .unwrap(),
    );
    headers.insert(&amp;quot;sec-fetch-dest&amp;quot;, &amp;quot;empty&amp;quot;.try_into().unwrap());

    for _ in 0..repeat_count {
        let req = client
            .post(&amp;quot;https://game-domain.blum.codes/api/v1/game/play&amp;quot;)
            .headers(headers.clone())
            .send()
            .await
            .unwrap();
        let status = req.status();
        match status {
            StatusCode::OK =&amp;gt; {
                let deserialized = req.json::&amp;lt;GamePlayResponse&amp;gt;().await;
                match deserialized {
                    Ok(deserialized) =&amp;gt; {
                        println!(&amp;quot;Got game id: {}&amp;quot;, deserialized.gameId);
                        println!(&amp;quot;Sleeping for {}ms&amp;quot;, wait_duration.as_millis());
                        tokio::time::sleep(wait_duration).await;
                        println!(&amp;quot;Finished sleeping&amp;quot;);
                        let points = rng.gen_range(min_points..max_points);
                        let params = GameClaimRequest {
                            gameId: deserialized.gameId,
                            points,
                        };
                        println!(&amp;quot;Trying to claim {} points&amp;quot;, points);
                        let response = client
                            .post(&amp;quot;https://game-domain.blum.codes/api/v1/game/claim&amp;quot;)
                            .headers(headers.clone())
                            .json(&amp;amp;params)
                            .send()
                            .await
                            .unwrap();
                        println!(
                            &amp;quot;Claim response status {}, {}&amp;quot;,
                            response.status(),
                            response.text().await.unwrap()
                        )
                    }
                    Err(_) =&amp;gt; {
                        println!(&amp;quot;Unable to deserialize&amp;quot;);
                        println!(&amp;quot;Sleeping for {}ms&amp;quot;, wait_duration.as_millis());
                        tokio::time::sleep(wait_duration).await;
                        println!(&amp;quot;Finished sleeping&amp;quot;);
                    }
                }
            }
            _ =&amp;gt; {
                println!(&amp;quot;{}&amp;quot;, status);
                println!(
                    &amp;quot;Sleeping for {}ms hoping it will work&amp;quot;,
                    wait_duration.as_millis()
                );
                tokio::time::sleep(wait_duration).await;
                println!(&amp;quot;Finished sleeping&amp;quot;);
            }
        }
    }
}&lt;/pre&gt;
  &lt;p id=&quot;sZvr&quot;&gt;Таким простим чином можна абузити Blum без усіх цих клікерів.&lt;br /&gt;Чи можуть цього бота відслідкувати?&lt;br /&gt;Мабуть так, але швидше лише тому що ми кидаємо мало запитів по балансу і тд, що можна додати про потребі.&lt;/p&gt;
  &lt;p id=&quot;PKMy&quot;&gt;Ресурси для вивчення Rust:&lt;/p&gt;
  &lt;ul id=&quot;arwM&quot;&gt;
    &lt;li id=&quot;Lrxu&quot;&gt;&lt;a href=&quot;https://doc.rust-lang.org/book/&quot; target=&quot;_blank&quot;&gt;The Rust Book&lt;/a&gt; — основний ресурс для вивчення Rust.&lt;/li&gt;
    &lt;li id=&quot;diOp&quot;&gt;&lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/&quot; target=&quot;_blank&quot;&gt;Rust by Example &lt;/a&gt;— Rust показаний на прикладах коду.&lt;/li&gt;
    &lt;li id=&quot;lSUS&quot;&gt;&lt;a href=&quot;https://github.com/rust-lang/rustlings/&quot; target=&quot;_blank&quot;&gt;Rustlings&lt;/a&gt; — вправи де вам дають поламаний код і вам треба його поремонтувати.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;JrSA&quot;&gt;Всі бібліотеки використані в статті можна знайти на &lt;a href=&quot;http://crates.io&quot; target=&quot;_blank&quot;&gt;crates.io&lt;/a&gt;, а документації до них на &lt;a href=&quot;http://docs.rs&quot; target=&quot;_blank&quot;&gt;docs.rs&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;N6dM&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:tonpokerwheel</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/tonpokerwheel?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Tonpoker Wheel точно не скам або казочка про детектива</title><published>2024-05-26T00:10:23.554Z</published><updated>2024-07-05T16:16:23.180Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/1a/b7/1ab788cd-14bf-4691-9a0c-8a2eeafbcacf.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/ae/d2/aed2e861-9bd1-4d72-aea6-9a88465f283c.png&quot;&gt;Якось ввечері я помічаю пост в телеграм каналі Catizen Announcement пост про їхній спільний івент з Ton Poker та Playdeck.
Зайшовши з основного акаунта я отримую лише один спін(мабуть інші були прокручені раніше) і отримую 1 цент.
Прокрутивши ще спін на 1 цент з другого акаунту в мене закрадається підозра, що тут завжди випадає якесь сміття.
Я відкриваю Burp Suite вмикаю intercept(щоб запити не відправлялися на сервер а зупинялися). 
Я не бачу запитів в яких є хоч якийсь рандом і припускаю(як виявиться потім помилково), що рандому або нема або він на стороні клієнта.
Відкривши дебагер я починаю пробувати розібратися що відбувається.
Щоб знайти який шматок відповідає за сам спін я вмикаю event listener breakpoint на click.</summary><content type="html">
  &lt;p id=&quot;17Kf&quot;&gt;Якось ввечері я помічаю пост в телеграм каналі Catizen Announcement пост про їхній спільний івент з Ton Poker та Playdeck.&lt;br /&gt;Зайшовши з основного акаунта я отримую лише один спін(мабуть інші були прокручені раніше) і отримую 1 цент.&lt;br /&gt;Прокрутивши ще спін на 1 цент з другого акаунту в мене закрадається підозра, що тут завжди випадає якесь сміття.&lt;br /&gt;Я відкриваю &lt;a href=&quot;https://portswigger.net/burp&quot; target=&quot;_blank&quot;&gt;Burp Suite&lt;/a&gt; вмикаю intercept(щоб запити не відправлялися на сервер а зупинялися). &lt;br /&gt;Я не бачу запитів в яких є хоч якийсь рандом і припускаю(як виявиться потім помилково), що рандому або нема або він на стороні клієнта.&lt;br /&gt;Відкривши дебагер я починаю пробувати розібратися що відбувається.&lt;br /&gt;Щоб знайти який шматок відповідає за сам спін я вмикаю event listener breakpoint на click.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
  &lt;figure id=&quot;N5Xp&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ae/d2/aed2e861-9bd1-4d72-aea6-9a88465f283c.png&quot; width=&quot;356&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;SIFf&quot;&gt;Таким чином поставивши брейкпоінти в коді я знаходжу функцію яка якраз оброблює спін.&lt;/p&gt;
  &lt;figure id=&quot;4vxW&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c8/59/c85977cb-ddff-4ff6-b0fb-d3aac574f52d.png&quot; width=&quot;540&quot; /&gt;
    &lt;figcaption&gt;Обфускований код&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;OdIo&quot;&gt;Код був обфускований але я більш менш зрозумів що він робить.&lt;br /&gt;Із геніальних мувів при обфускації(вона можливо була навіть зроблена руками):&lt;/p&gt;
  &lt;ul id=&quot;pDuu&quot;&gt;
    &lt;li id=&quot;eLBD&quot;&gt;Функції в змінних з однолітерними назвами.&lt;/li&gt;
    &lt;li id=&quot;8t5c&quot;&gt;Функції дублюються в декількох змінних, деякі з цих змінних навіть не використовуються.&lt;/li&gt;
    &lt;li id=&quot;Q5bn&quot;&gt;Індекс рандомного значення завжди більший на 0.5, від нього віднімають 0.5 щоб зробити правильним.&lt;/li&gt;
    &lt;li id=&quot;gznJ&quot;&gt;І можливо навіть більше того, на що я не звернув увагу.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;BSKn&quot;&gt;Передивившись історію запитів я помітив, що рандомне значення відсилається зразу після відкриття колеса, після прокрутки просто відправляється запит на підтвердження спіну за його id(sp).&lt;/p&gt;
  &lt;figure id=&quot;6kKb&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/00/ff/00ff246b-6f69-48f1-aca4-e9287ff39cf8.png&quot; width=&quot;2187&quot; /&gt;
    &lt;figcaption&gt;Початковий запит.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;o0Xw&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/70/97/70978233-5cab-425e-8709-a8c5af277924.png&quot; width=&quot;1098&quot; /&gt;
    &lt;figcaption&gt;Запит для підтвердження спіна.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;qomj&quot;&gt;Отож у нас два варіанти, або вони завжди видають невигідний результат, або ми можемо респінити поки не випаде дуже хороший результат і розвести їх на купу бабла(думаю очевидно який більш ймовірний).&lt;br /&gt;Але звісно це так собі пруф і це не цікаво.&lt;br /&gt;Отож я вирішив написати скрипт який буде відправляти такі запити і дивитися що випадає.&lt;br /&gt;Написати я вирішив його на &lt;a href=&quot;https://www.rust-lang.org/&quot; target=&quot;_blank&quot;&gt;Rust&lt;/a&gt;.&lt;br /&gt;Зараз буде код і пояснення до нього, перейти до результатів можна за цим &lt;a href=&quot;#XSK6&quot;&gt;лінком&lt;/a&gt;.&lt;/p&gt;
  &lt;pre id=&quot;rr6X&quot; data-lang=&quot;rust&quot;&gt;use rand::Rng;
use reqwest::header::{HeaderMap, HeaderValue};
use reqwest::{self, StatusCode};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
use tokio;&lt;/pre&gt;
  &lt;p id=&quot;AQeU&quot;&gt;Підключаємо ліби:&lt;/p&gt;
  &lt;ul id=&quot;Ue0w&quot;&gt;
    &lt;li id=&quot;yZB3&quot;&gt;&lt;a href=&quot;https://crates.io/crates/rand&quot; target=&quot;_blank&quot;&gt;rand&lt;/a&gt; — рандом, для рандомізації часу між запитами.&lt;/li&gt;
    &lt;li id=&quot;Ydyn&quot;&gt;&lt;a href=&quot;https://crates.io/crates/reqwest&quot; target=&quot;_blank&quot;&gt;reqwest&lt;/a&gt; — серце програми, бібліотека для кидання запитів.&lt;/li&gt;
    &lt;li id=&quot;M0sD&quot;&gt;&lt;a href=&quot;https://crates.io/crates/serde/&quot; target=&quot;_blank&quot;&gt;serde&lt;/a&gt; — білбіотека для серіалізації та десеріалізації, яку ми юзаємо щоб парсити json.&lt;/li&gt;
    &lt;li id=&quot;vRaH&quot;&gt;&lt;a href=&quot;https://crates.io/crates/tokio/&quot; target=&quot;_blank&quot;&gt;tokio&lt;/a&gt; — бібліотека для роботи з асинхронністю(тут асинхронність не дуже грала роль насправді).&lt;/li&gt;
    &lt;li id=&quot;bBuP&quot;&gt;std — стандартна бібліотека rust.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;7iHQ&quot; data-lang=&quot;rust&quot;&gt;#[derive(Serialize, Deserialize, Debug)]
struct PokerSector {
    key: String,
    r#type: String,
    label: String,
    color: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PokerResponse {
    tickets: i32,
    sectors: Vec&amp;lt;PokerSector&amp;gt;,
    sp: String,
    userShareLink: String,
    randInd: f32,
}&lt;/pre&gt;
  &lt;p id=&quot;3cAy&quot;&gt;Оголошуємо структури які відповідають відповідді на запит.&lt;br /&gt;r# це raw identifier бо type вже використовується.&lt;/p&gt;
  &lt;pre id=&quot;EZ8w&quot; data-lang=&quot;rust&quot;&gt;#[tokio::main]
async fn main() {&lt;/pre&gt;
  &lt;p id=&quot;cJai&quot;&gt;Оголошуємо головну функцію і даємо tokio знати що вона є головною(по дефолту вона не асинхронна).&lt;/p&gt;
  &lt;pre id=&quot;tuvz&quot; data-lang=&quot;rust&quot;&gt;let mut rng = rand::thread_rng();&lt;/pre&gt;
  &lt;p id=&quot;upPp&quot;&gt;Ініціалізуємо рандом.&lt;br /&gt;let — це оголошення змінної.&lt;br /&gt;mut — означає що змінна може міняти значення(по дефолту всі змінні в расті сталі).&lt;/p&gt;
  &lt;pre id=&quot;aH7B&quot; data-lang=&quot;rust&quot;&gt;let wait_millis = 1000;
let mut requests_count = 0;&lt;/pre&gt;
  &lt;p id=&quot;Qly6&quot;&gt;Ставимо початковий час очікування між запитами.&lt;br /&gt;Та ставимо рахівник запитів на 0.&lt;/p&gt;
  &lt;pre id=&quot;CpMo&quot; data-lang=&quot;rust&quot;&gt;let client = reqwest::Client::new();&lt;/pre&gt;
  &lt;p id=&quot;TGve&quot;&gt;Оголошуємо наш клієнт для запитів.&lt;/p&gt;
  &lt;pre id=&quot;QT9b&quot; data-lang=&quot;rust&quot;&gt;let mut params = HashMap::new();
params.insert(&amp;quot;initData&amp;quot;, &amp;quot;&amp;lt;initData&amp;gt;&amp;quot;);&lt;/pre&gt;
  &lt;p id=&quot;0uoa&quot;&gt;Оголошуємо параметри для нашого майбутнього запиту.&lt;br /&gt;Замість &amp;lt;initData&amp;gt; має бути initData, який можна взяти з запитів в браузері, але я брав з Burp Suite.&lt;/p&gt;
  &lt;pre id=&quot;Rhhp&quot; data-lang=&quot;rust&quot;&gt;let mut headers = HeaderMap::new();
headers.insert(
    &amp;quot;sec-ch-ua&amp;quot;,
    HeaderValue::from_str(r#&amp;quot;&amp;quot;Brave&amp;quot;;v=&amp;quot;123&amp;quot;, &amp;quot;Not:A-Brand&amp;quot;;v=&amp;quot;8&amp;quot;, &amp;quot;Chromium&amp;quot;;v=&amp;quot;123&amp;quot;&amp;quot;#)
        .unwrap(),
);
headers.insert(
    &amp;quot;sec-ch-ua-platform&amp;quot;,
    HeaderValue::from_str(r#&amp;quot;&amp;quot;Linux&amp;quot;&amp;quot;#).unwrap(),
);
headers.insert(&amp;quot;sec-ch-ua-mobile&amp;quot;, HeaderValue::from_str(r#&amp;quot;?0&amp;quot;#).unwrap());
headers.insert(&amp;quot;user-agent&amp;quot;, HeaderValue::from_str(r#&amp;quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36&amp;quot;#).unwrap());
headers.insert(
    &amp;quot;accept-language&amp;quot;,
    HeaderValue::from_str(r#&amp;quot;en-US,en;q=0.8&amp;quot;#).unwrap(),
);
headers.insert(
    &amp;quot;origin&amp;quot;,
    HeaderValue::from_str(r#&amp;quot;https://tgwa.tonpoker.online&amp;quot;#).unwrap(),
);
headers.insert(
    &amp;quot;sec-fetch-site&amp;quot;,
    HeaderValue::from_str(r#&amp;quot;same-site&amp;quot;#).unwrap(),
);
headers.insert(&amp;quot;sec-fetch-mode&amp;quot;, HeaderValue::from_str(r#&amp;quot;cors&amp;quot;#).unwrap());
headers.insert(&amp;quot;sec-fetch-dest&amp;quot;, HeaderValue::from_str(r#&amp;quot;empty&amp;quot;#).unwrap());
headers.insert(
    &amp;quot;referer&amp;quot;,
    HeaderValue::from_str(r#&amp;quot;https://tgwa.tonpoker.online/&amp;quot;#).unwrap(),
);&lt;/pre&gt;
  &lt;p id=&quot;XO2d&quot;&gt;Оголошуємо наші заголовки запиту і заповнюємо їх, не знаю чи всі вони треба, бо я їх просто скопіював з Burp Suite з запита який кидався через браузер.&lt;/p&gt;
  &lt;pre id=&quot;3sYx&quot; data-lang=&quot;rust&quot;&gt;loop {
    let req = client
        .post(&amp;quot;https://bridge.tonpoker.online/wheel/get&amp;quot;)
        .headers(headers.clone())
        .json(&amp;amp;params)
        .send()
        .await
        .unwrap();
&lt;/pre&gt;
  &lt;p id=&quot;Hy5W&quot;&gt;Починаємо нескінченний цикл запитів і кидаємо запит.&lt;br /&gt;.post означає що це POST запит, використовуємо .await щоб викликати future(асинхронна функція). .unwrap() означає дістати значення і у випадку помилки завершити програму(де-факто припустити що помилки нема і спробувати виконатися так).&lt;/p&gt;
  &lt;pre id=&quot;Rl6I&quot; data-lang=&quot;rust&quot;&gt;let status = req.status();&lt;/pre&gt;
  &lt;p id=&quot;leca&quot;&gt;Записуємо статус запита в змінну, в цьому випадку я зустрівчав лише два статуси:&lt;/p&gt;
  &lt;ul id=&quot;2o0f&quot;&gt;
    &lt;li id=&quot;Ka6A&quot;&gt;200 OK&lt;/li&gt;
    &lt;li id=&quot;yYhc&quot;&gt;429 Too Many Requests&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;rYQn&quot; data-lang=&quot;rust&quot;&gt;match status {
    StatusCode::OK =&amp;gt; {&lt;/pre&gt;
  &lt;p id=&quot;FFjD&quot;&gt;Конструкція match дає можливість нам розглянути різні випадки статусу(це зручніше чим купа if-else).&lt;br /&gt;Для початку розглянемо статсу OK(200).&lt;/p&gt;
  &lt;pre id=&quot;ztZA&quot; data-lang=&quot;rust&quot;&gt;let deserialized = req.json::&amp;lt;PokerResponse&amp;gt;().await;&lt;/pre&gt;
  &lt;p id=&quot;dE38&quot;&gt;Парсимо json, тут ми вже не припускаємо що помилки не буде, бо іноді може бути некоректна інфа і при 200(так один раз сталося).&lt;/p&gt;
  &lt;pre id=&quot;KEyd&quot; data-lang=&quot;rust&quot;&gt;match deserialized {
    Ok(deserialized) =&amp;gt; {
        let index: usize = (deserialized.randInd - 0.5) as usize;
        requests_count += 1;
        println!(
            &amp;quot;Count: {} Status:{} Index: {} Type: {} Label: {} SP: {}&amp;quot;,
            requests_count,
            status,
            index,
            deserialized.sectors[index].r#type,
            deserialized.sectors[index].label,
            deserialized.sp
        );
    }
    Err(e) =&amp;gt; {
        println!(&amp;quot;Strange error with OK status&amp;quot;);
    }
}&lt;/pre&gt;
  &lt;p id=&quot;wa94&quot;&gt;Знову конструкція match, якщо запит запирсився то отримуємо індекс(віднімаємо 0.5 і переводимо в тип для індексів usize), збільшуємо рахівник запитів на 1 і виводимо в консоль інформацію про запит.&lt;br /&gt;У випадку помилки пишемо в консоль про це(це не найкращий спосіб логів, краще розділяти помилки і дефолтну інфу, але це маленький скрипт тож можна й так).&lt;/p&gt;
  &lt;pre id=&quot;lvVK&quot; data-lang=&quot;rust&quot;&gt;let wait_time = Duration::from_millis(wait_millis + rng.gen_range(0..200));
println!(&amp;quot;Sleeping for {}&amp;quot;, wait_time.as_millis());
tokio::time::sleep(wait_time).await;
println!(&amp;quot;Finished sleeping&amp;quot;);&lt;/pre&gt;
  &lt;p id=&quot;Zgh7&quot;&gt;Генеруємо число від 0 до 200(0..200 це range схоже на range(0,200) в python) і додаємо його до базового часу очікування.&lt;br /&gt;Конкретно тут ми могли і синхронно очікувати, але в асинхронних програмах краще робити це асинхронно, бо в цей час інші частини програми могли б щось робити.&lt;/p&gt;
  &lt;pre id=&quot;JMvB&quot; data-lang=&quot;rust&quot;&gt;_ =&amp;gt; {
    println!(&amp;quot;{}&amp;quot;, status);
    let wait_time =
        Duration::from_millis(wait_millis + 1000 + rng.gen_range(1000..3000));
    println!(&amp;quot;Sleeping for {}&amp;quot;, wait_time.as_millis());
    tokio::time::sleep(wait_time).await;
    println!(&amp;quot;Finished sleeping&amp;quot;);
}&lt;/pre&gt;
  &lt;p id=&quot;kaSX&quot;&gt;Ми закінчили розглядати випадок OK(200), тепер для усіх інших випадків ми виводимо статус в консоль і анлогічо очікуємо, але тепер вже довший час.&lt;/p&gt;
  &lt;p id=&quot;z6dD&quot;&gt;Це кінець програми, весь код ось:&lt;/p&gt;
  &lt;pre id=&quot;aTqF&quot; data-lang=&quot;rust&quot;&gt;use rand::Rng;
use reqwest::header::{HeaderMap, HeaderValue};
use reqwest::{self, StatusCode};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
use tokio;

#[derive(Serialize, Deserialize, Debug)]
struct PokerSector {
    key: String,
    r#type: String,
    label: String,
    color: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PokerResponse {
    tickets: i32,
    sectors: Vec&amp;lt;PokerSector&amp;gt;,
    sp: String,
    userShareLink: String,
    randInd: f32,
}

#[tokio::main]
async fn main() {
    let mut rng = rand::thread_rng();
    let wait_millis = 1000;
    let mut requests_count = 0;
    let client = reqwest::Client::new();
    let mut params = HashMap::new();
    params.insert(&amp;quot;initData&amp;quot;, &amp;quot;&amp;lt;initData&amp;gt;&amp;quot;);
    let mut headers = HeaderMap::new();
    headers.insert(
        &amp;quot;sec-ch-ua&amp;quot;,
        HeaderValue::from_str(r#&amp;quot;&amp;quot;Brave&amp;quot;;v=&amp;quot;123&amp;quot;, &amp;quot;Not:A-Brand&amp;quot;;v=&amp;quot;8&amp;quot;, &amp;quot;Chromium&amp;quot;;v=&amp;quot;123&amp;quot;&amp;quot;#)
            .unwrap(),
    );
    headers.insert(
        &amp;quot;sec-ch-ua-platform&amp;quot;,
        HeaderValue::from_str(r#&amp;quot;&amp;quot;Linux&amp;quot;&amp;quot;#).unwrap(),
    );
    headers.insert(&amp;quot;sec-ch-ua-mobile&amp;quot;, HeaderValue::from_str(r#&amp;quot;?0&amp;quot;#).unwrap());
    headers.insert(&amp;quot;user-agent&amp;quot;, HeaderValue::from_str(r#&amp;quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36&amp;quot;#).unwrap());
    headers.insert(
        &amp;quot;accept-language&amp;quot;,
        HeaderValue::from_str(r#&amp;quot;en-US,en;q=0.8&amp;quot;#).unwrap(),
    );
    headers.insert(
        &amp;quot;origin&amp;quot;,
        HeaderValue::from_str(r#&amp;quot;https://tgwa.tonpoker.online&amp;quot;#).unwrap(),
    );
    headers.insert(
        &amp;quot;sec-fetch-site&amp;quot;,
        HeaderValue::from_str(r#&amp;quot;same-site&amp;quot;#).unwrap(),
    );
    headers.insert(&amp;quot;sec-fetch-mode&amp;quot;, HeaderValue::from_str(r#&amp;quot;cors&amp;quot;#).unwrap());
    headers.insert(&amp;quot;sec-fetch-dest&amp;quot;, HeaderValue::from_str(r#&amp;quot;empty&amp;quot;#).unwrap());
    headers.insert(
        &amp;quot;referer&amp;quot;,
        HeaderValue::from_str(r#&amp;quot;https://tgwa.tonpoker.online/&amp;quot;#).unwrap(),
    );
    loop {
        let req = client
            .post(&amp;quot;https://bridge.tonpoker.online/wheel/get&amp;quot;)
            .headers(headers.clone())
            .json(&amp;amp;params)
            .send()
            .await
            .unwrap();
        let status = req.status();
        match status {
            StatusCode::OK =&amp;gt; {
                let deserialized = req.json::&amp;lt;PokerResponse&amp;gt;().await;
                match deserialized {
                    Ok(deserialized) =&amp;gt; {
                        let index: usize = (deserialized.randInd - 0.5) as usize;
                        requests_count += 1;
                        println!(
                            &amp;quot;Count: {} Status:{} Index: {} Type: {} Label: {} SP: {}&amp;quot;,
                            requests_count,
                            status,
                            index,
                            deserialized.sectors[index].r#type,
                            deserialized.sectors[index].label,
                            deserialized.sp
                        );
                    }
                    Err(e) =&amp;gt; {
                        println!(&amp;quot;Strange error with OK status&amp;quot;);
                    }
                }
                let wait_time = Duration::from_millis(wait_millis + rng.gen_range(0..200));
                println!(&amp;quot;Sleeping for {}&amp;quot;, wait_time.as_millis());
                tokio::time::sleep(wait_time).await;
                println!(&amp;quot;Finished sleeping&amp;quot;);
            }
            _ =&amp;gt; {
                println!(&amp;quot;{}&amp;quot;, status);
                let wait_time =
                    Duration::from_millis(wait_millis + 1000 + rng.gen_range(1000..3000));
                println!(&amp;quot;Sleeping for {}&amp;quot;, wait_time.as_millis());
                tokio::time::sleep(wait_time).await;
                println!(&amp;quot;Finished sleeping&amp;quot;);
            }
        }
    }
}&lt;/pre&gt;
  &lt;p id=&quot;LLiE&quot;&gt;Якщо ви з якоїсь причини хочете це запустити(краще почитайте до кінця щоб зрозуміти чому ви мабуть не хочете цього робити), то не забудьте замінити &amp;lt;initData&amp;gt; на ваше значення initData.&lt;/p&gt;
  &lt;p id=&quot;XSK6&quot;&gt;Отож які результати?&lt;br /&gt;Під час тестів я один раз зміг вибити 5 центів і не зберіг sp, із того що я зберіг в файлик, таке:&lt;/p&gt;
  &lt;ul id=&quot;fjMH&quot;&gt;
    &lt;li id=&quot;2U5Z&quot;&gt;Всього успішних запитів 94.&lt;/li&gt;
    &lt;li id=&quot;B9oX&quot;&gt;На 10 центів 1 раз(я не пробував його активувати бо я отримую постійно Too Many Requests тепер).&lt;/li&gt;
    &lt;li id=&quot;JRbx&quot;&gt;На 1 цент 66 разів.&lt;/li&gt;
    &lt;li id=&quot;EpOw&quot;&gt;Фріспін(перекрутка) 27 разів.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;7G9X&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/81/82/8182929c-c61b-4eef-a63e-9d4718327b54.png&quot; width=&quot;1081&quot; /&gt;
    &lt;figcaption&gt;Графік результатів&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GbtN&quot;&gt;Отож чи гарантовано там не можна виграти більше? Ні.&lt;br /&gt;Але як можна помітити шанс на це дуже маленький.&lt;/p&gt;
  &lt;p id=&quot;PKMy&quot;&gt;Ресурси для вивчення Rust:&lt;/p&gt;
  &lt;ul id=&quot;arwM&quot;&gt;
    &lt;li id=&quot;Lrxu&quot;&gt;&lt;a href=&quot;https://doc.rust-lang.org/book/&quot; target=&quot;_blank&quot;&gt;The Rust Book&lt;/a&gt; — основний ресурс для вивчення Rust.&lt;/li&gt;
    &lt;li id=&quot;diOp&quot;&gt;&lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/&quot; target=&quot;_blank&quot;&gt;Rust by Example &lt;/a&gt;— Rust показаний на прикладах коду.&lt;/li&gt;
    &lt;li id=&quot;lSUS&quot;&gt;&lt;a href=&quot;https://github.com/rust-lang/rustlings/&quot; target=&quot;_blank&quot;&gt;Rustlings&lt;/a&gt; — вправи де вам дають поламаний код і вам треба його поремонтувати.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;JrSA&quot;&gt;Всі бібліотеки використані в статті можна знайти на &lt;a href=&quot;http://crates.io&quot; target=&quot;_blank&quot;&gt;crates.io&lt;/a&gt;, а документації до них на &lt;a href=&quot;http://docs.rs&quot; target=&quot;_blank&quot;&gt;docs.rs&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;N6dM&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:Vzq2qRF7jY3</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/Vzq2qRF7jY3?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Як спростити собі життя в selenium</title><published>2022-10-25T19:58:51.022Z</published><updated>2022-10-25T19:58:51.022Z</updated><summary type="html">В цій статті я розкажу як ви можете писати програми на selenium швидше, бо підозрюю що ви теж не дуже раді кожен раз копіювати xpath)))</summary><content type="html">
  &lt;p id=&quot;TKxQ&quot;&gt;В цій статті я розкажу як ви можете писати програми на selenium швидше, бо підозрюю що ви теж не дуже раді кожен раз копіювати xpath)))&lt;/p&gt;
  &lt;p id=&quot;QT0H&quot;&gt;Отже ви можете подумати чому б нам не вкористовувати Selenium IDE, але нажаль він генерує код просто підряд командами і не дочікується завантаження сторінки, отже нам не підходить.&lt;/p&gt;
  &lt;p id=&quot;Xf89&quot;&gt;Ми будемо використовувати ui vision rpa, так він не вміє конвертувати в код на python, але за те він гарно записує дії в json файл і я сам написав конвертор який конвертує його json файли в код на python.&lt;br /&gt;Він звісно не підтримує всього функціоналу цього розширення, але ті дії які воно може записати, він підтримує.&lt;/p&gt;
  &lt;h2 id=&quot;VC9r&quot;&gt;Встановлюємо розширення&lt;/h2&gt;
  &lt;p id=&quot;Tm8Z&quot;&gt;Встановіть його &lt;a href=&quot;https://chrome.google.com/webstore/detail/uivision-rpa/gcbalfbdmfieckjlnblleoemohcganoc&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt; і створіть нове макро.&lt;br /&gt;Коли запишите макро скопіюйте його json і запишіть у файл.&lt;/p&gt;
  &lt;h2 id=&quot;gYXj&quot;&gt;Встановлюємо конвертер&lt;/h2&gt;
  &lt;p id=&quot;bih4&quot;&gt;Тож як завантажити конвертер?&lt;br /&gt;Все просто він є на нашому гітхабі &lt;a href=&quot;https://github.com/cryptopidval/urpsei&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;.&lt;br /&gt;Вам просто треба запустити converter.py&lt;br /&gt;Тепер розберемо режими.&lt;/p&gt;
  &lt;h3 id=&quot;TQh2&quot;&gt;&lt;strong&gt;Автоматичний режим&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;Zm4d&quot;&gt;Щоб використати автоматичний режим дайте відповідь &amp;quot;y&amp;quot; на питання &amp;quot;Do you want to use default targets(y/n)?&amp;quot;.&lt;br /&gt;Тоді програма буде використовувати всюди ціль з поля target.&lt;br /&gt;В більшості випадків вам підійте цей режим хоча іноді ціль з поля target не працює.&lt;/p&gt;
  &lt;h3 id=&quot;QNIc&quot;&gt;Напіватоматичний режим&lt;/h3&gt;
  &lt;p id=&quot;DUfS&quot;&gt;Буде викоистовуватись якщо ви відповісте &amp;quot;n&amp;quot; на питання &amp;quot;Do you want to use default targets(y/n)?&amp;quot;.&lt;br /&gt;Вам треба буде ввести порядок за яким треба використовувати цілі.&lt;br /&gt;Цілі будуть пронумеровані.&lt;/p&gt;
  &lt;h3 id=&quot;DdAK&quot;&gt;Ручний режим&lt;/h3&gt;
  &lt;p id=&quot;CAFJ&quot;&gt;Тут в кожній команді вам треба самим вибрати ціль.&lt;/p&gt;
  &lt;p id=&quot;fePa&quot;&gt;Отже таким чином ви можете полегшити собі програмування на selenium, я постараюсь підготувати статтю про те, як працює цей конвертер тож підпишіться щоб не пропустити.&lt;/p&gt;
  &lt;p id=&quot;FNuf&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:l1Gc41GwkOM</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/l1Gc41GwkOM?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Як я захистив свої програми від піратства</title><published>2022-09-10T16:04:16.132Z</published><updated>2024-07-27T21:17:10.451Z</updated><summary type="html">В цьому пості я розповім про те як зробити перевірку ліцензій в своїй програмі і не тільки.</summary><content type="html">
  &lt;p id=&quot;aIeM&quot;&gt;В цьому пості я розповім про те як зробити перевірку ліцензій в своїй програмі і не тільки.&lt;/p&gt;
  &lt;h3 id=&quot;egtR&quot;&gt;&lt;strong&gt;Як перевіряються ліцензії?&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;E9Cc&quot;&gt;Значить наша програма відправляє назву програми, телеграм айді користувача, а також ліцензійний ключ на сервер.&lt;/p&gt;
  &lt;p id=&quot;YhZy&quot;&gt;На сервері ми маємо зберігати якось данні про користувачів ось які я вибрав колонки:active(чи активна ліцензія),id(унікальний айді в базі данних, призначається автоматично),tg_id(телеграм айді користувача),tg_username(телеграм юзернейм користувача),software_name(назва програми до якої цей ліцензій ключ),key(хеш ліцензійного ключа).&lt;br /&gt;Завдяки хешу якщо хтось отрмає доступ нашої бази данних він не побачить паролю.&lt;/p&gt;
  &lt;p id=&quot;Xs6d&quot;&gt;Для хешування ми будемо використовувати argon2.&lt;br /&gt;Для роботи з ним є бібліотека &lt;a href=&quot;https://pypi.org/project/argon2-cffi/&quot; target=&quot;_blank&quot;&gt;argon2-cffi&lt;/a&gt;, ставиться вона так:&lt;/p&gt;
  &lt;pre id=&quot;XjZH&quot;&gt;pip install argon2-cffi&lt;/pre&gt;
  &lt;p id=&quot;cuAY&quot;&gt;Використовувати її наприклад так:&lt;/p&gt;
  &lt;pre id=&quot;XdSY&quot;&gt;from argon2 import PasswordHasher
hasher = PasswordHasher()
password_hash = hasher.hash(&amp;quot;&amp;lt;якийсь пароль&amp;gt;&amp;quot;)
print(password_hash)&lt;/pre&gt;
  &lt;p id=&quot;42O3&quot;&gt;Ось &lt;a href=&quot;https://argon2-cffi.readthedocs.io/&quot; target=&quot;_blank&quot;&gt;документація&lt;/a&gt;.&lt;/p&gt;
  &lt;h3 id=&quot;IyNA&quot;&gt;Створення бази данних.&lt;/h3&gt;
  &lt;p id=&quot;iFhY&quot;&gt;Тепер коли ми знаємо як створювати хеші паролів як створити саму базу данних куди ми їх зможемо записати.&lt;br /&gt;Базу данних ми напишемо на mysql.&lt;br /&gt;Для полегшення життя є прога &lt;a href=&quot;https://dbeaver.io/&quot; target=&quot;_blank&quot;&gt;DBeaver&lt;/a&gt; для роботи з базами данних.&lt;br /&gt;Ось сам код для створення бази:&lt;/p&gt;
  &lt;pre id=&quot;suPR&quot;&gt;CREATE TABLE &amp;#x60;licenses&amp;#x60; (
  &amp;#x60;active&amp;#x60; tinyint(1),
  &amp;#x60;id&amp;#x60; int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  &amp;#x60;tg_username&amp;#x60; varchar(100),
  &amp;#x60;tg_id&amp;#x60; varchar(30),
  &amp;#x60;software_name&amp;#x60; varchar(300),
  &amp;#x60;key&amp;#x60; varchar(100)
);
&lt;/pre&gt;
  &lt;p id=&quot;8rOi&quot;&gt;Тепер пояснення що це все таке.&lt;/p&gt;
  &lt;pre id=&quot;1FCR&quot;&gt;CREATE TABLE &amp;#x60;licenses&amp;#x60; (&lt;/pre&gt;
  &lt;p id=&quot;1XeC&quot;&gt;Вказуємо що наша таблиця буде називатись &amp;quot;licenses&amp;quot;.&lt;/p&gt;
  &lt;pre id=&quot;0C6t&quot;&gt; &amp;#x60;active&amp;#x60; tinyint(1),&lt;/pre&gt;
  &lt;p id=&quot;bus8&quot;&gt;Поле active, може бути лише 1 або 0.&lt;br /&gt;Tinyint найменший тип чисел в mysql(наскільки я знаю).&lt;/p&gt;
  &lt;pre id=&quot;wI1i&quot;&gt;  &amp;#x60;id&amp;#x60; int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,&lt;/pre&gt;
  &lt;p id=&quot;0gww&quot;&gt;Унікальне айді кожного елемента в базі.&lt;br /&gt;Int стандартний тип чисел.&lt;/p&gt;
  &lt;pre id=&quot;Og1H&quot;&gt;&amp;#x60;tg_username&amp;#x60; varchar(100),&lt;/pre&gt;
  &lt;p id=&quot;lqoK&quot;&gt;Юзернейм в телеграмі користувача.&lt;br /&gt;Varchar це якийсь недовгий текст.&lt;/p&gt;
  &lt;pre id=&quot;Rtwr&quot;&gt;&amp;#x60;tg_id&amp;#x60; varchar(30),&lt;/pre&gt;
  &lt;p id=&quot;MAMW&quot;&gt;Айді користувача в телеграмі.&lt;br /&gt;Айді легше зберігати як символи оскільки так воно не впреться в ліміти чисел(можливо не найкраще рішення).&lt;/p&gt;
  &lt;pre id=&quot;rc6A&quot;&gt;&amp;#x60;software_name&amp;#x60; varchar(300),&lt;/pre&gt;
  &lt;p id=&quot;ke8F&quot;&gt;Назва програми, важливе поле щоб не можна було використовувати один ключ для всіх програм.&lt;/p&gt;
  &lt;pre id=&quot;Afxa&quot;&gt;&amp;#x60;key&amp;#x60; varchar(100)&lt;/pre&gt;
  &lt;p id=&quot;Lzl3&quot;&gt;Ключ, найважливіше поле, конкретніше це хеш пароля(ключа).&lt;/p&gt;
  &lt;pre id=&quot;Thj3&quot;&gt;);&lt;/pre&gt;
  &lt;p id=&quot;sbd2&quot;&gt;Кінець команди CREATE(а не сумний смайлик).&lt;/p&gt;
  &lt;h3 id=&quot;YAbJ&quot;&gt;Створення сервера для перевірки ліцензій.&lt;/h3&gt;
  &lt;p id=&quot;E14f&quot;&gt;Тепер коли у нас є база данних, саме час створити сервер для перевірки ліцензій.&lt;br /&gt;Писати я буду на php бо хостинг який я використовую підтримує лише його.&lt;/p&gt;
  &lt;pre id=&quot;qK70&quot;&gt;&amp;lt;?php&lt;/pre&gt;
  &lt;p id=&quot;LAsm&quot;&gt;Відкриття тегу php.&lt;/p&gt;
  &lt;pre id=&quot;myEq&quot;&gt;session_start();
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = new mysqli(&amp;#x27;host&amp;#x27;, &amp;#x27;username&amp;#x27;, &amp;#x27;password&amp;#x27;, &amp;#x27;database&amp;#x27;);&lt;/pre&gt;
  &lt;p id=&quot;9P82&quot;&gt;Запускаємо сесію mysqli(драйвер в php для роботи з mysql).&lt;br /&gt;Створюємо підключення до бази, тут треба замінити host, username, password, database на ваші данні від бази данних.&lt;br /&gt;Зберігаєм підключення до змінни link.&lt;/p&gt;
  &lt;pre id=&quot;ralo&quot;&gt;$link-&amp;gt;set_charset(&amp;#x27;utf8mb4&amp;#x27;);&lt;/pre&gt;
  &lt;p id=&quot;FATj&quot;&gt;Ставимо utf8(юнікод).&lt;/p&gt;
  &lt;pre id=&quot;awqu&quot;&gt;$key = $_POST[&amp;quot;key&amp;quot;];
$soft = $_POST[&amp;quot;soft&amp;quot;];
$tg_id = $_POST[&amp;quot;tg_id&amp;quot;];&lt;/pre&gt;
  &lt;p id=&quot;GHtT&quot;&gt;Данні від софта нам кидають через POST запити тому дістаємо ці змінні.&lt;/p&gt;
  &lt;pre id=&quot;vk7Z&quot;&gt;$stmt = $link-&amp;gt;prepare(&amp;quot;SELECT &amp;#x60;key&amp;#x60;,active FROM licenses WHERE &amp;#x60;tg_id&amp;#x60;=? and &amp;#x60;software_name&amp;#x60;=? LIMIT 1&amp;quot;);&lt;/pre&gt;
  &lt;p id=&quot;H8KT&quot;&gt;Пишемо код для нашого запиту в базу.&lt;br /&gt;Якщо простою мовою тут написано таке щось таке: Вибери один ключ та одну активність_ліцензії з бази данних &amp;quot;ліцензії&amp;quot; де тг_айді=? та назва_софту=?.&lt;br /&gt;Що ж таке ті знаки питання?&lt;br /&gt;Їх ми замінимо на значення телеграм айді та софту але оскільки ми не хочемо щоб нам загнали якусь не хорошу команду(звичайно таблицю не знесуть бо серверу я дав доступ лише до команди SELECT, але можливо зможуть користуватись софтом без ліцензії) то ми будемо вставляти ключ та тг айді через спеціальну команду.&lt;/p&gt;
  &lt;pre id=&quot;pQYs&quot;&gt;$stmt-&amp;gt;bind_param(&amp;#x27;ss&amp;#x27;, $tg_id, $soft);&lt;/pre&gt;
  &lt;p id=&quot;uliY&quot;&gt;Перший параметр пише які данні ми вставляємо замість знаків питання, в нашому випадку String,String або &amp;quot;ss&amp;quot;, наступними параметрами передаємо якраз значення.&lt;/p&gt;
  &lt;pre id=&quot;8Jkl&quot;&gt;$stmt-&amp;gt;execute();
$result = $stmt-&amp;gt;get_result();
$value = $result-&amp;gt;fetch_object();
$isactive=0;&lt;/pre&gt;
  &lt;p id=&quot;cex2&quot;&gt;Виконуємо запит до бази і зберігаємо результат в змінну.&lt;br /&gt;Також створюємо змінну в яку запишемо чи активна ліцензія.&lt;/p&gt;
  &lt;pre id=&quot;kFzb&quot;&gt;if (password_verify($key, $value-&amp;gt;key)){
	$isactive=$value-&amp;gt;active;
	echo $isactive;
}else{
	echo 0;
}&lt;/pre&gt;
  &lt;p id=&quot;3VNx&quot;&gt;Перевіряємо чи правильний ключ і записуємо в змінну чи спрацювала ліцензія.&lt;/p&gt;
  &lt;pre id=&quot;fSox&quot;&gt;$log  = &amp;quot;Tg id: &amp;quot;.$tg_id.&amp;#x27; - &amp;#x27;.date(&amp;quot;F j, Y, g:i a&amp;quot;).PHP_EOL.
	&amp;quot;IP: &amp;quot;.$_SERVER[&amp;#x27;REMOTE_ADDR&amp;#x27;].PHP_EOL.
    &amp;quot;Success: &amp;quot;.$isactive.PHP_EOL.
    &amp;quot;Soft: &amp;quot;.$soft.PHP_EOL.
    &amp;quot;-------------------------&amp;quot;.PHP_EOL;
	$filename=&amp;#x27;./log_&amp;#x27;.date(&amp;quot;j.n.Y&amp;quot;).&amp;#x27;.log&amp;#x27;;
	file_put_contents($filename, $log, FILE_APPEND);
	chmod($filename, 0240);&lt;/pre&gt;
  &lt;p id=&quot;C4yi&quot;&gt;В змінну лог зберігаєм тг айді, айпі, софт, точний час і чи успішний вхід.&lt;br /&gt;Далі це зберігаємо в файл(його назва буде &amp;lt;сьогоднішня дата&amp;gt;.log) і ставимо на нього так дозволи щоб через ftp ви могли читати але не можна за посиланням було завантажити лог звисайним людям.&lt;/p&gt;
  &lt;pre id=&quot;123s&quot;&gt;&amp;lt;?php
	session_start();
	mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
	$link = new mysqli(&amp;#x27;host&amp;#x27;, &amp;#x27;username&amp;#x27;, &amp;#x27;password&amp;#x27;, &amp;#x27;database&amp;#x27;);
	$link-&amp;gt;set_charset(&amp;#x27;utf8mb4&amp;#x27;); 
	$key = $_POST[&amp;quot;key&amp;quot;];
	$soft = $_POST[&amp;quot;soft&amp;quot;];
	$tg_id = $_POST[&amp;quot;tg_id&amp;quot;];
	$stmt = $link-&amp;gt;prepare(&amp;quot;SELECT &amp;#x60;key&amp;#x60;,active FROM licenses WHERE &amp;#x60;tg_id&amp;#x60;=? and &amp;#x60;software_name&amp;#x60;=? LIMIT 1&amp;quot;);
	$stmt-&amp;gt;bind_param(&amp;#x27;ss&amp;#x27;, $tg_id, $soft);
	$stmt-&amp;gt;execute();
	$result = $stmt-&amp;gt;get_result();
	$value = $result-&amp;gt;fetch_object();
	$isactive=0;
	if (password_verify($key, $value-&amp;gt;key)){
		$isactive=$value-&amp;gt;active;
		echo $isactive;
	}else{
		echo 0;
	}
	$log  = &amp;quot;Tg id: &amp;quot;.$tg_id.&amp;#x27; - &amp;#x27;.date(&amp;quot;F j, Y, g:i a&amp;quot;).PHP_EOL.
	&amp;quot;IP: &amp;quot;.$_SERVER[&amp;#x27;REMOTE_ADDR&amp;#x27;].PHP_EOL.
    &amp;quot;Success: &amp;quot;.$isactive.PHP_EOL.
    &amp;quot;Soft: &amp;quot;.$soft.PHP_EOL.
    &amp;quot;-------------------------&amp;quot;.PHP_EOL;
	$filename=&amp;#x27;./log_&amp;#x27;.date(&amp;quot;j.n.Y&amp;quot;).&amp;#x27;.log&amp;#x27;;
	file_put_contents($filename, $log, FILE_APPEND);
	chmod($filename, 0240);
		
?&amp;gt;
&lt;/pre&gt;
  &lt;p id=&quot;KDW7&quot;&gt;Фінальний код.&lt;br /&gt;Якщо всі перевірки пройдені то сервер верне 1.&lt;br /&gt;Отримати логи ви можете за ftp.&lt;/p&gt;
  &lt;h3 id=&quot;ZPSf&quot;&gt;Вшивання перевірки ліцензії в програму.&lt;/h3&gt;
  &lt;p id=&quot;ps6V&quot;&gt;У нас є сервер але на нього мають кидати запити.&lt;br /&gt;Цим і займеться наша програма.&lt;br /&gt;Зараз покажу на прикладі hello world-у.&lt;/p&gt;
  &lt;pre id=&quot;2VMW&quot;&gt;import requests&lt;/pre&gt;
  &lt;p id=&quot;2Q3k&quot;&gt;Імпортуємо бібліотеку requests через яку і будемо кидати запити.&lt;/p&gt;
  &lt;pre id=&quot;qeNk&quot;&gt;try:
    with open(&amp;quot;license.txt&amp;quot;) as l:
        tg_id,key=l.read().strip().split(&amp;quot;\n&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;YQCg&quot;&gt;Пробуємо відкрити файл і зберегти айді(з першого рядка) а також ключ(з другого рядка) в змінні tg_id та key.&lt;/p&gt;
  &lt;pre id=&quot;TGZ5&quot;&gt;    a=requests.post(&amp;quot;https://licenses.rostcraft.pp.ua/licenses.php&amp;quot;,data={&amp;quot;tg_id&amp;quot;:tg_id,&amp;quot;key&amp;quot;:key,&amp;quot;soft&amp;quot;:&amp;quot;test_bot&amp;quot;})
except:
    exit()&lt;/pre&gt;
  &lt;p id=&quot;yE71&quot;&gt;Кидаємо запит на наш сервер(замініть адресу яку вказав я на власну).&lt;br /&gt;На сервер кидаємо тг айді, ключ і назву софта.&lt;br /&gt;Будь-яка помилка призводить до виходу з програми.&lt;br /&gt;Наскільки я знаю важливо мати https бо це шифрування і tls сертифікат який доводить що це справжній сайт а не його підміна.&lt;/p&gt;
  &lt;pre id=&quot;sGQQ&quot;&gt;if a.status_code!=200:
    exit()
if a.text!=&amp;quot;1&amp;quot;:
    exit()&lt;/pre&gt;
  &lt;p id=&quot;4mna&quot;&gt;Якщо код статусу не 200(200 це успіх), або повернений результат не 1 то ми виходимо з програми.&lt;/p&gt;
  &lt;pre id=&quot;N9Vk&quot;&gt;print(&amp;quot;Hello world&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;uFgL&quot;&gt;Якщо перевірка пройдена то виходимо з програми.&lt;/p&gt;
  &lt;pre id=&quot;7SfQ&quot;&gt;import requests
try:
    with open(&amp;quot;license.txt&amp;quot;) as l:
        tg_id,key=l.read().strip().split(&amp;quot;\n&amp;quot;)
    a=requests.post(&amp;quot;https://licenses.rostcraft.pp.ua/licenses.php&amp;quot;,data={&amp;quot;tg_id&amp;quot;:tg_id,&amp;quot;key&amp;quot;:key,&amp;quot;soft&amp;quot;:&amp;quot;test_bot&amp;quot;})
except:
    exit()
if a.status_code!=200:
    exit()
if a.text!=&amp;quot;1&amp;quot;:
    exit()

print(&amp;quot;Hello world&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;Wnj7&quot;&gt;Весь код.&lt;/p&gt;
  &lt;h3 id=&quot;g60p&quot;&gt;Обфускація коду.&lt;/h3&gt;
  &lt;p id=&quot;tuj9&quot;&gt;Зараз користувачу нічого не заважає просто видалити перевірку тож ми це виправимо.&lt;br /&gt;Для цього будемо використовувати &lt;a href=&quot;https://pypi.org/project/pyarmor/&quot; target=&quot;_blank&quot;&gt;pyarmor&lt;/a&gt;.&lt;br /&gt;Наскільки я знаю він досить безпечний.&lt;br /&gt;Увага наскільки я знаю без використання super mode вашу програму можна вернути в вихідний код.&lt;br /&gt;Нам треба super mode, який на момент написання статті не вийшов для python 3.10 тому я буду використовувати python 3.9, але в можете глянути в &lt;a href=&quot;https://pyarmor.readthedocs.io/&quot; target=&quot;_blank&quot;&gt;документації &lt;/a&gt;чи є super mode для вашої версії python.&lt;br /&gt;Тепер зайдіть в папку з вашою прогою і напишіть:&lt;/p&gt;
  &lt;pre id=&quot;V491&quot;&gt;pyarmor obfuscate --advanced=2 .&lt;/pre&gt;
  &lt;p id=&quot;mwq5&quot;&gt;Це обфускує всі файли .py в папці і кидає їх в папку dist.&lt;br /&gt;--advanced=2 означає super mode.&lt;br /&gt;Також в папці dist буде файл pytransform, в нього основна програма передає обфускований код.&lt;br /&gt;Також ви можете вказати іншу платформу оскільки ті ж файли .pyd лише для вінди.&lt;br /&gt;Ось в документації про те як це зробити: &lt;a href=&quot;https://pyarmor.readthedocs.io/en/latest/advanced.html#distributing-obfuscated-scripts-to-other-platform&quot; target=&quot;_blank&quot;&gt;https://pyarmor.readthedocs.io/en/latest/advanced.html#distributing-obfuscated-scripts-to-other-platform&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;UPD: цей захист досить легко обійти як я побачив у майбутньому використовуючи підміну запитів, навіть якщо закрити цю дірку, то все одно захист можна буде обійти якщо постаратися.&lt;/p&gt;
  &lt;p id=&quot;ajWD&quot;&gt;На цьому все, якщо в захисті будуть знайдені дірки я буду оновлювати статтю.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:Y-Ak-robiti-veb-interfejsi-z-python-06-27</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/Y-Ak-robiti-veb-interfejsi-z-python-06-27?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Як робити веб інтерфейси з python</title><published>2022-07-18T19:25:37.189Z</published><updated>2022-07-18T19:25:37.189Z</updated><summary type="html">Ви можете знати про такі штуки як electron.
По факту це інтерфейс для програми на html, css, js.
Для пайтона є така бібліотека як eel, завдяки неї ми сьогодні напишемо простеньку програму яка показує час при натисненні на кнопку.
Поставити її можна командою:</summary><content type="html">
  &lt;p id=&quot;nY96&quot;&gt;Ви можете знати про такі штуки як electron.&lt;br /&gt;По факту це інтерфейс для програми на html, css, js.&lt;br /&gt;Для пайтона є така бібліотека як eel, завдяки неї ми сьогодні напишемо простеньку програму яка показує час при натисненні на кнопку.&lt;br /&gt;Поставити її можна командою:&lt;/p&gt;
  &lt;pre id=&quot;Y3vi&quot;&gt;pip install eel
&lt;/pre&gt;
  &lt;p id=&quot;iqyU&quot;&gt;Тепер створимо в папці нашого проекта папку web, туди будемо кидати наші файли html, css, js та якісь інші файлі(наприклад картинки).&lt;br /&gt;Сьогодні нам вистачть одного файлу html, але в більш великих проектах бажано розділяти html, css та js по різним файлам.&lt;br /&gt;Тепер глянемо код в нашому main.py&lt;/p&gt;
  &lt;pre id=&quot;fIWG&quot;&gt;import eel
from datetime import datetime
&lt;/pre&gt;
  &lt;p id=&quot;lCzS&quot;&gt;Імпортуємо eel для інтерфейсу та datetime для часу.&lt;/p&gt;
  &lt;pre id=&quot;jluv&quot;&gt;@eel.expose()
def what_time():
    return datetime.now().strftime(&amp;quot;%d/%m/%Y %H:%M:%S&amp;quot;)
&lt;/pre&gt;
  &lt;p id=&quot;8GRZ&quot;&gt;Розберемо по рядкам.&lt;br /&gt;@eel.expose це декоратор(що це таке можете глянути тут &lt;a href=&quot;https://docs.python.org/3/glossary.html&quot; target=&quot;_blank&quot;&gt;https://docs.python.org/3/glossary.html&lt;/a&gt; тут взагалі про багато штук в пайтоні і в тому числі про декоратори), цей декоратор дає можливість нам викликати цю функцію з javascript на нашій сторінці.&lt;br /&gt;На наступному рядку ми оголушеємо функцію.&lt;br /&gt;На наступному рядку ми одразу повертаємо дату в форматі який ми вказали в функції strftime.&lt;/p&gt;
  &lt;pre id=&quot;9K3c&quot;&gt;eel.init(&amp;quot;web&amp;quot;)
eel.start(&amp;quot;main.html&amp;quot;, mode=&amp;quot;chrome&amp;quot;, cmdline_args=[&amp;quot;--kiosk&amp;quot;])
&lt;/pre&gt;
  &lt;p id=&quot;gMfz&quot;&gt;Ініціалізуємо eel в папці web.&lt;br /&gt;На настпному рядку ми відкриваємо файл main.html в режимі chrome і в аргументах вказуємо --kiosk він означає що програма буде в повноекранному режимі.&lt;/p&gt;
  &lt;p id=&quot;wa6C&quot;&gt;Тепер розглянемо файл main html.&lt;/p&gt;
  &lt;p id=&quot;cq9j&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/p&gt;
  &lt;p id=&quot;W0ra&quot;&gt;&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;/p&gt;
  &lt;p id=&quot;Jq22&quot;&gt;На першому рядку вказуєм що це найновіше версія html.&lt;/p&gt;
  &lt;p id=&quot;Ow4F&quot;&gt;а наступному відкриваєм тег html&lt;/p&gt;
  &lt;pre id=&quot;chP4&quot;&gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
&amp;lt;title&amp;gt;Crypto Pidval&amp;lt;/title&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;eel.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;
  &lt;p id=&quot;6Y3h&quot;&gt;Вказуєм кодування utf-8 назву вікна Crypto Pidval та додаєм скрипт eel через який ми і будемо запускати функції з пайтона.&lt;/p&gt;
  &lt;pre id=&quot;60Qf&quot;&gt;&amp;lt;style&amp;gt;
    body{
        background: linear-gradient(to right, #40E0D0, #FF8C00, #FF0080);
    }
&lt;/pre&gt;
  &lt;p id=&quot;hx9f&quot;&gt;Відкриваєм тег style.&lt;br /&gt;Для тега body(основний тег) ставимо фон градієнта(його я взяв з &lt;a href=&quot;https://uigradients.com/&quot; target=&quot;_blank&quot;&gt;https://uigradients.com/&lt;/a&gt; прикольний сайт з градієнтами).&lt;/p&gt;
  &lt;pre id=&quot;K7QN&quot;&gt;button{
    background: linear-gradient(to right, #00F260, #0575E6);
    border: none;
    color: white;
    width: 190px;
    height: 108px;
    font-size: 2em;
    margin-left: 21em;
}
button:hover{
    background: linear-gradient(to right, #6EE856, #006BD2);
}
&lt;/pre&gt;
  &lt;p id=&quot;QS9Q&quot;&gt;Для кнопок ставимо фон градієнтом, прибираємо контури(вони мені не подобаються), ставимо колір тексту білим, ставимо ширину та висоту, а далі ставимо розмір тексту 2em(це одиниця виміру яку часто використовують для тексту), і відступаємо 21em щоб кнопка була по цетру(так я знаю що можна відцентрувати по нормальному, але тут це не обов&amp;#x27;язково).&lt;br /&gt;Далі ми ставимо щоб мінявся фон при наведені на кнопку.&lt;/p&gt;
  &lt;pre id=&quot;N5TU&quot;&gt;#time{
    color: #40E0D0;
    text-align: center;
}
&lt;/pre&gt;
  &lt;p id=&quot;iuic&quot;&gt;Ставимо колір нашому тексту з айді time і центруємо його.&lt;/p&gt;
  &lt;pre id=&quot;8lh5&quot;&gt;    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/pre&gt;
  &lt;p id=&quot;xuIY&quot;&gt;Закриваємо теги style та head.&lt;/p&gt;
  &lt;pre id=&quot;rkCm&quot;&gt;&amp;lt;body&amp;gt;
        &amp;lt;button onclick=&amp;quot;what_time();&amp;quot;&amp;gt;What is the time?&amp;lt;/button&amp;gt;
        &amp;lt;h1 id=&amp;quot;time&amp;quot;&amp;gt;Result&amp;lt;/h1&amp;gt;
&lt;/pre&gt;
  &lt;p id=&quot;JUUv&quot;&gt;Відкриваємо тег body.&lt;br /&gt;Також створюєм кнопку яка при нажатті вкикликає функцію what_time.&lt;br /&gt;Також текст з айді time.&lt;/p&gt;
  &lt;pre id=&quot;WytF&quot;&gt;&amp;lt;script&amp;gt;
    async function what_time(){
        result = await eel.what_time()();
        document.getElementById(&amp;#x27;time&amp;#x27;).innerHTML = result;
    }
&amp;lt;/script&amp;gt;
&lt;/pre&gt;
  &lt;p id=&quot;a7EG&quot;&gt;В цьому скрипті ми створюємо асинхронну функцію what_time(яка якраз і вкикликається при натисненні на кнопку).&lt;br /&gt;Далі вкиликаємо функцію what_time вже із пайтона і зберігаємо результат її виконання в змінну.&lt;br /&gt;Далі міняємо текст нашому тегу h1 на час.&lt;/p&gt;
  &lt;pre id=&quot;1tL5&quot;&gt;&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
  &lt;p id=&quot;g8r9&quot;&gt;Закриваємо теги.&lt;/p&gt;
  &lt;p id=&quot;BMiv&quot;&gt;Ось весь файл main.py:&lt;/p&gt;
  &lt;pre id=&quot;SRb1&quot;&gt;import eel
from datetime import datetime

@eel.expose()
def what_time():
    return datetime.now().strftime(&amp;quot;%d/%m/%Y %H:%M:%S&amp;quot;)
eel.init(&amp;quot;web&amp;quot;)
eel.start(&amp;quot;main.html&amp;quot;, mode=&amp;quot;chrome&amp;quot;, cmdline_args=[&amp;quot;--kiosk&amp;quot;])
&lt;/pre&gt;
  &lt;p id=&quot;jTzr&quot;&gt;І файл main.html:&lt;/p&gt;
  &lt;pre id=&quot;1EeI&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;Crypto Pidval&amp;lt;/title&amp;gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;eel.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;style&amp;gt;
        body{
            background: linear-gradient(to right, #40E0D0, #FF8C00, #FF0080);
        }
        button{
            background: linear-gradient(to right, #00F260, #0575E6);
            border: none;
            color: white;
            width: 190px;
            height: 108px;
            font-size: 2em;
            margin-left: 21em;
        }
        button:hover{
            background: linear-gradient(to right, #6EE856, #006BD2);
        }
        #time{
            color: #40E0D0;
            text-align: center;
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
        &amp;lt;button onclick=&amp;quot;what_time();&amp;quot;&amp;gt;What is the time?&amp;lt;/button&amp;gt;
        &amp;lt;h1 id=&amp;quot;time&amp;quot;&amp;gt;Result&amp;lt;/h1&amp;gt;
    &amp;lt;script&amp;gt;
        async function what_time(){
            result = await eel.what_time()();
            document.getElementById(&amp;#x27;time&amp;#x27;).innerHTML = result;
        }
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
  &lt;p id=&quot;9WMR&quot;&gt;На цьому все, Ось тут є &lt;a href=&quot;https://pypi.org/project/Eel/&quot; target=&quot;_blank&quot;&gt;документація &lt;/a&gt;eel.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:Y-Ak-zberigati-ta-zavantazhuvati-cookies-u-selenium-06-03</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/Y-Ak-zberigati-ta-zavantazhuvati-cookies-u-selenium-06-03?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Як зберігати та завантажувати cookies у selenium</title><published>2022-07-18T19:25:20.529Z</published><updated>2022-07-18T19:25:20.529Z</updated><summary type="html">Сьогодні ми напишемо невеличку програмку яка дозволить нам авторизуватись на сайт лише раз(ну якщо ви не забудете нажати ентер або не дочекаєтесь збереження як я під час тестів), а потім програма сама буде підвантажувати cookies.
Починаємо.</summary><content type="html">
  &lt;p id=&quot;sm9C&quot;&gt;Сьогодні ми напишемо невеличку програмку яка дозволить нам авторизуватись на сайт лише раз(ну якщо ви не забудете нажати ентер або не дочекаєтесь збереження як я під час тестів), а потім програма сама буде підвантажувати cookies.&lt;br /&gt;Починаємо.&lt;/p&gt;
  &lt;pre id=&quot;0DqY&quot;&gt;from selenium import webdriver
import pickle
&lt;/pre&gt;
  &lt;p id=&quot;rEr5&quot;&gt;Імпортим ліби.&lt;br /&gt;Selenium для керування браузером та pickle для зберігання/завантаження cookies.&lt;/p&gt;
  &lt;pre id=&quot;P7iP&quot;&gt;driver = webdriver.Chrome()
driver.maximize_window()
driver.get(&amp;quot;https://stackoverflow.com&amp;quot;)
&lt;/pre&gt;
  &lt;p id=&quot;hRkK&quot;&gt;Створюємо об&amp;#x27;єкт driver для керування браузером.&lt;br /&gt;Заходимо в повноекранний режим(просто не повноекранний режим мене бісить).&lt;br /&gt;Відкриваєм сайт без якого програмування майже неможливе(stackoverflow).&lt;/p&gt;
  &lt;pre id=&quot;KMbS&quot;&gt;try:
    with open(&amp;quot;cookies.pkl&amp;quot;, &amp;quot;rb&amp;quot;) as f:
        cookies = pickle.load(f)
    for cookie in cookies:
        driver.add_cookie(cookie)
&lt;/pre&gt;
  &lt;p id=&quot;VOtB&quot;&gt;Починаєм блок try.&lt;br /&gt;Тут ми пробуєм відкрити файл і прочитати cookies в змінну.&lt;br /&gt;Далі завантажуєм їх в браузер.&lt;br /&gt;Якщо що структура with просто за нас в кінці закриває файл що корисно(і так не закриті файли це погано).&lt;/p&gt;
  &lt;pre id=&quot;LHti&quot;&gt;except:
    input()
    with open(&amp;quot;cookies.pkl&amp;quot;, &amp;quot;wb&amp;quot;) as f:
        pickle.dump(driver.get_cookies(), f)
&lt;/pre&gt;
  &lt;p id=&quot;XN4E&quot;&gt;Якщо помилка чекаєм нажаття ентер і після цього записуєм cookies в файл.&lt;/p&gt;
  &lt;pre id=&quot;Is37&quot;&gt;else:
    driver.refresh()
&lt;/pre&gt;
  &lt;p id=&quot;MLWu&quot;&gt;Якщо помилки не було то перезавантажуєм сторінку щоб сайт побачив що ми авторизовані.&lt;/p&gt;
  &lt;pre id=&quot;7jIa&quot;&gt;print(&amp;quot;Done&amp;quot;)
&lt;/pre&gt;
  &lt;p id=&quot;5F94&quot;&gt;Пишем готово.&lt;br /&gt;Це просто для мене щоб я не закрив прогу раніше збереження cookies.&lt;br /&gt;В повноцінній програмі вам воно не треба.&lt;/p&gt;
  &lt;p id=&quot;5XX2&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:Y-Ak-pisati-klikeri-na-pajtoni-05-27</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/Y-Ak-pisati-klikeri-na-pajtoni-05-27?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Як писати клікери на пайтоні</title><published>2022-07-18T19:25:05.629Z</published><updated>2022-07-18T19:25:05.629Z</updated><summary type="html">Сьогодні ми напишемо клікера на пайтоні з pyautogui.
В більшості випадків краще використовувати щось інше але клікери теж прикольні.</summary><content type="html">
  &lt;p id=&quot;d7Km&quot;&gt;Сьогодні ми напишемо клікера на пайтоні з pyautogui.&lt;br /&gt;В більшості випадків краще використовувати щось інше але клікери теж прикольні.&lt;/p&gt;
  &lt;p id=&quot;P2FT&quot;&gt;Для початку встановим pyautogui:&lt;/p&gt;
  &lt;pre id=&quot;Ov07&quot;&gt;pip install pyautogui
&lt;/pre&gt;
  &lt;p id=&quot;L01Q&quot;&gt;Наш клікер для тесту буде клацати значок гугла.&lt;/p&gt;
  &lt;pre id=&quot;xqeZ&quot;&gt;import pyautogui
from time import sleep
&lt;/pre&gt;
  &lt;p id=&quot;6zIx&quot;&gt;Імпортимо pyautogui та функцію чекання з модулю time.&lt;/p&gt;
  &lt;pre id=&quot;jc0b&quot;&gt;sleep(3)
def climg(name):
    try:
        x,y=pyg.locateCenterOnScreen(f&amp;quot;{name}.png&amp;quot;)
    except:return
    pyg.click(x,y)
    sleep(0.3)
&lt;/pre&gt;
  &lt;p id=&quot;ZvLo&quot;&gt;Для початку чекаємо 3 секунди щоб встигнути перейти в інше вікно.&lt;br /&gt;Далі створюємо функцію, яка бере картинки png по імені яке передається в аргументі і клікає по цій картинці.&lt;br /&gt;Для початку зберігаєм координати в змінні x,y отримані функцією locateCenterOnScreen в яку ми вказуєм нашу картинку(картинки треба щоб були в тій же папці або довведеться вказувати повний шлях).&lt;br /&gt;Далі клікаєм і чекаєм трохи щоб все завантажилось.&lt;br /&gt;Не забудьте кинути скріншот значка гугла в папку зі скриптом з назвою google.png&lt;/p&gt;
  &lt;pre id=&quot;dkka&quot;&gt;climg(&amp;quot;google&amp;quot;)
&lt;/pre&gt;
  &lt;p id=&quot;hagH&quot;&gt;Клікаєм по значку гугла.&lt;/p&gt;
  &lt;pre id=&quot;W0C3&quot;&gt;import pyautogui as pyg
from time import sleep
sleep(3)
def climg(name):
    try:
        x,y=pyg.locateCenterOnScreen(f&amp;quot;{name}.png&amp;quot;)
    except:return
    pyg.click(x,y)
    sleep(0.3)
climg(&amp;quot;google&amp;quot;)
&lt;/pre&gt;
  &lt;p id=&quot;3cQK&quot;&gt;Таким чином можна було(принаймні раніше) автоматизувати sunflower land.&lt;br /&gt;Ось &lt;a href=&quot;https://pyautogui.readthedocs.io/en/latest/&quot; target=&quot;_blank&quot;&gt;документація&lt;/a&gt; pyautogui.&lt;br /&gt;Як на мене клікери не найкращі для крутих проектів, але це просто, швидко і досить цікаво.&lt;/p&gt;
  &lt;p id=&quot;FjOF&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:Znajomstvo-z-tampermonkey-05-23</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/Znajomstvo-z-tampermonkey-05-23?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Знайомство з tampermonkey</title><published>2022-07-18T19:24:55.992Z</published><updated>2022-07-18T19:24:55.992Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/3b/1c/3b1c6331-4648-4126-a3dd-88e1adf7140c.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/2f/60/2f601e35-e48c-40b6-9492-86d077af1903.png&quot;&gt;Сьогодні ми будемо вчити tampermonkey.
Скачати для Chromium-ів його можна тут.
Тепер розбираєм скрипт.</summary><content type="html">
  &lt;p id=&quot;W1Hh&quot;&gt;Сьогодні ми будемо вчити tampermonkey.&lt;br /&gt;Скачати для Chromium-ів його можна &lt;a href=&quot;https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;.&lt;br /&gt;Тепер розбираєм скрипт.&lt;/p&gt;
  &lt;pre id=&quot;1bT1&quot;&gt;// ==UserScript==
// @name         Crypto Pidval test
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Test script
// @author       https://t.me/cryptopidval
// @match        https://www.google.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&amp;amp;domain=google.com
// @grant        none
// ==/UserScript==
&lt;/pre&gt;
  &lt;p id=&quot;JJvE&quot;&gt;@name це назва скрипта.&lt;br /&gt;@description це опис.&lt;br /&gt;@version це версія скрипта.&lt;br /&gt;@author це автор скрипта.&lt;br /&gt;@match це як має виглядати посилання * це будь-які посилання.&lt;br /&gt;@icon це іконка.&lt;/p&gt;
  &lt;pre id=&quot;4cNf&quot;&gt;function simulateMouseClick(targetNode) {
    function triggerMouseEvent(targetNode, eventType) {
        var clickEvent = document.createEvent(&amp;#x27;MouseEvents&amp;#x27;);
        clickEvent.initEvent(eventType, true, true);
        targetNode.dispatchEvent(clickEvent);
    }
    [&amp;quot;mouseover&amp;quot;, &amp;quot;mousedown&amp;quot;, &amp;quot;mouseup&amp;quot;, &amp;quot;click&amp;quot;].forEach(function(eventType) {
        triggerMouseEvent(targetNode, eventType);
    });
};
&lt;/pre&gt;
  &lt;p id=&quot;ZnQE&quot;&gt;Функція що симулює кліки на javascript.&lt;br /&gt;Вона бере просто наш об&amp;#x27;єкт і трігерить івенти(як зміг пояснив, дякую добрим людям зі stackoverflow за код).&lt;/p&gt;
  &lt;pre id=&quot;O7eq&quot;&gt;function getElementsByXPath(xpath, parent)
{
    let results = [];
    let query = document.evaluate(xpath, parent || document,
        null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (let i = 0, length = query.snapshotLength; i &amp;lt; length; ++i) {
        results.push(query.snapshotItem(i));
    }
    return results;
};
&lt;/pre&gt;
  &lt;p id=&quot;1JW0&quot;&gt;Штука яка шукає елементи за xpath(його ви можете знати з selenium).&lt;br /&gt;По факту шукає за xpath лише document.evaluate а інше конвертує його в нормальний list.&lt;/p&gt;
  &lt;pre id=&quot;YPFB&quot;&gt;function main(){
    getElementsByXPath(&amp;quot;//h3[@class=&amp;#x27;LC20lb MBeuO DKV0Md&amp;#x27;]&amp;quot;).forEach(element=&amp;gt; {
        alert(element.textContent);
    });
};
&lt;/pre&gt;
  &lt;figure id=&quot;522g&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2f/60/2f601e35-e48c-40b6-9492-86d077af1903.png&quot; /&gt;
    &lt;figcaption&gt;Клас результатів.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;6LP1&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/72/22/7222f3a4-f4e8-419b-9b11-c690a6b0e90d.png&quot; /&gt;
    &lt;figcaption&gt;Повідомлення з текстом про результат.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;0XiH&quot;&gt;Основна функція.&lt;br /&gt;Шукає всі результати далі через foreach проходить по всім елементам списку і показує його текст.&lt;/p&gt;
  &lt;pre id=&quot;BNQc&quot;&gt;main();
&lt;/pre&gt;
  &lt;p id=&quot;KJv5&quot;&gt;Запускаєм основну функцію.&lt;/p&gt;
  &lt;p id=&quot;Tutq&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:Otrimuyemo-cinu-kripti-z-coinmarketcap-05-21</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/Otrimuyemo-cinu-kripti-z-coinmarketcap-05-21?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Отримуємо ціну крипти з coinmarketcap.</title><published>2022-07-18T19:24:43.737Z</published><updated>2022-07-18T19:24:43.737Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/d1/b2/d1b2d509-397c-4ba4-8395-b667f2b1bab2.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/64/aa/64aa7b03-b2fb-47e6-9796-7824888de89a.png&quot;&gt;Сьогодні я покажу два способи отримання інфи з coinmarketcap:
-Нормальний, через офіційне api.
-Колхозний через парсер, інформація не така точна(з api ви отримуєте 12 цифр після крапки в ціні біткоіна в доларах), але зате нема обмежень по використанню.</summary><content type="html">
  &lt;p id=&quot;nm4e&quot;&gt;Сьогодні я покажу два способи отримання інфи з coinmarketcap:&lt;br /&gt;-Нормальний, через офіційне api.&lt;br /&gt;-Колхозний через парсер, інформація не така точна(з api ви отримуєте 12 цифр після крапки в ціні біткоіна в доларах), але зате нема обмежень по використанню.&lt;/p&gt;
  &lt;h4 id=&quot;Через-api.&quot;&gt;Через api.&lt;/h4&gt;
  &lt;p id=&quot;iFWH&quot;&gt;Для початку треба отримати ключ api. Тому ідемо на цей &lt;a href=&quot;https://pro.coinmarketcap.com/signup/&quot; target=&quot;_blank&quot;&gt;сайт &lt;/a&gt;якщо ще не реєструвались на порталі для розробників, або на цей &lt;a href=&quot;https://pro.coinmarketcap.com/login&quot; target=&quot;_blank&quot;&gt;сайт&lt;/a&gt; якщо вже режструвались.&lt;/p&gt;
  &lt;figure id=&quot;q5C3&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/64/aa/64aa7b03-b2fb-47e6-9796-7824888de89a.png&quot; /&gt;
    &lt;figcaption&gt;Ключ api брати тут&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;5rYq&quot;&gt;Далі копіюєте свій ключ api.&lt;br /&gt;В файлі coinfig.py пишите таке:&lt;/p&gt;
  &lt;pre id=&quot;oDH0&quot;&gt;api_key = &amp;#x27;ВАШ КЛЮЧ API&amp;#x27;
&lt;/pre&gt;
  &lt;p id=&quot;nKpC&quot;&gt;Замість ВАШ КЛЮЧ API напишіт ваш ключ api)))&lt;br /&gt;Тепер main.py:&lt;/p&gt;
  &lt;pre id=&quot;3JJJ&quot;&gt;from requests import Request, Session
import config
&lt;/pre&gt;
  &lt;p id=&quot;eVlJ&quot;&gt;Імпортим requests для запитів до api та config де зберігається ключ api.&lt;/p&gt;
  &lt;pre id=&quot;Eynt&quot;&gt;url = &amp;#x27;https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest&amp;#x27;
&lt;/pre&gt;
  &lt;p id=&quot;vMR1&quot;&gt;Записуєм url.&lt;br /&gt;Там різні url для різного тому в кінці я залишу посилання на офіційну документацію.&lt;/p&gt;
  &lt;pre id=&quot;fOeW&quot;&gt;parameters ={
&amp;#x27;slug&amp;#x27;: &amp;#x27;bitcoin&amp;#x27;,
&amp;#x27;convert&amp;#x27;: &amp;#x27;USD&amp;#x27;
}
&lt;/pre&gt;
  &lt;p id=&quot;k7hf&quot;&gt;Ставимо &amp;#x27;slug&amp;#x27; в значення &amp;#x27;bitcoin&amp;#x27; це валюта ціна якої нам треба.&lt;br /&gt;&amp;#x27;convert&amp;#x27; ставимо в значення &amp;#x27;USD&amp;#x27;, як ви могли здогадатись це в якій валюті нам треба ціна.&lt;/p&gt;
  &lt;pre id=&quot;iHDG&quot;&gt;headers ={
    &amp;#x27;Accepts&amp;#x27;: &amp;#x27;application/json&amp;#x27;,
    &amp;#x27;X-CMC_PRO_API_KEY&amp;#x27;: config.api_key
}
&lt;/pre&gt;
  &lt;p id=&quot;wlGn&quot;&gt;&amp;#x27;Accepts&amp;#x27; це по логіці в якому форматі нам буде вертати результати, але я не впевнений.&lt;br /&gt;&amp;#x27;X-CMC_PRO_API_KEY&amp;#x27; це наш ключ api.&lt;/p&gt;
  &lt;pre id=&quot;PPVp&quot;&gt;session = Session()
session.headers.update(headers)
&lt;/pre&gt;
  &lt;p id=&quot;Z84F&quot;&gt;Створюєм сесію requests і додаєм наші заголовки.&lt;/p&gt;
  &lt;pre id=&quot;JxRN&quot;&gt;response = session.get(url, params=parameters)
print(response.json()[&amp;#x27;data&amp;#x27;][&amp;#x27;1&amp;#x27;][&amp;#x27;quote&amp;#x27;][&amp;#x27;USD&amp;#x27;][&amp;#x27;price&amp;#x27;])
&lt;/pre&gt;
  &lt;p id=&quot;rLMV&quot;&gt;Кидаєм запит до api і виводимо результати.&lt;br /&gt;Результат такий пиблизно буде: 29320.595168474585, але сподіваюсь у вас біткоін по 100к)))&lt;/p&gt;
  &lt;p id=&quot;Njkr&quot;&gt;Загалом найкращий спосіб але в безкоштовній версії 333 запита в день, але я думаю можна створити 5 акаунтів і раз в хвилину запити кидати зможете.&lt;br /&gt;Як і обіцяв офіційна &lt;a href=&quot;https://coinmarketcap.com/api/documentation/v1/&quot; target=&quot;_blank&quot;&gt;документація&lt;/a&gt;.&lt;/p&gt;
  &lt;h4 id=&quot;Без-api(колхоз).&quot;&gt;Без api(колхоз).&lt;/h4&gt;
  &lt;p id=&quot;U2eF&quot;&gt;Це дійсно колхозний спосіб для порівняння результати api 29320.595168474585 та результати без api 29,320.60 (кому видаляти можна) тобто з api 12 цифр після крапки а тут 2.&lt;br /&gt;Але зате тут скільки хочете в день(та й треба хоч десь парсери показати).&lt;/p&gt;
  &lt;p id=&quot;RUZ9&quot;&gt;Для початку треба поставити BeautifulSoup.&lt;br /&gt;pip install beautifulsoup4 це треба ввести в командний рядок/термінал.&lt;br /&gt;Тепер код:&lt;/p&gt;
  &lt;pre id=&quot;3rml&quot;&gt;import requests
from bs4 import BeautifulSoup
&lt;/pre&gt;
  &lt;p id=&quot;sw3N&quot;&gt;Імпортимо requests та BeautifulSoup.&lt;/p&gt;
  &lt;pre id=&quot;XEvQ&quot;&gt;page = requests.get(&amp;quot;https://coinmarketcap.com/currencies/bitcoin/&amp;quot;)
&lt;/pre&gt;
  &lt;p id=&quot;rc8y&quot;&gt;Отримуємо сторінку про bitcoin.&lt;/p&gt;
  &lt;pre id=&quot;Mipv&quot;&gt;soup=BeautifulSoup(page.content, &amp;#x27;html.parser&amp;#x27;)
&lt;/pre&gt;
  &lt;p id=&quot;E41n&quot;&gt;Налаштовуєм парсер щоб він міг шукати по нашій сторінці данні.&lt;/p&gt;
  &lt;pre id=&quot;czmO&quot;&gt;crypto_name=list(soup.find(class_=&amp;quot;sc-1q9q90x-0 jCInrl h1&amp;quot;).children)[0]
&lt;/pre&gt;
  &lt;figure id=&quot;IOza&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b6/a8/b6a8c107-51ab-421b-84af-4e168486584f.png&quot; /&gt;
    &lt;figcaption&gt;Надпис Bitcoin&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;VjIx&quot;&gt;Знаходимо для початку елемент(завдяки пошуку за класом) який є батьківським для надпису Bitcoin(і так я знаю що в посиланні нашому і так написано біткоін, але по перше ми могли б писати в посиланні btc а по друге парсинг треба показати.&lt;br /&gt;Потім конвертуємо список дочірніх елементів в нормальний список і беремо нульовий елемент(це і є надпис &amp;quot;Bitcoin&amp;quot;).&lt;/p&gt;
  &lt;pre id=&quot;B80y&quot;&gt;crypto_price=soup.find(class_=&amp;quot;priceValue&amp;quot;).text
&lt;/pre&gt;
  &lt;figure id=&quot;GY3g&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/95/f1/95f100aa-05d3-4310-b0e2-1fb416aa2ec0.png&quot; /&gt;
    &lt;figcaption&gt;Надпис ціни&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;F5r7&quot;&gt;Беремо елемент ціни за класом і отримуємо з цього елемента текст.&lt;/p&gt;
  &lt;pre id=&quot;fE9L&quot;&gt;print(crypto_name,crypto_price)
&lt;/pre&gt;
  &lt;p id=&quot;dht5&quot;&gt;Виводимо назву крипти та ціну.&lt;/p&gt;
  &lt;p id=&quot;InfZ&quot;&gt;Як бачите без api код навіть менше, але це не відміняє його колхозність.&lt;/p&gt;
  &lt;p id=&quot;b0XZ&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>cryptopidval:Bo7jykbN7ET</id><link rel="alternate" type="text/html" href="https://teletype.in/@cryptopidval/Bo7jykbN7ET?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cryptopidval"></link><title>Як підключити Phantom Wallet через Selenium</title><published>2022-07-18T19:24:27.276Z</published><updated>2023-03-01T21:08:19.449Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/7a/72/7a72336f-5a04-445b-bb75-38b56846546c.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/de/e4/dee465d2-9d2a-435d-86af-a1d8bab0b175.png&quot;&gt;Для початку імортнемо ліби: selenium, time та config.</summary><content type="html">
  &lt;pre id=&quot;wlN3&quot;&gt;from selenium import webdriver
from time import sleep
import config
&lt;/pre&gt;
  &lt;p id=&quot;2Lmd&quot;&gt;Для початку імортнемо ліби: selenium, time та config.&lt;/p&gt;
  &lt;p id=&quot;XO7q&quot;&gt;Остання ліба це файл який вам треба створити &amp;quot;config.py&amp;quot;, в ньому буде секретна фраза від гаманця та пароль який на нього поставиться.&lt;/p&gt;
  &lt;p id=&quot;ppmA&quot;&gt;З time ми імпортуємо sleep це штука яка просто нічого не робить(спить) певну кількість секунд.&lt;/p&gt;
  &lt;p id=&quot;QmLD&quot;&gt;&lt;strong&gt;Як додати розширення? &lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;yt5B&quot;&gt;В фаєрфоксі трохи все інакше тому ось &lt;a href=&quot;https://www.lambdatest.com/blog/adding-firefox-extensions-with-selenium-in-python/&quot; target=&quot;_blank&quot;&gt;стаття&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;Fazt&quot;&gt;Для хрома ось так.&lt;br /&gt;Для початку треба отримати файл розширення на цьому &lt;a href=&quot;https://crxextractor.com/&quot; target=&quot;_blank&quot;&gt;сайті &lt;/a&gt;вставляєте посилання на розширення в chrome webstore.&lt;br /&gt;Оце &lt;a href=&quot;https://chrome.google.com/webstore/detail/phantom/bfnaelmomeimhlpmgjnjophhpkkoljpa&quot; target=&quot;_blank&quot;&gt;Phantom&lt;/a&gt; який ми будемо використовувати.&lt;br /&gt;Файл crx який ми скачали кидаємо в папку з прогою.&lt;br /&gt;Ось код:&lt;/p&gt;
  &lt;pre id=&quot;rjpc&quot;&gt;EXTENSION_PATH = &amp;#x27;extension_22_4_26_0.crx&amp;#x27;
opt = webdriver.ChromeOptions()
opt.add_extension(EXTENSION_PATH)
driver = webdriver.Chrome(chrome_options=opt)
&lt;/pre&gt;
  &lt;p id=&quot;Pwnz&quot;&gt;Цей код бере наше розширення(ім&amp;#x27;я файлу ставите своє) і підключає його.&lt;/p&gt;
  &lt;pre id=&quot;nZ7V&quot;&gt;driver.get(&amp;quot;chrome-extension://bfnaelmomeimhlpmgjnjophhpkkoljpa/onboarding.html&amp;quot;)
&lt;/pre&gt;
  &lt;figure id=&quot;lKEW&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/de/e4/dee465d2-9d2a-435d-86af-a1d8bab0b175.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Головна сторінка Phantom.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;yOh2&quot;&gt;Останній шматок коду який для chrome та firefox різний. &lt;br /&gt;Він відкриває головну сторінку Phantom. &lt;br /&gt;Оці букви ви берете з посилання розширення &lt;a href=&quot;https://chrome.google.com/webstore/detail/phantom/bfnaelmomeimhlpmgjnjophhpkkoljpa&quot; target=&quot;_blank&quot;&gt;https://chrome.google.com/webstore/detail/phantom/&lt;strong&gt;bfnaelmomeimhlpmgjnjophhpkkoljpa&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;pre id=&quot;Pj7r&quot;&gt;driver.switch_to.window(driver.window_handles[-1])
sleep(3)
&lt;/pre&gt;
  &lt;p id=&quot;nXP2&quot;&gt;Переключаємось на вкладку яку ми відкрили, а також чекаємо 3 секунди щоб все підвантажилось.&lt;/p&gt;
  &lt;pre id=&quot;ENNw&quot;&gt;driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[1].click()
sleep(3)
&lt;/pre&gt;
  &lt;p id=&quot;s0sJ&quot;&gt;Клацаємо на другу кнопку яка відповідає за імпорт гаманця. І знову чекаємо)))&lt;/p&gt;
  &lt;pre id=&quot;QvlX&quot;&gt;for i,j in enumerate(config.secret_phrase.split()):
&lt;/pre&gt;
  &lt;p id=&quot;FgCV&quot;&gt;for цикл тут в i індекси, а в j слова фрази.&lt;br /&gt;&lt;strong&gt;Наступні рядки будуть в for циклі!&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;QPH7&quot;&gt;driver.execute_script(&amp;quot;arguments[0].setAttribute(&amp;#x27;type&amp;#x27;,arguments[1])&amp;quot;,driver.find_element_by_id(f&amp;quot;word_{i}&amp;quot;), &amp;quot;password&amp;quot;)
&lt;/pre&gt;
  &lt;p id=&quot;JcaK&quot;&gt;Тут використовується execute_script він ставить атрибут type для інпут password.&lt;br /&gt;Завдяки find ми беремо елемент куди ми вставимо слова фрази.&lt;br /&gt;Отже тепер коли ми вставимо туди фразу її не буде видно що добре.&lt;/p&gt;
  &lt;pre id=&quot;rRue&quot;&gt;driver.find_element_by_id(f&amp;quot;word_{i}&amp;quot;).send_keys(j)
&lt;/pre&gt;
  &lt;figure id=&quot;G8fq&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f9/4c/f94c5873-fc61-4a94-93a2-aecf657fb4a9.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Поля для вводу сід фрази.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9ZYl&quot;&gt;Вставляємо слово фрази.&lt;br /&gt;UPD станом на 01.03.2023 тут треба трохи змінити останні два рядки на:&lt;/p&gt;
  &lt;pre id=&quot;6ZIF&quot;&gt;driver.execute_script(&amp;quot;arguments[0].setAttribute(&amp;#x27;type&amp;#x27;,arguments[1])&amp;quot;,driver.find_element(By.XPATH , f&amp;quot;/html/body/div/main/div[2]/form/div/div[2]/div[{i+1}]/input&amp;quot;), &amp;quot;password&amp;quot;)
driver.find_element(By.XPATH , f&amp;quot;/html/body/div/main/div[2]/form/div/div[2]/div[{i+1}]/input&amp;quot;).send_keys(j)&lt;/pre&gt;
  &lt;p id=&quot;GLGt&quot;&gt;&lt;strong&gt;Тепер рядки вже не в for циклі!&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;wzyV&quot;&gt;sleep(3)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[0].click()
&lt;/pre&gt;
  &lt;figure id=&quot;rq5y&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1e/1f/1e1f2a23-8304-482c-8f7d-362fe0e679ef.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Кнопка Import Wallet.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;T0sj&quot;&gt;Чекаємо 3 секунди і клацаємо на кнопку import wallet.&lt;/p&gt;
  &lt;pre id=&quot;WqdH&quot;&gt;while True:
  if &amp;quot;Import Selected Accounts&amp;quot; in driver.page_source:break
  else:sleep(1)
&lt;/pre&gt;
  &lt;p id=&quot;7W0p&quot;&gt;Якщо з&amp;#x27;явилось Import Selected Accounts а отже сторінка підвантажилась виходимо із циклу.&lt;br /&gt;Якщо ні, то чекаєм секунду.&lt;/p&gt;
  &lt;pre id=&quot;ZjUF&quot;&gt;sleep(3)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[0].click()
&lt;/pre&gt;
  &lt;figure id=&quot;wnv2&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bf/c0/bfc0a818-2f49-4bd1-adc4-d4b9ed7f6253.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Кнопка Import Selected Accounts.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;FikP&quot;&gt;Клацаємо на кнопку Import Selected Accounts.&lt;/p&gt;
  &lt;pre id=&quot;xXD6&quot;&gt;while True:
    try:
        driver.find_element_by_name(&amp;quot;password&amp;quot;)
    except:sleep(1)
    else:break
&lt;/pre&gt;
  &lt;p id=&quot;Nbce&quot;&gt;В цьому циклі ми шукаємо елемент з атрибутом name=&amp;quot;password&amp;quot; якщо він є то виходимо з циклу, якщо ні, то чекаєму 1 сеукунду.&lt;/p&gt;
  &lt;pre id=&quot;dM8K&quot;&gt;driver.find_element_by_name(&amp;quot;password&amp;quot;).send_keys(config.wallet_password)
driver.find_element_by_name(&amp;quot;confirmPassword&amp;quot;).send_keys(config.wallet_password)
&lt;/pre&gt;
  &lt;figure id=&quot;VEm8&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/85/05/8505ed78-634c-4c13-adbe-c8827e8d548e.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Поля ля паролів.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;AEGZ&quot;&gt;Тут ми пишемо та підтверджуємо пароль.&lt;/p&gt;
  &lt;pre id=&quot;VcQ8&quot;&gt;driver.find_elements_by_tag_name(&amp;quot;input&amp;quot;)[2].click()
sleep(1)
&lt;/pre&gt;
  &lt;figure id=&quot;cwln&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c7/f4/c7f41f76-8413-4819-80ef-6c850fe04226.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Кнопка підтвердження Terms of Service.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;I55Y&quot;&gt;Клацаємо на підтвердження Terms of Service.&lt;br /&gt;І чекаємо 1 секунду.&lt;/p&gt;
  &lt;pre id=&quot;mfJl&quot;&gt;driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[0].click()
sleep(1)
&lt;/pre&gt;
  &lt;figure id=&quot;HJeF&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f5/1b/f51bacff-4040-449c-ab9d-a3ad0cb15b9f.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Кнопка Continue.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Sx05&quot;&gt;Клацаємо на кнопу &amp;quot;Continue&amp;quot;.&lt;/p&gt;
  &lt;pre id=&quot;m0Bz&quot;&gt;driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[-1].click()
sleep(1)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[-1].click()
&lt;/pre&gt;
  &lt;figure id=&quot;aDD2&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ab/19/ab199b8b-db85-4ada-a553-71c761978986.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Кнопка Continue.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;79IE&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ee/de/eedeeecd-7707-4b5e-854a-69a72253e4a5.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Кнопка Finish.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;s18B&quot;&gt;Клацаєм &amp;quot;Continue&amp;quot; знову.&lt;br /&gt;Чекаєм 1 секунду.&lt;br /&gt;І клацаємо &amp;quot;Finish&amp;quot;.&lt;br /&gt;Фінальний main.py:&lt;/p&gt;
  &lt;pre id=&quot;1RuS&quot;&gt;from selenium import webdriver
from time import sleep
import config
EXTENSION_PATH = &amp;#x27;extension_22_4_26_0.crx&amp;#x27;
opt = webdriver.ChromeOptions()
opt.add_extension(EXTENSION_PATH)
driver = webdriver.Chrome(chrome_options=opt)
driver.get(&amp;quot;chrome-extension://bfnaelmomeimhlpmgjnjophhpkkoljpa/onboarding.html&amp;quot;)
driver.switch_to.window(driver.window_handles[-1])
sleep(3)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[1].click()
sleep(3)
for i,j in enumerate(config.secret_phrase.split()):
    driver.execute_script(&amp;quot;arguments[0].setAttribute(&amp;#x27;type&amp;#x27;,arguments[1])&amp;quot;,driver.find_element_by_id(f&amp;quot;word_{i}&amp;quot;), &amp;quot;password&amp;quot;)
    driver.find_element_by_id(f&amp;quot;word_{i}&amp;quot;).send_keys(j)
sleep(3)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[0].click()
while True:
    if &amp;quot;Import Selected Accounts&amp;quot; in driver.page_source:break
    else:sleep(1)
sleep(3)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[0].click()
while True:
    try:
        driver.find_element_by_name(&amp;quot;password&amp;quot;)
    except:sleep(1)
    else:break
driver.find_element_by_name(&amp;quot;password&amp;quot;).send_keys(config.wallet_password)
driver.find_element_by_name(&amp;quot;confirmPassword&amp;quot;).send_keys(config.wallet_password)
driver.find_elements_by_tag_name(&amp;quot;input&amp;quot;)[2].click()
sleep(1)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[0].click()
sleep(1)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[-1].click()
sleep(1)
driver.find_elements_by_tag_name(&amp;quot;button&amp;quot;)[-1].click()
&lt;/pre&gt;
  &lt;p id=&quot;kT1p&quot;&gt;config.py:&lt;/p&gt;
  &lt;pre id=&quot;kqLT&quot;&gt;secret_phrase=&amp;quot;secret phrase&amp;quot;
wallet_password=&amp;quot;wallet password&amp;quot;
&lt;/pre&gt;
  &lt;p id=&quot;WUtH&quot;&gt;Сюди треба вставити фразу та пароль.&lt;/p&gt;
  &lt;p id=&quot;Yuu0&quot;&gt;На цьому все.&lt;br /&gt;Всім удачі!&lt;br /&gt;Підготовлено каналом: &lt;a href=&quot;https://t.me/cryptopidval&quot; target=&quot;_blank&quot;&gt;https://t.me/cryptopidval&lt;/a&gt;&lt;/p&gt;

</content></entry></feed>