websocket-client 0.1.9 → 0.2.0
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/examples/simple.rb +5 -6
- data/lib/websocket_client/byte_sink.rb +48 -0
- data/lib/websocket_client/byte_source.rb +102 -0
- data/lib/websocket_client/client.rb +62 -87
- data/lib/websocket_client/frame_io.rb +106 -0
- data/lib/websocket_client/protocol/ietf_00.rb +86 -0
- metadata +9 -6
- data/lib/websocket_client/ietf_00.rb +0 -123
data/examples/simple.rb
CHANGED
@@ -5,22 +5,21 @@ $: << File.dirname(__FILE__) + '/../lib'
|
|
5
5
|
require 'websocket_client'
|
6
6
|
|
7
7
|
## Create a disconnected client
|
8
|
-
client = WebSocketClient.create( 'ws://localhost:8081/websockets/' )
|
8
|
+
client = WebSocketClient.create( 'ws://localhost:8081/websockets/echo/' )
|
9
9
|
|
10
|
-
|
10
|
+
## Set up the message handler before connecting
|
11
11
|
client.on_message do |msg|
|
12
|
-
puts "received #{msg}"
|
12
|
+
puts "> received message: #{msg}"
|
13
13
|
end
|
14
14
|
|
15
15
|
## Connect
|
16
16
|
client.connect()
|
17
17
|
|
18
18
|
## Use the connected client
|
19
|
-
puts "sending"
|
20
19
|
client.send( "HOWDY-1" )
|
21
20
|
client.send( "HOWDY-2" )
|
22
21
|
client.send( "HOWDY-3" )
|
23
22
|
sleep(1)
|
24
23
|
|
25
|
-
## Explicit disconncet
|
26
|
-
client.disconnect
|
24
|
+
## Explicit disconncet and wait
|
25
|
+
client.disconnect( true )
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
module WebSocketClient
|
3
|
+
|
4
|
+
class ByteSink
|
5
|
+
|
6
|
+
CR = 0x0D
|
7
|
+
NL = 0x0A
|
8
|
+
|
9
|
+
def write_line(line)
|
10
|
+
line.bytes.each do |b|
|
11
|
+
write( b )
|
12
|
+
end
|
13
|
+
write( CR )
|
14
|
+
write( NL )
|
15
|
+
end
|
16
|
+
|
17
|
+
def flush
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class SocketByteSink < ByteSink
|
22
|
+
def initialize(socket)
|
23
|
+
@socket = socket
|
24
|
+
end
|
25
|
+
|
26
|
+
def write(byte)
|
27
|
+
@socket.putc( byte )
|
28
|
+
end
|
29
|
+
|
30
|
+
def flush
|
31
|
+
@socket.flush
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ArrayByteSink < ByteSink
|
36
|
+
def initialize()
|
37
|
+
@sink = []
|
38
|
+
end
|
39
|
+
|
40
|
+
def write(byte)
|
41
|
+
@sink << byte
|
42
|
+
end
|
43
|
+
|
44
|
+
def bytes
|
45
|
+
@sink
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
|
2
|
+
module WebSocketClient
|
3
|
+
|
4
|
+
class ByteSource
|
5
|
+
def getbytes(num)
|
6
|
+
bytes = []
|
7
|
+
1.upto( num ) do
|
8
|
+
break if ( eof? )
|
9
|
+
bytes << getbyte()
|
10
|
+
end
|
11
|
+
bytes
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BufferedByteSource < ByteSource
|
16
|
+
def initialize(source)
|
17
|
+
@source = source
|
18
|
+
@buffer = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def getbyte
|
22
|
+
return @source.getbyte if @buffer.empty?
|
23
|
+
@buffer.shift
|
24
|
+
end
|
25
|
+
|
26
|
+
def peekbyte(index=0)
|
27
|
+
while ( @buffer.size < (index+1) )
|
28
|
+
return nil if ( @source.eof? )
|
29
|
+
@buffer << @source.getbyte
|
30
|
+
end
|
31
|
+
return @buffer[index]
|
32
|
+
end
|
33
|
+
|
34
|
+
def eof?
|
35
|
+
return @source.eof? if @buffer.empty?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def getline
|
40
|
+
line = ''
|
41
|
+
while ( ! eof? )
|
42
|
+
b = getbyte
|
43
|
+
case ( b )
|
44
|
+
when 0x0D then # carriage-return
|
45
|
+
if peekbyte == 0x0A # newline
|
46
|
+
getbyte # consume it also
|
47
|
+
end
|
48
|
+
break
|
49
|
+
when 0x0A then # newline
|
50
|
+
break
|
51
|
+
else
|
52
|
+
line << b
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return line
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
class SocketByteSource < ByteSource
|
62
|
+
def initialize(socket)
|
63
|
+
@socket = socket
|
64
|
+
if ( socket.respond_to? :getbyte )
|
65
|
+
alias :getbyte :getbyte_19
|
66
|
+
else
|
67
|
+
alias :getbyte :getbyte_18
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def getbyte_18
|
72
|
+
@socket.getc
|
73
|
+
end
|
74
|
+
|
75
|
+
def getbyte_19
|
76
|
+
@socket.getbyte
|
77
|
+
end
|
78
|
+
|
79
|
+
def eof?
|
80
|
+
@socket.eof?
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
class ArrayByteSource < ByteSource
|
86
|
+
def initialize(array)
|
87
|
+
@array = array
|
88
|
+
@cur = 0
|
89
|
+
end
|
90
|
+
|
91
|
+
def getbyte
|
92
|
+
b = @array[@cur]
|
93
|
+
@cur += 1
|
94
|
+
b
|
95
|
+
end
|
96
|
+
|
97
|
+
def eof?
|
98
|
+
( @cur >= @array.size )
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -1,22 +1,12 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'uri'
|
3
|
-
require 'websocket_client/
|
3
|
+
require 'websocket_client/frame_io'
|
4
|
+
require 'websocket_client/protocol/ietf_00'
|
4
5
|
|
5
6
|
|
6
7
|
module WebSocketClient
|
7
8
|
|
8
|
-
DEFAULT_HANDSHAKE = Ietf00
|
9
|
-
|
10
|
-
class DebugSocket
|
11
|
-
def initialize(socket)
|
12
|
-
@socket = socket
|
13
|
-
end
|
14
|
-
|
15
|
-
def method_missing(method, *args)
|
16
|
-
puts "> #{method}(#{args.join( ', ')})"
|
17
|
-
@socket.__send__( method, *args )
|
18
|
-
end
|
19
|
-
end
|
9
|
+
DEFAULT_HANDSHAKE = Protocol::Ietf00
|
20
10
|
|
21
11
|
def self.create(uri,handshake_class=WebSocketClient::DEFAULT_HANDSHAKE,&block)
|
22
12
|
Client.new(uri, handshake_class, &block)
|
@@ -25,59 +15,76 @@ module WebSocketClient
|
|
25
15
|
class Client
|
26
16
|
attr_reader :uri
|
27
17
|
|
18
|
+
attr_reader :source
|
19
|
+
attr_reader :sink
|
20
|
+
|
28
21
|
def initialize(uri,handshake_class=WebSocketClient::DEFAULT_HANDSHAKE, &block)
|
29
|
-
@handshake_class
|
30
|
-
@
|
31
|
-
@on_message_handler = nil
|
22
|
+
@handshake_class = handshake_class
|
23
|
+
@on_message_handler = nil
|
32
24
|
@on_disconnect_handler = nil
|
33
|
-
@handler_thread
|
34
|
-
@
|
35
|
-
|
36
|
-
when String
|
37
|
-
@uri = URI.parse( uri )
|
38
|
-
else
|
39
|
-
@uri = uri
|
40
|
-
end
|
25
|
+
@handler_thread = nil
|
26
|
+
@uri = cleanse_uri( uri )
|
27
|
+
|
41
28
|
block.call( self ) if block
|
42
29
|
end
|
30
|
+
|
31
|
+
def cleanse_uri(uri)
|
32
|
+
return URI.parse( uri ) if ( String === uri )
|
33
|
+
uri
|
34
|
+
end
|
43
35
|
|
44
36
|
def connect(&block)
|
45
|
-
|
46
|
-
|
47
|
-
@
|
48
|
-
|
49
|
-
|
37
|
+
socket = TCPSocket.open(uri.host, uri.port)
|
38
|
+
@source = BufferedByteSource.new( SocketByteSource.new( socket ) )
|
39
|
+
@sink = SocketByteSink.new( socket )
|
40
|
+
@handshake = @handshake_class.new( uri, @source, @sink )
|
41
|
+
|
42
|
+
internal_connect(source, sink)
|
43
|
+
run_client( &block )
|
44
|
+
end
|
45
|
+
|
46
|
+
def internal_connect(source, sink)
|
47
|
+
@frame_reader = FrameReader.new( source )
|
48
|
+
@frame_writer = FrameWriter.new( sink )
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_client(&block)
|
52
|
+
on_connect
|
50
53
|
start_handler
|
51
|
-
|
52
54
|
if ( block )
|
53
55
|
begin
|
54
|
-
|
56
|
+
block.call( self )
|
55
57
|
ensure
|
56
58
|
disconnect()
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
|
-
def disconnect
|
62
|
-
@
|
63
|
-
|
64
|
-
@close_state = :requested
|
63
|
+
def disconnect(wait_for=false)
|
64
|
+
@frame_writer.write_close_frame()
|
65
|
+
wait_for_disconnect if wait_for
|
65
66
|
end
|
66
67
|
|
67
|
-
def send(
|
68
|
-
@
|
69
|
-
@socket.flush
|
68
|
+
def send(text)
|
69
|
+
@frame_writer.write_as_text_frame( text )
|
70
70
|
end
|
71
71
|
|
72
|
-
def
|
72
|
+
def wait_for_disconnect()
|
73
73
|
@handler_thread.join
|
74
74
|
end
|
75
75
|
|
76
|
+
def on_connect(&block)
|
77
|
+
if ( block )
|
78
|
+
@on_connect_handler = block
|
79
|
+
else
|
80
|
+
@on_connect_handler.call() if @on_connect_handler
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
76
84
|
def on_message(msg=nil,&block)
|
77
85
|
if ( block )
|
78
86
|
@on_message_handler = block
|
79
87
|
else
|
80
|
-
puts "> on_message #{msg}"
|
81
88
|
@on_message_handler.call( msg ) if @on_message_handler
|
82
89
|
end
|
83
90
|
end
|
@@ -86,59 +93,27 @@ module WebSocketClient
|
|
86
93
|
if ( block )
|
87
94
|
@on_disconnect_handler = block
|
88
95
|
else
|
89
|
-
|
90
|
-
@on_disconnect_handler.call( msg ) if @on_disconnect_handler
|
96
|
+
@on_disconnect_handler.call() if @on_disconnect_handler
|
91
97
|
end
|
92
98
|
end
|
93
99
|
|
94
100
|
def start_handler
|
95
|
-
@handler_thread = Thread.new(
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
puts "> full-closed by server"
|
109
|
-
socket.close
|
110
|
-
break
|
111
|
-
else
|
112
|
-
if ( @close_state == :half_closed )
|
113
|
-
socket.close
|
114
|
-
break
|
115
|
-
else
|
116
|
-
msg_state = :none
|
117
|
-
end
|
118
|
-
end
|
119
|
-
elsif ( c == 0xFF )
|
120
|
-
if ( msg_state == :none )
|
121
|
-
msg_state = :half_closed
|
122
|
-
puts "> half-closed by server"
|
123
|
-
else
|
124
|
-
if ( @close_state == :requested )
|
125
|
-
@close_state = :half_closed
|
126
|
-
else
|
127
|
-
on_message( msg )
|
128
|
-
msg = ''
|
129
|
-
msg_state = :none
|
130
|
-
end
|
131
|
-
end
|
132
|
-
else
|
133
|
-
if ( @close_state != nil )
|
134
|
-
@close_state = nil
|
135
|
-
end
|
136
|
-
msg_state = :in_progress
|
137
|
-
msg << c
|
138
|
-
end
|
101
|
+
@handler_thread = Thread.new() do
|
102
|
+
run_handler_loop
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def run_handler_loop
|
107
|
+
while ( ! @frame_reader.eof? )
|
108
|
+
frame = @frame_reader.read_frame
|
109
|
+
case ( frame.type )
|
110
|
+
when :text
|
111
|
+
on_message( frame.text )
|
112
|
+
when :close
|
113
|
+
break
|
139
114
|
end
|
140
|
-
on_disconnect
|
141
115
|
end
|
116
|
+
on_disconnect
|
142
117
|
end
|
143
118
|
|
144
119
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
require 'websocket_client/byte_source'
|
3
|
+
require 'websocket_client/byte_sink'
|
4
|
+
|
5
|
+
module WebSocketClient
|
6
|
+
|
7
|
+
class TextFrame
|
8
|
+
|
9
|
+
attr_accessor :text
|
10
|
+
|
11
|
+
def initialize(text)
|
12
|
+
@text = text
|
13
|
+
end
|
14
|
+
|
15
|
+
def type
|
16
|
+
:text
|
17
|
+
end
|
18
|
+
|
19
|
+
def bytes
|
20
|
+
[ 0x00, @text.bytes.to_a, 0xFF ].flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class CloseFrame
|
26
|
+
INSTANCE = CloseFrame.new.freeze
|
27
|
+
|
28
|
+
def type
|
29
|
+
:close
|
30
|
+
end
|
31
|
+
|
32
|
+
def bytes
|
33
|
+
[ 0xFF, 0x00 ]
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def initialize()
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class FrameWriter
|
42
|
+
attr_reader :sink
|
43
|
+
attr_accessor :debug
|
44
|
+
|
45
|
+
def initialize(sink,debug=false)
|
46
|
+
@sink = sink
|
47
|
+
@debug = debug
|
48
|
+
end
|
49
|
+
|
50
|
+
def write_close_frame()
|
51
|
+
write_frame( CloseFrame::INSTANCE )
|
52
|
+
end
|
53
|
+
|
54
|
+
def write_as_text_frame(text)
|
55
|
+
write_frame( TextFrame.new( text ) )
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_frame(frame)
|
59
|
+
frame.bytes.each do |b|
|
60
|
+
@sink.write( b )
|
61
|
+
end
|
62
|
+
@sink.flush
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class FrameReader
|
67
|
+
|
68
|
+
attr_reader :source
|
69
|
+
attr_accessor :debug
|
70
|
+
|
71
|
+
def initialize(source,debug=true)
|
72
|
+
@source = source
|
73
|
+
@debug = debug
|
74
|
+
end
|
75
|
+
|
76
|
+
def eof?
|
77
|
+
@source.eof?
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_frame()
|
81
|
+
buffer = nil
|
82
|
+
state = :none
|
83
|
+
while ( ! source.eof? )
|
84
|
+
b = source.getbyte
|
85
|
+
case ( b )
|
86
|
+
when 0x00
|
87
|
+
if ( state == :half_closed )
|
88
|
+
return CloseFrame::INSTANCE
|
89
|
+
end
|
90
|
+
buffer = ''
|
91
|
+
when 0xFF
|
92
|
+
if ( ! buffer.nil? )
|
93
|
+
return TextFrame.new( buffer )
|
94
|
+
else
|
95
|
+
state = :half_closed
|
96
|
+
end
|
97
|
+
else
|
98
|
+
buffer << b
|
99
|
+
end
|
100
|
+
end
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'uri'
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
module WebSocketClient
|
6
|
+
module Protocol
|
7
|
+
class Ietf00
|
8
|
+
|
9
|
+
attr_reader :source
|
10
|
+
attr_reader :sink
|
11
|
+
|
12
|
+
def initialize(uri, source, sink)
|
13
|
+
@source = source
|
14
|
+
@sink = sink
|
15
|
+
perform_http_prolog(uri)
|
16
|
+
end
|
17
|
+
|
18
|
+
def perform_http_prolog(uri)
|
19
|
+
key1, key2, key3, solution = generate_keys()
|
20
|
+
|
21
|
+
sink.write_line "GET #{uri.path} HTTP/1.1"
|
22
|
+
sink.write_line "Host: #{uri.host}"
|
23
|
+
sink.write_line "Connection: upgrade"
|
24
|
+
sink.write_line "Upgrade: websocket"
|
25
|
+
sink.write_line "Origin: http://#{uri.host}/"
|
26
|
+
sink.write_line "Sec-WebSocket-Key1: #{key1}"
|
27
|
+
sink.write_line "Sec-WebSocket-Key2: #{key2}"
|
28
|
+
sink.write_line ""
|
29
|
+
sink.write_line key3
|
30
|
+
sink.flush
|
31
|
+
|
32
|
+
while ( ! source.eof? )
|
33
|
+
line = source.getline
|
34
|
+
break if ( line.strip == '' )
|
35
|
+
end
|
36
|
+
|
37
|
+
challenge = source.getbytes( 16 )
|
38
|
+
source.getline
|
39
|
+
|
40
|
+
if ( challenge == solution )
|
41
|
+
#
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_keys()
|
46
|
+
key1 = generate_header_key
|
47
|
+
key2 = generate_header_key
|
48
|
+
key3 = generate_content_key
|
49
|
+
[ key1, key2, key3, solve( key1, key2, key3 ) ]
|
50
|
+
end
|
51
|
+
|
52
|
+
def solve(key1, key2, key3)
|
53
|
+
int1 = solve_header_key( key1 )
|
54
|
+
int2 = solve_header_key( key2 )
|
55
|
+
input = int1.to_s + int2.to_s + key3
|
56
|
+
Digest::MD5.digest( input ).bytes.to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
def solve_header_key(key)
|
60
|
+
key_digits = key.strip.gsub( /[^0-9]/, '').to_i
|
61
|
+
key_spaces = key.strip.gsub( /[^ ]/, '').size
|
62
|
+
solution = key_digits / key_spaces
|
63
|
+
solution
|
64
|
+
end
|
65
|
+
|
66
|
+
def generate_header_key
|
67
|
+
key = ''
|
68
|
+
1.upto(32) do
|
69
|
+
key << rand(90) + 32
|
70
|
+
end
|
71
|
+
1.upto( rand(10) + 2 ) do
|
72
|
+
key[rand(key.size-1)+1,1] = ' '
|
73
|
+
end
|
74
|
+
1.upto( rand(10) + 2 ) do
|
75
|
+
key[rand(key.size-1)+1,1] = rand(9).to_s
|
76
|
+
end
|
77
|
+
key
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_content_key
|
81
|
+
'tacobob1'
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: websocket-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- The TorqueBox Team
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-06-
|
18
|
+
date: 2011-06-12 00:00:00 Z
|
19
19
|
dependencies: []
|
20
20
|
|
21
21
|
description:
|
@@ -27,8 +27,11 @@ extensions: []
|
|
27
27
|
extra_rdoc_files: []
|
28
28
|
|
29
29
|
files:
|
30
|
+
- lib/websocket_client/byte_sink.rb
|
31
|
+
- lib/websocket_client/byte_source.rb
|
30
32
|
- lib/websocket_client/client.rb
|
31
|
-
- lib/websocket_client/
|
33
|
+
- lib/websocket_client/frame_io.rb
|
34
|
+
- lib/websocket_client/protocol/ietf_00.rb
|
32
35
|
- lib/websocket_client.rb
|
33
36
|
- examples/simple.rb
|
34
37
|
- examples/with_block.rb
|
@@ -1,123 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require 'uri'
|
3
|
-
require 'digest/md5'
|
4
|
-
|
5
|
-
module WebSocketClient
|
6
|
-
|
7
|
-
class Ietf00
|
8
|
-
|
9
|
-
def initialize(uri, socket)
|
10
|
-
puts "initialize for #{socket}"
|
11
|
-
@socket = socket
|
12
|
-
key1, key2, key3, solution = generate_keys()
|
13
|
-
|
14
|
-
puts "> sending prolog"
|
15
|
-
@socket.puts "GET #{uri.path} HTTP/1.1"
|
16
|
-
@socket.puts "Host: #{uri.host}"
|
17
|
-
@socket.puts "Connection: upgrade"
|
18
|
-
@socket.puts "Upgrade: websocket"
|
19
|
-
@socket.puts "Origin: http://#{uri.host}/"
|
20
|
-
@socket.puts "Sec-WebSocket-Version: 8"
|
21
|
-
@socket.puts "Sec-WebSocket-Key1: #{key1}"
|
22
|
-
@socket.puts "Sec-WebSocket-Key2: #{key2}"
|
23
|
-
@socket.puts ""
|
24
|
-
@socket.print key3
|
25
|
-
@socket.puts ""
|
26
|
-
@socket.flush
|
27
|
-
|
28
|
-
while ( ! @socket.eof? )
|
29
|
-
line = readline( socket )
|
30
|
-
puts ">> #{line}"
|
31
|
-
break if ( line.strip == '' )
|
32
|
-
end
|
33
|
-
|
34
|
-
begin
|
35
|
-
challenge = @socket.read( 16 )
|
36
|
-
puts "Challenge: #{challenge}"
|
37
|
-
readline( @socket )
|
38
|
-
puts "read"
|
39
|
-
rescue Exception=>e
|
40
|
-
puts e.message
|
41
|
-
puts e.backtrace
|
42
|
-
end
|
43
|
-
|
44
|
-
puts "> challenge-response #{challenge}"
|
45
|
-
if ( challenge == solution )
|
46
|
-
puts "success!"
|
47
|
-
end
|
48
|
-
#dump 'solution', solution
|
49
|
-
#dump 'challenge', challenge
|
50
|
-
end
|
51
|
-
|
52
|
-
def readline(socket)
|
53
|
-
line = ''
|
54
|
-
while ( ! socket.eof? )
|
55
|
-
if ( socket.respond_to? :getbyte )
|
56
|
-
c = socket.getbyte
|
57
|
-
else
|
58
|
-
c = socket.getc
|
59
|
-
end
|
60
|
-
puts "> #{c} #{c.class} #{c == '\n'}"
|
61
|
-
|
62
|
-
line << c
|
63
|
-
|
64
|
-
if ( c == 10 )
|
65
|
-
break
|
66
|
-
end
|
67
|
-
end
|
68
|
-
line
|
69
|
-
end
|
70
|
-
|
71
|
-
def encode_text_message(msg)
|
72
|
-
@socket.putc 0x00
|
73
|
-
@socket.print msg
|
74
|
-
@socket.putc 0xFF
|
75
|
-
@socket.flush
|
76
|
-
end
|
77
|
-
|
78
|
-
def generate_keys()
|
79
|
-
key1 = generate_header_key
|
80
|
-
key2 = generate_header_key
|
81
|
-
key3 = generate_content_key
|
82
|
-
[ key1, key2, key3, solve( key1, key2, key3 ) ]
|
83
|
-
end
|
84
|
-
|
85
|
-
def solve(key1, key2, key3)
|
86
|
-
int1 = solve_header_key( key1 )
|
87
|
-
int2 = solve_header_key( key2 )
|
88
|
-
input = int1.to_s + int2.to_s + key3
|
89
|
-
Digest::MD5.digest( input )
|
90
|
-
end
|
91
|
-
|
92
|
-
def solve_header_key(key)
|
93
|
-
key_digits = key.strip.gsub( /[^0-9]/, '').to_i
|
94
|
-
key_spaces = key.strip.gsub( /[^ ]/, '').size
|
95
|
-
solution = key_digits / key_spaces
|
96
|
-
solution
|
97
|
-
end
|
98
|
-
|
99
|
-
def generate_header_key
|
100
|
-
key = ''
|
101
|
-
1.upto(32) do
|
102
|
-
key << rand(90) + 32
|
103
|
-
end
|
104
|
-
1.upto( rand(10) + 2 ) do
|
105
|
-
key[rand(key.size-1)+1,1] = ' '
|
106
|
-
end
|
107
|
-
1.upto( rand(10) + 2 ) do
|
108
|
-
key[rand(key.size-1)+1,1] = rand(9).to_s
|
109
|
-
end
|
110
|
-
key
|
111
|
-
end
|
112
|
-
|
113
|
-
def generate_content_key
|
114
|
-
key = []
|
115
|
-
'tacobob1'.each_byte do |byte|
|
116
|
-
key << byte
|
117
|
-
end
|
118
|
-
key.pack('cccccccc')
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|