Skip to content

Instantly share code, notes, and snippets.

@karlbright
Created October 8, 2018 23:59
Show Gist options
  • Save karlbright/1aaae4cb32db5ff2dbcdcfe170b10482 to your computer and use it in GitHub Desktop.
Save karlbright/1aaae4cb32db5ff2dbcdcfe170b10482 to your computer and use it in GitHub Desktop.
use reqwest::{self, Error};
pub fn get_gettorrent_data_for_url(url: &String) -> Result<String, Error> {
let body = reqwest::get(url)?.text()?;
Ok(body)
}
pub mod http;
pub mod torrent;
pub mod url;
pub mod xml;
use base64;
use crypto::aes;
use crypto::blockmodes::PkcsPadding;
use crypto::buffer::{RefReadBuffer, RefWriteBuffer};
// Decode response <torrent>
// binascii.unhexlify <checksum>
// if first 8 bytes are '\x01\x02\x03\x04\x11\x02e.'
// - START OF HEADING + START OF TEXT + END OF TEXT + END OF TRANSMISSION + DEVICE CONTROL 1 + START OF TEXT + e + .
// - md5 digest '%E0(tK8r]8KKU=crz!Vuex0b#I)H+!0n}%f0]L_x0ch++?-<#YHwXkvM6UL'
// - and use as key to aes decrypt 128 CBC with empty IV '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
// if first 4 bytes are '\x01\x02\x03\x04'
// - START OF HEADING + START OF TEXT + END OF TEXT + END OF TRANSMISSION
// - md5 digest 'tslive_key'
// - and use as key to aes decrypt 128 CBC with empty IV '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
// if first 4 bytes are '\x11\x02e.'
// - DEVICE CONTROL 1 + START OF TEXT + e + .
// - md5 digest '=Atl6GD#Vb+#QwW9zJy34lBOcM-7R7G)'
// - and use as key to aes decrypt 128 CBC with empty IV '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
// bencode decode result of above with ordered dict
pub fn decode_torrent_string_from_xml_response(torrent: &String) -> Vec<u8> {
let decoded = decode_base64_torrent_string(&torrent);
println!("{}", String::from_utf8_lossy(&decoded));
let decrypted = decrypt_decoded_string(&decoded);
decrypted
}
fn decode_base64_torrent_string(torrent: &String) -> Vec<u8> {
base64::decode(torrent).unwrap()
}
fn decrypt_decoded_string(torrent: &Vec<u8>) -> Vec<u8> {
let key = "824e0bc114f58cdb5a49a0c0f142b424".as_bytes();
let mut out = Vec::new();
{
let mut input = RefReadBuffer::new(&torrent);
let mut output = RefWriteBuffer::new(&mut out);
let mut decryptor = aes::cbc_decryptor(
aes::KeySize::KeySize128,
key,
b"00000000000000000000000000000000",
PkcsPadding,
);
decryptor
.decrypt(&mut input, &mut output, true)
.expect("Failed to decrypt");
}
out
}
use rand;
use rand::Rng;
use sha1::Sha1;
const REQUEST_SECRET: &str = "q\\\'X!;UL0J_<R*z#GBTL(9mCeRJbm/;L.oi9.`\\\"iETli9GD]`t&xlT(]MhJ{NVN,Q.)r~(6+9Bt(G,O%2c/g@sPi]<c[i\\\\ga]fkbHgwH:->ok4w8><y]^:Lw465+W4a(:";
const TLDS: [&str; 3] = ["org", "info", "net"];
pub fn get_gettorrent_url_for_pid(pid: &str) -> String {
let mut rng = rand::thread_rng();
let host = get_hostname_for_gettorrent(&mut rng);
let path = get_path_for_gettorrent();
let query = get_querystring_for_gettorrent(&pid, &mut rng);
format!("{}{}{}", host, path, query)
}
fn get_hostname_for_gettorrent<R: Rng>(rng: &mut R) -> String {
let server = rng.gen_range(1, 4);
let tld = TLDS[rng.gen_range(0, 3) as usize];
format!("http://s{}.torrentstream.{}", server, tld)
}
fn get_path_for_gettorrent() -> &'static str {
"/gettorrent"
}
fn get_querystring_for_gettorrent<R: Rng>(pid: &str, rng: &mut R) -> String {
let num = rng.gen_range(1, <isize>::max_value());
let querystring = format!("_n=3.1.16.1&_p=win32&_r={}&_v=3011601&pid={}", num, pid);
let signature = generate_signature_for_request(&querystring);
format!("?{}&_s={}", querystring, signature)
}
fn generate_signature_for_request(querystring: &String) -> String {
let mut hash = Sha1::new();
let signature = querystring.replace("&", "#") + REQUEST_SECRET;
hash.update(signature.as_bytes());
hash.digest().to_string()
}
use serde_xml_rs;
#[derive(Deserialize, Debug)]
pub struct XMLResponse {
#[serde(rename = "sig")]
pub signature: String,
pub torrent: String,
pub checksum: String,
}
pub fn parse_gettorrent_response_xml(xml: &String) -> XMLResponse {
serde_xml_rs::deserialize(xml.as_bytes()).unwrap()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment