i2p 0.1.4

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.
@@ -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