cf_alturl.pl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #!/usr/bin/perl -w
  2. # This Irssi script automatically check incoming http/https links
  3. # and replace it to archive one if it is MITMed.
  4. #
  5. # Irssi /set Options
  6. # you can view your current settigns by running "/set cflarealt" in Irssi
  7. #
  8. # /set cflarealt_debug <on|off> -- (off) if you have a problem try turning this on to debug
  9. # /set cflarealt_send2channel <on|off> -- (off) send the converted URL publicly to everyone in your channels
  10. # /set cflarealt_channels <"#channel1, #channel2, etc"> -- Channels to automatically convert. Empty Defaults to all
  11. #
  12. # /set cflarealt_shorturl_activate <on|off> -- (off) set it 'on' to use shortner
  13. # /set cflarealt_shorturl_min <40> -- (40) How long a url has to be to trigger automatic url shortening
  14. # /set cflarealt_shorturl_useonion <on|off> -- (off) set it 'on' to use .onion
  15. #
  16. # /set cflarealt_localdbpath <"string to path"> -- () '/path/database/split/'
  17. # /set cflarealt_uselocaldb <on|off> -- (off) if 'on', please set path to local database (or the script will die)
  18. #
  19. # /set cflarealt_printurl <on|off> -- (off) if 'on' print converted URL
  20. # /set cflarealt_donotsend <on|off> -- (off) if 'on' do not send converted URL
  21. #---------------------------------------------------------------------
  22. ##use strict;
  23. use vars qw($VERSION %IRSSI);
  24. $VERSION = "20231101";
  25. %IRSSI = (
  26. # Special thanks to: "eo, tsaavik"
  27. authors => "Anonymous",
  28. contact => 'anonymous@stop_cloudflare.nab',
  29. name => "irssi_cf_alturl.pl",
  30. description => "Cloudflare URL replacer",
  31. license => "WTFPL",
  32. changed => "$VERSION"
  33. );
  34. use Irssi;
  35. use Irssi::Irc;
  36. use LWP::Simple;
  37. use LWP::UserAgent;
  38. my (
  39. $cfg_minurllen, $cfg_send2chan, $cfg_useshort, $cfg_shortonion,
  40. $cfg_isdebug, $cfg_uselocaldb, $cfg_localdbpath, $cfg_chanlist
  41. );
  42. my ( $cfg_printurl, $cfg_donotsendurl );
  43. my @cached = ();
  44. sub setuphandler {
  45. Irssi::settings_add_bool( "cflarealt", "cflarealt_send2channel", 0 );
  46. if ( Irssi::settings_get_bool("cflarealt_send2channel") ) {
  47. print "cflarealt: sending of shorturl's to public channels enabled";
  48. $cfg_send2chan = 1;
  49. }
  50. Irssi::settings_add_bool( "cflarealt", "cflarealt_shorturl_activate", 0 );
  51. if ( Irssi::settings_get_bool("cflarealt_shorturl_activate") ) {
  52. print "cflarealt: URL shortner enabled";
  53. ##$cfg_useshort = 1;
  54. print "(disabled - onion down)";
  55. }
  56. Irssi::settings_add_bool( "cflarealt", "cflarealt_shorturl_useonion", 0 );
  57. if ( Irssi::settings_get_bool("cflarealt_shorturl_useonion") ) {
  58. print "cflarealt: URL onion enabled";
  59. $cfg_shortonion = 1;
  60. }
  61. Irssi::settings_add_str( "cflarealt", "cflarealt_channels", "" );
  62. $cfg_chanlist = Irssi::settings_get_str("cflarealt_channels");
  63. if ($cfg_chanlist) {
  64. print "cflarealt: Following channels are now parsed $cfg_chanlist";
  65. }
  66. Irssi::settings_add_int( "cflarealt", "cflarealt_shorturl_min", 40 );
  67. my $old_min_url_length = $cfg_minurllen;
  68. $cfg_minurllen = Irssi::settings_get_int("cflarealt_shorturl_min");
  69. if ( $cfg_minurllen != $old_min_url_length ) {
  70. print "cflarealt: min_url_length sucessfully set to $cfg_minurllen";
  71. }
  72. Irssi::settings_add_bool( "cflarealt", "cflarealt_debug", 0 );
  73. my $old_debug = $cfg_isdebug;
  74. $cfg_isdebug = Irssi::settings_get_bool("cflarealt_debug");
  75. if ( $cfg_isdebug != $old_debug ) {
  76. if ($cfg_isdebug) {
  77. print "cflarealt: Debug Mode Enabled";
  78. $cfg_isdebug = 1;
  79. }
  80. else {
  81. print "cflarealt: Debug Mode Disabled";
  82. $cfg_isdebug = 0;
  83. }
  84. }
  85. Irssi::settings_add_bool( "cflarealt", "cflarealt_uselocaldb", 0 );
  86. if ( Irssi::settings_get_bool("cflarealt_uselocaldb") ) {
  87. print "cflarealt: Lookup Local DB enabled";
  88. $cfg_uselocaldb = 1;
  89. }
  90. Irssi::settings_add_str( "cflarealt", "cflarealt_localdbpath", "" );
  91. $cfg_localdbpath = Irssi::settings_get_str("cflarealt_localdbpath");
  92. if ($cfg_localdbpath) {
  93. print "cflarealt: DB path set to $cfg_localdbpath";
  94. }
  95. Irssi::settings_add_bool( "cflarealt", "cflarealt_printurl", 0 );
  96. if ( Irssi::settings_get_bool("cflarealt_printurl") ) {
  97. print "cflarealt: print URL enabled";
  98. $cfg_printurl = 1;
  99. }
  100. Irssi::settings_add_bool( "cflarealt", "cflarealt_donotsend", 0 );
  101. if ( Irssi::settings_get_bool("cflarealt_donotsend") ) {
  102. print "cflarealt: dont-send enabled";
  103. $cfg_donotsendurl = 1;
  104. }
  105. }
  106. sub GotUrl {
  107. my ( $server, $data, $nick, $addr, $target ) = @_;
  108. if ( !$server || !$server->{connected} ) {
  109. Irssi::print("Not connected to server");
  110. return;
  111. }
  112. return unless ( goodchan($target) );
  113. $data =~ s/^\s+//;
  114. $data =~ s/\s+$//;
  115. my @urls = ();
  116. my @knownShortFQDN = ( 'tinyurl.com', 'bit.ly' );
  117. my ( $url, $a, $return, $char, $ch ) = "";
  118. my $same = 0;
  119. return unless ( ( $data =~ /\bhttp\:/ ) || ( $data =~ /\bhttps\:/ ) );
  120. deb("$target triggered GotUrl() with url: $data");
  121. # split on whitespace and get the url(s) out
  122. # done this way in case there are more than
  123. # one url per line.
  124. foreach ( split( /\s/, $data ) ) {
  125. if ( ( $_ =~ /^http\:/ ) || ( $_ =~ /^https\:/ ) ) {
  126. foreach $a (@urls) {
  127. if ( $_ eq $a ) {
  128. # incase they use the same url on the line.
  129. $same = 1;
  130. next;
  131. }
  132. }
  133. if ( $same == 0 ) {
  134. $same = 0;
  135. push( @urls, $_ );
  136. }
  137. }
  138. }
  139. my ( $myurl, $fqdn, $junk, $mytype );
  140. my ( $url, $browser, $response, $answer );
  141. my ( $line, $ifoundit );
  142. foreach (@urls) {
  143. $myurl = $_;
  144. ( $junk, $fqdn ) = split( /\/\//, $myurl, 2 );
  145. ( $fqdn, $junk ) = split( /\//, $fqdn, 2 );
  146. $mytype = '';
  147. if ( length($fqdn) >= 4 ) {
  148. ## Start of Act
  149. ## ACT0. If ShortURL, expand it. (knownShortFQDN)
  150. if ( grep( /^$fqdn$/, @knownShortFQDN ) ) {
  151. deb("$target Expand $fqdn");
  152. $browser = LWP::UserAgent->new;
  153. $answer = HTTP::Request->new( GET => $myurl );
  154. $response = $browser->request($answer);
  155. if ( $response->is_success and $response->previous ) {
  156. if ( $myurl ne $response->request->uri ) {
  157. $junk = $response->request->uri;
  158. if ( index( $junk, 'http' ) == 0 ) {
  159. deb("$target Expanded $fqdn");
  160. $myurl = $junk;
  161. ( $junk, $fqdn ) = split( /\/\//, $myurl, 2 );
  162. ( $fqdn, $junk ) = split( /\//, $fqdn, 2 );
  163. }
  164. }
  165. }
  166. }
  167. ## ACT1: Update URL if Cloudflared
  168. if ( grep( /^$fqdn$/, @cached ) ) {
  169. deb("$target Found in Cache $fqdn");
  170. $mytype = '^B^C3[Archive]^O ';
  171. $myurl = 'https://web.archive.org/web/' . $myurl;
  172. }
  173. else {
  174. if ( $cfg_uselocaldb == 1 ) {
  175. deb("$target Lookup local DB about $fqdn");
  176. open( CFSFILE,
  177. $cfg_localdbpath
  178. . "cloudflare_"
  179. . substr( $fqdn, 0, 1 )
  180. . ".txt" )
  181. or die "file not found for $fqdn";
  182. $ifoundit = 0;
  183. while (<CFSFILE>) {
  184. $line = $_;
  185. $line =~ s/\R//g;
  186. if ( $line eq $fqdn ) {
  187. $ifoundit = 1;
  188. last;
  189. }
  190. }
  191. close CFSFILE;
  192. if ( $ifoundit == 1 ) {
  193. push( @cached, $fqdn );
  194. $mytype = '^B^C3[Archive]^O ';
  195. $myurl = 'https://web.archive.org/web/' . $myurl;
  196. }
  197. }
  198. else {
  199. deb("$target Asking API about $fqdn");
  200. $answer = '';
  201. $url =
  202. 'https://karma.crimeflare.eu.org/api/?f='
  203. . $fqdn;
  204. $browser = LWP::UserAgent->new;
  205. $browser->agent("Mozilla/5.0 (Irssi)");
  206. $response = $browser->get($url);
  207. $answer = $response->content;
  208. if ( $answer eq '[true,true]' ) {
  209. push( @cached, $fqdn );
  210. $mytype = '^B^C3[Archive]^O ';
  211. $myurl = 'https://web.archive.org/web/' . $myurl;
  212. }
  213. }
  214. }
  215. ## ACT2: Short URL __if__ enabled and long
  216. if ( $cfg_useshort == 1 ) {
  217. if ( length($myurl) > $cfg_minurllen ) {
  218. if ( $cfg_shortonion == 1 ) {
  219. deb("$target Creating Short Onion for $myurl");
  220. $url = 'http://hbfkuwcbzhcht33fetbiajuh7i6gqupgnyupxcmujiky34drzmpajrid.onion/?i=new&url=' . $myurl;
  221. $browser = LWP::UserAgent->new;
  222. $browser->agent("Mozilla/5.0 (Irssi)");
  223. $response = $browser->get($url);
  224. $answer = $response->content;
  225. if (
  226. index( $answer,
  227. 'http://hbfkuwcbzhcht33fetbiajuh7i6gqupgnyupxcmujiky34drzmpajrid.onion/?' ) == 0
  228. )
  229. {
  230. if ( $mytype eq '' ) {
  231. $mytype = '^B^C7[Onion]^O ';
  232. }
  233. else {
  234. $mytype = '^B^C2[Onion,Archive]^O ';
  235. }
  236. $myurl = $answer;
  237. }
  238. }
  239. else {
  240. deb("$target Creating Short URL for $myurl");
  241. $url =
  242. 'https://ux.nu/api/short?format=plain&url=' . $myurl;
  243. $browser = LWP::UserAgent->new;
  244. $browser->agent("Mozilla/5.0 (Irssi)");
  245. $response = $browser->get($url);
  246. $answer = $response->content;
  247. if ( index( $answer, 'https://ux.nu/' ) == 0 ) {
  248. if ( $mytype eq '' ) {
  249. $mytype = '^B^C7[Short]^O ';
  250. }
  251. else {
  252. $mytype = '^B^C2[Short,Archive]^O ';
  253. }
  254. $myurl = $answer;
  255. }
  256. }
  257. }
  258. }
  259. ##ACT3: Result
  260. if ( $cfg_printurl == 1 ) {
  261. Irssi::print("URL: $mytype$myurl");
  262. }
  263. if ( $cfg_donotsendurl != 1 ) {
  264. if ( $cfg_send2chan == 1 ) {
  265. $server->command("msg $target $myurl");
  266. }
  267. else {
  268. $server->print( "$target", "$mytype$myurl",
  269. MSGLEVEL_CLIENTCRAP );
  270. }
  271. }
  272. ## End of Act
  273. }
  274. deb("$target process done for input $myurl");
  275. }
  276. ## Cleanup cache
  277. if ( $#cached > 500 ) {
  278. @cached = ();
  279. }
  280. return;
  281. }
  282. sub deb($) {
  283. Irssi::print(shift) if ( $cfg_isdebug == 1 );
  284. }
  285. sub goodchan {
  286. my $chan = shift;
  287. return ("OK") if ( !$cfg_chanlist );
  288. foreach ( split( /\,/, $cfg_chanlist ) ) {
  289. return ("$_") if ( $_ =~ /$chan/i );
  290. }
  291. return undef;
  292. }
  293. setuphandler();
  294. Irssi::signal_add( "setup changed", "setuphandler" );
  295. Irssi::signal_add_last( "message public", "GotUrl" );
  296. Irssi::signal_add_last( "ctcp action", "GotUrl" );