contrast-agent 6.1.2 → 6.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (220) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/.simplecov +1 -0
  4. data/Rakefile +0 -27
  5. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +7 -5
  6. data/ext/cs__assess_kernel/cs__assess_kernel.c +14 -3
  7. data/ext/cs__assess_kernel/cs__assess_kernel.h +2 -0
  8. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +10 -3
  9. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +2 -1
  10. data/ext/cs__assess_regexp/cs__assess_regexp.c +9 -7
  11. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.c → cs__assess_string_interpolation/cs__assess_string_interpolation.c} +14 -3
  12. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.h → cs__assess_string_interpolation/cs__assess_string_interpolation.h} +1 -1
  13. data/ext/{cs__assess_string_interpolation26 → cs__assess_string_interpolation}/extconf.rb +0 -0
  14. data/ext/cs__common/cs__common.c +5 -4
  15. data/ext/cs__contrast_patch/cs__contrast_patch.c +3 -10
  16. data/lib/contrast/agent/assess/events/source_event.rb +16 -12
  17. data/lib/contrast/agent/assess/policy/policy_node.rb +6 -0
  18. data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -41
  19. data/lib/contrast/agent/assess/policy/propagation_node.rb +8 -0
  20. data/lib/contrast/agent/assess/policy/propagator/base.rb +2 -0
  21. data/lib/contrast/agent/assess/policy/source_method.rb +2 -47
  22. data/lib/contrast/agent/assess/policy/source_node.rb +1 -0
  23. data/lib/contrast/agent/assess/policy/trigger_method.rb +1 -1
  24. data/lib/contrast/agent/assess/policy/trigger_node.rb +8 -0
  25. data/lib/contrast/agent/assess/property/evented.rb +4 -18
  26. data/lib/contrast/agent/assess/tag.rb +19 -0
  27. data/lib/contrast/agent/at_exit_hook.rb +9 -8
  28. data/lib/contrast/agent/inventory/database_config.rb +6 -3
  29. data/lib/contrast/agent/inventory/dependency_analysis.rb +3 -2
  30. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +13 -9
  31. data/lib/contrast/agent/middleware.rb +4 -0
  32. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +27 -2
  33. data/lib/contrast/agent/patching/policy/policy.rb +5 -0
  34. data/lib/contrast/agent/patching/policy/policy_node.rb +6 -0
  35. data/lib/contrast/agent/patching/policy/trigger_node.rb +3 -0
  36. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +3 -4
  37. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -0
  38. data/lib/contrast/agent/protect/policy/rule_applicator.rb +2 -2
  39. data/lib/contrast/agent/protect/rule/base.rb +1 -0
  40. data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -0
  41. data/lib/contrast/agent/protect/rule/xss.rb +4 -0
  42. data/lib/contrast/agent/reporting/reporter.rb +33 -17
  43. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +21 -15
  44. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +3 -18
  45. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
  46. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
  47. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +83 -16
  48. data/lib/contrast/agent/reporting/reporting_events/finding.rb +9 -3
  49. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
  50. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
  51. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
  52. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
  53. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
  54. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
  55. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
  56. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
  57. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
  58. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
  59. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +18 -20
  60. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -24
  61. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +13 -6
  62. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +10 -4
  63. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +10 -4
  64. data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +9 -0
  65. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
  66. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
  67. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
  68. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +2 -6
  69. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -32
  70. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -4
  71. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
  72. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +60 -2
  73. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +32 -10
  74. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +1 -1
  75. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +58 -26
  76. data/lib/contrast/agent/reporting/settings/application_settings.rb +8 -23
  77. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +27 -33
  78. data/lib/contrast/agent/reporting/settings/bot_blocker.rb +68 -0
  79. data/lib/contrast/agent/reporting/settings/code_exclusion.rb +27 -0
  80. data/lib/contrast/agent/reporting/settings/exclusion_base.rb +33 -0
  81. data/lib/contrast/agent/reporting/settings/exclusions.rb +39 -57
  82. data/lib/contrast/agent/reporting/settings/helpers.rb +56 -0
  83. data/lib/contrast/agent/reporting/settings/input_exclusion.rb +37 -0
  84. data/lib/contrast/agent/reporting/settings/ip_filter.rb +35 -0
  85. data/lib/contrast/agent/reporting/settings/keyword.rb +74 -0
  86. data/lib/contrast/agent/reporting/settings/log_enhancer.rb +65 -0
  87. data/lib/contrast/agent/reporting/settings/protect.rb +4 -2
  88. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +62 -115
  89. data/lib/contrast/agent/reporting/settings/reaction.rb +11 -2
  90. data/lib/contrast/agent/reporting/settings/rule_definition.rb +63 -0
  91. data/lib/contrast/agent/reporting/settings/sampling.rb +10 -0
  92. data/lib/contrast/agent/reporting/settings/sanitizer.rb +38 -0
  93. data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +9 -1
  94. data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +7 -0
  95. data/lib/contrast/agent/reporting/settings/server_features.rb +8 -0
  96. data/lib/contrast/agent/reporting/settings/syslog.rb +176 -0
  97. data/lib/contrast/agent/reporting/settings/url_exclusion.rb +42 -0
  98. data/lib/contrast/agent/reporting/settings/validator.rb +17 -0
  99. data/lib/contrast/agent/request.rb +5 -7
  100. data/lib/contrast/agent/request_context.rb +8 -13
  101. data/lib/contrast/agent/request_context_extend.rb +8 -9
  102. data/lib/contrast/agent/request_handler.rb +10 -35
  103. data/lib/contrast/agent/rule_set.rb +4 -0
  104. data/lib/contrast/agent/service_heartbeat.rb +1 -1
  105. data/lib/contrast/agent/static_analysis.rb +6 -15
  106. data/lib/contrast/agent/telemetry/base.rb +35 -35
  107. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
  108. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
  109. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
  110. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
  111. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
  112. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
  113. data/lib/contrast/agent/thread_watcher.rb +2 -6
  114. data/lib/contrast/agent/version.rb +1 -1
  115. data/lib/contrast/agent.rb +1 -3
  116. data/lib/contrast/api/communication/socket.rb +1 -0
  117. data/lib/contrast/api/decorators/message.rb +0 -6
  118. data/lib/contrast/api/decorators.rb +0 -3
  119. data/lib/contrast/api/dtm.pb.rb +1 -1
  120. data/lib/contrast/api/settings.pb.rb +1 -1
  121. data/lib/contrast/components/assess.rb +0 -6
  122. data/lib/contrast/components/config.rb +18 -2
  123. data/lib/contrast/config/base_configuration.rb +0 -13
  124. data/lib/contrast/config/root_configuration.rb +1 -0
  125. data/lib/contrast/config/ruby_configuration.rb +2 -9
  126. data/lib/contrast/configuration.rb +0 -2
  127. data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
  128. data/lib/contrast/extension/assess/hash.rb +3 -2
  129. data/lib/contrast/extension/assess/kernel.rb +22 -0
  130. data/lib/contrast/extension/assess/marshal.rb +16 -0
  131. data/lib/contrast/extension/assess/string.rb +21 -20
  132. data/lib/contrast/framework/base_support.rb +13 -4
  133. data/lib/contrast/framework/grape/support.rb +6 -6
  134. data/lib/contrast/framework/manager.rb +7 -23
  135. data/lib/contrast/framework/manager_extend.rb +1 -1
  136. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -15
  137. data/lib/contrast/framework/rails/support.rb +9 -2
  138. data/lib/contrast/framework/sinatra/support.rb +3 -2
  139. data/lib/contrast/logger/aliased_logging.rb +33 -26
  140. data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
  141. data/lib/contrast/utils/lru_cache.rb +3 -0
  142. data/lib/contrast/utils/middleware_utils.rb +2 -0
  143. data/lib/contrast/utils/patching/policy/patch_utils.rb +5 -22
  144. data/lib/contrast/utils/response_utils.rb +14 -1
  145. data/lib/contrast/utils/telemetry.rb +9 -0
  146. data/lib/contrast/utils/telemetry_client.rb +7 -7
  147. data/lib/contrast/utils/telemetry_hash.rb +36 -12
  148. data/lib/contrast/utils/telemetry_identifier.rb +8 -0
  149. data/lib/contrast/utils/thread_tracker.rb +26 -9
  150. data/lib/contrast/utils/timer.rb +6 -1
  151. data/lib/contrast.rb +35 -3
  152. data/lib/protobuf/code_generator.rb +129 -0
  153. data/lib/protobuf/decoder.rb +28 -0
  154. data/lib/protobuf/deprecation.rb +117 -0
  155. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +79 -0
  156. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +360 -0
  157. data/lib/protobuf/descriptors.rb +3 -0
  158. data/lib/protobuf/encoder.rb +11 -0
  159. data/lib/protobuf/enum.rb +365 -0
  160. data/lib/protobuf/exceptions.rb +9 -0
  161. data/lib/protobuf/field/base_field.rb +380 -0
  162. data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
  163. data/lib/protobuf/field/bool_field.rb +64 -0
  164. data/lib/protobuf/field/bytes_field.rb +67 -0
  165. data/lib/protobuf/field/double_field.rb +25 -0
  166. data/lib/protobuf/field/enum_field.rb +56 -0
  167. data/lib/protobuf/field/field_array.rb +102 -0
  168. data/lib/protobuf/field/field_hash.rb +122 -0
  169. data/lib/protobuf/field/fixed32_field.rb +25 -0
  170. data/lib/protobuf/field/fixed64_field.rb +28 -0
  171. data/lib/protobuf/field/float_field.rb +43 -0
  172. data/lib/protobuf/field/int32_field.rb +21 -0
  173. data/lib/protobuf/field/int64_field.rb +34 -0
  174. data/lib/protobuf/field/integer_field.rb +23 -0
  175. data/lib/protobuf/field/message_field.rb +51 -0
  176. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  177. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  178. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  179. data/lib/protobuf/field/sint32_field.rb +21 -0
  180. data/lib/protobuf/field/sint64_field.rb +21 -0
  181. data/lib/protobuf/field/string_field.rb +51 -0
  182. data/lib/protobuf/field/uint32_field.rb +21 -0
  183. data/lib/protobuf/field/uint64_field.rb +21 -0
  184. data/lib/protobuf/field/varint_field.rb +77 -0
  185. data/lib/protobuf/field.rb +74 -0
  186. data/lib/protobuf/generators/base.rb +85 -0
  187. data/lib/protobuf/generators/enum_generator.rb +39 -0
  188. data/lib/protobuf/generators/extension_generator.rb +27 -0
  189. data/lib/protobuf/generators/field_generator.rb +193 -0
  190. data/lib/protobuf/generators/file_generator.rb +262 -0
  191. data/lib/protobuf/generators/group_generator.rb +122 -0
  192. data/lib/protobuf/generators/message_generator.rb +104 -0
  193. data/lib/protobuf/generators/option_generator.rb +17 -0
  194. data/lib/protobuf/generators/printable.rb +160 -0
  195. data/lib/protobuf/generators/service_generator.rb +50 -0
  196. data/lib/protobuf/lifecycle.rb +33 -0
  197. data/lib/protobuf/logging.rb +39 -0
  198. data/lib/protobuf/message/fields.rb +233 -0
  199. data/lib/protobuf/message/serialization.rb +85 -0
  200. data/lib/protobuf/message.rb +241 -0
  201. data/lib/protobuf/optionable.rb +72 -0
  202. data/lib/protobuf/tasks/compile.rake +80 -0
  203. data/lib/protobuf/tasks.rb +1 -0
  204. data/lib/protobuf/varint.rb +20 -0
  205. data/lib/protobuf/varint_pure.rb +31 -0
  206. data/lib/protobuf/version.rb +3 -0
  207. data/lib/protobuf/wire_type.rb +10 -0
  208. data/lib/protobuf.rb +91 -0
  209. data/proto/dynamic_discovery.proto +46 -0
  210. data/proto/google/protobuf/compiler/plugin.proto +183 -0
  211. data/proto/google/protobuf/descriptor.proto +911 -0
  212. data/proto/rpc.proto +71 -0
  213. data/resources/assess/policy.json +2 -11
  214. data/ruby-agent.gemspec +2 -2
  215. metadata +105 -30
  216. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
  217. data/lib/contrast/api/decorators/application_update.rb +0 -52
  218. data/lib/contrast/api/decorators/library.rb +0 -56
  219. data/lib/contrast/api/decorators/library_usage_update.rb +0 -31
  220. data/lib/contrast/framework/platform_version.rb +0 -22
@@ -0,0 +1,50 @@
1
+ require 'protobuf/generators/base'
2
+ require 'protobuf/generators/option_generator'
3
+
4
+ module Protobuf
5
+ module Generators
6
+ class ServiceGenerator < Base
7
+
8
+ def compile
9
+ run_once(:compile) do
10
+ print_class(descriptor.name, :service) do
11
+ print OptionGenerator.new(descriptor.options, current_indent).to_s if descriptor.options
12
+ descriptor.method.each do |method_descriptor|
13
+ print_method(method_descriptor)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def print_method(method_descriptor)
22
+ request_klass = modulize(method_descriptor.input_type)
23
+ response_klass = modulize(method_descriptor.output_type)
24
+ name = ENV.key?('PB_USE_RAW_RPC_NAMES') ? method_descriptor.name : method_descriptor.name.underscore
25
+ options = {}
26
+ if method_descriptor.options
27
+ method_descriptor.options.each_field do |field_option|
28
+ option_value = method_descriptor.options[field_option.name]
29
+ next unless method_descriptor.options.field?(field_option.name)
30
+ options[field_option.fully_qualified_name] = serialize_value(option_value)
31
+ end
32
+ end
33
+
34
+ rpc = "rpc :#{name}, #{request_klass}, #{response_klass}"
35
+
36
+ if options.empty?
37
+ puts rpc
38
+ return
39
+ end
40
+
41
+ puts rpc + " do"
42
+ options.each do |option_name, value|
43
+ indent { puts "set_option #{option_name.inspect}, #{value}" }
44
+ end
45
+ puts "end"
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,33 @@
1
+ module Protobuf
2
+ class Lifecycle
3
+ class << self
4
+ def register(event_name)
5
+ fail "Lifecycle register must have a block" unless block_given?
6
+ event_name = normalized_event_name(event_name)
7
+
8
+ ::ActiveSupport::Notifications.subscribe(event_name) do |_name, _start, _finish, _id, args|
9
+ yield(*args)
10
+ end
11
+ end
12
+ alias :on register
13
+
14
+ def trigger(event_name, *args)
15
+ event_name = normalized_event_name(event_name)
16
+
17
+ ::ActiveSupport::Notifications.instrument(event_name, args)
18
+ end
19
+
20
+ replacement = ::ActiveSupport::Notifications
21
+
22
+ ::Protobuf.deprecator.deprecate_methods(
23
+ self,
24
+ :register => "#{replacement}.#{replacement.method(:subscribe).name}".to_sym,
25
+ :trigger => "#{replacement}.#{replacement.method(:instrument).name}".to_sym,
26
+ )
27
+
28
+ def normalized_event_name(event_name)
29
+ event_name.to_s.downcase
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ require 'logger'
2
+
3
+ module Protobuf
4
+ module Logging
5
+ def self.initialize_logger(log_target = $stdout, log_level = ::Logger::INFO)
6
+ @logger = Logger.new(log_target)
7
+ @logger.level = log_level
8
+ @logger
9
+ end
10
+
11
+ def self.logger
12
+ defined?(@logger) ? @logger : initialize_logger
13
+ end
14
+
15
+ class << self
16
+ attr_writer :logger
17
+ end
18
+
19
+ def logger
20
+ ::Protobuf::Logging.logger
21
+ end
22
+
23
+ def log_exception(ex)
24
+ logger.error { ex.message }
25
+ logger.error { ex.backtrace[0..5].join("\n") }
26
+ logger.debug { ex.backtrace.join("\n") }
27
+ end
28
+
29
+ def log_signature
30
+ @_log_signature ||= "[#{self.class == Class ? name : self.class.name}]"
31
+ end
32
+
33
+ def sign_message(message)
34
+ "#{log_signature} #{message}"
35
+ end
36
+ end
37
+ end
38
+
39
+ # Inspired by [mperham](https://github.com/mperham/sidekiq)
@@ -0,0 +1,233 @@
1
+ require "set"
2
+
3
+ module Protobuf
4
+ class Message
5
+ module Fields
6
+
7
+ ACCESSOR_SUFFIXES = ["", "=", "!", "?"].freeze
8
+
9
+ def self.extended(other)
10
+ other.extend(ClassMethods)
11
+ ::Protobuf.deprecator.define_deprecated_methods(
12
+ other.singleton_class,
13
+ :get_ext_field_by_name => :get_extension_field,
14
+ :get_ext_field_by_tag => :get_extension_field,
15
+ :get_field_by_name => :get_field,
16
+ :get_field_by_tag => :get_field,
17
+ )
18
+ end
19
+
20
+ module ClassMethods
21
+ def inherited(subclass)
22
+ inherit_fields!(subclass)
23
+ subclass.const_set("PROTOBUF_MESSAGE_REQUIRED_FIELD_TAGS", subclass.required_field_tags)
24
+ subclass.const_set("PROTOBUF_MESSAGE_GET_FIELD", subclass.field_store)
25
+ subclass.class_eval <<-RUBY, __FILE__, __LINE__
26
+ def _protobuf_message_field
27
+ PROTOBUF_MESSAGE_GET_FIELD
28
+ end
29
+
30
+ def _protobuf_message_unset_required_field_tags
31
+ @_protobuf_message_unset_required_field_tags ||= PROTOBUF_MESSAGE_REQUIRED_FIELD_TAGS.dup
32
+ end
33
+ RUBY
34
+ end
35
+
36
+ ##
37
+ # Field Definition Methods
38
+ #
39
+
40
+ # Define an optional field.
41
+ #
42
+ def optional(type_class, name, tag, options = {})
43
+ define_field(:optional, type_class, name, tag, options)
44
+ end
45
+
46
+ # Define a repeated field.
47
+ #
48
+ def repeated(type_class, name, tag, options = {})
49
+ define_field(:repeated, type_class, name, tag, options)
50
+ end
51
+
52
+ # Define a required field.
53
+ #
54
+ def required(type_class, name, tag, options = {})
55
+ required_field_tags << tag
56
+ define_field(:required, type_class, name, tag, options)
57
+ end
58
+
59
+ # Define a map field.
60
+ #
61
+ def map(key_type_class, value_type_class, name, tag, options = {})
62
+ # manufacture a message that represents the map entry, used for
63
+ # serialization and deserialization
64
+ entry_type = Class.new(::Protobuf::Message) do
65
+ set_option :map_entry, true
66
+ optional key_type_class, :key, 1
67
+ optional value_type_class, :value, 2
68
+ end
69
+ define_field(:repeated, entry_type, name, tag, options)
70
+ end
71
+
72
+ # Define an extension range.
73
+ #
74
+ def extensions(range)
75
+ extension_ranges << range
76
+ end
77
+
78
+ ##
79
+ # Field Access Methods
80
+ #
81
+ def all_fields
82
+ @all_fields ||= field_store.values.uniq.sort_by(&:tag)
83
+ end
84
+
85
+ def extension_fields
86
+ @extension_fields ||= all_fields.select(&:extension?)
87
+ end
88
+
89
+ def extension_ranges
90
+ @extension_ranges ||= []
91
+ end
92
+
93
+ def required_field_tags
94
+ @required_field_tags ||= []
95
+ end
96
+
97
+ def extension_tag?(tag)
98
+ tag.respond_to?(:to_i) && get_extension_field(tag).present?
99
+ end
100
+
101
+ def field_store
102
+ @field_store ||= {}
103
+ end
104
+
105
+ def fields
106
+ @fields ||= all_fields.reject(&:extension?)
107
+ end
108
+
109
+ def field_tag?(tag, allow_extension = false)
110
+ tag.respond_to?(:to_i) && get_field(tag, allow_extension).present?
111
+ end
112
+
113
+ def get_extension_field(name_or_tag)
114
+ field = field_store[name_or_tag]
115
+ field if field.try(:extension?) { false }
116
+ end
117
+
118
+ def get_field(name_or_tag, allow_extension = false)
119
+ field = field_store[name_or_tag]
120
+
121
+ if field && (allow_extension || !field.extension?)
122
+ field
123
+ else
124
+ nil
125
+ end
126
+ end
127
+
128
+ def define_field(rule, type_class, fully_qualified_field_name, tag, options)
129
+ raise_if_tag_collision(tag, fully_qualified_field_name)
130
+ raise_if_name_collision(fully_qualified_field_name)
131
+
132
+ # Determine appropirate accessor for fields depending on name collisions via extensions:
133
+
134
+ # Case 1: Base field = "string_field" and no extensions of the same name
135
+ # Result:
136
+ # message.string_field #=> @values["string_field"]
137
+ # message[:string_field] #=> @values["string_field"]
138
+ # message['string_field'] #=> @values["string_field"]
139
+
140
+ # Case 2: Base field = "string_field" and extension 1 = ".my_package.string_field", extension N = ".package_N.string_field"...
141
+ # Result:
142
+ # message.string_field #=> @values["string_field"]
143
+ # message[:string_field] #=> @values["string_field"]
144
+ # message['string_field'] #=> @values["string_field"]
145
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
146
+ # message['.my_package.string_field'] #=> @values[".my_package.string_field"]
147
+
148
+ # Case 3: No base field, extension 1 = ".my_package.string_field", extension 2 = ".other_package.string_field", extension N...
149
+ # Result:
150
+ # message.string_field #=> raise NoMethodError (no simple accessor allowed)
151
+ # message[:string_field] #=> raise NoMethodError (no simple accessor allowed)
152
+ # message['string_field'] #=> raise NoMethodError (no simple accessor allowed)
153
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
154
+ # message['.my_package.string_field'] #=> @values[".my_package.string_field"]
155
+ # message[:'.other_package.string_field'] #=> @values[".other_package.string_field"]
156
+ # message['.other_package.string_field'] #=> @values[".other_package.string_field"]
157
+
158
+ # Case 4: No base field, extension = ".my_package.string_field", no other extensions
159
+ # Result:
160
+ # message.string_field #=> @values[".my_package.string_field"]
161
+ # message[:string_field] #=> @values[".my_package.string_field"]
162
+ # message['string_field'] #=> @values[".my_package.string_field"]
163
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
164
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
165
+
166
+ simple_name =
167
+ if options[:extension]
168
+ base_name = fully_qualified_field_name.to_s.split('.').last.to_sym
169
+ if field_store[base_name]
170
+ # Case 3
171
+ if field_store[base_name].extension?
172
+ remove_existing_accessors(base_name)
173
+ end
174
+ nil
175
+ # Case 4
176
+ else
177
+ base_name
178
+ end
179
+ else
180
+ # Case 1
181
+ fully_qualified_field_name
182
+ end
183
+
184
+ field = ::Protobuf::Field.build(self, rule, type_class, fully_qualified_field_name,
185
+ tag, simple_name, options)
186
+ field_store[tag] = field
187
+ field_store[fully_qualified_field_name.to_sym] = field
188
+ field_store[fully_qualified_field_name.to_s] = field
189
+ if simple_name && simple_name != fully_qualified_field_name
190
+ field_store[simple_name.to_sym] = field
191
+ field_store[simple_name.to_s] = field
192
+ end
193
+ # defining a new field for the message will cause cached @all_fields, @extension_fields,
194
+ # and @fields to be incorrect; reset them
195
+ @all_fields = @extension_fields = @fields = nil
196
+ end
197
+
198
+ def remove_existing_accessors(accessor)
199
+ field_store.delete(accessor.to_sym).try(:fully_qualified_name_only!)
200
+ field_store.delete(accessor.to_s)
201
+ ACCESSOR_SUFFIXES.each do |modifier|
202
+ begin
203
+ remove_method("#{accessor}#{modifier}")
204
+ # rubocop: disable Lint/HandleExceptions
205
+ rescue NameError
206
+ # Do not remove the method
207
+ end
208
+ end
209
+ end
210
+
211
+ def raise_if_tag_collision(tag, field_name)
212
+ if get_field(tag, true)
213
+ fail TagCollisionError, %(Field number #{tag} has already been used in "#{name}" by field "#{field_name}".)
214
+ end
215
+ end
216
+
217
+ def raise_if_name_collision(field_name)
218
+ if get_field(field_name, true)
219
+ fail DuplicateFieldNameError, %(Field name #{field_name} has already been used in "#{name}".)
220
+ end
221
+ end
222
+
223
+ def inherit_fields!(subclass)
224
+ instance_variables.each do |iv|
225
+ subclass.instance_variable_set(iv, instance_variable_get(iv))
226
+ end
227
+ end
228
+ private :inherit_fields!
229
+
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,85 @@
1
+ require 'stringio'
2
+ require 'protobuf/decoder'
3
+ require 'protobuf/encoder'
4
+
5
+ module Protobuf
6
+ class Message
7
+ module Serialization
8
+
9
+ module ClassMethods
10
+ def decode(bytes)
11
+ new.decode(bytes)
12
+ end
13
+
14
+ def decode_from(stream)
15
+ new.decode_from(stream)
16
+ end
17
+
18
+ # Create a new object with the given values and return the encoded bytes.
19
+ def encode(fields = {})
20
+ new(fields).encode
21
+ end
22
+ end
23
+
24
+ def self.included(other)
25
+ other.extend(ClassMethods)
26
+ end
27
+
28
+ ##
29
+ # Instance Methods
30
+ #
31
+
32
+ # Decode the given non-stream bytes into this message.
33
+ #
34
+ def decode(bytes)
35
+ decode_from(::StringIO.new(bytes))
36
+ end
37
+
38
+ # Decode the given stream into this message.
39
+ #
40
+ def decode_from(stream)
41
+ ::Protobuf::Decoder.decode_each_field(stream) do |tag, bytes|
42
+ set_field_bytes(tag, bytes)
43
+ end
44
+
45
+ self
46
+ end
47
+
48
+ # Encode this message
49
+ #
50
+ def encode
51
+ stream = ::StringIO.new
52
+ stream.set_encoding(::Protobuf::Field::BytesField::BYTES_ENCODING)
53
+ encode_to(stream)
54
+ stream.string
55
+ end
56
+
57
+ # Encode this message to the given stream.
58
+ #
59
+ def encode_to(stream)
60
+ ::Protobuf::Encoder.encode(self, stream)
61
+ end
62
+
63
+ ##
64
+ # Instance Aliases
65
+ #
66
+ alias :parse_from_string decode
67
+ alias :deserialize decode
68
+ alias :parse_from decode_from
69
+ alias :deserialize_from decode_from
70
+ alias :to_s encode
71
+ alias :bytes encode
72
+ alias :serialize encode
73
+ alias :serialize_to_string encode
74
+ alias :serialize_to encode_to
75
+
76
+ private
77
+
78
+ def set_field_bytes(tag, bytes)
79
+ field = _protobuf_message_field[tag]
80
+ field.set(self, bytes) if field
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,241 @@
1
+ require 'protobuf/message/fields'
2
+ require 'protobuf/message/serialization'
3
+ require 'protobuf/varint'
4
+
5
+ module Protobuf
6
+ class Message
7
+
8
+ ##
9
+ # Includes & Extends
10
+ #
11
+
12
+ extend ::Protobuf::Message::Fields
13
+ include ::Protobuf::Message::Serialization
14
+ ::Protobuf::Optionable.inject(self) { ::CSGoogle::Protobuf::MessageOptions }
15
+
16
+ ##
17
+ # Class Methods
18
+ #
19
+
20
+ def self.to_json
21
+ name
22
+ end
23
+
24
+ ##
25
+ # Constructor
26
+ #
27
+
28
+ def initialize(fields = {})
29
+ @values = {}
30
+ fields.to_hash.each do |name, value|
31
+ set_field(name, value, true)
32
+ end
33
+
34
+ yield self if block_given?
35
+ end
36
+
37
+ ##
38
+ # Public Instance Methods
39
+ #
40
+
41
+ def clear!
42
+ @values.delete_if do |_, value|
43
+ if value.is_a?(::Protobuf::Field::FieldArray) || value.is_a?(::Protobuf::Field::FieldHash)
44
+ value.clear
45
+ false
46
+ else
47
+ true
48
+ end
49
+ end
50
+ self
51
+ end
52
+
53
+ def clone
54
+ copy_to(super, :clone)
55
+ end
56
+
57
+ def dup
58
+ copy_to(super, :dup)
59
+ end
60
+
61
+ # Iterate over every field, invoking the given block
62
+ #
63
+ def each_field
64
+ return to_enum(:each_field) unless block_given?
65
+
66
+ self.class.all_fields.each do |field|
67
+ value = self[field.name]
68
+ yield(field, value)
69
+ end
70
+ end
71
+
72
+ def each_field_for_serialization
73
+ _protobuf_message_unset_required_field_tags.each do |tag|
74
+ fail ::Protobuf::SerializationError, "Required field #{self.class.name}##{_protobuf_message_field[tag].name} does not have a value."
75
+ end
76
+
77
+ @values.each_key do |fully_qualified_name|
78
+ field = _protobuf_message_field[fully_qualified_name]
79
+ yield(field, field.value_from_values_for_serialization(@values))
80
+ end
81
+ end
82
+
83
+ def field?(name)
84
+ field = _protobuf_message_field[name]
85
+
86
+ if field
87
+ field.field?(@values)
88
+ else
89
+ false
90
+ end
91
+ end
92
+ alias :respond_to_has? field?
93
+ ::Protobuf.deprecator.define_deprecated_methods(self, :has_field? => :field?)
94
+
95
+ def inspect
96
+ attrs = self.class.fields.map do |field|
97
+ [field.name, self[field.name].inspect].join('=')
98
+ end.join(' ')
99
+
100
+ "#<#{self.class} #{attrs}>"
101
+ end
102
+
103
+ def respond_to_has_and_present?(key)
104
+ field = _protobuf_message_field[key]
105
+
106
+ if field
107
+ field.field_and_present?(@values)
108
+ else
109
+ false
110
+ end
111
+ end
112
+
113
+ # Return a hash-representation of the given fields for this message type.
114
+ def to_hash
115
+ result = {}
116
+
117
+ @values.each_key do |field_name|
118
+ field = _protobuf_message_field[field_name]
119
+ field.to_message_hash(@values, result)
120
+ end
121
+
122
+ result
123
+ end
124
+
125
+ def to_hash_with_string_keys
126
+ result = {}
127
+
128
+ @values.each_key do |field_name|
129
+ field = _protobuf_message_field[field_name]
130
+ field.to_message_hash_with_string_key(@values, result)
131
+ end
132
+
133
+ result
134
+ end
135
+
136
+ def to_json(options = {})
137
+ to_json_hash.to_json(options)
138
+ end
139
+
140
+ # Return a hash-representation of the given fields for this message type that
141
+ # is safe to convert to JSON.
142
+ def to_json_hash
143
+ result = {}
144
+
145
+ @values.each_key do |field_name|
146
+ value = self[field_name]
147
+ field = self.class.get_field(field_name, true)
148
+
149
+ # NB: to_json_hash_value should come before json_encode so as to handle
150
+ # repeated fields without extra logic.
151
+ hashed_value = if value.respond_to?(:to_json_hash_value)
152
+ value.to_json_hash_value
153
+ elsif field.respond_to?(:json_encode)
154
+ field.json_encode(value)
155
+ else
156
+ value
157
+ end
158
+
159
+ result[field.name] = hashed_value
160
+ end
161
+
162
+ result
163
+ end
164
+
165
+ def to_proto
166
+ self
167
+ end
168
+
169
+ def ==(other)
170
+ return false unless other.is_a?(self.class)
171
+ each_field do |field, value|
172
+ return false unless value == other[field.name]
173
+ end
174
+ true
175
+ end
176
+
177
+ def [](name)
178
+ field = _protobuf_message_field[name]
179
+ field.value_from_values(@values)
180
+ rescue # not having a field should be the exceptional state
181
+ raise if field
182
+ fail ArgumentError, "invalid field name=#{name.inspect}"
183
+ end
184
+
185
+ def []=(name, value)
186
+ set_field(name, value, true)
187
+ end
188
+
189
+ def set_field(name, value, ignore_nil_for_repeated, field = nil)
190
+ field ||= _protobuf_message_field[name]
191
+
192
+ if field
193
+ field.set_field(@values, value, ignore_nil_for_repeated, self)
194
+ else
195
+ fail(::Protobuf::FieldNotDefinedError, name) unless ::Protobuf.ignore_unknown_fields?
196
+ end
197
+ end
198
+
199
+ ##
200
+ # Instance Aliases
201
+ #
202
+ alias :to_hash_value to_hash
203
+ alias :to_json_hash_value to_json_hash
204
+ alias :to_proto_hash to_hash
205
+ alias :responds_to_has? respond_to_has?
206
+ alias :respond_to_and_has? respond_to_has?
207
+ alias :responds_to_and_has? respond_to_has?
208
+ alias :respond_to_has_present? respond_to_has_and_present?
209
+ alias :respond_to_and_has_present? respond_to_has_and_present?
210
+ alias :respond_to_and_has_and_present? respond_to_has_and_present?
211
+ alias :responds_to_has_present? respond_to_has_and_present?
212
+ alias :responds_to_and_has_present? respond_to_has_and_present?
213
+ alias :responds_to_and_has_and_present? respond_to_has_and_present?
214
+
215
+ ##
216
+ # Private Instance Methods
217
+ #
218
+
219
+ private
220
+
221
+ def copy_to(object, method)
222
+ duplicate = proc do |obj|
223
+ case obj
224
+ when Message, String then obj.__send__(method)
225
+ else obj
226
+ end
227
+ end
228
+
229
+ object.__send__(:initialize)
230
+ @values.each do |name, value|
231
+ if value.is_a?(::Protobuf::Field::FieldArray)
232
+ object[name].replace(value.map { |v| duplicate.call(v) })
233
+ else
234
+ object[name] = duplicate.call(value)
235
+ end
236
+ end
237
+ object
238
+ end
239
+
240
+ end
241
+ end