summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xdiscord.tcl99
1 files changed, 83 insertions, 16 deletions
diff --git a/discord.tcl b/discord.tcl
index 0548b9b..5cc8b80 100755
--- a/discord.tcl
+++ b/discord.tcl
@@ -38,6 +38,13 @@ namespace eval discord {
return $r
}
+ proc every {ms body} {
+ if {[catch $body] != 0} {
+ return
+ }
+ after $ms [namespace code [info level 0]]
+ }
+
set html_mapping { "\"" &quot; ' &apos; & &amp; < &lt; > &gt; }
proc login {email password callback {captcha {}}} {
@@ -108,13 +115,49 @@ namespace eval discord {
proc authorize_ip {click_url callback} {
proc authorize_ip_command {callback http_token} {
upvar #0 $http_token state
- puts $state(body)
- puts $state(meta)
+ dict for {key value} $state(meta) {
+ dict append headers [string tolower $key] $value
+ }
+ proc authorize_ip_post_command {callback http_token} {
+ upvar #0 $http_token state
+ if {[lindex [::http::code $http_token] 1] <= 299 && [lindex [::http::code $http_token] 1] >= 200} {
+ {*}$callback ok
+ } else {
+ set code {}
+ if {[catch {
+ set message [dict get [::json::json2dict $state(body)] message]
+ set code [dict get [::json::json2dict $state(body)] code]
+ }] != 0} {
+ {*}$callback error $state(body)
+ } else {
+ if {$code == 50014} {
+ # expired token
+ {*}$callback invalid_token $message
+ } else {
+ {*}$callback error $state(body)
+ }
+ }
+ }
+ ::http::cleanup $http_token
+ }
+ ::http::geturl https://discord.com/api/v9/auth/authorize-ip -query "{\"token\":[::json::write string [lindex [split [dict get $headers location] "="] 1]]}" -timeout 10000 -type application/json -command [list [namespace which authorize_ip_post_command] $callback]
+ ::http::cleanup $http_token
}
- puts $click_url
::http::geturl $click_url -timeout 10000 -command "[namespace which authorize_ip_command] {$callback}"
}
-
+ proc authorize_ip_example_callback {type {arg1 {}}} {
+ switch $type {
+ ok {
+ puts "ip authorized"
+ }
+ invalid_token {
+ puts "invalid, possibly expired, token. message from server: $arg1"
+ }
+ error {
+ puts "unable to parse response from server: $arg1"
+ }
+ }
+ }
oo::class create discord {
constructor {{stor {login {} password {} token {} user_id {}}}} {
my variable log storage
@@ -122,10 +165,7 @@ namespace eval discord {
set log [logger::init discord]
}
destructor {
- my variable log storage sockets
- foreach socket $sockets {
- close $socket
- }
+ my variable log storage
if {[my is_connected] != -1} {
my disconnect
}
@@ -150,10 +190,12 @@ namespace eval discord {
method login {callback {captcha {}}} {
my variable storage log
proc login_callback {self_discordobj callback type {arg1 ""} {arg2 ""}} {
- my variable log log sockets sockets
+ my variable storage log
switch $type {
ok {
${log}::notice "login ok: token is $arg1, user_id is $arg2"
+ dict set storage token $arg1
+ dict set storage user_id $arg2
{*}$callback ok [list $arg1 $arg2]
}
captcha {
@@ -195,7 +237,7 @@ namespace eval discord {
$client send {200 ok} {content-type text/plain} "http server resources were freed. please close this browser tab.
"
}
- ::www::server create s 0 [list /captcha.html [list [namespace which captcha.html] $arg1] /submit [list [namespace which submit] $self_discordobj $callback [namespace current]::s] /stop.txt [list [namespace which stop.txt] [namespace which s]]]
+ ::www::server create s 0 [list /captcha.html [list [namespace which captcha.html] $arg1] /submit [list [namespace which submit] $self_discordobj $callback [namespace current]::s] /stop.txt [list [namespace which stop.txt] [namespace current]::s]]
${log}::notice "please solve captcha at http://127.0.0.1:[s ports]/captcha.html"
{*}$callback captcha "http://127.0.0.1:[s ports]/captcha.html"
}
@@ -209,18 +251,25 @@ namespace eval discord {
}
}
}
- ::discord::login [dict get $storage login] [dict get $storage password] "[namespace which login_callback] [self] $callback" $captcha
+ ::discord::login [dict get $storage login] [dict get $storage password] [list [namespace which login_callback] [self] $callback] $captcha
}
+ # websocket complains that it couldn't remove socket from socketmap in ::http, but future connections to same host and port are working regardless. if something doesn't work in this direction, this is likely the cause -- 2022-08-09
method connect {} {
my variable sock log storage
if {[my is_connected] != -1} {
my disconnect
}
+ ${log}::notice "trying to connect"
proc handler { sock type msg } {
- my variable log
+ my variable log last_packet
switch $type {
text {
${log}::debug "received a message: $msg"
+ set p [::json::json2dict $msg]
+ set last_packet [dict get $p s]
+ if [dict exists $p d heartbeat_interval] {
+ set heartbeat_interval [dict get $p d heartbeat_interval]
+ }
}
connect {
${log}::notice "connected"
@@ -237,7 +286,8 @@ namespace eval discord {
}
}
}
- set sock [::websocket::open "wss://gateway.discord.gg/?encoding=json&v=9" [namespace which handler]]
+ # in order to overwrite the user-agent header
+ set sock [::websocket::open "wss://gateway.discord.gg/?encoding=json&v=9" [namespace which handler] -headers {Origin https://discord.com User-Agent "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"}]
${log}::debug "created sock, $sock"
}
method is_connected {} {
@@ -253,11 +303,28 @@ namespace eval discord {
}
}
if [string match *discord.tcl* $argv0] {
- ::discord::authorize_ip https://click.discord.com/ls/click?upn=qDOo8cnwIoKzt0aLL1cBeJWc43CAiLlKYSQGUErhKV7fF2lroxEuEaMS14HcVQRWKEsXxCWfVqMYFnAqiyFKlyc60qLVSfrR2BpIhn60wAL4y7X8dEY5UhD7n-2BEIulILGfHWzhi03YqYAqwN1dzNDsL7BrPVj5dWSRz43qNCKZs2Mre7Chd4IbpPox9Y-2F4ktYY4N_PdlvdP47mdorwIWlvGoY-2Fnv9MARx98jl0olgQff-2FSKZtFfa9W0dHpN7isUf-2BBQiGTEplWgkKV5AWO17KWsssOLh7AWnsZoy5YvVHlKWck92RQ5vrqN5LMcYUfucbVfjTrOdjPoOJLpa-2F6uIpp4HgFjgpPQjxA-2B3Mm9UmJJTSAUKfWdzMYiWkDqft72DZnIyAHKkjDaEO8wSn3CcCTqm-2FzMMTi-2BVKGxWIQb2p-2F6LNSxtos3YXgYUOtHh5pLu6WeUIvmdhDYWgvG9534NpmGXELQ-3D-3D {}
- vwait forever
::discord::discord create d
d set_login_password $env(DC_E) $env(DC_P)
- d login ::discord::login_example_callback
+ proc login_callback {dobj type {arg1 {}}} {
+ switch $type {
+ ok {
+ puts "ok, login successful"
+ $dobj connect
+ }
+ captcha {
+ puts "solve the captcha at address $arg1"
+ }
+ error_message {
+ puts "the server sent a human-readable error message: $arg1"
+ }
+ error {
+ puts "error: $arg1"
+ }
+ }
+ }
+ d login [list [namespace which login_callback] [namespace which d]]
+ after 10000 set end 1
+ vwait end
vwait forever
::discord::login env(DC_E) env(DC_P) login_example_callback
d connect