i2p 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ module I2P
2
+ ##
3
+ # **I2P key pair data structure.**
4
+ #
5
+ # @see http://docs.i2p2.de/core/net/i2p/data/PrivateKeyFile.html
6
+ # @since 0.1.3
7
+ class KeyPair < Structure
8
+ BYTESIZE = 663 # minimum
9
+
10
+ ##
11
+ # Reads a key pair from the given `input` stream.
12
+ #
13
+ # @param [IO, StringIO] input
14
+ # @return [KeyPair]
15
+ def self.read(input)
16
+ self.new(Destination.read(input), PrivateKey.read(input), SigningPrivateKey.read(input))
17
+ end
18
+
19
+ ##
20
+ # Initializes a new key pair instance.
21
+ #
22
+ # @param [Destination] destination
23
+ # @param [PrivateKey] private_key
24
+ # @param [SigningPrivateKey] signing_key
25
+ def initialize(destination, private_key, signing_key)
26
+ @destination = destination
27
+ @private_key = private_key
28
+ @signing_key = signing_key
29
+ end
30
+
31
+ ##
32
+ # @return [Destination]
33
+ attr_accessor :destination
34
+
35
+ ##
36
+ # @return [PrivateKey]
37
+ attr_accessor :private_key
38
+
39
+ ##
40
+ # @return [SigningPrivateKey]
41
+ attr_accessor :signing_key
42
+
43
+ ##
44
+ # Returns the byte size of this key pair.
45
+ #
46
+ # @return [Integer]
47
+ def size
48
+ destination.size + private_key.size + signing_key.size
49
+ end
50
+ alias_method :bytesize, :size
51
+
52
+ ##
53
+ # Returns the binary string representation of this key pair.
54
+ #
55
+ # @return [String]
56
+ def to_s
57
+ StringIO.open do |buffer|
58
+ buffer.write(destination.to_s)
59
+ buffer.write(private_key.to_s)
60
+ buffer.write(signing_key.to_s)
61
+ buffer.string
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,14 @@
1
+ module I2P
2
+ ##
3
+ # **I2P private key data structure.**
4
+ #
5
+ # An I2P private key is a 2048-bit (256-byte) integer. The private key
6
+ # represents only the exponent, not the primes, which are constant and
7
+ # defined in the crypto spec.
8
+ #
9
+ # @see http://docs.i2p2.de/core/net/i2p/data/PrivateKey.html
10
+ # @since 0.1.3
11
+ class PrivateKey < Key
12
+ BYTESIZE = 256
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module I2P
2
+ ##
3
+ # **I2P public key data structure.**
4
+ #
5
+ # An I2P public key is a 2048-bit (256-byte) integer. The public key
6
+ # represents only the exponent, not the primes, which are constant and
7
+ # defined in the crypto spec.
8
+ #
9
+ # @see http://docs.i2p2.de/core/net/i2p/data/PublicKey.html
10
+ # @since 0.1.3
11
+ class PublicKey < Key
12
+ BYTESIZE = 256
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module I2P
2
+ ##
3
+ # **I2P signing private key data structure.**
4
+ #
5
+ # @see http://docs.i2p2.de/core/net/i2p/data/SigningPrivateKey.html
6
+ # @since 0.1.3
7
+ class SigningPrivateKey < Key
8
+ BYTESIZE = 20
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module I2P
2
+ ##
3
+ # **I2P signing public key data structure.**
4
+ #
5
+ # @see http://docs.i2p2.de/core/net/i2p/data/SigningPublicKey.html
6
+ # @since 0.1.3
7
+ class SigningPublicKey < Key
8
+ BYTESIZE = 128
9
+ end
10
+ end
@@ -0,0 +1,84 @@
1
+ module I2P
2
+ ##
3
+ # **I2P data structure.**
4
+ #
5
+ # Defines a base class for I2P data structures.
6
+ #
7
+ # @see http://docs.i2p2.de/core/net/i2p/data/DataStructure.html
8
+ # @see http://docs.i2p2.de/core/net/i2p/data/DataStructureImpl.html
9
+ # @since 0.1.3
10
+ class Structure
11
+ ##
12
+ # Parses a data structure from the given `base64` string.
13
+ #
14
+ # @param [String, #to_s] base64
15
+ # @return [Structure]
16
+ def self.parse(base64)
17
+ base64 = base64.dup
18
+ base64.gsub!('~', '/')
19
+ base64.gsub!('-', '+')
20
+ self.read(StringIO.new(base64.unpack('m').first))
21
+ end
22
+
23
+ ##
24
+ # Reads a data structure from the given `input` stream.
25
+ #
26
+ # @param [IO, StringIO] input
27
+ # @return [Structure]
28
+ def self.read(input)
29
+ raise NotImplementedError.new("#{self}.read")
30
+ end
31
+
32
+ ##
33
+ # Returns the byte size of this data structure.
34
+ #
35
+ # @return [Integer]
36
+ def size
37
+ if self.class.const_defined?(:BYTESIZE)
38
+ self.class.const_get(:BYTESIZE)
39
+ else
40
+ raise NotImplementedError.new("#{self.class}#size")
41
+ end
42
+ end
43
+ alias_method :bytesize, :size
44
+
45
+ ##
46
+ # Returns `true` if `other == self` and `other` has the same class as
47
+ # this data structure.
48
+ #
49
+ # @param [Object] other
50
+ # @return [Boolean]
51
+ def eql?(other)
52
+ other.is_a?(self.class) && self == other
53
+ end
54
+
55
+ ##
56
+ # Returns `true` if `other` has the same binary string representation as
57
+ # this data structure.
58
+ #
59
+ # @param [Object] other
60
+ # @return [Boolean]
61
+ def ==(other)
62
+ to_s == other.to_s
63
+ end
64
+
65
+ ##
66
+ # Returns the Base64-encoded representation of this data structure.
67
+ #
68
+ # @return [String]
69
+ def to_base64
70
+ base64 = [to_s].pack('m').delete("\n")
71
+ base64.gsub!('/', '~')
72
+ base64.gsub!('+', '-')
73
+ base64
74
+ end
75
+
76
+ ##
77
+ # Returns the binary string representation of this data structure.
78
+ #
79
+ # @return [String]
80
+ def to_s
81
+ raise NotImplementedError.new("#{self.class}#to_s")
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,207 @@
1
+ module I2P
2
+ ##
3
+ # I2P address book parser.
4
+ #
5
+ # @example Opening the default hosts.txt file
6
+ # I2P::Hosts.open do |hosts|
7
+ # ...
8
+ # end
9
+ #
10
+ # @example Opening the given hosts.txt file
11
+ # I2P::Hosts.open("/path/to/hosts.txt") do |hosts|
12
+ # ...
13
+ # end
14
+ #
15
+ # @since 0.1.2
16
+ class Hosts
17
+ include Enumerable
18
+
19
+ DEFAULT_FILE = '~/.i2p/hosts.txt' # Unix only
20
+
21
+ ##
22
+ # Looks up the I2P destination for `hostname`.
23
+ #
24
+ # @example
25
+ # I2P::Hosts["forum.i2p"]
26
+ #
27
+ # @param [String, #to_s] hostname
28
+ # @return [Destination]
29
+ def self.[](hostname)
30
+ self.open { |hosts| hosts[hostname] }
31
+ end
32
+
33
+ ##
34
+ # Opens a `hosts.txt` file for reading.
35
+ #
36
+ # @example Opening the default hosts.txt file
37
+ # I2P::Hosts.open do |hosts|
38
+ # ...
39
+ # end
40
+ #
41
+ # @example Opening the given hosts.txt file
42
+ # I2P::Hosts.open("/path/to/hosts.txt") do |hosts|
43
+ # ...
44
+ # end
45
+ #
46
+ # @param [String, #to_s] filename
47
+ # @param [Hash{Symbol => Object}] options
48
+ # @yield [hosts]
49
+ # @yieldparam [Hosts] hosts
50
+ # @return [Hosts]
51
+ def self.open(filename = DEFAULT_FILE, options = {}, &block)
52
+ hosts = self.new(filename, options)
53
+ block_given? ? block.call(hosts) : hosts
54
+ end
55
+
56
+ # @return [Hash]
57
+ attr_reader :options
58
+
59
+ # @return [Hash]
60
+ attr_reader :cache
61
+
62
+ # @return [String]
63
+ attr_reader :filename
64
+
65
+ ##
66
+ # @param [String, #to_s] filename
67
+ # @param [Hash{Symbol => Object}] options
68
+ # @yield [hosts]
69
+ # @yieldparam [Hosts] hosts
70
+ def initialize(filename = DEFAULT_FILE, options = {}, &block)
71
+ @cache = {}
72
+ @filename = File.expand_path(filename.to_s)
73
+ @options = options.dup
74
+ block.call(self) if block_given?
75
+ end
76
+
77
+ ##
78
+ # Returns `true` if `hosts.txt` doesn't contain any hostnames.
79
+ #
80
+ # @example
81
+ # hosts.empty?
82
+ #
83
+ # @return [Boolean]
84
+ def empty?
85
+ count.zero?
86
+ end
87
+
88
+ ##
89
+ # Returns the number of hostnames in `hosts.txt`.
90
+ #
91
+ # @example
92
+ # hosts.count
93
+ #
94
+ # @return [Integer]
95
+ def count
96
+ each.count
97
+ end
98
+
99
+ ##
100
+ # Returns `true` if `hosts.txt` includes `value`. The `value` can be
101
+ # either a hostname or an I2P destination.
102
+ #
103
+ # @example
104
+ # hosts.include?("forum.i2p")
105
+ #
106
+ # @param [Destination, Regexp, #to_s] value
107
+ # @return [Boolean]
108
+ def include?(value)
109
+ case value
110
+ when Destination then each.any? { |k, v| value.eql?(v) }
111
+ when Regexp then each.any? { |k, v| value === k }
112
+ else each.any? { |k, v| value.to_s.eql?(k) }
113
+ end
114
+ end
115
+
116
+ ##
117
+ # Returns the I2P destination for `hostname`.
118
+ #
119
+ # @example
120
+ # hosts["forum.i2p"]
121
+ #
122
+ # @param [String, #to_s] hostname
123
+ # @return [Destination]
124
+ def [](hostname)
125
+ @cache[hostname.to_s] ||= each_line.find do |line|
126
+ k, v = parse_line(line)
127
+ break Destination.parse(v) if hostname === k
128
+ end
129
+ end
130
+
131
+ ##
132
+ # Enumerates the hostnames and I2P destinations in `hosts.txt`.
133
+ #
134
+ # @example
135
+ # hosts.each do |hostname, destination|
136
+ # ...
137
+ # end
138
+ #
139
+ # @yield [hostname, destination]
140
+ # @yieldparam [String] hostname
141
+ # @yieldparam [Destination] destination
142
+ # @return [Enumerator]
143
+ def each(&block)
144
+ if block_given?
145
+ each_line do |line|
146
+ k, v = parse_line(line)
147
+ block.call(k, Destination.parse(v))
148
+ end
149
+ end
150
+ enum_for(:each)
151
+ end
152
+
153
+ ##
154
+ # Returns all hostname mappings as an array.
155
+ #
156
+ # @return [Array]
157
+ def to_a
158
+ each.inject([]) { |result, kv| result.push(kv) }
159
+ end
160
+
161
+ ##
162
+ # Returns all hostname mappings as a hash.
163
+ #
164
+ # @return [Hash]
165
+ def to_hash
166
+ each.inject({}) { |result, (k, v)| result.merge!(k => v) }
167
+ end
168
+
169
+ ##
170
+ # Returns all hostname mappings as a string.
171
+ #
172
+ # @return [String]
173
+ def to_s
174
+ each.inject([]) { |result, (k, v)| result.push([k, v.to_base64].join('=')) }.push('').join($/)
175
+ end
176
+
177
+ protected
178
+
179
+ ##
180
+ # Enumerates each line in the `hosts.txt` file.
181
+ #
182
+ # @yield [line]
183
+ # @yieldparam [String] line
184
+ # @return [Enumerator]
185
+ def each_line(&block)
186
+ if block_given?
187
+ File.open(@filename, 'rb') do |file|
188
+ file.each_line do |line|
189
+ line, = line.split('#', 2) if line.include?(?#)
190
+ line.chomp!.strip!
191
+ block.call(line) unless line.empty?
192
+ end
193
+ end
194
+ end
195
+ enum_for(:each_line)
196
+ end
197
+
198
+ ##
199
+ # Parses a hostname mapping line from `hosts.txt`.
200
+ #
201
+ # @param [String]
202
+ # @return [Array(String, String)]
203
+ def parse_line(line)
204
+ line.chomp.split('=', 2).map(&:strip)
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,40 @@
1
+ module I2P
2
+ ##
3
+ # **I2P Simple Anonymous Messaging (SAM) protocol.**
4
+ #
5
+ # This is an implementation of the SAM V3 protocol, available since I2P
6
+ # release [0.7.3](http://www.i2p2.de/release-0.7.3.html).
7
+ #
8
+ # Note that for security reasons, the SAM application bridge is not
9
+ # enabled by default in new I2P installations. To use `I2P::SAM`,
10
+ # you must first manually enable SAM in the router console's
11
+ # [client configuration](http://localhost:7657/configclients.jsp).
12
+ #
13
+ # Note also that I2P by default doesn't bring up the SAM bridge until 120
14
+ # seconds after router startup. This delay can be changed by editing the
15
+ # `~/.i2p/clients.config` configuration file.
16
+ #
17
+ # @see http://www.i2p2.de/applications.html
18
+ # @see http://www.i2p2.de/samv3.html
19
+ module SAM
20
+ PROTOCOL_VERSION = 3.0
21
+ DEFAULT_HOST = (ENV['I2P_SAM_HOST'] || '127.0.0.1').to_s
22
+ DEFAULT_PORT = (ENV['I2P_SAM_PORT'] || 7656).to_i
23
+
24
+ autoload :Client, 'i2p/sam/client'
25
+
26
+ ##
27
+ # **I2P Simple Anonymous Messaging (SAM) protocol error conditions.**
28
+ class Error < StandardError # I2P_ERROR
29
+ class ProtocolNotSupported < Error; end # NOVERSION
30
+ class SessionIDNotValid < Error; end # INVALID_ID
31
+ class SessionIDAlreadyUsed < Error; end # DUPLICATED_ID
32
+ class DestinationAlreadyUsed < Error; end # DUPLICATED_DEST
33
+ class KeyNotValid < Error; end # INVALID_KEY
34
+ class KeyNotFound < Error; end # KEY_NOT_FOUND
35
+ class PeerNotReachable < Error; end # CANT_REACH_PEER
36
+ class PeerNotFound < Error; end # PEER_NOT_FOUND
37
+ class Timeout < Error; end # TIMEOUT
38
+ end
39
+ end
40
+ end