contrast-agent 6.7.0 → 6.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.simplecov +0 -1
  4. data/Rakefile +0 -1
  5. data/ext/cs__assess_array/cs__assess_array.c +41 -10
  6. data/ext/cs__assess_array/cs__assess_array.h +4 -1
  7. data/lib/contrast/agent/assess/policy/trigger_method.rb +2 -2
  8. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
  9. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -1
  10. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +1 -1
  11. data/lib/contrast/agent/excluder.rb +52 -34
  12. data/lib/contrast/agent/exclusion_matcher.rb +21 -9
  13. data/lib/contrast/agent/middleware.rb +4 -4
  14. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +6 -0
  15. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +146 -127
  16. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +20 -0
  17. data/lib/contrast/agent/protect/policy/rule_applicator.rb +1 -1
  18. data/lib/contrast/agent/protect/rule/base.rb +45 -53
  19. data/lib/contrast/agent/protect/rule/base_service.rb +48 -24
  20. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +98 -0
  21. data/lib/contrast/agent/protect/rule/bot_blocker.rb +81 -0
  22. data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -1
  23. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +8 -5
  24. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +22 -22
  25. data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +69 -0
  26. data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +68 -0
  27. data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +2 -58
  28. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
  29. data/lib/contrast/agent/protect/rule/deserialization.rb +3 -14
  30. data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +2 -2
  31. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +0 -11
  32. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +29 -34
  33. data/lib/contrast/agent/protect/rule/no_sqli.rb +25 -18
  34. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_input_classification.rb +61 -0
  35. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +114 -0
  36. data/lib/contrast/agent/protect/rule/path_traversal.rb +38 -12
  37. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +33 -15
  38. data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +0 -14
  39. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -62
  40. data/lib/contrast/agent/protect/rule/sqli.rb +70 -0
  41. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +39 -63
  42. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +6 -33
  43. data/lib/contrast/agent/protect/rule/xss/reflected_xss_input_classification.rb +58 -0
  44. data/lib/contrast/agent/protect/rule/xss.rb +14 -20
  45. data/lib/contrast/agent/protect/rule/xxe.rb +4 -24
  46. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +18 -39
  47. data/lib/contrast/agent/reporting/attack_result/response_type.rb +9 -9
  48. data/lib/contrast/agent/reporting/details/ip_denylist_details.rb +10 -2
  49. data/lib/contrast/agent/reporting/details/virtual_patch_details.rb +8 -2
  50. data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +27 -0
  51. data/lib/contrast/agent/reporting/input_analysis/details/protect_rule_details.rb +15 -0
  52. data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +1 -2
  53. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +16 -2
  54. data/lib/contrast/agent/reporting/masker/masker.rb +2 -0
  55. data/lib/contrast/agent/reporting/reporter.rb +1 -14
  56. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +15 -12
  57. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +3 -3
  58. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -2
  59. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +0 -2
  60. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +0 -1
  61. data/lib/contrast/agent/reporting/reporting_events/finding.rb +4 -4
  62. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +0 -5
  63. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +0 -1
  64. data/lib/contrast/agent/reporting/reporting_events/poll.rb +1 -11
  65. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +0 -1
  66. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +0 -1
  67. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +2 -2
  68. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +1 -1
  69. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +0 -3
  70. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -0
  71. data/lib/contrast/agent/reporting/settings/code_exclusion.rb +6 -1
  72. data/lib/contrast/agent/reporting/settings/exclusion_base.rb +18 -0
  73. data/lib/contrast/agent/reporting/settings/exclusions.rb +2 -1
  74. data/lib/contrast/agent/reporting/settings/input_exclusion.rb +9 -3
  75. data/lib/contrast/agent/reporting/settings/protect.rb +15 -15
  76. data/lib/contrast/agent/request.rb +2 -14
  77. data/lib/contrast/agent/request_context.rb +6 -9
  78. data/lib/contrast/agent/request_context_extend.rb +9 -148
  79. data/lib/contrast/agent/thread_watcher.rb +3 -18
  80. data/lib/contrast/agent/version.rb +1 -1
  81. data/lib/contrast/agent.rb +0 -11
  82. data/lib/contrast/agent_lib/api/command_injection.rb +46 -0
  83. data/lib/contrast/agent_lib/api/init.rb +101 -0
  84. data/lib/contrast/agent_lib/api/input_tracing.rb +267 -0
  85. data/lib/contrast/agent_lib/api/method_tempering.rb +29 -0
  86. data/lib/contrast/agent_lib/api/panic.rb +87 -0
  87. data/lib/contrast/agent_lib/api/path_semantic_file_security_bypass.rb +40 -0
  88. data/lib/contrast/agent_lib/interface.rb +260 -0
  89. data/lib/contrast/agent_lib/interface_base.rb +118 -0
  90. data/lib/contrast/agent_lib/return_types/eval_result.rb +44 -0
  91. data/lib/contrast/agent_lib/test.rb +29 -0
  92. data/lib/contrast/api/communication/connection_status.rb +5 -5
  93. data/lib/contrast/components/agent.rb +0 -14
  94. data/lib/contrast/components/app_context.rb +0 -2
  95. data/lib/contrast/components/app_context_extend.rb +0 -25
  96. data/lib/contrast/components/config.rb +1 -18
  97. data/lib/contrast/components/protect.rb +4 -1
  98. data/lib/contrast/components/ruby_component.rb +1 -1
  99. data/lib/contrast/components/settings.rb +37 -89
  100. data/lib/contrast/config/protect_rule_configuration.rb +7 -7
  101. data/lib/contrast/config/protect_rules_configuration.rb +20 -58
  102. data/lib/contrast/configuration.rb +1 -10
  103. data/lib/contrast/extension/assess/array.rb +9 -0
  104. data/lib/contrast/extension/delegator.rb +2 -0
  105. data/lib/contrast/framework/manager.rb +3 -1
  106. data/lib/contrast/framework/rails/railtie.rb +0 -1
  107. data/lib/contrast/framework/rails/support.rb +0 -1
  108. data/lib/contrast/tasks/config.rb +1 -8
  109. data/lib/contrast/utils/duck_utils.rb +1 -0
  110. data/lib/contrast/utils/input_classification_base.rb +156 -0
  111. data/lib/contrast/utils/os.rb +0 -20
  112. data/lib/contrast/utils/response_utils.rb +0 -16
  113. data/lib/contrast/utils/stack_trace_utils.rb +3 -15
  114. data/lib/contrast/utils/string_utils.rb +10 -7
  115. data/lib/contrast.rb +2 -3
  116. data/resources/protect/policy.json +1 -2
  117. data/ruby-agent.gemspec +2 -5
  118. metadata +42 -112
  119. data/exe/contrast_service +0 -23
  120. data/lib/contrast/agent/protect/rule/cmdi/cmdi_worth_watching.rb +0 -64
  121. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +0 -118
  122. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +0 -45
  123. data/lib/contrast/agent/reaction_processor.rb +0 -47
  124. data/lib/contrast/agent/service_heartbeat.rb +0 -35
  125. data/lib/contrast/api/communication/messaging_queue.rb +0 -128
  126. data/lib/contrast/api/communication/response_processor.rb +0 -90
  127. data/lib/contrast/api/communication/service_lifecycle.rb +0 -77
  128. data/lib/contrast/api/communication/socket.rb +0 -44
  129. data/lib/contrast/api/communication/socket_client.rb +0 -130
  130. data/lib/contrast/api/communication/speedracer.rb +0 -138
  131. data/lib/contrast/api/communication/tcp_socket.rb +0 -32
  132. data/lib/contrast/api/communication/unix_socket.rb +0 -28
  133. data/lib/contrast/api/communication.rb +0 -20
  134. data/lib/contrast/api/decorators/address.rb +0 -59
  135. data/lib/contrast/api/decorators/agent_startup.rb +0 -56
  136. data/lib/contrast/api/decorators/application_settings.rb +0 -43
  137. data/lib/contrast/api/decorators/application_startup.rb +0 -56
  138. data/lib/contrast/api/decorators/bot_blocker.rb +0 -37
  139. data/lib/contrast/api/decorators/http_request.rb +0 -137
  140. data/lib/contrast/api/decorators/input_analysis.rb +0 -18
  141. data/lib/contrast/api/decorators/instrumentation_mode.rb +0 -35
  142. data/lib/contrast/api/decorators/ip_denylist.rb +0 -37
  143. data/lib/contrast/api/decorators/message.rb +0 -67
  144. data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -52
  145. data/lib/contrast/api/decorators/response_type.rb +0 -17
  146. data/lib/contrast/api/decorators/server_features.rb +0 -25
  147. data/lib/contrast/api/decorators/user_input.rb +0 -51
  148. data/lib/contrast/api/decorators/virtual_patch.rb +0 -34
  149. data/lib/contrast/api/decorators.rb +0 -22
  150. data/lib/contrast/api/dtm.pb.rb +0 -363
  151. data/lib/contrast/api/settings.pb.rb +0 -500
  152. data/lib/contrast/api.rb +0 -16
  153. data/lib/contrast/components/contrast_service.rb +0 -88
  154. data/lib/contrast/components/service.rb +0 -55
  155. data/lib/contrast/tasks/service.rb +0 -84
  156. data/lib/contrast/utils/input_classification.rb +0 -73
  157. data/lib/protobuf/code_generator.rb +0 -129
  158. data/lib/protobuf/decoder.rb +0 -28
  159. data/lib/protobuf/deprecation.rb +0 -117
  160. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +0 -79
  161. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +0 -360
  162. data/lib/protobuf/descriptors.rb +0 -3
  163. data/lib/protobuf/encoder.rb +0 -11
  164. data/lib/protobuf/enum.rb +0 -365
  165. data/lib/protobuf/exceptions.rb +0 -9
  166. data/lib/protobuf/field/base_field.rb +0 -380
  167. data/lib/protobuf/field/base_field_object_definitions.rb +0 -504
  168. data/lib/protobuf/field/bool_field.rb +0 -64
  169. data/lib/protobuf/field/bytes_field.rb +0 -67
  170. data/lib/protobuf/field/double_field.rb +0 -25
  171. data/lib/protobuf/field/enum_field.rb +0 -56
  172. data/lib/protobuf/field/field_array.rb +0 -102
  173. data/lib/protobuf/field/field_hash.rb +0 -122
  174. data/lib/protobuf/field/fixed32_field.rb +0 -25
  175. data/lib/protobuf/field/fixed64_field.rb +0 -28
  176. data/lib/protobuf/field/float_field.rb +0 -43
  177. data/lib/protobuf/field/int32_field.rb +0 -21
  178. data/lib/protobuf/field/int64_field.rb +0 -34
  179. data/lib/protobuf/field/integer_field.rb +0 -23
  180. data/lib/protobuf/field/message_field.rb +0 -51
  181. data/lib/protobuf/field/sfixed32_field.rb +0 -27
  182. data/lib/protobuf/field/sfixed64_field.rb +0 -28
  183. data/lib/protobuf/field/signed_integer_field.rb +0 -29
  184. data/lib/protobuf/field/sint32_field.rb +0 -21
  185. data/lib/protobuf/field/sint64_field.rb +0 -21
  186. data/lib/protobuf/field/string_field.rb +0 -51
  187. data/lib/protobuf/field/uint32_field.rb +0 -21
  188. data/lib/protobuf/field/uint64_field.rb +0 -21
  189. data/lib/protobuf/field/varint_field.rb +0 -77
  190. data/lib/protobuf/field.rb +0 -74
  191. data/lib/protobuf/generators/base.rb +0 -85
  192. data/lib/protobuf/generators/enum_generator.rb +0 -39
  193. data/lib/protobuf/generators/extension_generator.rb +0 -27
  194. data/lib/protobuf/generators/field_generator.rb +0 -193
  195. data/lib/protobuf/generators/file_generator.rb +0 -262
  196. data/lib/protobuf/generators/group_generator.rb +0 -122
  197. data/lib/protobuf/generators/message_generator.rb +0 -104
  198. data/lib/protobuf/generators/option_generator.rb +0 -17
  199. data/lib/protobuf/generators/printable.rb +0 -160
  200. data/lib/protobuf/generators/service_generator.rb +0 -50
  201. data/lib/protobuf/lifecycle.rb +0 -33
  202. data/lib/protobuf/logging.rb +0 -39
  203. data/lib/protobuf/message/fields.rb +0 -233
  204. data/lib/protobuf/message/serialization.rb +0 -85
  205. data/lib/protobuf/message.rb +0 -241
  206. data/lib/protobuf/optionable.rb +0 -72
  207. data/lib/protobuf/tasks/compile.rake +0 -80
  208. data/lib/protobuf/tasks.rb +0 -1
  209. data/lib/protobuf/varint.rb +0 -20
  210. data/lib/protobuf/varint_pure.rb +0 -31
  211. data/lib/protobuf/version.rb +0 -3
  212. data/lib/protobuf/wire_type.rb +0 -10
  213. data/lib/protobuf.rb +0 -91
  214. data/proto/dynamic_discovery.proto +0 -46
  215. data/proto/google/protobuf/compiler/plugin.proto +0 -183
  216. data/proto/google/protobuf/descriptor.proto +0 -911
  217. data/proto/rpc.proto +0 -71
  218. data/service_executables/.gitkeep +0 -0
  219. data/service_executables/VERSION +0 -1
  220. data/service_executables/linux/contrast-service +0 -0
  221. data/service_executables/mac/contrast-service +0 -0
@@ -1,262 +0,0 @@
1
- require 'set'
2
- require 'protobuf/generators/base'
3
- require 'protobuf/generators/group_generator'
4
-
5
- module Protobuf
6
- module Generators
7
- class FileGenerator < Base
8
-
9
- attr_reader :output_file
10
-
11
- def initialize(*args)
12
- super
13
- @output_file = ::CSGoogle::Protobuf::Compiler::CodeGeneratorResponse::File.new(:name => file_name)
14
- @extension_fields = Hash.new { |h, k| h[k] = [] }
15
- @known_messages = {}
16
- @known_enums = {}
17
- @dangling_messages = {}
18
- end
19
-
20
- def file_name
21
- convert_filename(descriptor.name, false)
22
- end
23
-
24
- def compile
25
- run_once(:compile) do
26
- map_extensions(descriptor, [descriptor.package])
27
-
28
- print_file_comment
29
- print_generic_requires
30
- print_import_requires
31
-
32
- print_package do
33
- inject_optionable
34
- group = GroupGenerator.new(current_indent)
35
- group.add_options(descriptor.options) if descriptor.options
36
- group.add_enums(descriptor.enum_type, :namespace => [descriptor.package])
37
- group.add_message_declarations(descriptor.message_type)
38
- group.add_messages(descriptor.message_type, :extension_fields => @extension_fields, :namespace => [descriptor.package])
39
- group.add_extended_messages(unknown_extensions)
40
- group.add_services(descriptor.service)
41
-
42
- group.add_header(:enum, 'Enum Classes')
43
- group.add_header(:message_declaration, 'Message Classes')
44
- group.add_header(:options, 'File Options')
45
- group.add_header(:message, 'Message Fields')
46
- group.add_header(:extended_message, 'Extended Message Fields')
47
- group.add_header(:service, 'Service Classes')
48
- print group.to_s
49
- end
50
-
51
- end
52
- end
53
-
54
- def unknown_extensions
55
- @unknown_extensions ||= @extension_fields.map do |message_name, fields|
56
- message_klass = modulize(message_name).safe_constantize
57
- if message_klass
58
- unknown_fields = fields.reject do |field|
59
- @known_messages[message_name] && message_klass.get_field(field.name, true)
60
- end
61
- [message_name, unknown_fields]
62
- else
63
- [message_name, fields]
64
- end
65
- end
66
- end
67
-
68
- def generate_output_file
69
- compile
70
- output_file.content = to_s
71
- output_file
72
- end
73
-
74
- # Recursively map out all extensions known in this file.
75
- # The key is the type_name of the message being extended, and
76
- # the value is an array of field descriptors.
77
- #
78
- def map_extensions(descriptor, namespaces)
79
- if fully_qualified_token?(descriptor.name)
80
- fully_qualified_namespace = descriptor.name
81
- elsif !(namespace = namespaces.reject(&:empty?).join(".")).empty?
82
- fully_qualified_namespace = ".#{namespace}"
83
- end
84
- # Record all the message descriptor name's we encounter (should be the whole tree).
85
- if descriptor.is_a?(::CSGoogle::Protobuf::DescriptorProto)
86
- @known_messages[fully_qualified_namespace || descriptor.name] = descriptor
87
- elsif descriptor.is_a?(::CSGoogle::Protobuf::EnumDescriptorProto)
88
- @known_enums[fully_qualified_namespace || descriptor.name] = descriptor
89
- return
90
- end
91
-
92
- descriptor.extension.each do |field_descriptor|
93
- unless fully_qualified_token?(field_descriptor.name) && fully_qualified_namespace
94
- field_descriptor.name = "#{fully_qualified_namespace}.#{field_descriptor.name}"
95
- end
96
- @extension_fields[field_descriptor.extendee] << field_descriptor
97
- end
98
-
99
- [:message_type, :nested_type, :enum_type].each do |type|
100
- next unless descriptor.respond_to_has_and_present?(type)
101
-
102
- descriptor.public_send(type).each do |type_descriptor|
103
- map_extensions(type_descriptor, (namespaces + [type_descriptor.name]))
104
- end
105
- end
106
- end
107
-
108
- def print_file_comment
109
- puts "# encoding: utf-8"
110
- puts
111
- puts "##"
112
- puts "# This file is auto-generated. DO NOT EDIT!"
113
- puts "#"
114
- end
115
-
116
- def print_generic_requires
117
- print_require("protobuf")
118
- print_require("protobuf/rpc/service") if descriptor.service.count > 0
119
- puts
120
- end
121
-
122
- def print_import_requires
123
- return if descriptor.dependency.empty?
124
-
125
- header "Imports"
126
-
127
- descriptor.dependency.each do |dependency|
128
- print_require(convert_filename(dependency), ENV.key?('PB_REQUIRE_RELATIVE'))
129
- end
130
-
131
- puts
132
- end
133
-
134
- def print_package(&block)
135
- namespaces = descriptor.package.split('.')
136
- if namespaces.empty? && ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')
137
- namespaces = [File.basename(descriptor.name).sub('.proto', '')]
138
- end
139
- namespaces.reverse.reduce(block) do |previous, namespace|
140
- -> { print_module(namespace, &previous) }
141
- end.call
142
- end
143
-
144
- def eval_unknown_extensions!
145
- @@evaled_dependencies ||= Set.new # rubocop:disable Style/ClassVars
146
- @@all_messages ||= {} # rubocop:disable Style/ClassVars
147
- @@all_enums ||= {} # rubocop:disable Style/ClassVars
148
-
149
- map_extensions(descriptor, [descriptor.package])
150
- @known_messages.each do |name, descriptor|
151
- @@all_messages[name] = descriptor
152
- end
153
- @known_enums.each do |name, descriptor|
154
- @@all_enums[name] = descriptor
155
- end
156
-
157
- # create package namespace
158
- print_package {}
159
- eval_code
160
-
161
- unknown_extensions.each do |extendee, fields|
162
- eval_dependencies(extendee)
163
- fields.each do |field|
164
- eval_dependencies(field.type_name)
165
- end
166
- end
167
- group = GroupGenerator.new(0)
168
- group.add_extended_messages(unknown_extensions, false)
169
- print group.to_s
170
- eval_code
171
- rescue => e
172
- warn "Error loading unknown extensions #{descriptor.name.inspect} error=#{e}"
173
- raise e
174
- end
175
-
176
- private
177
-
178
- def convert_filename(filename, for_require = true)
179
- filename.sub(/\.proto/, (for_require ? '.pb' : '.pb.rb'))
180
- end
181
-
182
- def fully_qualified_token?(token)
183
- token[0] == '.'
184
- end
185
-
186
- def eval_dependencies(name, namespace = nil)
187
- name = "#{namespace}.#{name}" if namespace && !fully_qualified_token?(name)
188
- return if name.empty? || @@evaled_dependencies.include?(name) || modulize(name).safe_constantize
189
-
190
- # if name = .foo.bar.Baz look for classes / modules named ::Foo::Bar and ::Foo
191
- # module == pure namespace (e.g. the descriptor package name)
192
- # class == nested messages
193
- create_ruby_namespace_heiarchy(name)
194
-
195
- if (message = @@all_messages[name])
196
- # Create the blank namespace in case there are nested types
197
- eval_message_code(name)
198
-
199
- message.nested_type.each do |nested_type|
200
- eval_dependencies(nested_type.name, name) unless nested_type.name.empty?
201
- end
202
- message.field.each do |field|
203
- eval_dependencies(field.type_name, name) unless field.type_name.empty?
204
- end
205
- message.enum_type.each do |enum_type|
206
- eval_dependencies(enum_type.name, name)
207
- end
208
-
209
- # Check @@evaled_dependencies again in case there was a dependency
210
- # loop that already loaded this message
211
- return if @@evaled_dependencies.include?(name)
212
- eval_message_code(name, message.field)
213
- @@evaled_dependencies << name
214
-
215
- elsif (enum = @@all_enums[name])
216
- # Check @@evaled_dependencies again in case there was a dependency
217
- # loop that already loaded this enum
218
- return if @@evaled_dependencies.include?(name)
219
- namespace = name.split(".")
220
- eval_enum_code(enum, namespace[0..-2].join("."))
221
- @@evaled_dependencies << name
222
- else
223
- fail "Error loading unknown dependencies, could not find message or enum #{name.inspect}"
224
- end
225
- end
226
-
227
- def eval_message_code(fully_qualified_namespace, fields = [])
228
- group = GroupGenerator.new(0)
229
- group.add_extended_messages({ fully_qualified_namespace => fields }, false)
230
- print group.to_s
231
- eval_code
232
- end
233
-
234
- def eval_enum_code(enum, fully_qualified_namespace)
235
- group = GroupGenerator.new(0)
236
- group.add_enums([enum], :namespace => [fully_qualified_namespace])
237
- print group.to_s
238
- eval_code(modulize(fully_qualified_namespace).safe_constantize || Object)
239
- end
240
-
241
- def eval_code(context = Object)
242
- warn "#{context.inspect}.module_eval #{print_contents.inspect}" if ENV['PB_DEBUG']
243
- context.module_eval print_contents.to_s
244
- @io.truncate(0)
245
- @io.rewind
246
- end
247
-
248
- def create_ruby_namespace_heiarchy(namespace)
249
- loop do
250
- namespace, _match, _tail = namespace.rpartition(".")
251
- break if namespace.empty?
252
- eval_dependencies(namespace)
253
- end
254
- end
255
-
256
- def inject_optionable
257
- return if descriptor.package.empty? && !ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')
258
- puts "::Protobuf::Optionable.inject(self) { ::CSGoogle::Protobuf::FileOptions }"
259
- end
260
- end
261
- end
262
- end
@@ -1,122 +0,0 @@
1
- require 'protobuf/generators/enum_generator'
2
- require 'protobuf/generators/extension_generator'
3
- require 'protobuf/generators/field_generator'
4
- require 'protobuf/generators/message_generator'
5
- require 'protobuf/generators/option_generator'
6
- require 'protobuf/generators/service_generator'
7
-
8
- module Protobuf
9
- module Generators
10
- class GroupGenerator
11
- include ::Protobuf::Generators::Printable
12
-
13
- attr_reader :groups, :indent_level
14
- attr_writer :order
15
-
16
- def initialize(indent_level = 0)
17
- @groups = Hash.new { |h, k| h[k] = [] }
18
- @headers = {}
19
- @comments = {}
20
- @handlers = {}
21
- @indent_level = indent_level
22
- @order = [:enum, :message_declaration, :options, :message, :extended_message, :service]
23
- init_printer(indent_level)
24
- end
25
-
26
- def add_options(option_descriptor)
27
- @groups[:options] << OptionGenerator.new(option_descriptor, indent_level)
28
- end
29
-
30
- def add_enums(enum_descriptors, options)
31
- enum_descriptors.each do |enum_descriptor|
32
- @groups[:enum] << EnumGenerator.new(enum_descriptor, indent_level, options)
33
- end
34
- end
35
-
36
- def add_comment(type, message)
37
- @comments[type] = message
38
- end
39
-
40
- def add_extended_messages(extended_messages, skip_empty_fields = true)
41
- extended_messages.each do |message_type, field_descriptors|
42
- next if skip_empty_fields && field_descriptors.empty?
43
- @groups[:extended_message] << ExtensionGenerator.new(message_type, field_descriptors, indent_level)
44
- end
45
- end
46
-
47
- def add_extension_fields(field_descriptors)
48
- field_descriptors.each do |field_descriptor|
49
- @groups[:extension_field] << FieldGenerator.new(field_descriptor, nil, indent_level)
50
- end
51
- end
52
-
53
- def add_extension_ranges(extension_ranges, &item_handler)
54
- @groups[:extension_range] = extension_ranges
55
- @handlers[:extension_range] = item_handler
56
- end
57
-
58
- def add_header(type, message)
59
- @headers[type] = message
60
- end
61
-
62
- def add_message_declarations(descriptors)
63
- descriptors.each do |descriptor|
64
- # elide synthetic map entry messages (we handle map fields differently)
65
- next if descriptor.options.try(:map_entry?) { false }
66
- @groups[:message_declaration] << MessageGenerator.new(descriptor, indent_level, :declaration => true)
67
- end
68
- end
69
-
70
- def add_message_fields(field_descriptors, msg_descriptor)
71
- field_descriptors.each do |field_descriptor|
72
- @groups[:field] << FieldGenerator.new(field_descriptor, msg_descriptor, indent_level)
73
- end
74
- end
75
-
76
- def add_messages(descriptors, options = {})
77
- descriptors.each do |descriptor|
78
- # elide synthetic map entry message (we handle map fields differently)
79
- next if descriptor.options.try(:map_entry?) { false }
80
- @groups[:message] << MessageGenerator.new(descriptor, indent_level, options)
81
- end
82
- end
83
-
84
- def add_services(service_descriptors)
85
- service_descriptors.each do |service_descriptor|
86
- @groups[:service] << ServiceGenerator.new(service_descriptor, indent_level)
87
- end
88
- end
89
-
90
- def compile
91
- @order.each do |type|
92
- items = @groups[type]
93
- next if items.empty?
94
-
95
- item_handler = @handlers[type]
96
-
97
- item_header = @headers[type]
98
- header(item_header) if item_header
99
-
100
- item_comment = @comments[type]
101
- comment(item_comment) if item_comment
102
-
103
- items.each do |item|
104
- if item_handler
105
- puts item_handler.call(item)
106
- else
107
- print item.to_s
108
- end
109
- end
110
-
111
- puts if type == :message_declaration || type == :options
112
- end
113
- end
114
-
115
- def to_s
116
- compile
117
- print_contents
118
- end
119
-
120
- end
121
- end
122
- end
@@ -1,104 +0,0 @@
1
- require 'protobuf/generators/base'
2
- require 'protobuf/generators/group_generator'
3
-
4
- module Protobuf
5
- module Generators
6
- class MessageGenerator < Base
7
-
8
- def initialize(descriptor, indent_level, options = {})
9
- super
10
- @only_declarations = options.fetch(:declaration) { false }
11
- @extension_fields = options.fetch(:extension_fields) { {} }
12
- end
13
-
14
- def compile
15
- run_once(:compile) do
16
- if @only_declarations
17
- compile_declaration
18
- else
19
- compile_message
20
- end
21
- end
22
- end
23
-
24
- def compile_declaration
25
- run_once(:compile_declaration) do
26
- if printable?
27
- print_class(descriptor.name, :message) do
28
- group = GroupGenerator.new(current_indent)
29
- group.add_enums(descriptor.enum_type, :namespace => type_namespace)
30
- group.add_message_declarations(descriptor.nested_type)
31
- print group.to_s
32
- end
33
- else
34
- print_class(descriptor.name, :message)
35
- end
36
- end
37
- end
38
-
39
- def compile_message
40
- run_once(:compile_message) do
41
- if printable?
42
- print_class(descriptor.name, nil) do
43
- group = GroupGenerator.new(current_indent)
44
- group.add_messages(descriptor.nested_type, :extension_fields => @extension_fields, :namespace => type_namespace)
45
- group.add_comment(:options, 'Message Options')
46
- group.add_options(descriptor.options) if options?
47
- group.add_message_fields(descriptor.field, descriptor)
48
- self.class.validate_tags(fully_qualified_type_namespace, descriptor.field.map(&:number))
49
-
50
- group.add_comment(:extension_range, 'Extension Fields')
51
- group.add_extension_ranges(descriptor.extension_range) do |extension_range|
52
- "extensions #{extension_range.start}...#{extension_range.end}"
53
- end
54
-
55
- group.add_extension_fields(message_extension_fields)
56
-
57
- group.order = [:message, :options, :field, :extension_range, :extension_field]
58
- print group.to_s
59
- end
60
- end
61
- end
62
- end
63
-
64
- private
65
-
66
- def extensions?
67
- !message_extension_fields.empty?
68
- end
69
-
70
- def fields?
71
- descriptor.field.count > 0
72
- end
73
-
74
- def options?
75
- descriptor.options
76
- end
77
-
78
- def nested_enums?
79
- descriptor.enum_type.count > 0
80
- end
81
-
82
- def nested_messages?
83
- descriptor.nested_type.count > 0
84
- end
85
-
86
- def nested_types?
87
- nested_enums? || nested_messages?
88
- end
89
-
90
- def printable?
91
- if @only_declarations
92
- nested_types?
93
- else
94
- fields? || nested_messages? || extensions? || options?
95
- end
96
- end
97
-
98
- def message_extension_fields
99
- @extension_fields.fetch(fully_qualified_type_namespace) { [] }
100
- end
101
-
102
- end
103
- end
104
- end
@@ -1,17 +0,0 @@
1
- require 'protobuf/generators/base'
2
-
3
- module Protobuf
4
- module Generators
5
- class OptionGenerator < Base
6
- def compile
7
- run_once(:compile) do
8
- descriptor.each_field.map do |field, value|
9
- next unless descriptor.field?(field.name)
10
- serialized_value = serialize_value(value)
11
- puts "set_option #{field.fully_qualified_name.inspect}, #{serialized_value}"
12
- end
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,160 +0,0 @@
1
- module Protobuf
2
- module Generators
3
- module Printable
4
-
5
- PARENT_CLASS_MESSAGE = "::Protobuf::Message".freeze
6
- PARENT_CLASS_ENUM = "::Protobuf::Enum".freeze
7
- PARENT_CLASS_SERVICE = "::Protobuf::Rpc::Service".freeze
8
-
9
- # Initialize the printer.
10
- # Must be called by any class/module that includes the Printable module.
11
- #
12
- def init_printer(indent_level)
13
- @io = ::StringIO.new
14
- self.current_indent = indent_level.to_i
15
- end
16
-
17
- protected
18
-
19
- attr_accessor :current_indent
20
-
21
- private
22
-
23
- # Print a one-line comment.
24
- #
25
- def comment(message)
26
- puts "# #{message}"
27
- end
28
-
29
- # Print a "header" comment.
30
- #
31
- # header("Lorem ipsum dolor")
32
- # ##
33
- # # Lorem ipsum dolor
34
- # #
35
- def header(message)
36
- puts
37
- puts "##"
38
- puts "# #{message}"
39
- puts "#"
40
- end
41
-
42
- # Increase the indent level. An outdent will only occur if given a block
43
- # (after the block is finished).
44
- #
45
- def indent
46
- self.current_indent += 1
47
- yield
48
- outdent
49
- end
50
-
51
- # Take a string and upcase the first character of each namespace.
52
- # Due to the nature of varying standards about how class/modules are named
53
- # (e.g. CamelCase, Underscore_Case, SCREAMING_SNAKE_CASE), we only want
54
- # to capitalize the first character to ensure ruby will treat the value
55
- # as a constant. Otherwise we do not attempt to change the
56
- # token's definition.
57
- #
58
- # modulize("foo.bar.Baz") -> "::Foo::Bar::Baz"
59
- # modulize("foo.bar.baz") -> "::Foo::Bar::Baz"
60
- # modulize("foo.bar.BAZ") -> "::Foo::Bar::BAZ"
61
- #
62
- def modulize(name)
63
- name = name.gsub(/\./, '::')
64
- name = name.gsub(/(^(?:::)?[a-z]|::[a-z])/, &:upcase)
65
- name
66
- end
67
-
68
- # Decrease the indent level. Cannot be negative.
69
- #
70
- def outdent
71
- self.current_indent -= 1 unless current_indent.zero?
72
- end
73
-
74
- # Return the parent class for a given type.
75
- # Valid types are :message, :enum, and :service, otherwise an error
76
- # will be thrown.
77
- #
78
- def parent_class(type)
79
- case type
80
- when :message then
81
- PARENT_CLASS_MESSAGE
82
- when :enum then
83
- PARENT_CLASS_ENUM
84
- when :service then
85
- PARENT_CLASS_SERVICE
86
- else
87
- fail "Unknown parent class type #{type}: #{caller[0..5].join("\n")}"
88
- end
89
- end
90
-
91
- # Print a class or module block, indicated by type.
92
- # If a class, can be given a parent class to inherit from.
93
- # If a block is given, call the block from within an indent block.
94
- # Otherwise, end the block on the same line.
95
- #
96
- def print_block(name, parent_klass, type)
97
- name = modulize(name)
98
- block_def = "#{type} #{name}"
99
- block_def += " < #{parent_class(parent_klass)}" if parent_klass
100
-
101
- if block_given?
102
- puts block_def
103
- indent { yield }
104
- puts "end"
105
- puts
106
- else
107
- block_def += "; end"
108
- puts block_def
109
- end
110
- end
111
-
112
- # Use print_block to print a class, with optional parent class
113
- # to inherit from. Accepts a block for use with print_block.
114
- #
115
- def print_class(name, parent_klass, &block)
116
- print_block(name, parent_klass, :class, &block)
117
- end
118
-
119
- # Use print_block to print a module.
120
- # Accepts a block for use with print_block.
121
- #
122
- def print_module(name, &block)
123
- print_block(name, nil, :module, &block)
124
- end
125
-
126
- # Print a file require.
127
- #
128
- # print_require('foo/bar/baz') -> "require 'foo/bar/baz'"
129
- #
130
- def print_require(file, relative = false)
131
- puts "require#{'_relative' if relative} '#{file}'"
132
- end
133
-
134
- # Puts the given message prefixed by the indent level.
135
- # If no message is given print a newline.
136
- #
137
- def puts(message = nil)
138
- if message
139
- @io.puts((" " * current_indent) + message)
140
- else
141
- @io.puts
142
- end
143
- end
144
-
145
- # Print the given message raw, no indent.
146
- #
147
- def print(contents)
148
- @io.print(contents)
149
- end
150
-
151
- # Returns the contents of the underlying StringIO object.
152
- #
153
- def print_contents
154
- @io.rewind
155
- @io.read
156
- end
157
-
158
- end
159
- end
160
- end