From 78498ca1f31c9e74924cdd39c45dcdd2da8ba916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Sun, 7 Aug 2022 02:44:59 +0200 Subject: initial commit --- discord.tcl | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100755 discord.tcl (limited to 'discord.tcl') diff --git a/discord.tcl b/discord.tcl new file mode 100755 index 0000000..85da7f0 --- /dev/null +++ b/discord.tcl @@ -0,0 +1,233 @@ +#!/usr/bin/tclsh +source www.tcl +namespace eval discord { + + package require Tcl 8.4 + package require http 2.7 + package require logger + package require sha1 + package require base64 + package require websocket 1.3.1 + ::websocket::loglevel "debug" + + package require tls + http::register https 443 [list ::tls::socket -autoservername true] + + package require Tcl 8.5 + package require json::write 1.0.3 + + package require Tcl 8.4 + package require json 1.3.3 + + package require TclOO + + package require logger + + package require lambda + + #unused + proc escape {string} { + set r "" + foreach t [split $string ""] { + if [regexp {[[:print:]]} $t] { + append r $t + } else { + append r "\\x[format %02X [scan $t %c]]" + } + } + return $r + } + + set html_mapping { "\"" " ' ' & & < < > > } + + # unused + set httpd_body { + method content {} { + set in [my FormData] + set sitekey sitekey_replace_me + my puts " +
+ +
+ +
+ you sent: [string map html_mapping $in] +
+ " + } + } + + proc login {email password callback {captcha {}}} { + if {$captcha == {}} { + set capt null + } else { + set capt [::json::write string $captcha] + } + proc login_command {callback token} { + upvar #0 $token state + if {[catch { + set token [dict get [::json::json2dict $state(body)] token] + set user_id [dict get [::json::json2dict $state(body)] user_id] + } result] != 0} { + if {[catch { + set captcha_sitekey [dict get [::json::json2dict $state(body)] captcha_sitekey] + } result] != 0} { + [{*}$callback error $result $state(body)] + } else { + [{*}$callback captcha $captcha_sitekey] + } + } else { + [{*}$callback ok $token $user_id] + } + ::http::cleanup $token + } + ::http::geturl https://discord.com/api/v9/auth/login -query "{\"login\":[::json::write string $email],\"password\":[::json::write string $password],\"undelete\":\"false\",\"captcha_key\":$capt,\"login_source\":null,\"gift_code_sku_id\":null}" -timeout 10000 -type application/json -command "[namespace which login_command] {$callback}" + } + + proc connect_example_callback {type {arg1 1}} { + switch $type { + ok { + puts stderr "connect success!" + } + authfail { + puts stderr "auth failed, try login again!" + } + error { + puts stderr "error connecting: $arg1" + } + } + } + + proc login_example_callback {type {arg1 {}}} { + switch $type { + ok { + puts "ok, login successful" + } + captcha { + puts "solve the captcha at address $arg1" + } + error { + puts "error: $arg1" + } + } + } + + oo::class create discord { + constructor {{stor {login {} password {} token {} user_id {}}}} { + my variable log storage + set storage $stor + set log [logger::init discord] + } + destructor { + my variable log storage sockets + foreach socket $sockets { + close $socket + } + if {[my is_connected] != -1} { + my disconnect + } + ${log}::delete + return storage + } + method disconnect {} { + my variable sock + ::websocket::close $sock 1000 "Tcl/Tk discord odjemalec se poslavlja" + unset sock + } + method set_login_password {login password} { + my variable storage + dict set storage login $login + dict set storage password $password + } + method set_token {token} { + my variable storage + dict set storage token + } + # handles captcha interactively + method login {callback} { + my variable storage log + proc login_callback {that callback type {arg1 ""} {arg2 ""}} { + namespace upvar $that log log sockets sockets + switch $type { + ok { + ${log}::notice "login ok: token is $arg1, user_id is $arg2" + [{*}$callback ok [list $arg1 $arg2]] + } + captcha { + ${log}::warn "login captcha: sitekey is $arg1" + proc httpd {that_login_callback chan addr port} { + namespace upvar $that_login_callback log log arg1 sitekey + fconfigure $chan -blocking 0 + proc readable {that_login_callback} { + namespace upvar $that_login_callback arg1 sitekey + gets + } + chan eventĀ $chan readable [list [namespace which readable] [self namespace]] + ${log}::notice "new connection to httpd from $addr:$port" + } + oo::class create + set srv [socket -server [list [namespace which httpd] [self namespace]] 0] + lappend sockets $srv + ${log}::notice "please solve captcha at http://127.0.0.1:[lindex [fconfigure $srv -sockname] 2]/captcha.html" + [{*}$callback captcha "http://127.0.0.1:[lindex [fconfigure $srv -sockname] 2]/captcha.html"] + } + error { + ${log}::error "login error: message is $arg1, response from server is $arg2" + [{*}$callback error [list $arg1 $arg2]] + } + } + } + ::discord::login [dict get $storage login] [dict get $storage password] "[namespace which login_callback] [self namespace] $callback" + } + method connect {} { + my variable sock log storage + if {[my is_connected] != -1} { + my disconnect + } + proc handler { sock type msg } { + my variable log + switch $type { + text { + ${log}::debug "received a message: $msg" + } + connect { + ${log}::notice "connected" + } + disconnect { + ${log}::notice "disconnected" + } + close { + ${log}::notice "pending closure of connection" + } + # binary and ping are unsupported + default { + ${log}::warn "received an unsupported handler call. type is $type, msg is $msg" + } + } + } + set sock [::websocket::open "wss://gateway.discord.gg/?encoding=json&v=9" [namespace which handler]] + ${log}::debug "created sock, $sock" + } + method is_connected {} { + my variable sock log + if {![info exists sock]} { + return -1 + } + if {[::websocket::conninfo $sock state] == "CONNECTED"} { + return [::websocket::conninfo $sock peername] + } + return 0 + } + } +} + +::discord::discord create d +d set_login_password $env(DC_E) $env(DC_P) +d login ::discord::login_example_callback +vwait forever +::discord::login env(DC_E) env(DC_P) login_example_callback +d connect +gets stdin +d disconnect +gets stdin +d destroy -- cgit v1.2.3