newrelic_security 0.1.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.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- data/.github/ISSUE_TEMPLATE/enhancement.md +27 -0
- data/.github/actions/simplecov-report/LICENSE +22 -0
- data/.github/actions/simplecov-report/README.md +36 -0
- data/.github/actions/simplecov-report/__tests__/.keep +0 -0
- data/.github/actions/simplecov-report/__tests__/main.test.ts +3 -0
- data/.github/actions/simplecov-report/action.yml +25 -0
- data/.github/actions/simplecov-report/dist/index.js +10238 -0
- data/.github/actions/simplecov-report/dummy_coverage/.last_run.json +5 -0
- data/.github/actions/simplecov-report/jest.config.js +11 -0
- data/.github/actions/simplecov-report/package.json +51 -0
- data/.github/actions/simplecov-report/src/main.ts +54 -0
- data/.github/actions/simplecov-report/src/report.ts +28 -0
- data/.github/actions/simplecov-report/tsconfig.json +12 -0
- data/.github/workflows/pr_ci.yml +77 -0
- data/.github/workflows/release.yml +51 -0
- data/.github/workflows/repolinter.yml +31 -0
- data/.github/workflows/rubocop.yml +17 -0
- data/.github/workflows/scripts/rubygems-authenticate.py +13 -0
- data/.github/workflows/scripts/rubygems-publish.rb +33 -0
- data/.gitignore +72 -0
- data/.rubocop.yml +9 -0
- data/.rubocop_todo.yml +1414 -0
- data/.simplecov +16 -0
- data/CHANGELOG.md +69 -0
- data/CONTRIBUTING.md +22 -0
- data/Gemfile +6 -0
- data/Gemfile_test +58 -0
- data/LICENSE +43 -0
- data/README.md +133 -0
- data/README_agent.md +44 -0
- data/Rakefile +28 -0
- data/THIRD_PARTY_NOTICES.md +36 -0
- data/lib/newrelic_security/agent/agent.rb +109 -0
- data/lib/newrelic_security/agent/configuration/default_source.rb +8 -0
- data/lib/newrelic_security/agent/configuration/environment_source.rb +8 -0
- data/lib/newrelic_security/agent/configuration/manager.rb +178 -0
- data/lib/newrelic_security/agent/configuration/manual_source.rb +8 -0
- data/lib/newrelic_security/agent/configuration/server_source.rb +8 -0
- data/lib/newrelic_security/agent/configuration/yaml_source.rb +8 -0
- data/lib/newrelic_security/agent/control/app_info.rb +132 -0
- data/lib/newrelic_security/agent/control/application_url_mappings.rb +66 -0
- data/lib/newrelic_security/agent/control/collector.rb +117 -0
- data/lib/newrelic_security/agent/control/control_command.rb +117 -0
- data/lib/newrelic_security/agent/control/critical_message.rb +58 -0
- data/lib/newrelic_security/agent/control/event.rb +149 -0
- data/lib/newrelic_security/agent/control/event_counter.rb +28 -0
- data/lib/newrelic_security/agent/control/event_processor.rb +134 -0
- data/lib/newrelic_security/agent/control/event_stats.rb +26 -0
- data/lib/newrelic_security/agent/control/event_subscriber.rb +28 -0
- data/lib/newrelic_security/agent/control/exit_event.rb +38 -0
- data/lib/newrelic_security/agent/control/fuzz_request.rb +18 -0
- data/lib/newrelic_security/agent/control/grpc_context.rb +57 -0
- data/lib/newrelic_security/agent/control/health_check.rb +136 -0
- data/lib/newrelic_security/agent/control/http_context.rb +73 -0
- data/lib/newrelic_security/agent/control/iast_client.rb +151 -0
- data/lib/newrelic_security/agent/control/iast_data_transfer_request.rb +32 -0
- data/lib/newrelic_security/agent/control/reflected_xss.rb +258 -0
- data/lib/newrelic_security/agent/control/websocket_client.rb +131 -0
- data/lib/newrelic_security/agent/logging/init_logger.rb +91 -0
- data/lib/newrelic_security/agent/logging/logger.rb +92 -0
- data/lib/newrelic_security/agent/logging/null_logger.rb +21 -0
- data/lib/newrelic_security/agent/resources/cert.pem +50 -0
- data/lib/newrelic_security/agent/utils/agent_utils.rb +219 -0
- data/lib/newrelic_security/agent.rb +57 -0
- data/lib/newrelic_security/constants.rb +67 -0
- data/lib/newrelic_security/instrumentation-security/active_record/mysql2_adapter/chain.rb +70 -0
- data/lib/newrelic_security/instrumentation-security/active_record/mysql2_adapter/instrumentation.rb +187 -0
- data/lib/newrelic_security/instrumentation-security/active_record/mysql2_adapter/prepend.rb +54 -0
- data/lib/newrelic_security/instrumentation-security/active_record/postgresql_adapter/chain.rb +60 -0
- data/lib/newrelic_security/instrumentation-security/active_record/postgresql_adapter/instrumentation.rb +143 -0
- data/lib/newrelic_security/instrumentation-security/active_record/postgresql_adapter/prepend.rb +48 -0
- data/lib/newrelic_security/instrumentation-security/active_record/sqlite3_adapter/chain.rb +72 -0
- data/lib/newrelic_security/instrumentation-security/active_record/sqlite3_adapter/instrumentation.rb +187 -0
- data/lib/newrelic_security/instrumentation-security/active_record/sqlite3_adapter/prepend.rb +54 -0
- data/lib/newrelic_security/instrumentation-security/async-http/chain.rb +21 -0
- data/lib/newrelic_security/instrumentation-security/async-http/instrumentation.rb +46 -0
- data/lib/newrelic_security/instrumentation-security/async-http/prepend.rb +16 -0
- data/lib/newrelic_security/instrumentation-security/curb/chain.rb +26 -0
- data/lib/newrelic_security/instrumentation-security/curb/instrumentation.rb +52 -0
- data/lib/newrelic_security/instrumentation-security/curb/prepend.rb +18 -0
- data/lib/newrelic_security/instrumentation-security/dir/chain.rb +42 -0
- data/lib/newrelic_security/instrumentation-security/dir/instrumentation.rb +102 -0
- data/lib/newrelic_security/instrumentation-security/dir/prepend.rb +28 -0
- data/lib/newrelic_security/instrumentation-security/ethon/chain.rb +53 -0
- data/lib/newrelic_security/instrumentation-security/ethon/instrumentation.rb +122 -0
- data/lib/newrelic_security/instrumentation-security/ethon/prepend.rb +39 -0
- data/lib/newrelic_security/instrumentation-security/excon/chain.rb +23 -0
- data/lib/newrelic_security/instrumentation-security/excon/instrumentation.rb +44 -0
- data/lib/newrelic_security/instrumentation-security/excon/prepend.rb +17 -0
- data/lib/newrelic_security/instrumentation-security/file/chain.rb +34 -0
- data/lib/newrelic_security/instrumentation-security/file/instrumentation.rb +62 -0
- data/lib/newrelic_security/instrumentation-security/file/prepend.rb +22 -0
- data/lib/newrelic_security/instrumentation-security/grape/chain.rb +42 -0
- data/lib/newrelic_security/instrumentation-security/grape/instrumentation.rb +56 -0
- data/lib/newrelic_security/instrumentation-security/grape/prepend.rb +30 -0
- data/lib/newrelic_security/instrumentation-security/grpc/client/chain.rb +47 -0
- data/lib/newrelic_security/instrumentation-security/grpc/client/instrumentation.rb +37 -0
- data/lib/newrelic_security/instrumentation-security/grpc/client/prepend.rb +36 -0
- data/lib/newrelic_security/instrumentation-security/grpc/server/chain.rb +62 -0
- data/lib/newrelic_security/instrumentation-security/grpc/server/instrumentation.rb +65 -0
- data/lib/newrelic_security/instrumentation-security/grpc/server/prepend.rb +46 -0
- data/lib/newrelic_security/instrumentation-security/httpclient/chain.rb +30 -0
- data/lib/newrelic_security/instrumentation-security/httpclient/instrumentation.rb +82 -0
- data/lib/newrelic_security/instrumentation-security/httpclient/prepend.rb +22 -0
- data/lib/newrelic_security/instrumentation-security/httprb/chain.rb +21 -0
- data/lib/newrelic_security/instrumentation-security/httprb/instrumentation.rb +44 -0
- data/lib/newrelic_security/instrumentation-security/httprb/prepend.rb +16 -0
- data/lib/newrelic_security/instrumentation-security/httpx/chain.rb +23 -0
- data/lib/newrelic_security/instrumentation-security/httpx/instrumentation.rb +51 -0
- data/lib/newrelic_security/instrumentation-security/httpx/prepend.rb +18 -0
- data/lib/newrelic_security/instrumentation-security/instrumentation_loader.rb +50 -0
- data/lib/newrelic_security/instrumentation-security/instrumentation_utils.rb +165 -0
- data/lib/newrelic_security/instrumentation-security/io/chain.rb +113 -0
- data/lib/newrelic_security/instrumentation-security/io/instrumentation.rb +300 -0
- data/lib/newrelic_security/instrumentation-security/io/prepend.rb +86 -0
- data/lib/newrelic_security/instrumentation-security/kernel/chain.rb +65 -0
- data/lib/newrelic_security/instrumentation-security/kernel/instrumentation.rb +167 -0
- data/lib/newrelic_security/instrumentation-security/kernel/prepend.rb +50 -0
- data/lib/newrelic_security/instrumentation-security/mongo/chain.rb +106 -0
- data/lib/newrelic_security/instrumentation-security/mongo/instrumentation.rb +273 -0
- data/lib/newrelic_security/instrumentation-security/mongo/prepend.rb +77 -0
- data/lib/newrelic_security/instrumentation-security/mysql2/chain.rb +53 -0
- data/lib/newrelic_security/instrumentation-security/mysql2/instrumentation.rb +84 -0
- data/lib/newrelic_security/instrumentation-security/mysql2/prepend.rb +37 -0
- data/lib/newrelic_security/instrumentation-security/net_http/chain.rb +21 -0
- data/lib/newrelic_security/instrumentation-security/net_http/instrumentation.rb +60 -0
- data/lib/newrelic_security/instrumentation-security/net_http/prepend.rb +16 -0
- data/lib/newrelic_security/instrumentation-security/net_ldap/chain.rb +21 -0
- data/lib/newrelic_security/instrumentation-security/net_ldap/instrumentation.rb +42 -0
- data/lib/newrelic_security/instrumentation-security/net_ldap/prepend.rb +16 -0
- data/lib/newrelic_security/instrumentation-security/nokogiri/chain.rb +46 -0
- data/lib/newrelic_security/instrumentation-security/nokogiri/instrumentation.rb +36 -0
- data/lib/newrelic_security/instrumentation-security/nokogiri/prepend.rb +31 -0
- data/lib/newrelic_security/instrumentation-security/padrino/chain.rb +26 -0
- data/lib/newrelic_security/instrumentation-security/padrino/instrumentation.rb +42 -0
- data/lib/newrelic_security/instrumentation-security/padrino/prepend.rb +20 -0
- data/lib/newrelic_security/instrumentation-security/patron/chain.rb +23 -0
- data/lib/newrelic_security/instrumentation-security/patron/instrumentation.rb +50 -0
- data/lib/newrelic_security/instrumentation-security/patron/prepend.rb +18 -0
- data/lib/newrelic_security/instrumentation-security/pg/chain.rb +49 -0
- data/lib/newrelic_security/instrumentation-security/pg/instrumentation.rb +102 -0
- data/lib/newrelic_security/instrumentation-security/pg/prepend.rb +36 -0
- data/lib/newrelic_security/instrumentation-security/pty/chain.rb +31 -0
- data/lib/newrelic_security/instrumentation-security/pty/instrumentation.rb +52 -0
- data/lib/newrelic_security/instrumentation-security/pty/prepend.rb +22 -0
- data/lib/newrelic_security/instrumentation-security/rails/chain.rb +46 -0
- data/lib/newrelic_security/instrumentation-security/rails/instrumentation.rb +67 -0
- data/lib/newrelic_security/instrumentation-security/rails/prepend.rb +33 -0
- data/lib/newrelic_security/instrumentation-security/roda/chain.rb +22 -0
- data/lib/newrelic_security/instrumentation-security/roda/instrumentation.rb +41 -0
- data/lib/newrelic_security/instrumentation-security/roda/prepend.rb +16 -0
- data/lib/newrelic_security/instrumentation-security/sinatra/chain.rb +29 -0
- data/lib/newrelic_security/instrumentation-security/sinatra/instrumentation.rb +49 -0
- data/lib/newrelic_security/instrumentation-security/sinatra/prepend.rb +21 -0
- data/lib/newrelic_security/instrumentation-security/sqlite3/chain.rb +79 -0
- data/lib/newrelic_security/instrumentation-security/sqlite3/instrumentation.rb +164 -0
- data/lib/newrelic_security/instrumentation-security/sqlite3/prepend.rb +56 -0
- data/lib/newrelic_security/newrelic-security-api/api.rb +72 -0
- data/lib/newrelic_security/version.rb +5 -0
- data/lib/newrelic_security/websocket-client-simple/client.rb +128 -0
- data/lib/newrelic_security/websocket-client-simple/event_emitter.rb +72 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/error.rb +129 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/exception_handler.rb +32 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/base.rb +62 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/data.rb +49 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/base.rb +41 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler03.rb +224 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler04.rb +18 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler05.rb +15 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler07.rb +78 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler75.rb +78 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler.rb +15 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/incoming/client.rb +17 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/incoming/server.rb +17 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/incoming.rb +52 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/outgoing/client.rb +17 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/outgoing/server.rb +17 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/outgoing.rb +35 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame.rb +11 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/base.rb +142 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/client.rb +130 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/base.rb +49 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client.rb +32 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client01.rb +20 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client04.rb +63 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client11.rb +22 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client75.rb +39 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client76.rb +105 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server.rb +10 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server04.rb +56 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server75.rb +40 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server76.rb +75 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler.rb +21 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/server.rb +179 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake.rb +10 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/nice_inspect.rb +12 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/version.rb +5 -0
- data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket.rb +50 -0
- data/lib/newrelic_security.rb +6 -0
- data/lib/tasks/all.rb +8 -0
- data/lib/tasks/coverage_report.rake +27 -0
- data/newrelic_security.gemspec +51 -0
- metadata +342 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NewRelic::Security::WebSocket
|
|
4
|
+
class Error < RuntimeError
|
|
5
|
+
class Frame < NewRelic::Security::WebSocket::Error
|
|
6
|
+
class ControlFramePayloadTooLong < NewRelic::Security::WebSocket::Error::Frame
|
|
7
|
+
def message
|
|
8
|
+
:control_frame_payload_too_long
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class DataFrameInsteadContinuation < NewRelic::Security::WebSocket::Error::Frame
|
|
13
|
+
def message
|
|
14
|
+
:data_frame_instead_continuation
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class FragmentedControlFrame < NewRelic::Security::WebSocket::Error::Frame
|
|
19
|
+
def message
|
|
20
|
+
:fragmented_control_frame
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Invalid < NewRelic::Security::WebSocket::Error::Frame
|
|
25
|
+
def message
|
|
26
|
+
:invalid_frame
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class InvalidPayloadEncoding < NewRelic::Security::WebSocket::Error::Frame
|
|
31
|
+
def message
|
|
32
|
+
:invalid_payload_encoding
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class MaskTooShort < NewRelic::Security::WebSocket::Error::Frame
|
|
37
|
+
def message
|
|
38
|
+
:mask_is_too_short
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class ReservedBitUsed < NewRelic::Security::WebSocket::Error::Frame
|
|
43
|
+
def message
|
|
44
|
+
:reserved_bit_used
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class TooLong < NewRelic::Security::WebSocket::Error::Frame
|
|
49
|
+
def message
|
|
50
|
+
:frame_too_long
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class UnexpectedContinuationFrame < NewRelic::Security::WebSocket::Error::Frame
|
|
55
|
+
def message
|
|
56
|
+
:unexpected_continuation_frame
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class UnknownFrameType < NewRelic::Security::WebSocket::Error::Frame
|
|
61
|
+
def message
|
|
62
|
+
:unknown_frame_type
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
class UnknownOpcode < NewRelic::Security::WebSocket::Error::Frame
|
|
67
|
+
def message
|
|
68
|
+
:unknown_opcode
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class UnknownCloseCode < NewRelic::Security::WebSocket::Error::Frame
|
|
73
|
+
def message
|
|
74
|
+
:unknown_close_code
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class UnknownVersion < NewRelic::Security::WebSocket::Error::Frame
|
|
79
|
+
def message
|
|
80
|
+
:unknown_protocol_version
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Handshake < NewRelic::Security::WebSocket::Error
|
|
86
|
+
class GetRequestRequired < NewRelic::Security::WebSocket::Error::Handshake
|
|
87
|
+
def message
|
|
88
|
+
:get_request_required
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class InvalidAuthentication < NewRelic::Security::WebSocket::Error::Handshake
|
|
93
|
+
def message
|
|
94
|
+
:invalid_handshake_authentication
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class InvalidHeader < NewRelic::Security::WebSocket::Error::Handshake
|
|
99
|
+
def message
|
|
100
|
+
:invalid_header
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class UnsupportedProtocol < NewRelic::Security::WebSocket::Error::Handshake
|
|
105
|
+
def message
|
|
106
|
+
:unsupported_protocol
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
class InvalidStatusCode < NewRelic::Security::WebSocket::Error::Handshake
|
|
111
|
+
def message
|
|
112
|
+
:invalid_status_code
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class NoHostProvided < NewRelic::Security::WebSocket::Error::Handshake
|
|
117
|
+
def message
|
|
118
|
+
:no_host_provided
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
class UnknownVersion < NewRelic::Security::WebSocket::Error::Handshake
|
|
123
|
+
def message
|
|
124
|
+
:unknown_protocol_version
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/exception_handler.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NewRelic::Security::WebSocket
|
|
4
|
+
module ExceptionHandler
|
|
5
|
+
attr_accessor :error
|
|
6
|
+
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.extend(ClassMethods)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
# Rescue from NewRelic::Security::WebSocket::Error errors.
|
|
13
|
+
#
|
|
14
|
+
# @param [String] method_name Name of method that should be wrapped and rescued
|
|
15
|
+
# @param [Hash] options Options for rescue
|
|
16
|
+
#
|
|
17
|
+
# @option options [Any] :return Value that should be returned instead of raised error
|
|
18
|
+
def rescue_method(method_name, options = {})
|
|
19
|
+
define_method "#{method_name}_with_rescue" do |*args|
|
|
20
|
+
begin
|
|
21
|
+
send("#{method_name}_without_rescue", *args)
|
|
22
|
+
rescue NewRelic::Security::WebSocket::Error => e
|
|
23
|
+
self.error = e.message.to_sym
|
|
24
|
+
NewRelic::Security::WebSocket.should_raise ? raise : options[:return]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
alias_method "#{method_name}_without_rescue", method_name
|
|
28
|
+
alias_method method_name, "#{method_name}_with_rescue"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NewRelic::Security::WebSocket
|
|
4
|
+
module Frame
|
|
5
|
+
# @abstract Subclass and override to implement custom frames
|
|
6
|
+
class Base
|
|
7
|
+
include ExceptionHandler
|
|
8
|
+
include NiceInspect
|
|
9
|
+
|
|
10
|
+
attr_reader :type, :version, :error
|
|
11
|
+
attr_accessor :data, :code
|
|
12
|
+
|
|
13
|
+
# Initialize frame
|
|
14
|
+
# @param args [Hash] Arguments for frame
|
|
15
|
+
# @option args [String] :data default data for frame
|
|
16
|
+
# @option args [String] :type Type of frame - available types are "text", "binary", "ping", "pong" and "close"(support depends on draft version)
|
|
17
|
+
# @option args [Integer] :code Code for close frame. Supported by drafts > 05.
|
|
18
|
+
# @option args [Integer] :version Version of draft. Currently supported version are 75, 76 and 00-13.
|
|
19
|
+
def initialize(args = {})
|
|
20
|
+
@type = args[:type].to_sym if args[:type]
|
|
21
|
+
@code = args[:code]
|
|
22
|
+
@data = Data.new(args[:data].to_s)
|
|
23
|
+
@version = args[:version] || DEFAULT_VERSION
|
|
24
|
+
@handler = nil
|
|
25
|
+
include_version
|
|
26
|
+
end
|
|
27
|
+
rescue_method :initialize
|
|
28
|
+
|
|
29
|
+
# Check if some errors occured
|
|
30
|
+
# @return [Boolean] True if error is set
|
|
31
|
+
def error?
|
|
32
|
+
!@error.nil?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Is selected type supported for selected handler?
|
|
36
|
+
def support_type?
|
|
37
|
+
@handler.supported_frames.include?(@type)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Implement in submodules
|
|
41
|
+
def supported_frames
|
|
42
|
+
raise NotImplementedError
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# Include set of methods for selected protocol version
|
|
48
|
+
# @return [Boolean] false if protocol number is unknown, otherwise true
|
|
49
|
+
def include_version
|
|
50
|
+
@handler = case @version
|
|
51
|
+
when 75..76 then Handler::Handler75.new(self)
|
|
52
|
+
when 0..2 then Handler::Handler75.new(self)
|
|
53
|
+
when 3 then Handler::Handler03.new(self)
|
|
54
|
+
when 4 then Handler::Handler04.new(self)
|
|
55
|
+
when 5..6 then Handler::Handler05.new(self)
|
|
56
|
+
when 7..13 then Handler::Handler07.new(self)
|
|
57
|
+
else raise NewRelic::Security::WebSocket::Error::Frame::UnknownVersion
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NewRelic::Security::WebSocket
|
|
4
|
+
module Frame
|
|
5
|
+
class Data < String
|
|
6
|
+
def initialize(*args)
|
|
7
|
+
super(*convert_args(args))
|
|
8
|
+
@masking_key = nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def <<(*args)
|
|
12
|
+
super(*convert_args(args))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Convert all arguments to ASCII-8BIT for easier traversing
|
|
16
|
+
def convert_args(args)
|
|
17
|
+
args.collect { |arg| arg.dup.force_encoding('ASCII-8BIT') }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Extract mask from 4 first bytes according to spec
|
|
21
|
+
def set_mask
|
|
22
|
+
raise NewRelic::Security::WebSocket::Error::Frame::MaskTooShort if bytesize < 4
|
|
23
|
+
@masking_key = self[0..3].bytes.to_a
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Remove mask flag - it will still be present in payload
|
|
27
|
+
def unset_mask
|
|
28
|
+
@masking_key = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Extract `count` bytes starting from `start_index` and unmask it if needed.
|
|
32
|
+
def getbytes(start_index, count)
|
|
33
|
+
data = self[start_index, count]
|
|
34
|
+
data = mask(data.bytes.to_a, @masking_key).pack('C*') if @masking_key
|
|
35
|
+
data
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Mask whole payload using mask key
|
|
39
|
+
def mask(payload, mask)
|
|
40
|
+
return mask_native(payload, mask) if respond_to?(:mask_native)
|
|
41
|
+
result = []
|
|
42
|
+
payload.each_with_index do |byte, i|
|
|
43
|
+
result[i] = byte ^ mask[i % 4]
|
|
44
|
+
end
|
|
45
|
+
result
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NewRelic::Security::WebSocket
|
|
4
|
+
module Frame
|
|
5
|
+
module Handler
|
|
6
|
+
class Base
|
|
7
|
+
def initialize(frame)
|
|
8
|
+
@frame = frame
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Convert data to raw frame ready to send to client
|
|
12
|
+
# @return [String] Encoded frame
|
|
13
|
+
def encode_frame
|
|
14
|
+
raise NotImplementedError
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Convert raw data to decoded frame
|
|
18
|
+
# @return [NewRelic::Security::WebSocket::Frame::Incoming] Frame if found, nil otherwise
|
|
19
|
+
def decode_frame
|
|
20
|
+
raise NotImplementedError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# Check if frame is one of control frames
|
|
26
|
+
# @param [Symbol] frame_type Frame type
|
|
27
|
+
# @return [Boolean] True if given frame type is control frame
|
|
28
|
+
def control_frame?(frame_type)
|
|
29
|
+
!%i[text binary continuation].include?(frame_type)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Check if frame is one of data frames
|
|
33
|
+
# @param [Symbol] frame_type Frame type
|
|
34
|
+
# @return [Boolean] True if given frame type is data frame
|
|
35
|
+
def data_frame?(frame_type)
|
|
36
|
+
%i[text binary].include?(frame_type)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'securerandom'
|
|
5
|
+
|
|
6
|
+
module NewRelic::Security::WebSocket
|
|
7
|
+
module Frame
|
|
8
|
+
module Handler
|
|
9
|
+
class Handler03 < Base
|
|
10
|
+
# Hash of frame names and it's opcodes
|
|
11
|
+
FRAME_TYPES = {
|
|
12
|
+
continuation: 0,
|
|
13
|
+
close: 1,
|
|
14
|
+
ping: 2,
|
|
15
|
+
pong: 3,
|
|
16
|
+
text: 4,
|
|
17
|
+
binary: 5
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
# Hash of frame opcodes and it's names
|
|
21
|
+
FRAME_TYPES_INVERSE = FRAME_TYPES.invert.freeze
|
|
22
|
+
|
|
23
|
+
def initialize(frame)
|
|
24
|
+
super
|
|
25
|
+
@application_data_buffer = nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @see NewRelic::Security::WebSocket::Frame::Base#supported_frames
|
|
29
|
+
def supported_frames
|
|
30
|
+
%i[text binary close ping pong]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @see NewRelic::Security::WebSocket::Frame::Handler::Base#encode_frame
|
|
34
|
+
def encode_frame
|
|
35
|
+
frame = if @frame.outgoing_masking?
|
|
36
|
+
masking_key = SecureRandom.random_bytes(4)
|
|
37
|
+
tmp_data = Data.new(masking_key + @frame.data)
|
|
38
|
+
tmp_data.set_mask
|
|
39
|
+
masking_key + tmp_data.getbytes(4, tmp_data.size)
|
|
40
|
+
else
|
|
41
|
+
@frame.data
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
encode_header + frame
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @see NewRelic::Security::WebSocket::Frame::Handler::Base#decode_frame
|
|
48
|
+
def decode_frame
|
|
49
|
+
while @frame.data.size > 1
|
|
50
|
+
valid_header, more, frame_type, mask, payload_length = decode_header
|
|
51
|
+
return unless valid_header
|
|
52
|
+
|
|
53
|
+
application_data = decode_payload(payload_length, mask)
|
|
54
|
+
|
|
55
|
+
if more
|
|
56
|
+
decode_continuation_frame(application_data, frame_type)
|
|
57
|
+
elsif frame_type == :continuation
|
|
58
|
+
return decode_finish_continuation_frame(application_data)
|
|
59
|
+
else
|
|
60
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::InvalidPayloadEncoding) if frame_type == :text && !application_data.valid_encoding?
|
|
61
|
+
return @frame.class.new(version: @frame.version, type: frame_type, data: application_data, decoded: true)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Allow turning on or off masking
|
|
68
|
+
def masking?
|
|
69
|
+
false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# This allows flipping the more bit to fin for draft 04
|
|
75
|
+
def fin
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Convert frame type name to opcode
|
|
80
|
+
# @param [Symbol] frame_type Frame type name
|
|
81
|
+
# @return [Integer] opcode or nil
|
|
82
|
+
# @raise [NewRelic::Security::WebSocket::Error] if frame opcode is not known
|
|
83
|
+
def type_to_opcode(frame_type)
|
|
84
|
+
FRAME_TYPES[frame_type] || raise(NewRelic::Security::WebSocket::Error::Frame::UnknownFrameType)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Convert frame opcode to type name
|
|
88
|
+
# @param [Integer] opcode Opcode
|
|
89
|
+
# @return [Symbol] Frame type name or nil
|
|
90
|
+
# @raise [NewRelic::Security::WebSocket::Error] if frame type name is not known
|
|
91
|
+
def opcode_to_type(opcode)
|
|
92
|
+
FRAME_TYPES_INVERSE[opcode] || raise(NewRelic::Security::WebSocket::Error::Frame::UnknownOpcode)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def encode_header
|
|
96
|
+
mask = @frame.outgoing_masking? ? 0b10000000 : 0b00000000
|
|
97
|
+
|
|
98
|
+
output = String.new('')
|
|
99
|
+
output << (type_to_opcode(@frame.type) | (fin ? 0b10000000 : 0b00000000)) # since more, rsv1-3 are 0 and 0x80 for Draft 4
|
|
100
|
+
output << encode_payload_length(@frame.data.size, mask)
|
|
101
|
+
output
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def encode_payload_length(length, mask)
|
|
105
|
+
output = String.new('')
|
|
106
|
+
if length <= 125
|
|
107
|
+
output << (length | mask) # since rsv4 is 0
|
|
108
|
+
elsif length < 65_536 # write 2 byte length
|
|
109
|
+
output << (126 | mask)
|
|
110
|
+
output << [length].pack('n')
|
|
111
|
+
else # write 8 byte length
|
|
112
|
+
output << (127 | mask)
|
|
113
|
+
output << [length >> 32, length & 0xFFFFFFFF].pack('NN')
|
|
114
|
+
end
|
|
115
|
+
output
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def decode_header
|
|
119
|
+
more, frame_type = decode_first_byte
|
|
120
|
+
header_length, payload_length, mask = decode_second_byte(frame_type)
|
|
121
|
+
return unless header_length
|
|
122
|
+
|
|
123
|
+
# Compute the expected frame length
|
|
124
|
+
frame_length = header_length + payload_length
|
|
125
|
+
frame_length += 4 if mask
|
|
126
|
+
|
|
127
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::TooLong) if frame_length > NewRelic::Security::WebSocket.max_frame_size
|
|
128
|
+
|
|
129
|
+
# Check buffer size
|
|
130
|
+
return unless buffer_exists?(frame_length) # Buffer incomplete
|
|
131
|
+
|
|
132
|
+
# Remove frame header
|
|
133
|
+
@frame.data.slice!(0...header_length)
|
|
134
|
+
|
|
135
|
+
[true, more, frame_type, mask, payload_length]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def buffer_exists?(buffer_number)
|
|
139
|
+
!@frame.data.getbyte(buffer_number - 1).nil?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def decode_first_byte
|
|
143
|
+
first_byte = @frame.data.getbyte(0)
|
|
144
|
+
|
|
145
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::ReservedBitUsed) if first_byte & 0b01110000 != 0b00000000
|
|
146
|
+
|
|
147
|
+
more = ((first_byte & 0b10000000) == 0b10000000) ^ fin
|
|
148
|
+
frame_type = opcode_to_type first_byte & 0b00001111
|
|
149
|
+
|
|
150
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::FragmentedControlFrame) if more && control_frame?(frame_type)
|
|
151
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::DataFrameInsteadContinuation) if data_frame?(frame_type) && !@application_data_buffer.nil?
|
|
152
|
+
|
|
153
|
+
[more, frame_type]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def decode_second_byte(frame_type)
|
|
157
|
+
second_byte = @frame.data.getbyte(1)
|
|
158
|
+
|
|
159
|
+
mask = @frame.incoming_masking? && (second_byte & 0b10000000) == 0b10000000
|
|
160
|
+
length = second_byte & 0b01111111
|
|
161
|
+
|
|
162
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::ControlFramePayloadTooLong) if length > 125 && control_frame?(frame_type)
|
|
163
|
+
|
|
164
|
+
header_length, payload_length = decode_payload_length(length)
|
|
165
|
+
|
|
166
|
+
[header_length, payload_length, mask]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def decode_payload_length(length)
|
|
170
|
+
case length
|
|
171
|
+
when 127 # Length defined by 8 bytes
|
|
172
|
+
# Check buffer size
|
|
173
|
+
return unless buffer_exists?(10) # Buffer incomplete
|
|
174
|
+
|
|
175
|
+
# Only using the last 4 bytes for now, till I work out how to
|
|
176
|
+
# unpack 8 bytes. I'm sure 4GB frames will do for now :)
|
|
177
|
+
[10, @frame.data.getbytes(6, 4).unpack('N').first]
|
|
178
|
+
when 126 # Length defined by 2 bytes
|
|
179
|
+
# Check buffer size
|
|
180
|
+
return unless buffer_exists?(4) # Buffer incomplete
|
|
181
|
+
|
|
182
|
+
[4, @frame.data.getbytes(2, 2).unpack('n').first]
|
|
183
|
+
else
|
|
184
|
+
[2, length]
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def decode_payload(payload_length, mask)
|
|
189
|
+
pointer = 0
|
|
190
|
+
|
|
191
|
+
# Read application data (unmasked if required)
|
|
192
|
+
@frame.data.set_mask if mask
|
|
193
|
+
pointer += 4 if mask
|
|
194
|
+
payload = @frame.data.getbytes(pointer, payload_length)
|
|
195
|
+
payload.force_encoding('UTF-8')
|
|
196
|
+
pointer += payload_length
|
|
197
|
+
@frame.data.unset_mask if mask
|
|
198
|
+
|
|
199
|
+
# Throw away data up to pointer
|
|
200
|
+
@frame.data.slice!(0...pointer)
|
|
201
|
+
|
|
202
|
+
payload
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def decode_continuation_frame(application_data, frame_type)
|
|
206
|
+
@application_data_buffer ||= String.new('')
|
|
207
|
+
@application_data_buffer << application_data
|
|
208
|
+
@frame_type ||= frame_type
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def decode_finish_continuation_frame(application_data)
|
|
212
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::UnexpectedContinuationFrame) unless @frame_type
|
|
213
|
+
@application_data_buffer << application_data
|
|
214
|
+
# Test valid UTF-8 encoding
|
|
215
|
+
raise(NewRelic::Security::WebSocket::Error::Frame::InvalidPayloadEncoding) if @frame_type == :text && !@application_data_buffer.valid_encoding?
|
|
216
|
+
message = @frame.class.new(version: @frame.version, type: @frame_type, data: @application_data_buffer, decoded: true)
|
|
217
|
+
@application_data_buffer = nil
|
|
218
|
+
@frame_type = nil
|
|
219
|
+
message
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NewRelic::Security::WebSocket
|
|
5
|
+
module Frame
|
|
6
|
+
module Handler
|
|
7
|
+
class Handler04 < Handler03
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# The only difference between draft 03 framing and draft 04 framing is
|
|
11
|
+
# that the MORE bit has been changed to a FIN bit
|
|
12
|
+
def fin
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NewRelic::Security::WebSocket
|
|
5
|
+
module Frame
|
|
6
|
+
module Handler
|
|
7
|
+
class Handler05 < Handler04
|
|
8
|
+
# Since handler 5 masking should be enabled by default
|
|
9
|
+
def masking?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NewRelic::Security::WebSocket
|
|
5
|
+
module Frame
|
|
6
|
+
module Handler
|
|
7
|
+
class Handler07 < Handler05
|
|
8
|
+
# Hash of frame names and it's opcodes
|
|
9
|
+
FRAME_TYPES = {
|
|
10
|
+
continuation: 0,
|
|
11
|
+
text: 1,
|
|
12
|
+
binary: 2,
|
|
13
|
+
close: 8,
|
|
14
|
+
ping: 9,
|
|
15
|
+
pong: 10
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
# Hash of frame opcodes and it's names
|
|
19
|
+
FRAME_TYPES_INVERSE = FRAME_TYPES.invert.freeze
|
|
20
|
+
|
|
21
|
+
def encode_frame
|
|
22
|
+
if @frame.type == :close
|
|
23
|
+
code = @frame.code || 1000
|
|
24
|
+
raise NewRelic::Security::WebSocket::Error::Frame::UnknownCloseCode unless valid_code?(code)
|
|
25
|
+
@frame.data = Data.new([code].pack('n') + @frame.data.to_s)
|
|
26
|
+
@frame.code = nil
|
|
27
|
+
end
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def decode_frame
|
|
32
|
+
result = super
|
|
33
|
+
if close_code?(result)
|
|
34
|
+
code = result.data.slice!(0..1)
|
|
35
|
+
result.code = code.unpack('n').first
|
|
36
|
+
raise NewRelic::Security::WebSocket::Error::Frame::UnknownCloseCode unless valid_code?(result.code)
|
|
37
|
+
raise NewRelic::Security::WebSocket::Error::Frame::InvalidPayloadEncoding unless valid_encoding?(result.data)
|
|
38
|
+
end
|
|
39
|
+
result
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def valid_code?(code)
|
|
45
|
+
[1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011].include?(code) || (3000..4999).cover?(code)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def valid_encoding?(data)
|
|
49
|
+
return true if data.nil?
|
|
50
|
+
data.encode('UTF-8')
|
|
51
|
+
true
|
|
52
|
+
rescue StandardError
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def close_code?(frame)
|
|
57
|
+
frame && frame.type == :close && !frame.data.empty?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Convert frame type name to opcode
|
|
61
|
+
# @param [Symbol] frame_type Frame type name
|
|
62
|
+
# @return [Integer] opcode or nil
|
|
63
|
+
# @raise [NewRelic::Security::WebSocket::Error] if frame opcode is not known
|
|
64
|
+
def type_to_opcode(frame_type)
|
|
65
|
+
FRAME_TYPES[frame_type] || raise(NewRelic::Security::WebSocket::Error::Frame::UnknownFrameType)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Convert frame opcode to type name
|
|
69
|
+
# @param [Integer] opcode Opcode
|
|
70
|
+
# @return [Symbol] Frame type name or nil
|
|
71
|
+
# @raise [NewRelic::Security::WebSocket::Error] if frame type name is not known
|
|
72
|
+
def opcode_to_type(opcode)
|
|
73
|
+
FRAME_TYPES_INVERSE[opcode] || raise(NewRelic::Security::WebSocket::Error::Frame::UnknownOpcode)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|