1- use futures:: StreamExt ;
2-
1+ use rand:: Rng ;
32use std:: time:: Duration ;
3+ use tokio:: io:: { AsyncReadExt , AsyncWriteExt } ;
44
55use async_trait:: async_trait;
66
@@ -26,6 +26,20 @@ impl IRC {
2626 pub fn new ( ) -> Self {
2727 IRC { tls : false }
2828 }
29+
30+ fn generate_random_username ( ) -> String {
31+ let mut rng = rand:: thread_rng ( ) ;
32+ let length = rng. gen_range ( 5 ..=9 ) ;
33+ ( 0 ..length)
34+ . map ( |_| {
35+ if rng. gen_bool ( 0.5 ) {
36+ rng. gen_range ( b'a' ..=b'z' ) as char
37+ } else {
38+ rng. gen_range ( b'A' ..=b'Z' ) as char
39+ }
40+ } )
41+ . collect ( )
42+ }
2943}
3044
3145#[ async_trait]
@@ -44,43 +58,39 @@ impl Plugin for IRC {
4458 creds : & Credentials ,
4559 timeout : Duration ,
4660 ) -> Result < Option < Vec < Loot > > , Error > {
47- let ( address, port ) =
48- utils:: parse_target ( & creds. target , if self . tls { 6697 } else { 6667 } ) ?;
61+ let address =
62+ utils:: parse_target_address ( & creds. target , if self . tls { 6697 } else { 6667 } ) ?;
4963
50- let mut config = irc:: client:: data:: Config :: default ( ) ;
51- config. nickname = Some ( creds. username . to_owned ( ) ) ;
52- // Prevents erroring when getting a ERR_NICKNAMEINUSE response from the server because of concurrency
53- config. alt_nicks = vec ! [
54- "legba1" . to_owned( ) ,
55- "legba2" . to_owned( ) ,
56- "legba3" . to_owned( ) ,
57- ] ;
58- config. server = Some ( address. to_owned ( ) ) ;
59- config. port = Some ( port) ;
60- config. password = Some ( creds. password . to_owned ( ) ) ;
61- config. use_tls = Some ( self . tls ) ;
64+ let mut stream = crate :: utils:: net:: async_tcp_stream ( & address, timeout, self . tls ) . await ?;
6265
63- let mut client = tokio:: time:: timeout ( timeout, irc:: client:: Client :: from_config ( config) )
66+ let username = IRC :: generate_random_username ( ) ;
67+ stream
68+ . write_all (
69+ format ! (
70+ "NICK {}\r \n USER {} 0 * :{}\r \n PASS {}\r \n " ,
71+ username, username, username, creds. password
72+ )
73+ . as_bytes ( ) ,
74+ )
6475 . await
65- . map_err ( |e| e. to_string ( ) ) ?
6676 . map_err ( |e| e. to_string ( ) ) ?;
67- if client. identify ( ) . is_ok ( ) {
68- let mut stream = client. stream ( ) . map_err ( |e| e. to_string ( ) ) ?;
69- while let Some ( message) = stream. next ( ) . await . transpose ( ) . map_err ( |e| e. to_string ( ) ) ? {
70- if matches ! (
71- message. command,
72- irc:: proto:: Command :: Response ( irc:: proto:: Response :: RPL_WELCOME , ..)
73- ) {
74- return Ok ( Some ( vec ! [ Loot :: new(
75- "irc" ,
76- & address,
77- [ ( "password" . to_owned( ) , creds. password. to_owned( ) ) ] ,
78- ) ] ) ) ;
79- }
77+
78+ let mut buffer = vec ! [ 0 ; 1024 ] ;
79+ let mut accumulated_data = Vec :: new ( ) ;
80+ loop {
81+ let bytes_read = stream. read ( & mut buffer) . await . map_err ( |e| e. to_string ( ) ) ?;
82+ if bytes_read == 0 {
83+ return Ok ( None ) ;
84+ }
85+ accumulated_data. extend_from_slice ( & buffer[ ..bytes_read] ) ;
86+ let response = String :: from_utf8_lossy ( & accumulated_data) ;
87+ if response. contains ( " 001 " ) && response. contains ( "Welcome" ) {
88+ return Ok ( Some ( vec ! [ Loot :: new(
89+ "irc" ,
90+ & address,
91+ [ ( "password" . to_owned( ) , creds. password. to_owned( ) ) ] ,
92+ ) ] ) ) ;
8093 }
81- Ok ( None )
82- } else {
83- Ok ( None )
8494 }
8595 }
8696}
0 commit comments