i2prm.rb 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. =begin
  2. Copyright 2020 Marek Küthe
  3. This program is free software. It comes without any warranty, to
  4. the extent permitted by applicable law. You can redistribute it
  5. and/or modify it under the terms of the Do What The Fuck You Want
  6. To Public License, Version 2, as published by Sam Hocevar. See
  7. http://www.wtfpl.net/ for more details.
  8. =end
  9. require "socket"
  10. # rescue
  11. if ARGV[0] == "rescue"
  12. sock = TCPSocket.new "127.0.0.1", 2827
  13. sock.gets
  14. sock.gets
  15. sock.puts "getnick i2pm"
  16. puts "BOB API: " + sock.gets.chomp
  17. sleep 2
  18. sock.puts "stop"
  19. puts "BOB API: " + sock.gets.chomp
  20. sleep 2
  21. sock.puts "clear"
  22. puts "BOB API: " + sock.gets.chomp
  23. sleep 2
  24. sock.puts "clear"
  25. puts "BOB API: " + sock.gets.chomp
  26. sleep 2
  27. sock.puts "quit"
  28. puts "BOB API: " + sock.gets.chomp
  29. sock.close
  30. puts "Complete!"
  31. exit
  32. elsif ARGV[0] == "feedback"
  33. puts "Thank you for giving me feedback on i2prm. Please note the product is not stable. So errors can occur.
  34. You can give me feedback via email:
  35. mark22k@mail.i2p or mark22k@i2pmail.org"
  36. exit
  37. elsif ARGV[0] == "fxruby"
  38. puts "fxruby is the module that I use to create a GUI. If there are any problems, there are hints on GitHub: https://github.com/larskanis/fxruby"
  39. exit
  40. elsif ARGV[0] == "whyrescue"
  41. puts "The rescue command is used if i2prm has been closed without disconnecting. If this happens, a new connection cannot be established when restarting. To solve this problem you can run *ruby i2prm.rb rescue*."
  42. exit
  43. elsif ARGV[0] == "help"
  44. $helptext = 'i2prm is a peer-to-peer messenger that uses the I2P network.
  45. The BOB API is used to communicate with the I2P router.
  46. The messages can be encrypted again in addition to the I2P encryption.
  47. Download and install i2prm
  48. Install the Ruby interpreter. There is a manual on ruby-lang.org
  49. Install fxruby. First, a few components have to be installed in Ubuntu/Debian:
  50. sudo apt-get install g++ libxrandr-dev libfox-1.6-dev command.
  51. There\'s nothing to do with Windows.
  52. To install the gem you can run gem install fxruby on the command line.
  53. Next you can download the current version on BitBucket [Mirror].
  54. If necessary, the i2prm.rb file must be extracted from the ZIP folder.
  55. The program can then be started from the command line with ruby i2prm.rb.
  56. How do I connect i2prm to the I2P network?
  57. Enter a nickname in the I2P Row Messenger window if necessary. This is freely selectable.
  58. Anyone who knows your base64 can also determine your nickname. If you don\'t want to type
  59. in, you can also leave the randomly generated nickname.
  60. Then click the "Connect" button and wait. Depending on how well the I2P router is integrated,
  61. this process can take a little longer. When the process has been successfully completed,
  62. the status changes to "Connected" and the message "OK tunnel starting" appears below.
  63. How do I connect to someone else?
  64. In the "I2P Row Messenger" window in the "Contact\'s base64:"
  65. text box, enter the base64 address of the contact you want to add.
  66. Next click on Add contact.
  67. Wait a few seconds. This process can take up to a minute.
  68. The text "Ready. Receive public: true" should appear on the lower label.
  69. If the Java error "no route to host" appears, one of the two contacts is not
  70. integrated enough in the I2P network. It\'s best to try again in a few
  71. minutes. If it still doesn\'t work, restarting i2prm can sometimes help.
  72. If the connection process was successful, the nickname of the contact appears
  73. next in the Contact List in the Messages window.
  74. How do I send a message?
  75. In the Messages window in the contact list, select the nickname to which you want to send a message.
  76. Enter the message in the bottom text box of the Messages window.
  77. To send the message encrypted, enter a symbol (;) in the text box or click on the "Send" button.
  78. To send the message unencrypted, click on the "U" button.
  79. How do I close a conversation?
  80. In the Messages window in the contact list, select the nickname of the
  81. conversation at which you want to close the conversation.
  82. Then click on the "Close" button at the bottom right.
  83. The message ERROR tunnel settings incomplete appears.
  84. What can I do about it?
  85. This message often appears when i2prm has ended but the connection continues. To fix this
  86. error, start the Ruby script with the argument "rescue" ie ruby i2prm.rb rescue.
  87. This process takes a bit. Finally, the message "Complete!" appear.
  88. The whole issue should look something like this:
  89. BOB API: OK Nickname set to i2pm
  90. BOB API: OK tunnel stopping
  91. BOB API: OK cleared
  92. BOB API: ERROR no nickname has been set
  93. BOB API: OK Bye!
  94. Complete!
  95. What does the v, i, m and u mean in square brackets in messages?
  96. When an encrypted message is sent, it is automatically signed to
  97. confirm that it actually came from the sender. Unencrypted messages are not signed.
  98. v(valid) means that the signature is valid.
  99. i(invalid) means that the signature is invalid.
  100. u(unencrypted) means that the message is unencrypted and therefore not signed.
  101. m(me or myself) means that the message comes from yourself and is therefore also valid.
  102. How do I change the key strength?
  103. Note: To change this, you have to change the source code of the program.
  104. The default strength is 4096 bytes.
  105. This key is used to encrypt/decrypt the received messages.
  106. Open the i2prm.rb file with any editor. However, I recommend using syntax highlighting for an overview.
  107. Find the line with the following content: $mykeypair = Encryption::Keypair.new 4096
  108. Replace the number 4096 with the desired key strength.
  109. How do I change the length of the verification string?
  110. Note: To change this, you have to change the source code of the program.
  111. The connection partner is sent a verification string to confirm that it has
  112. transmitted its real base64. The default length is 32 characters.
  113. Open the i2prm.rb file with any editor. However, I recommend using syntax highlighting for an overview.
  114. Find the line with the following content: $codelen = 32
  115. Replace the number 32 with the desired key length.'
  116. require "fox16"
  117. class HelpWindow < Fox::FXMainWindow
  118. include Fox
  119. def initialize app
  120. super(app, "Help", :width=>600, :height=>400)
  121. helpText = FXText.new self, :opts => LAYOUT_FILL
  122. helpText.editable = false
  123. helpText.text = $helptext
  124. end
  125. def create
  126. super
  127. show(Fox::PLACEMENT_SCREEN)
  128. end
  129. end
  130. app = Fox::FXApp.new
  131. help = HelpWindow.new app
  132. app.create
  133. app.run
  134. exit
  135. end
  136. require "fox16"
  137. require "gdbm"
  138. require "openssl"
  139. $db = GDBM.new "i2prm.gdbm"
  140. $blocklist = $db["blocklist"].to_s.split "~~~"
  141. at_exit {
  142. $db["blocklist"] = $blocklist.join "~~~"
  143. $db.close
  144. }
  145. if $db.has_key? "keypair-privkey"
  146. $privkey = OpenSSL::PKey::RSA.new $db["keypair-privkey"].chars.map { |c| c == "|" ? "\n" : c }.join
  147. $pubkey = $privkey.public_key
  148. else
  149. $privkey = OpenSSL::PKey::RSA.new 4096
  150. $pubkey = $privkey.public_key
  151. $db["keypair-privkey"] = $privkey.to_s.chars.map { |c| c == "\n" ? "|" : c }.join
  152. end
  153. $i2cpsettings = Hash.new
  154. $sendpubkey = $pubkey.to_s.chars.map { |c| c == "\n" ? "|" : c }.join
  155. $codelen = 32
  156. $codes = Hash.new
  157. $msgs = Hash.new
  158. $current = ""
  159. $sockss = Hash.new
  160. $b64ss = Hash.new
  161. $digest = OpenSSL::Digest::SHA512.new
  162. $logfile = "i2prm.err.log"
  163. $logio = File.new $logfile, "w"
  164. $sigintcounter = 0
  165. at_exit { $logio.close }
  166. $outport = rand(2000..2050)
  167. $inport = rand(2000..2050)
  168. while $outport == $inport
  169. $inport = rand(2000..2050)
  170. end
  171. $icon = "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00@\x00\x00\x00@\b\x06\x00\x00\x00\xAAiq\xDE\x00\x00\x00\x04sBIT\b\b\b\b|\bd\x88\x00\x00\x00\tpHYs\x00\x00\x00\xCE\x00\x00\x00\xCE\x01\x94\xFE\x93\xA0\x00\x00\x00\x19tEXtSoftware\x00www.inkscape.org\x9B\xEE<\x1A\x00\x00\t-IDATx\x9C\xE5\x9B{lS\xD7\x19\xC0\x7F\xD7\xD7v\xE2Gn\x1C\x03I\x9C&\x90`\xCC\xB3\xA5\x11\x90\xB6c\x84\x01*lb\xD5\x06\xAC\x9B\x98\x06eB\xDD\xFAG7\xA4E\xDA:\xB5\xEB\x16\xA9h\xD2V\xAD\xA0\xB1\xAA\b\x06ja\xAA\xD8V\xCA\xB4\x8D?\xB6\x16\xD8\v(\x14\rB\x804\x0E4\x90\xF2\x88\xC9\x03\xE7m\xC7\xF1\xBD\xFB\xE3&!\xF6\xBD&v\xECk\xE8\xFA\x93\"\xC5\xE7|\xE7\xDC\xEF\xFB\xEE9\xE7~\xE7\xBB\xE7\n\x8CAQ\x14'`\xE1\xFF\x9B\x88 \b\xBD#?\x04\x00EQ\x1E\x05\xF6\x03\x8F\xDC/\xAD\xB2L=\xB0A\x10\x84\xF3#\x0E\xA8\a\x1E\xBE\xBF:e\x9D\xF3\x82 <*(\x8A\x92\at\x8F'=\x14\x1D\xA2\xAB\xA7\x8Bh4\x8AKra\xB5X\xB3\xA0c\n\f\x84\xE1V\aX\xCCPT\x00\xD6\xA4f\xB2d\xE6\x1Es^Q\x14N\xD5\x9D\xE2\xC8\x89#4\\n`(:\x04\x80 \b\xF8\xA6\xF9\xA8~\xAC\x9A\x15O\xAC@\x14\xC5\xCC\x18\x91*\x83\x11\xD8s\x18\xF6\xFF\rN7\x80,\xAB\xE5V\v,\xAB\x84\xEF|\x05\xD6-\x05AH\xD4\x83EP\x14\xC5\rt\xC4\xD7\x04\xBB\x83l\x7Fs;\x1F]\xF9\xE8\x9E:\x94\x14\x95P\xB3\xB9\x86\xD2\xE2\xD2\xF4\x8CI\x95\x8B\xCD\xF0\xB5\x9F\x80\xFF\x93{\xCB}\xA1\x12\x0E\xD4B\x91[\xAFv\x92\xAE\x03\x82\xDDA^\xDE\xF62m\x9DmI\xE9b\xB7\xD9\xA9\xDDR\xCB\xD4\x92\xA9I\xC9\xA7\xCD\xB9&X\xB6\x05\xBA\xFB\x92\x93\xAF\xF0\xC0\xC9\x9DPX\x10_3\xC9\x14_\xA2(\n\xDB\xDF\xDC\x9E\xB4\xF1\x00\xFD\x03\xFD\xBC\xBA\xFBU\xC2\x83\xE1\xA4\xDBL\x98\xDE\x01X\xF3b\xF2\xC6\x034\xDF\x82\xF5\xB5\xA0(\x9A*\x8D\x03N\xD5\x9D\x1Aw\xD8\xEB\xD1\xD6\xD9\xC6\xE1c\x87Sn\x972\xBF:\x00-\x81\xD4\xDB\xFD\xE3,\x1C\xFA\xB7\xA6X\xE3\x80#'\x8Eh\x84\xCCQ\x85\xF5'\xBB\xD9\xB97\xC0\x9E]\xAD<w4\x88}P\xEB\xCD\xF7\x8F\xBF\x8F\xA2\xE3\xE5\x8C\xA1(\xB0\xE7\xAF\xDAr\xD7\x10\xFC\xB6\t:>\x80\e\xA7\xE1\x95k`\xD1\xD1c\xF7\x9F5E\xE6\xB1?\x86\xA2C4\\n\xD0\b=\xFDa/k\xCE\x8C\x06O,\xBF\xD8\x8F\#$\xF3\xDA\xEA\xD8\x85\xA5\xB3\xAB\x93\x9B\xB7o\"*\"\r\r\r\x98L&rrr\x98;w.\x92$\x01\xD0\xD5\xD5E]]\x1D\xB2,c\xB1X\xF0\xF9|\x14\x16\x16\x02000\xC0\x993g\x88F\xA3\x98\xCDf\xBC^/\x1E\x8F\xE7\xEE\x05\x1A\xAE\xC1u\x9D\xA9\xB9\xB7\t\xD6\x8CY\xC6^\xFA\x04\x14\x01~\x1A\xB7&\x1D;\v\x91!\xF5Q9L\xCC\b\bv\x05G\x1FucYv\xA9_SVu%\x843$k\xCA\xDB\xEF\xB4\x93\x9F\x9F\xCF\xF4\xE9\xD3q:\x9D\x94\x96\x96b\xB3\xD9F\xEB\x1D\x0E\a^\xAF\x17I\x92\xF0x<8\x1C\x8E\xD1:\xAB\xD5\x8A\xD7\xEB\xC5\xE5r\xDD\xAD\xEB\x0F\xC1\xF1z\xF5\xEE_k\xD5\x1A_0\x04_\xD5<\xC4\xE0Y\x1D\xD9\xC1\b\xB4v\xC6\x14\xC58@V\xB4\x06\x81:\x05\xE2\x11\x00\xB3\x8E\xB8\x1C\x95Q\x14\x85I\x93&1k\xD6,\xACV+\xFD\xFD\xFD\xF0\xE3\x9D0o#r[\x10I\x92\x989s&\x92$\xA9u5;`\xFE&\x94;=8\x9DNf\xCC\x98AAA\x81Z\xF7\xD2.\xA8~\x1E\x0E\xFE\x13\xA2:\x17\xCC\x91\x87\x03\xFA8\xAC\xFA\xB6\x10\x89\xBD\xC11S\xC0%\xB9\x10\x04A3\x8F?\xF4\xE6\xB2\xFCb\xEC(h\xF4X\t\xDA5K\bn\x97\e\xBB\xDD>\xFA\xDB\xE9t\xAA\xFF||\x13\xAE\x05\xB0F\xA2X\xF3\xF2\xB4uW[1G\xA2H\x93]\xB1\x1D\xAE^\f\x1F\xDF\x82E\xB3\xE1N\x8F\xD6\xA0V+\x9C\x94\xE0sq\xC1\xEC\xC1\xC9ZY\x93\tJb\xCBc\x1C`\xB5X\xF1M\xF3\xE1\xBF\xEA\x8F\x11\xDA\xBF$\x1FGH\xA6\xEAJ\ba\xD8\xF8\x1D_\x8CS\x14\xC8s\xE4Q\xE6)\xD3^\x18\xE0\xED\x9F\xA9\xC3Yrh\xEB\xDE\xD9\x9A\xB8n\xE5\"\xF5\x0F\xA0\xAC\x10&\xE7C{W\xAC\xCC\xB7f\xC2\xEF\xFC\xB0\xB8\e\x14\xE0\xDD\xC9\xF0\xC3\nm_\x8B\x1F\x86\xDC\xD8\x10\xDE\x1C/S\xFDX\xB5\xC6\x01\xFDV\x81\xD7V\xBBq\x84\x15,QE\xF7\xCE\x03TWUc2\xE9\xD7a\x16\xF5\r\x1C\xAFn,\xA2\t\xBE\xF9$\xEC8\x18[~5\x17\x96\xCC\x87\xE2A\b\x99 \xA81Ke\xC3*M\x91F\xDB\x15O\xAC\xA0\xA4\xA8D\xB7}_\x8E\x90\xD0x\xA7\xDD\xC9\x9A\x95k\xC6\xB1 \x03\xBC\xB8\x11\\N\xFD\xBAVkb\xE3\xE7U\xC0\xE6/k\x8A5\xD6\x88\xA2H\xCD\xE6\x1A\xEC6\xBBF8\x11\xA2Id\xCB\xA6-HN)\xE96\x13\xA6\xC8\xADN'1\xC1H\xD3#\xDF\x01\x7F|E\x1Diq\xE8\xF6RZ\\J\xED\x96Z\xA6\xB8\xA7\x8C\xDB\xB7\xC3\xEE\xE0\x85\xE7^`\xFE\xEC\xF9\xC9+\x94._z\x1C\xFE\xF2\x8B\xC4#a,\xD3K\xE0_\xAF\xC3l\xFD}J\xC2\xDD @x0\xCC\xE1c\x879z\xF2(\xEDw\xDAc\xEA\xF2\x1Cy,Y\xB4\x84\xB5\xAB\xD6f\xE7\xCE\xEBq\xFB\x0E\xFC|?\xBC\xFD\x9Eva\x9CV\f\xCF>\x05?\xF8\x06\xD8s\x13\xF5\xA0\xBF\e\xD4\xE3F\xE0\x06\xED\x9D\xEDD\xE5(n\x97\x9B\xA9\x9E\xA9\x89\x17\xBCl\x13\x95\xA1\xFE\x8A\x1A%\x9AE(\xF7$\xBC\xE3q$\xEF\x80D\xF8\x9B\xFD4_of\xD5\x92U\b\x89\x13\x0F\x0F*\x93\x12,\x99\xC9\xB3\xEF\xD0>._\xBB\xCC<\xDF\xBC\xAC&E\x82\xC1\xE0h\xC0&\xCB2.\x97kB\x99\xA9\xB4\x1D\xF0\xCC\xDAgh\xBE\xDE\xCCCE\x0F\xA5\xDBUJD\xA3Q\x1A\e\e\xE9\xE9\xE9\xC1\xE7\xF3QP\xA0Iv$E\xDAS\xE0~\x11\b\x04\xE8\xE8\xE8\xC0l6#\x8A\"\xE5\xE5\xE5\x13\x19\x01\xE9\xAF\x01\x00~\xBF\x9F\xE6\xE6f\x04A\xA0\xAC\xAC\x8C9s\xE6\xA4\xD3]6I\x7F\r\x00F\xB7\xBF\xE1p\x98\xDC\xDC\x84\x8F\x9C\fR\x03\xD8\x81\xADi\xF7\xF4)\x9C\x02C\x80\e\xC8\x05n\xA7\xDBYfF@v1\x03g\xC8\xC0\xFA\r$\b\x85'\x8A,\xCB\xD4\xFE\xBA\x96m{\xB7e\xB2[\x1Df\x02\xD33\xD2SFG\x80\xAC\xC8\xB4\xB6\xB5\xD2\xD7\x9FB\xCA:I.]\xBA\xA4f\x88P\xDFL-X\xB0 #\x81W\xC6\xD7\x80\xF0`\x18\x93`\xC2b\xC9\xEC[\xF6\xBE\xBE>\x9A\x9A\x9A\b\x85B\xF8|>\xDCnw&\x1C\x90\xF95@4\x89\xB4\xB4\xB4\x8C*g\xB7\xDB)**J\xBB\xDF\x96\x96\x16L&\x13\x0E\x87\x83\x96\x96\x16\xDCn\xDDW])\x93q\a\x98L&\xECv;~\xBF\x1F\xA7\xD39\x9A\xF2N\x8F\bs\xE6\xCCF?\xFB\x99\x1E\x19\xDF\xCE)\x8AB__\x1F\xA5\xA5\xA5H\x92D__\xBA\xEBA/P\x0Eh\xD3Y\x99 \xF3S@\x14\xF1z\xBD\x99\xEC\x11\x90\x80\x89\xC5\xFA\xE3a\xF8\x86\xFE\xC8\xC9#l}}+=}:)\xED\xA4\xB0\x01\r\xC0\x1F2\xA8\xD5]\fw\xC0\x85\xC6\v\\l\xBAH\xC7\x9D\a3\xD84<\x14\x0E\x0F\x86\xE9\fv\xE2)\xF4\x8C/<\x86`0H]]\x1D\x81@\x80\x82\x82\x02*++\x992e\xFC\x1Ce\x8A\x18\x1F\n\xE7Xs\x10\x11\t\x04\xD4W\xDA\xB2,\xC7\xBE\xF0L\x80\xD9l\xA6\xA2\xA2\x02\xB7\xDB\x8D\xD5j5l\x93\x95\x95\xBD\x80\xD9l\xA6\xB1\xB1\x91\xC1\xC1A|>\x1F\x8A\xA2\x8C\e\xC4\x88\xA2\x88\xCDf#??\x1F\x87\xC3aX\xBA-+\x0E\x18\x18\x18\xC0\xE5R\xDF;\x0E\f\f$\xE1\x80\xF3\xD8l\xEFa\xB3}\x1F0\xF64\xDA\x03\xBA\x1D^\a\xFC\t\xF8;\xF0\xA4\x91\x17\xBA_\xDBa\x19\xB8\x00\x8C\x9C\xF0\x9A\n\xCC\xE3\xEEC\xA9\x16\xF8<\xB0\xD4pM\xB2<\x02:\x81_\x02o\x01\xF1\xE7|\x8A\x80o\x03?\xC2\xA8\xA0G\x87\xCC\xE4\x04\x93\xE3?\xC0\xD3\x8C\x9F\xC5)\x02\xDEA\x1D\x01\x86\xA3=&g\f'Pc\xF9dRX\x01`%\xF0\x81\xA1\x1A\x8D\x90\x05\a\xF4\x00_\aB)\xB4\t\r\xB7\xE9\x1DO0m\xB2\xE0\x80m\xC0-\xDD\x9A\xEE\xDE\x1C\xBA{s\x12\xB4\xBB\x01l7J\xA9Q\xB2\xB0\x06\xCC\x02\x9AbJ\x82\xDD\xB9\xFCf\xFF\xE3\\\xF0\xAB\x89\x92Gf\xB5\xF2\xBD\x8D\xA7\xC9\xCF\x8B\x1F%3\x00?\x06b\xF4\x1Ap\x9Dx\xE3\x01v\xFF~\xD1\xA8\xF1\x00\xF5\x8D\xC5\xEC:\xB0P\xA7\xFDe\xD4\x91`\x1C\x06;@\xAB|$\"r\xEE\x92v/p\xAE\xC1C$\xA2\xF7j\xEB\xBA\x01z\xDD\xC5`\ah\xE3,\x93(#\x8A\xDA3|fQ\xC1\xA4Snt(l\xB0\x03\xCA\x88\xCF\xE3\x89&\x85\xEA\xAA\xAB\x1A\xC9\xA5UW\x11M\xF1\a2\x85\xE1>\x8C\xC3\xE0P\xB8\x10\xA8\x04\xCE\xC6\x94nZw\x0E\xAB%\xCA\xF1\xFF\xAA\xA78\x96,la\xFDS\xF5:\xED\x17\x02:\a\x1E3H\x16\x9E\x02o\x00\xCFO\xB0\xEDN\xE0\xBB\x19\xD4EC6B\xE1\bP\x05\x9CO\xB1]%p\x1A\x83\ai6Ba\vp\b5\xC6O\x96b\xE0]\xB2\x91\xAE\xC8\xD2^\xA0\x025\xB6_\x94\x84l\xD5\xB0l\xB9\x91\n\x8D\x92\xC5sn\xD3P\r{\vXN\xEC\xDD5\x03+\x80}\xC0I\xD4\xFC@vH\xFA\xC3\xC9\xCC\x13\x06F>j\xF0`\xF4\xF3>\x01\xD2\xC8\xA7\xB3\xE7\xF9\xEC|7<B\x9D \b\x95#S`\x03\xA9/\xD3\x9Ff\xEA\x80\x8D\x10\x17\xA6}\x16?\x9F\xFF\x1F<t\xF7\x13\xA9\x8B}(\x00\x00\x00\x00IEND\xAEB`\x82"
  172. $dark = true if ARGV[0] == "dark"
  173. $keys = Hash.new
  174. # I2CP Settings
  175. # $i2cpsettings["i2cp.username"] = ""
  176. # $i2cpsettings["i2cp.password"] = ""
  177. # $i2cpsettings["i2cp.SSL"] = "true
  178. $i2cpsettings["inbound.backupQuantity"] = 1
  179. $i2cpsettings["outbound.backupQuantity"] = 1
  180. $i2cpsettings["inbound.length"] = 3
  181. $i2cpsettings["outbound.length"] = 3
  182. #$i2cpsettings["inbound.length"] = 0
  183. #$i2cpsettings["outbound.length"] = 0
  184. $i2cpsettings["inbound.quantity"] = 2
  185. $i2cpsettings["outbound.quantity"] = 2
  186. $i2cpsettings["i2cp.destination.sigType"] = "EdDSA_SHA512_Ed25519"
  187. $i2cpsettings["i2cp.leaseSetEncType"] = "4,0"
  188. def unpackKey packedkey, remname
  189. $keys[remname] = OpenSSL::PKey::RSA.new packedkey.chars.map { |c| c == "|" ? "\n" : c }.join
  190. end
  191. def receiveEncHandler from, enc, push = true
  192. mat = /(.*) ;verify=(.*);/.match enc
  193. content = $privkey.private_decrypt mat[1].split(" ").map { |x| x.to_i }.pack("c*")
  194. veri = $keys[from].verify $digest, mat[2].split(" ").map { |x| x.to_i }.pack("c*"), mat[1]
  195. receiveHandler from, content, push, veri
  196. end
  197. def receiveHandler from, content, push = true, veri = nil
  198. msg = "#{from} #{veri == nil ? (push ? "[u]" :"[m]") : "[" + (veri ? "v" : "i") + "]"}, #{Time.new.strftime("%d/%m/%Y %H:%M")}: #{content}"
  199. $msgs[from] = "#{msg}\n#{$msgs[from]}"
  200. if $current == from
  201. $msgBox.text = "#{msg}\n#{$msgBox.text}"
  202. elsif push
  203. Thread.new {
  204. old = $consoleLabel.text
  205. $consoleLabel.text = "New message from #{from}"
  206. sleep 2
  207. $consoleLabel.text = old
  208. }
  209. end
  210. end
  211. def putsHash remname
  212. hash = Digest::SHA512.base64digest $keys[remname].to_s
  213. $msgs[remname] = "[i2prm], #{Time.new.strftime("%d/%m/%Y %H:%M")}: The hash of contact #{remname} is #{hash}.\n#{$msgs[remname]}"
  214. if $current == remname
  215. $msgBox.text = "[i2prm], #{Time.new.strftime("%d/%m/%Y %H:%M")}: The hash of contact #{remname} is #{hash}.\n#{$msgBox.text}"
  216. end
  217. end
  218. def randomcode len=32
  219. symbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
  220. res = ""
  221. rnd = Random.new
  222. for i in 0...len
  223. res += symbols[rnd.rand(0...symbols.length)]
  224. end
  225. return res
  226. end
  227. def textBoxDark obj, bg = Fox.FXRGB(26, 26, 26)
  228. obj.backColor = bg
  229. obj.textColor = Fox.FXRGB(255, 255, 255)
  230. obj.cursorColor = Fox.FXRGB(255, 0, 0)
  231. obj.selTextColor = Fox.FXRGB(204, 204, 204)
  232. obj.selBackColor = Fox.FXRGB(51, 0, 0)
  233. end
  234. def labelDark obj, nativeBg = Fox.FXRGB(0, 0, 0)
  235. obj.backColor = nativeBg
  236. obj.textColor = Fox.FXRGB(242, 242, 242)
  237. end
  238. def buttonDark obj
  239. obj.backColor = Fox.FXRGB(26, 26, 26)
  240. obj.textColor = Fox.FXRGB(255, 255, 255)
  241. end
  242. def ParseHTTPResponse ans
  243. head = Hash.new
  244. lins = ans.lines
  245. fw = lins[0].index " "
  246. i = 1
  247. while i < lins.length
  248. fw = lins[i].index ":"
  249. head[lins[i][0...fw]] = lins[i][fw+2..-1].chomp
  250. i += 1
  251. end
  252. return head
  253. end
  254. class MsgWindow < Fox::FXMainWindow
  255. include Fox
  256. def initialize app
  257. super(app, "Messages", :width=>640, :height=>410)
  258. self.icon = $icon
  259. self.miniIcon = $icon
  260. mainFrame = FXHorizontalFrame.new self, :opts => LAYOUT_FILL
  261. listFrame = FXVerticalFrame.new mainFrame, :opts => LAYOUT_FILL_Y
  262. $contactsBox = FXList.new listFrame, :opts => LAYOUT_FILL_Y|LIST_SINGLESELECT|LAYOUT_FILL_X
  263. closeButton = FXButton.new listFrame, "Close conversation"
  264. reconnectButton = FXButton.new listFrame, "Reconnect"
  265. blockButton = FXButton.new listFrame, "Block user"
  266. unblockButton = FXButton.new listFrame, "Unblock user"
  267. blockButton.disable
  268. unblockButton.disable
  269. msgFrame = FXVerticalFrame.new mainFrame, :opts => LAYOUT_FILL
  270. $msgBox = FXText.new msgFrame, :opts => LAYOUT_FILL|TEXT_AUTOSCROLL
  271. $msgBox.editable = false
  272. $b64ShowBox = FXTextField.new msgFrame, 60, :opts => LAYOUT_FILL_X
  273. $b64ShowBox.editable = false
  274. sendFrame = FXHorizontalFrame.new msgFrame
  275. sendtextBox = FXTextField.new sendFrame, 51, :opts => LAYOUT_FILL_X
  276. sendButton = FXButton.new sendFrame, "Send"
  277. usendButton = FXButton.new sendFrame, "U"
  278. if $dark
  279. mainFrame.backColor = Fox.FXRGB(0, 0, 0)
  280. $contactsBox.backColor = Fox.FXRGB(26, 26, 26)
  281. $contactsBox.textColor = Fox.FXRGB(255, 255, 255)
  282. $contactsBox.selBackColor = Fox.FXRGB(0, 77, 0)
  283. msgFrame.backColor = Fox.FXRGB(0, 0, 0)
  284. textBoxDark $msgBox
  285. textBoxDark $b64ShowBox
  286. sendFrame.backColor = Fox.FXRGB(0, 0, 0)
  287. textBoxDark sendtextBox
  288. sendtextBox.backColor = Fox.FXRGB(13, 13, 13)
  289. buttonDark sendButton
  290. buttonDark usendButton
  291. buttonDark closeButton
  292. buttonDark blockButton
  293. buttonDark unblockButton
  294. end
  295. $contactsBox.connect SEL_COMMAND do |sender, sel, index|
  296. $current = $contactsBox.getItem(sender.currentItem).text
  297. $msgBox.text = $msgs[$current].nil? ? "":$msgs[$current]
  298. $b64ShowBox.text = $b64ss[$current]
  299. if $blocklist.include? $b64ss[$current]
  300. blockButton.disable
  301. unblockButton.enable
  302. else
  303. blockButton.enable
  304. unblockButton.disable
  305. end
  306. end
  307. sendButton.connect(SEL_COMMAND) { sendHandler sendtextBox }
  308. usendButton.connect(SEL_COMMAND) { sendHandler sendtextBox, false }
  309. reconnectButton.connect SEL_COMMAND do
  310. if $current == ""
  311. $consoleLabel.text = "Please select a nickname."
  312. else
  313. reconnectHandler
  314. end
  315. end
  316. closeButton.connect SEL_COMMAND do
  317. if $current != ""
  318. $sockss[$current].close
  319. end
  320. end
  321. blockButton.connect SEL_COMMAND do
  322. $blocklist << $b64ss[$current]
  323. blockButton.disable
  324. unblockButton.enable
  325. end
  326. unblockButton.connect SEL_COMMAND do
  327. $blocklist.delete $b64ss[$current]
  328. blockButton.enable
  329. unblockButton.disable
  330. end
  331. sendtextBox.connect(SEL_CHANGED) do
  332. Thread.new(sendtextBox) { |sendtextBox|
  333. if sendtextBox.text[-1] == ";"
  334. sendtextBox.text = sendtextBox.text.delete_suffix ";"
  335. sendHandler sendtextBox
  336. end
  337. }
  338. end
  339. end
  340. def reconnectHandler
  341. Thread.new {
  342. begin
  343. Thread.new {
  344. $addContactButton.disable
  345. sleep 4
  346. $addContactButton.enable
  347. }
  348. sock = TCPSocket.new "127.0.0.1", $inport
  349. sock.puts $b64ss[$current]
  350. ans = sock.gets.chomp
  351. if ans[0..7] != "Hi. I am"
  352. sock.puts "Your answer caused a protocol error. I will now disconnect."
  353. if ans.include? "java.net.NoRouteToHostException: Connection timed out"
  354. $consoleLabel.text = "A connection to the partner could not be established. The router may not be integrated enough or the partner may be offline."
  355. else
  356. $consoleLabel.text = "protocol error: ans - #{ans}"
  357. end
  358. sock.close
  359. Thread.current.exit
  360. end
  361. remname = ans[10..-20]
  362. if remname != $current
  363. sock.puts "Our reconnect attempt does not work with this nickname. The desired nickname is #{$current}."
  364. sock.close
  365. Thread.current.exit
  366. end
  367. sock.puts "I want to talk to you."
  368. if ($consoleLabel.text = sock.gets.chomp) != "What is your b64?"
  369. $consoleLabel.text = "proerr"
  370. sock.puts "Your answer caused a protocol error. I will now disconnect."
  371. sock.close
  372. Thread.current.exit
  373. end
  374. sock.puts $myb64
  375. #p $myb64
  376. sleep 0.5
  377. if ($consoleLabel.text = sock.gets.chomp).include? "Your base64 is blocked."
  378. $consoleLabel.text = "Your base64 was blocked."
  379. sock.close
  380. Thread.current.exit
  381. elsif $consoleLabel.text != "I will send you a verification message."
  382. sock.puts "Your answer caused a protocol error. I will now disconnect."
  383. sock.close
  384. Thread.current.exit
  385. end
  386. if ($consoleLabel.text = sock.gets.chomp) != "What is your code?"
  387. sock.puts "Your answer caused a protocol error. I will now disconnect."
  388. sock.close
  389. Thread.current.exit
  390. end
  391. timer = 0
  392. while $codes[remname].nil? or timer == 20
  393. sleep 0.5
  394. timer += 1
  395. end
  396. sock.puts $codes[remname]
  397. $codes.delete remname
  398. #p $codes
  399. if ($consoleLabel.text = sock.gets.chomp) != "Your code is valid. What is your name?"
  400. sock.close
  401. Thread.current.exit
  402. end
  403. sock.puts $nickname
  404. if ($consoleLabel.text = sock.gets.chomp) != "Now send me a verification message."
  405. sock.close
  406. Thread.current.exit
  407. end
  408. code = randomcode $codelen
  409. clifc = TCPSocket.new "127.0.0.1", $inport
  410. clifc.puts $b64ss[$current]
  411. clifc.puts "Your code from _#{$nickname}_ is _#{code}_."
  412. sleep 0.5
  413. clifc.close
  414. sock.puts "I Agree."
  415. ans = sock.gets.chomp
  416. if ($consoleLabel.text = ans[0..9]) != "My code is"
  417. sock.puts "Your answer caused a protocol error. I will now disconnect."
  418. sock.close
  419. Thread.current.exit
  420. end
  421. if ($consoleLabel.text = ans[12..-2]) != code
  422. sock.puts "Your code is invalid. I will now disconnect."
  423. sock.close
  424. Thread.current.exit
  425. else
  426. sock.puts "Your code is valid."
  427. if ($consoleLabel.text = sock.gets.chomp) != "What is your public key?"
  428. sock.close
  429. Thread.current.exit
  430. end
  431. sock.puts $sendpubkey
  432. if ($consoleLabel.text = sock.gets.chomp) != "I have received your public key and will now send my public key."
  433. sock.close
  434. Thread.current.exit
  435. end
  436. unpackKey sock.gets.chomp, remname
  437. sock.puts "I have received your public key."
  438. $sockss[remname] = sock
  439. $consoleLabel.text = "Ready. Recived public key: #{! $keys[remname].nil?}"
  440. putsHash remname
  441. loop do
  442. begin
  443. if (msg = sock.gets).nil? == false
  444. msg = msg.chomp
  445. if msg[0..26] == "I have a message for you - "
  446. receiveHandler remname, msg[27..-1]
  447. elsif msg[0..37] == "I have an encrypted message for you - "
  448. receiveEncHandler remname, msg[38..-1]
  449. end
  450. end
  451. rescue
  452. if sock.closed?
  453. ind = $contactsBox.findItem remname
  454. if ind != -1
  455. $contactsBox.removeItem ind
  456. end
  457. $msgBox.text = ""
  458. $current = ""
  459. $b64ShowBox.text = ""
  460. Thread.current.exit
  461. end
  462. end
  463. end
  464. end
  465. rescue Exception => e
  466. $consoleLabel.text = e.message
  467. $logio.write e.full_message
  468. end
  469. }
  470. end
  471. def sendHandler sendtextBox, enc = true
  472. if $current == ""
  473. $consoleLabel.text = "Please select a nickname."
  474. return
  475. end
  476. sock = $sockss[$current]
  477. if sock.closed?
  478. $consoleLabel.text = "#{$current} is offline."
  479. else
  480. begin
  481. if enc
  482. codmsg = $keys[$current].public_encrypt(sendtextBox.text).bytes.join " "
  483. sock.puts "I have an encrypted message for you - #{codmsg} ;verify=#{$privkey.sign($digest, codmsg).bytes.join " "};"
  484. else
  485. sock.puts "I have a message for you - #{sendtextBox.text}"
  486. end
  487. receiveHandler $current, sendtextBox.text, false
  488. sendtextBox.text = ""
  489. rescue Errno::EPIPE => e
  490. $consoleLabel.text = "#{$current} is offline."
  491. end
  492. end
  493. end
  494. def create
  495. super
  496. show(Fox::PLACEMENT_SCREEN)
  497. end
  498. end
  499. class OptionsWindow < Fox::FXMainWindow
  500. include Fox
  501. def initialize app
  502. super(app, "I2P Row Messanger", :width=>335, :height=>145)
  503. self.icon = $icon
  504. self.miniIcon = $icon
  505. bgColor = Fox.FXRGB(13, 13, 13)
  506. tbBgColor = Fox.FXRGB(26, 26, 26)
  507. self.backColor = bgColor if $dark
  508. nicknameFrame = FXHorizontalFrame.new self, :padBottom => 3
  509. nicknameBoxLabel = FXLabel.new nicknameFrame, "Nickname:"
  510. nicknameBox = FXTextField.new nicknameFrame, 20, :opts => LAYOUT_FILL_X
  511. if $db.has_key? "nickname"
  512. nicknameBox.text = $db["nickname"]
  513. else
  514. nicknameBox.text = randomcode 7
  515. $db["nickname"] = nicknameBox.text
  516. end
  517. nicknameBox.connect(SEL_CHANGED) do
  518. $db["nickname"] = nicknameBox.text
  519. end
  520. connectButton = FXButton.new nicknameFrame, "Connect"
  521. if $dark
  522. connectButton.borderColor = Fox.FXRGB(0, 255, 255)
  523. connectButton.shadowColor = Fox.FXRGB(255, 0, 255)
  524. buttonDark connectButton
  525. else
  526. connectButton.borderColor = Fox.FXRGB(255, 0, 0)
  527. connectButton.shadowColor = Fox.FXRGB(0, 255, 0)
  528. end
  529. b64Frame = FXHorizontalFrame.new self, :padBottom => 3, :padTop => 0
  530. b64BoxLabel = FXLabel.new b64Frame, "Your base64:"
  531. b64Box = FXTextField.new b64Frame, 11, :opts => LAYOUT_FILL_X
  532. b64Box.editable = false
  533. hashLabel = FXLabel.new b64Frame, "Your Hash:"
  534. hashBox = FXTextField.new b64Frame, 6, :opts => LAYOUT_FILL_X
  535. hashBox.editable = false
  536. hashBox.text = Digest::SHA512.base64digest $pubkey.to_s
  537. addFrame = FXHorizontalFrame.new self, :padBottom => 0, :padTop => 1.5
  538. cb64BoxLabel = FXLabel.new addFrame, "Contact's base64: "
  539. cb64Box = FXTextField.new addFrame, 13, :opts => LAYOUT_FILL_X
  540. $addContactButton = FXButton.new addFrame, "Add contact"
  541. $addContactButton.disable
  542. $statusLabel = FXLabel.new self, "Status: Disconnected", :padBottom => 0, :padTop => 5, :padLeft => 15
  543. $consoleLabel = FXLabel.new self, "Console: ", :padTop => 0, :padLeft => 15
  544. if $dark
  545. nicknameFrame.backColor = bgColor
  546. labelDark nicknameBoxLabel, bgColor
  547. textBoxDark nicknameBox, tbBgColor
  548. b64Frame.backColor = bgColor
  549. labelDark b64BoxLabel, bgColor
  550. textBoxDark b64Box, tbBgColor
  551. addFrame.backColor = bgColor
  552. labelDark cb64BoxLabel, bgColor
  553. textBoxDark cb64Box, tbBgColor
  554. buttonDark $addContactButton
  555. labelDark $statusLabel, bgColor
  556. labelDark $consoleLabel, bgColor
  557. end
  558. connectButton.connect(SEL_COMMAND) { connectHandler connectButton, nicknameBox, b64Box }
  559. app.addSignal("SIGINT") {
  560. $sigintcounter += 1
  561. if $sigintcounter < 3
  562. connectHandler connectButton, nicknameBox, b64Box if $statusLabel.text == "Status: Connected"
  563. exit
  564. else
  565. exit!
  566. end
  567. }
  568. $addContactButton.connect(SEL_COMMAND) { addHandler cb64Box }
  569. end
  570. def addHandler cb64Box
  571. Thread.new {
  572. begin
  573. Thread.new {
  574. $addContactButton.disable
  575. sleep 4
  576. $addContactButton.enable
  577. }
  578. sock = TCPSocket.new "127.0.0.1", $inport
  579. sock.puts cb64Box.text
  580. ans = sock.gets.chomp
  581. if ans[0..7] != "Hi. I am"
  582. sock.puts "Your answer caused a protocol error. I will now disconnect."
  583. if ans.include? "java.net.NoRouteToHostException: Connection timed out"
  584. $consoleLabel.text = "A connection to the partner could not be established. The router may not be integrated enough or the partner may be offline."
  585. else
  586. $consoleLabel.text = "protocol error: ans - #{ans}"
  587. end
  588. sock.close
  589. Thread.current.exit
  590. end
  591. remname = ans[10..-20]
  592. sock.puts "I want to talk to you."
  593. if ($consoleLabel.text = sock.gets.chomp) != "What is your b64?"
  594. sock.puts "Your answer caused a protocol error. I will now disconnect."
  595. sock.close
  596. Thread.current.exit
  597. end
  598. sock.puts $myb64
  599. #p $myb64
  600. sleep 0.5
  601. if ($consoleLabel.text = sock.gets.chomp).include? "Your base64 is blocked."
  602. $consoleLabel.text = "Your base64 was blocked."
  603. sock.close
  604. Thread.current.exit
  605. elsif $consoleLabel.text != "I will send you a verification message."
  606. sock.puts "Your answer caused a protocol error. I will now disconnect."
  607. sock.close
  608. Thread.current.exit
  609. end
  610. if ($consoleLabel.text = sock.gets.chomp) != "What is your code?"
  611. sock.puts "Your answer caused a protocol error. I will now disconnect."
  612. sock.close
  613. Thread.current.exit
  614. end
  615. timer = 0
  616. while $codes[remname].nil? or timer == 20
  617. sleep 0.5
  618. timer += 1
  619. end
  620. sock.puts $codes[remname]
  621. $codes.delete remname
  622. #p $codes
  623. if ($consoleLabel.text = sock.gets.chomp) != "Your code is valid. What is your name?"
  624. sock.close
  625. Thread.current.exit
  626. end
  627. sock.puts $nickname
  628. if ($consoleLabel.text = sock.gets.chomp) != "Now send me a verification message."
  629. sock.close
  630. Thread.current.exit
  631. end
  632. code = randomcode $codelen
  633. clifc = TCPSocket.new "127.0.0.1", $inport
  634. clifc.puts cb64Box.text
  635. clifc.puts "Your code from _#{$nickname}_ is _#{code}_."
  636. sleep 0.5
  637. clifc.close
  638. sock.puts "I Agree."
  639. ans = sock.gets.chomp
  640. if ($consoleLabel.text = ans[0..9]) != "My code is"
  641. sock.puts "Your answer caused a protocol error. I will now disconnect."
  642. sock.close
  643. Thread.current.exit
  644. end
  645. if ($consoleLabel.text = ans[12..-2]) != code
  646. sock.puts "Your code is invalid. I will now disconnect."
  647. sock.close
  648. Thread.current.exit
  649. else
  650. sock.puts "Your code is valid."
  651. unless $msgs[remname].nil?
  652. remname += randomcode 3
  653. end
  654. if ($consoleLabel.text = sock.gets.chomp) != "What is your public key?"
  655. sock.close
  656. Thread.current.exit
  657. end
  658. sock.puts $sendpubkey
  659. if ($consoleLabel.text = sock.gets.chomp) != "I have received your public key and will now send my public key."
  660. sock.close
  661. Thread.current.exit
  662. end
  663. unpackKey sock.gets.chomp, remname
  664. sock.puts "I have received your public key."
  665. $msgs[remname] = ""
  666. $sockss[remname] = sock
  667. $contactsBox.appendItem(remname)
  668. $consoleLabel.text = "Ready. Recived public key: #{! $keys[remname].nil?}"
  669. $b64ss[remname] = cb64Box.text
  670. putsHash remname
  671. loop do
  672. begin
  673. if (msg = sock.gets).nil? == false
  674. msg = msg.chomp
  675. if msg[0..26] == "I have a message for you - "
  676. receiveHandler remname, msg[27..-1]
  677. elsif msg[0..37] == "I have an encrypted message for you - "
  678. receiveEncHandler remname, msg[38..-1]
  679. end
  680. end
  681. rescue
  682. if sock.closed?
  683. ind = $contactsBox.findItem remname
  684. if ind != -1
  685. $contactsBox.removeItem ind
  686. end
  687. $msgBox.text = ""
  688. $current = ""
  689. $b64ShowBox.text = ""
  690. Thread.current.exit
  691. end
  692. end
  693. end
  694. end
  695. rescue Exception => e
  696. $consoleLabel.text = e.message
  697. $logio.write e.full_message
  698. end
  699. }
  700. end
  701. def abortConnecting errmsg, nicknameBox, connectButton
  702. $consoleLabel.text = errmsg
  703. $logio.write errmsg
  704. nicknameBox.editable = true
  705. connectButton.text = "Connect"
  706. $statusLabel.text = "Status: Disconnected"
  707. end
  708. def connectHandler myself, nicknameBox, b64Box
  709. if myself.text == "Connect"
  710. $statusLabel.text = "Status: Connecting..."
  711. nicknameBox.editable = false
  712. $nickname = nicknameBox.text
  713. if $nickname == ""
  714. abortConnecting "Please enter a nickname.", nicknameBox, myself
  715. return
  716. end
  717. $serv = Thread.new do
  718. begin
  719. $cli = TCPSocket.new "127.0.0.1", 2827
  720. rescue Errno::ECONNREFUSED => e
  721. abortConnecting e.message, nicknameBox, myself
  722. $logio.write e.full_message
  723. Thread.stop
  724. end
  725. $consoleLabel.text = $cli.gets.chomp
  726. $consoleLabel.text = $cli.gets.chomp
  727. $cli.puts "setnick i2prm"
  728. $consoleLabel.text = $cli.gets.chomp
  729. $i2cpsettings.each_pair { |set, val|
  730. $cli.puts "option #{set.to_s}=#{val.to_s}"
  731. $consoleLabel.text = $cli.gets.chomp
  732. }
  733. if $db.has_key? "i2p-keys"
  734. $cli.puts "setkeys #{$db["i2p-keys"]}"
  735. myb64 = $cli.gets.chomp
  736. b64Box.text = myb64[3..-1]
  737. $myb64 = myb64[3..-1]
  738. else
  739. $cli.puts "newkeys"
  740. myb64 = $cli.gets.chomp
  741. b64Box.text = myb64[3..-1]
  742. $myb64 = myb64[3..-1]
  743. $cli.puts "getkeys"
  744. $db["i2p-keys"] = $cli.gets.chomp[3..-1]
  745. end
  746. $consoleLabel.text = myb64
  747. $cli.puts "outhost 127.0.0.1"
  748. $consoleLabel.text = $cli.gets.chomp
  749. $cli.puts "outport #{$outport}"
  750. $consoleLabel.text = $cli.gets.chomp
  751. $cli.puts "inhost 127.0.0.1"
  752. $consoleLabel.text = $cli.gets.chomp
  753. $cli.puts "inport #{$inport}"
  754. $consoleLabel.text = $cli.gets.chomp
  755. $cli.puts "start"
  756. $consoleLabel.text = $cli.gets.chomp
  757. $statusLabel.text = "Status: Connected"
  758. $addContactButton.enable
  759. serv = TCPServer.new "127.0.0.1", $outport
  760. loop do
  761. Thread.new(serv.accept) { |sock|
  762. begin
  763. sock.gets
  764. sock.puts "Hi. I am _#{$nickname}_ What do you want?"
  765. wanted = sock.gets.chomp
  766. if wanted[0..14] == "Your code from "
  767. mat = /Your code from _(.*)_ is _(.*)_./.match(wanted)
  768. $codes[mat[1]] = mat[2]
  769. sock.close
  770. Thread.current.exit
  771. elsif wanted[0..4] == "GET /" || wanted == "I would like information about this i2prm."
  772. data = wanted + "\n"
  773. while (ans = sock.gets).chop != ""
  774. data += ans
  775. end
  776. head = ParseHTTPResponse data
  777. sock.puts
  778. if head.has_key? "Host"
  779. sock.puts "You make a request to #{head["Host"].to_s} with the user agent #{head["User-Agent"].to_s}."
  780. sock.puts "This is the address of an i2prm messenger."
  781. else
  782. sock.puts "You make a request to an address of an i2prm messenger."
  783. end
  784. sock.puts
  785. sock.puts "User information:"
  786. sock.puts " - Nickname: #{$nickname}"
  787. sock.puts " - base64: #{$myb64}"
  788. sock.puts " - Public key: #{$pubkey.to_s}"
  789. sock.puts " - Hash: #{Digest::SHA512.base64digest $pubkey.to_s}"
  790. sock.close
  791. Thread.current.exit
  792. end
  793. $consoleLabel.text = "Incoming connection"
  794. sock.puts "What is your b64?"
  795. b64 = sock.gets.chomp
  796. $cli.puts "verify #{b64}"
  797. if $blocklist.include? b64
  798. sock.puts "Your base64 is blocked. I will now disconnect."
  799. $consoleLabel.text = "Someone (#{b64[0...8]}) tried to connect. It was blocked."
  800. sock.close
  801. Thread.current.exit
  802. end
  803. if $cli.gets.chomp[0..2] != "OK"
  804. sock.puts "Your b64 is invalid. I will now disconnect."
  805. sock.close
  806. Thread.current.exit
  807. end
  808. sock.puts "I will send you a verification message."
  809. code = randomcode $codelen
  810. clifc = TCPSocket.new "127.0.0.1", $inport
  811. clifc.puts b64
  812. clifc.puts "Your code from _#{$nickname}_ is _#{code}_."
  813. sleep 0.5
  814. clifc.close
  815. sock.puts "What is your code?"
  816. codein = sock.gets.chomp
  817. if code != codein
  818. sock.puts "Your code is invalid. I will now disconnect."
  819. sock.close
  820. Thread.current.exit
  821. end
  822. sock.puts "Your code is valid. What is your name?"
  823. remname = sock.gets.chomp
  824. sock.puts "Now send me a verification message."
  825. if sock.gets.chomp != "I Agree."
  826. sock.puts "Your answer caused a protocol error. I will now disconnect."
  827. sock.close
  828. Thread.current.exit
  829. end
  830. $consoleLabel.text = "Incoming connection from #{remname}"
  831. timer = 0
  832. while $codes[remname].nil? or timer == 20
  833. sleep 0.5
  834. timer += 1
  835. end
  836. sock.puts "My code is _#{$codes[remname]}_"
  837. if sock.gets.chomp != "Your code is valid."
  838. sock.close
  839. Thread.current.exit
  840. end
  841. $codes.delete remname
  842. unless $msgs[remname].nil?
  843. remname += randomcode 3
  844. end
  845. sock.puts "What is your public key?"
  846. unpackKey sock.gets.chomp, remname
  847. sock.puts "I have received your public key and will now send my public key."
  848. sock.puts $sendpubkey
  849. if sock.gets.chomp != "I have received your public key."
  850. sock.puts "Your answer caused a protocol error. I will now disconnect."
  851. sock.close
  852. Thread.current.exit
  853. end
  854. $msgs[remname] = ""
  855. $sockss[remname] = sock
  856. $contactsBox.appendItem(remname)
  857. $consoleLabel.text = "Ready. Recived public key: #{! $keys[remname].nil?}"
  858. $b64ss[remname] = b64
  859. putsHash remname
  860. ## waiting
  861. loop do
  862. begin
  863. if (msg = sock.gets).nil? == false
  864. msg = msg.chomp
  865. if msg[0..26] == "I have a message for you - "
  866. receiveHandler remname, msg[27..-1]
  867. elsif msg[0..37] == "I have an encrypted message for you - "
  868. receiveEncHandler remname, msg[38..-1]
  869. elsif msg[0...4] == "ping"
  870. sock.puts "pong"
  871. end
  872. end
  873. rescue
  874. if sock.closed?
  875. ind = $contactsBox.findItem remname
  876. if ind != -1
  877. $contactsBox.removeItem ind
  878. end
  879. $msgBox.text = ""
  880. $current = ""
  881. $b64ShowBox.text = ""
  882. Thread.current.exit
  883. end
  884. end
  885. end
  886. rescue Exception => e
  887. $consoleLabel.text = e.message
  888. $logio.write e.full_message
  889. end
  890. }
  891. end
  892. end
  893. myself.text = "Disconnect"
  894. else
  895. $statusLabel.text = "Status: Disconnecting..."
  896. $cli.puts "stop"
  897. $consoleLabel.text = $cli.gets.chomp
  898. sleep 2
  899. $cli.puts "clear"
  900. $consoleLabel.text = $cli.gets.chomp
  901. $cli.puts "quit"
  902. $consoleLabel.text = $cli.gets.chomp
  903. $cli.close
  904. $serv.exit
  905. exit
  906. end
  907. end
  908. def create
  909. super
  910. show(Fox::PLACEMENT_SCREEN)
  911. end
  912. end
  913. app = Fox::FXApp.new
  914. $icon = Fox::FXPNGIcon.new app, $icon
  915. op = OptionsWindow.new app
  916. msg = MsgWindow.new app
  917. app.create
  918. app.run
  919. exit