Skip to content

Commit 9ad9504

Browse files
committed
Add a Value::WebSocket class
1 parent d862526 commit 9ad9504

File tree

2 files changed

+636
-0
lines changed

2 files changed

+636
-0
lines changed

lib/ronin/recon/values/web_socket.rb

+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# frozen_string_literal: true
2+
#
3+
# ronin-recon - A micro-framework and tool for performing reconnaissance.
4+
#
5+
# Copyright (c) 2023-2024 Hal Brodigan ([email protected])
6+
#
7+
# ronin-recon is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU Lesser General Public License as published
9+
# by the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# ronin-recon is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU Lesser General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Lesser General Public License
18+
# along with ronin-recon. If not, see <https://www.gnu.org/licenses/>.
19+
#
20+
21+
require_relative '../value'
22+
23+
require 'uri'
24+
25+
module Ronin
26+
module Recon
27+
module Values
28+
#
29+
# Represents a WebSocket.
30+
#
31+
# @api public
32+
#
33+
# @since 0.2.0
34+
#
35+
class WebSocket < Value
36+
37+
# Indicates whether the WebSocket uses `ws://` or `wss://`.
38+
#
39+
# @return ['ws', 'wss']
40+
attr_reader :scheme
41+
42+
# The WebSocket's hostname.
43+
#
44+
# @return [String]
45+
attr_reader :host
46+
47+
# The WebSocket's port number.
48+
#
49+
# @return [Integer]
50+
attr_reader :port
51+
52+
# The WebSocket's path.
53+
#
54+
# @return [String]
55+
attr_reader :path
56+
57+
# The WebSocket's query
58+
#
59+
# @return [String]
60+
attr_reader :query
61+
62+
#
63+
# Initializes the WebSocket value.
64+
#
65+
# @param ['ws', 'wss'] scheme
66+
# Indicates whether the WebSocket uses `ws://` or `wss://`.
67+
#
68+
# @param [String] host
69+
# The WebSocket's host.
70+
#
71+
# @param [Integer] port
72+
# The WebSocket's port.
73+
#
74+
# @param [String] path
75+
# The WebSocket's path.
76+
#
77+
# @param [String] query
78+
# The WebSocket's query.
79+
#
80+
def initialize(scheme,host,port,path=nil,query=nil)
81+
@scheme = scheme
82+
@host = host
83+
@port = port
84+
@path = path
85+
@query = query
86+
end
87+
88+
#
89+
# Initializes the 'ws://' WebSocket.
90+
#
91+
# @param [String] host
92+
# The WebSocket's host.
93+
#
94+
# @param [Integer] port
95+
# The WebSocket's port.
96+
#
97+
# @param [String] path
98+
# The WebSocket's path.
99+
#
100+
# @param [String] query
101+
# The WebSocket's query.
102+
#
103+
def self.ws(host,port=80,path=nil,query=nil)
104+
new('ws',host,port,path,query)
105+
end
106+
107+
#
108+
# Initializes the 'wss://' WebSocket.
109+
#
110+
# @param [String] host
111+
# The WebSocket's host.
112+
#
113+
# @param [Integer] port
114+
# The WebSocket's port.
115+
#
116+
# @param [String] path
117+
# The WebSocket's path.
118+
#
119+
# @param [String] query
120+
# The WebSocket's query.
121+
#
122+
def self.wss(host,port=443,path=nil,query=nil)
123+
new('wss',host,port,path,query)
124+
end
125+
126+
#
127+
# Parses a URL.
128+
#
129+
# @param [String] url
130+
# The URL string to parse.
131+
#
132+
# @return [WebSocket]
133+
# The parsed WebSocket object.
134+
#
135+
def self.parse(url)
136+
uri = URI(url)
137+
138+
Values::WebSocket.new(uri.scheme,uri.host,uri.port,uri.path,uri.query)
139+
end
140+
141+
#
142+
# Compares the WebSocket to another value.
143+
#
144+
# @param [Value] other
145+
#
146+
# @return [Boolean]
147+
#
148+
def eql?(other)
149+
self.class == other.class &&
150+
@scheme == other.scheme &&
151+
@host == other.host &&
152+
@port == other.port &&
153+
@path == other.path &&
154+
@query == other.query
155+
end
156+
157+
#
158+
# Case equality method used for fuzzy matching.
159+
#
160+
# @param [Value] other
161+
# The other value to compare.
162+
#
163+
# @return [Boolean]
164+
# Imdicates whether the other value same as {WebSocket}
165+
#
166+
def ===(other)
167+
case other
168+
when WebSocket
169+
eql?(other)
170+
else
171+
false
172+
end
173+
end
174+
175+
#
176+
# The "hash" value of the WebSocket.
177+
#
178+
# @return [Integer]
179+
# The hash value of {#scheme}, {#host}, {#port}, {#path} and {#query}.
180+
#
181+
def hash
182+
[self.class, @scheme, @host, @port, @path, @query].hash
183+
end
184+
185+
# Mapping of {#scheme} values to URI classes.
186+
#
187+
# @api private
188+
URI_CLASSES = {
189+
'wss' => URI::WSS,
190+
'ws' => URI::WS
191+
}
192+
193+
#
194+
# Converts the WebSocket to URI.
195+
#
196+
# @return [URI::WS, URI::WSS]
197+
# The URI object for the website.
198+
#
199+
def to_uri
200+
URI_CLASSES.fetch(@scheme).build(host: @host, port: @port, path: @path, query: @query)
201+
end
202+
203+
#
204+
# Converts the WebSocket to a String.
205+
#
206+
# @return [String]
207+
# The base URL value for the WebSocket.
208+
#
209+
def to_s
210+
if ((@scheme == 'wss') && (@port != 443)) ||
211+
((@scheme == 'ws') && (@port != 80))
212+
"#{@scheme}://#{@host}:#{@port}#{@path}#{@query}"
213+
else
214+
"#{@scheme}://#{@host}#{@path}#{@query}"
215+
end
216+
end
217+
218+
#
219+
# Coerces the WebSocket value into JSON.
220+
#
221+
# @return [Hash{Symbol => Object}]
222+
# The Ruby Hash that will be converted into JSON.
223+
#
224+
def as_json
225+
{
226+
type: :web_socket,
227+
scheme: @scheme,
228+
host: @host,
229+
port: @port,
230+
path: @path,
231+
query: @query
232+
}
233+
end
234+
235+
#
236+
# Returns the type or kind of recon value.
237+
#
238+
# @return [:web_socket]
239+
#
240+
# @note
241+
# This is used internally to map a recon value class to a printable
242+
# type.
243+
#
244+
# @api private
245+
#
246+
def self.value_type
247+
:web_socket
248+
end
249+
end
250+
end
251+
end
252+
end

0 commit comments

Comments
 (0)