torchat 0.0.1.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +43 -0
- data/bin/torchatd +537 -0
- data/doc/protocol/broadcast.md +26 -0
- data/doc/protocol/groupchat.md +140 -0
- data/doc/protocol/latency.md +30 -0
- data/doc/protocol/standard.md +279 -0
- data/doc/protocol/typing.md +41 -0
- data/etc/torchat.yml +12 -0
- data/lib/torchat.rb +239 -0
- data/lib/torchat/protocol.rb +256 -0
- data/lib/torchat/protocol/broadcast.rb +40 -0
- data/lib/torchat/protocol/groupchat.rb +197 -0
- data/lib/torchat/protocol/latency.rb +44 -0
- data/lib/torchat/protocol/standard.rb +367 -0
- data/lib/torchat/protocol/typing.rb +36 -0
- data/lib/torchat/session.rb +603 -0
- data/lib/torchat/session/broadcast/message.rb +50 -0
- data/lib/torchat/session/broadcasts.rb +72 -0
- data/lib/torchat/session/buddies.rb +152 -0
- data/lib/torchat/session/buddy.rb +343 -0
- data/lib/torchat/session/buddy/joined_group_chat.rb +42 -0
- data/lib/torchat/session/buddy/joined_group_chats.rb +46 -0
- data/lib/torchat/session/buddy/latency.rb +54 -0
- data/lib/torchat/session/event.rb +79 -0
- data/lib/torchat/session/file_transfer.rb +173 -0
- data/lib/torchat/session/file_transfer/block.rb +51 -0
- data/lib/torchat/session/file_transfers.rb +89 -0
- data/lib/torchat/session/group_chat.rb +123 -0
- data/lib/torchat/session/group_chat/participant.rb +38 -0
- data/lib/torchat/session/group_chat/participants.rb +52 -0
- data/lib/torchat/session/group_chats.rb +74 -0
- data/lib/torchat/session/incoming.rb +187 -0
- data/lib/torchat/session/outgoing.rb +102 -0
- data/lib/torchat/tor.rb +107 -0
- data/lib/torchat/utils.rb +87 -0
- data/lib/torchat/version.rb +24 -0
- data/test/file_transfer/receiver.rb +41 -0
- data/test/file_transfer/sender.rb +45 -0
- data/test/group_chat/a.rb +37 -0
- data/test/group_chat/b.rb +37 -0
- data/test/group_chat/c.rb +57 -0
- data/torchat.gemspec +21 -0
- metadata +140 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'em-socksify'
|
21
|
+
|
22
|
+
class Torchat; class Session
|
23
|
+
|
24
|
+
class Outgoing < EventMachine::Protocols::LineAndTextProtocol
|
25
|
+
include EM::Socksify
|
26
|
+
|
27
|
+
attr_accessor :owner
|
28
|
+
|
29
|
+
def post_init
|
30
|
+
@delayed = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def connection_completed
|
34
|
+
old, new = comm_inactivity_timeout, @session.connection_timeout
|
35
|
+
|
36
|
+
set_comm_inactivity_timeout new
|
37
|
+
|
38
|
+
@session.fire :connect_to, address: @owner.address, port: @owner.port
|
39
|
+
|
40
|
+
socksify(@owner.address, @owner.port).callback {
|
41
|
+
set_comm_inactivity_timeout old
|
42
|
+
|
43
|
+
@owner.connected
|
44
|
+
}.errback {|exc|
|
45
|
+
Torchat.debug exc, level: 3
|
46
|
+
|
47
|
+
@owner.disconnect
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def verification_completed
|
52
|
+
@delayed.each {|packet|
|
53
|
+
send_packet! packet
|
54
|
+
}
|
55
|
+
|
56
|
+
@delayed = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def receive_line (line)
|
60
|
+
packet = Protocol.unpack(line.chomp, @owner)
|
61
|
+
|
62
|
+
return unless packet.type.to_s.start_with 'file'
|
63
|
+
|
64
|
+
@owner.session.received_packet packet
|
65
|
+
end
|
66
|
+
|
67
|
+
def send_packet (*args)
|
68
|
+
packet = Protocol.packet(*args)
|
69
|
+
|
70
|
+
if @delayed
|
71
|
+
@delayed << packet
|
72
|
+
else
|
73
|
+
send_packet! packet
|
74
|
+
end
|
75
|
+
|
76
|
+
packet
|
77
|
+
end
|
78
|
+
|
79
|
+
def send_packet! (*args)
|
80
|
+
packet = Protocol.packet(*args)
|
81
|
+
|
82
|
+
Torchat.debug ">> #{@owner ? @owner.id : 'unknown'} #{packet.inspect}", level: 2
|
83
|
+
|
84
|
+
send_data packet.pack
|
85
|
+
|
86
|
+
packet
|
87
|
+
end
|
88
|
+
|
89
|
+
def unbind
|
90
|
+
if error?
|
91
|
+
Torchat.debug "errno #{EM.report_connection_error_status(@signature)}", level: 2
|
92
|
+
end
|
93
|
+
|
94
|
+
if @owner.connecting?
|
95
|
+
@owner.failed!
|
96
|
+
else
|
97
|
+
@owner.disconnect
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end; end
|
data/lib/torchat/tor.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
class Torchat
|
21
|
+
|
22
|
+
class Tor
|
23
|
+
class Instance < EM::Connection
|
24
|
+
def receive_data (data)
|
25
|
+
return unless ENV['DEBUG'] && ENV['DEBUG'].to_i >= 5
|
26
|
+
|
27
|
+
print data.gsub(/^/, 'tor] ')
|
28
|
+
end
|
29
|
+
|
30
|
+
alias stop close_connection
|
31
|
+
|
32
|
+
def unbind
|
33
|
+
@owner.error unless get_status.success?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :config
|
38
|
+
attr_accessor :file
|
39
|
+
|
40
|
+
def initialize (config)
|
41
|
+
@config = config
|
42
|
+
|
43
|
+
@file = 'torrc'
|
44
|
+
end
|
45
|
+
|
46
|
+
def start (path, *args, &block)
|
47
|
+
return if @instance
|
48
|
+
|
49
|
+
if block
|
50
|
+
@error = args.shift
|
51
|
+
end
|
52
|
+
|
53
|
+
block = args.shift
|
54
|
+
@error ||= args.shift
|
55
|
+
|
56
|
+
File.expand_path(path).tap {|path|
|
57
|
+
FileUtils.mkpath path
|
58
|
+
|
59
|
+
Dir.chdir path do
|
60
|
+
unless File.exists?(@file)
|
61
|
+
File.open(@file, 'w') { |f| f.print rc }
|
62
|
+
end
|
63
|
+
|
64
|
+
EM.popen "tor -f '#@file'", Instance do |t|
|
65
|
+
@instance = t
|
66
|
+
|
67
|
+
t.instance_variable_set :@owner, self
|
68
|
+
end
|
69
|
+
|
70
|
+
block.arity.zero? ? block.call : block.call(path) if block
|
71
|
+
end
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def stop
|
76
|
+
return unless @instance
|
77
|
+
|
78
|
+
@instance.close_connection
|
79
|
+
end
|
80
|
+
|
81
|
+
def error
|
82
|
+
@error.call if @error
|
83
|
+
end
|
84
|
+
|
85
|
+
def rc
|
86
|
+
<<-EOF.gsub /^\t+/, ''
|
87
|
+
SocksPort #{config['connection']['outgoing']['port']}
|
88
|
+
|
89
|
+
HiddenServiceDir hidden_service
|
90
|
+
HiddenServicePort 11009 #{
|
91
|
+
config['connection']['incoming']['host']
|
92
|
+
}:#{
|
93
|
+
config['connection']['incoming']['port']
|
94
|
+
}
|
95
|
+
|
96
|
+
DataDirectory tor_data
|
97
|
+
|
98
|
+
AvoidDiskWrites 1
|
99
|
+
LongLivedPorts 11009
|
100
|
+
FetchDirInfoEarly 1
|
101
|
+
CircuitBuildTimeout 30
|
102
|
+
NumEntryGuards 6
|
103
|
+
EOF
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'securerandom'
|
21
|
+
|
22
|
+
class Torchat
|
23
|
+
def self.debug?
|
24
|
+
return false unless env = ENV['DEBUG'] || ENV['TORCHAT_DEBUG']
|
25
|
+
|
26
|
+
env.to_i.zero? ? 1 : env.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
if debug?
|
30
|
+
require 'ap'
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.debug (argument, options = {})
|
34
|
+
return if !debug? && !options[:force]
|
35
|
+
|
36
|
+
return if debug? < (options[:level] || 1) && !options[:force]
|
37
|
+
|
38
|
+
output = options[:prefix] ? options[:prefix] : "[#{Time.new}] "
|
39
|
+
|
40
|
+
if argument.is_a?(Exception)
|
41
|
+
output << "From: #{caller[0, options[:deep] || 1].join("\n")}\n"
|
42
|
+
output << "#{argument.class}: #{argument.message}\n"
|
43
|
+
output << argument.backtrace.collect {|stack|
|
44
|
+
stack
|
45
|
+
}.join("\n")
|
46
|
+
output << "\n\n"
|
47
|
+
elsif argument.is_a?(String)
|
48
|
+
output << "#{argument}\n"
|
49
|
+
else
|
50
|
+
output << "#{argument.inspect}\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
if options[:separator]
|
54
|
+
output << options[:separator]
|
55
|
+
end
|
56
|
+
|
57
|
+
$stderr.puts output
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.valid_address? (address)
|
61
|
+
!!address.match(/^[234567abcdefghijklmnopqrstuvwxyz]{16}\.onion$/i)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.valid_id? (id)
|
65
|
+
!!id.match(/^[234567abcdefghijklmnopqrstuvwxyz]{16}$/i)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.new_cookie
|
69
|
+
SecureRandom.uuid
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.normalize_id (value, return_nil = false)
|
73
|
+
if value.respond_to? :id
|
74
|
+
value = value.id
|
75
|
+
end
|
76
|
+
|
77
|
+
value = value.to_s[/^(.*?)(\.onion)?$/, 1]
|
78
|
+
|
79
|
+
unless valid_id?(value)
|
80
|
+
return if return_nil
|
81
|
+
|
82
|
+
raise ArgumentError, 'the given ID is invalid'
|
83
|
+
end
|
84
|
+
|
85
|
+
value
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of torchat for ruby.
|
5
|
+
#
|
6
|
+
# torchat for ruby is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# torchat for ruby is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with torchat for ruby. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
class Torchat
|
21
|
+
def self.version
|
22
|
+
'0.0.1.rc.1'
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'torchat'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
|
7
|
+
OptionParser.new do |o|
|
8
|
+
o.on '-p', '--profile PROFILE', 'the profile name' do |name|
|
9
|
+
options[:profile] = name
|
10
|
+
end
|
11
|
+
end.parse!
|
12
|
+
|
13
|
+
EM.run {
|
14
|
+
Torchat.profile(options[:profile]).start {|s|
|
15
|
+
s.when :connect_to do |e|
|
16
|
+
Torchat.debug "connecting to #{e.address}:#{e.port}"
|
17
|
+
end
|
18
|
+
|
19
|
+
s.on :connect_failure do |e|
|
20
|
+
Torchat.debug "#{e.buddy.id} failed to connect"
|
21
|
+
end
|
22
|
+
|
23
|
+
s.on :connect do |e|
|
24
|
+
Torchat.debug "#{e.buddy.id} connected"
|
25
|
+
end
|
26
|
+
|
27
|
+
s.on :verify do |e|
|
28
|
+
Torchat.debug "#{e.buddy.id} has been verified"
|
29
|
+
end
|
30
|
+
|
31
|
+
s.on :disconnect do |e|
|
32
|
+
Torchat.debug "#{e.buddy.id} disconnected"
|
33
|
+
end
|
34
|
+
|
35
|
+
s.on :file_transfer_activity do |e|
|
36
|
+
puts e.file_transfer.inspect
|
37
|
+
end
|
38
|
+
|
39
|
+
s.online!
|
40
|
+
}
|
41
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'torchat'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
|
7
|
+
OptionParser.new do |o|
|
8
|
+
o.on '-p', '--profile PROFILE', 'the profile name' do |name|
|
9
|
+
options[:profile] = name
|
10
|
+
end
|
11
|
+
|
12
|
+
o.on '-s', '--send-to NAME', 'the name of the receiver' do |name|
|
13
|
+
options[:send_to] = name
|
14
|
+
end
|
15
|
+
end.parse!
|
16
|
+
|
17
|
+
EM.run {
|
18
|
+
Torchat.profile(options[:profile]).start {|s|
|
19
|
+
s.when :connect_to do |e|
|
20
|
+
Torchat.debug "connecting to #{e.address}:#{e.port}"
|
21
|
+
end
|
22
|
+
|
23
|
+
s.on :connect_failure do |e|
|
24
|
+
Torchat.debug "#{e.buddy.id} failed to connect"
|
25
|
+
end
|
26
|
+
|
27
|
+
s.on :connect do |e|
|
28
|
+
Torchat.debug "#{e.buddy.id} connected"
|
29
|
+
end
|
30
|
+
|
31
|
+
s.on :verify do |e|
|
32
|
+
Torchat.debug "#{e.buddy.id} has been verified"
|
33
|
+
end
|
34
|
+
|
35
|
+
s.on :disconnect do |e|
|
36
|
+
Torchat.debug "#{e.buddy.id} disconnected"
|
37
|
+
end
|
38
|
+
|
39
|
+
s.buddies.add_temporary(options[:send_to]).on :ready do |e|
|
40
|
+
e.buddy.send_file ARGV.first
|
41
|
+
end
|
42
|
+
|
43
|
+
s.online!
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'torchat'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
|
7
|
+
OptionParser.new do |o|
|
8
|
+
o.on '-p', '--profile PROFILE', 'the profile name' do |name|
|
9
|
+
options[:profile] = name
|
10
|
+
end
|
11
|
+
end.parse!
|
12
|
+
|
13
|
+
EM.run {
|
14
|
+
Torchat.profile(options[:profile]).start {|s|
|
15
|
+
s.when :connect_to do |e|
|
16
|
+
Torchat.debug "connecting to #{e.address}:#{e.port}"
|
17
|
+
end
|
18
|
+
|
19
|
+
s.on :connect_failure do |e|
|
20
|
+
Torchat.debug "#{e.buddy.id} failed to connect"
|
21
|
+
end
|
22
|
+
|
23
|
+
s.on :connect do |e|
|
24
|
+
Torchat.debug "#{e.buddy.id} connected"
|
25
|
+
end
|
26
|
+
|
27
|
+
s.on :verify do |e|
|
28
|
+
Torchat.debug "#{e.buddy.id} has been verified"
|
29
|
+
end
|
30
|
+
|
31
|
+
s.on :disconnect do |e|
|
32
|
+
Torchat.debug "#{e.buddy.id} disconnected"
|
33
|
+
end
|
34
|
+
|
35
|
+
s.online!
|
36
|
+
}
|
37
|
+
}
|