skull_island 2.0.5 → 2.3.1

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.
@@ -44,7 +44,7 @@ module SkullIsland
44
44
  end
45
45
 
46
46
  def project=(project_id)
47
- unless project_id.is_a?(String) && project_id.match?(/^[\w_\-\.~]+$/)
47
+ unless project_id.is_a?(String) && project_id.match?(/^[\w_\-.~]+$/)
48
48
  raise Exceptions::InvalidArguments, 'project'
49
49
  end
50
50
 
@@ -16,6 +16,8 @@ module SkullIsland
16
16
 
17
17
  # rubocop:disable Style/GuardClause
18
18
  # rubocop:disable Security/Eval
19
+ # The delayed_set method allows a second phase of Erb templating immediately
20
+ # before sending data to the API. This allows the `lookup` function to work dynamically
19
21
  def delayed_set(property, data, key = property.to_s)
20
22
  if data[key]
21
23
  value = recursive_erubi(data[key])
@@ -27,11 +29,12 @@ module SkullIsland
27
29
  end
28
30
 
29
31
  def recursive_erubi(data)
30
- if data.is_a?(String)
32
+ case data
33
+ when String
31
34
  eval(Erubi::Engine.new(data).src)
32
- elsif data.is_a?(Array)
35
+ when Array
33
36
  data.map { |item| recursive_erubi(item) }
34
- elsif data.is_a?(Hash)
37
+ when Hash
35
38
  data.map { |k, v| [k, recursive_erubi(v)] }.to_h
36
39
  else
37
40
  data
@@ -72,7 +75,7 @@ module SkullIsland
72
75
  end
73
76
 
74
77
  def host_regex
75
- /^(([\w]|[\w][\w\-]*[\w])\.)*([\w]|[\w][\w\-]*[\w])$/
78
+ /^((\w|\w[\w\-]*\w)\.)*(\w|\w[\w\-]*\w)$/
76
79
  end
77
80
 
78
81
  def id_property
@@ -87,9 +90,8 @@ module SkullIsland
87
90
  self.class.immutable?
88
91
  end
89
92
 
90
- # rubocop:disable Metrics/CyclomaticComplexity
91
93
  # rubocop:disable Metrics/PerceivedComplexity
92
- def import_update_or_skip(verbose: false, test: false, index:)
94
+ def import_update_or_skip(index:, verbose: false, test: false)
93
95
  if find_by_digest
94
96
  puts "[INFO] Skipping #{self.class} index #{index} (#{id})" if verbose
95
97
  elsif test
@@ -102,12 +104,16 @@ module SkullIsland
102
104
  puts "[ERR] Failed to save #{self.class} index #{index}"
103
105
  end
104
106
  end
105
- # rubocop:enable Metrics/CyclomaticComplexity
107
+
106
108
  # rubocop:enable Metrics/PerceivedComplexity
107
109
 
108
110
  # Looks up IDs (and usually wraps them in a Hash)
109
111
  def lookup(type, value, raw = false)
110
112
  id_value = case type
113
+ when :ca_certificate
114
+ Resources::CACertificate.find(:name, value).id
115
+ when :certificate
116
+ Resources::Certificate.find(:name, value).id
111
117
  when :consumer
112
118
  Resources::Consumer.find(:username, value).id
113
119
  when :route
@@ -209,6 +215,9 @@ module SkullIsland
209
215
  @api_client.invalidate_cache_for(self.class.relative_uri.to_s) # clear any collection class
210
216
  @tainted = false
211
217
  true
218
+ rescue RestClient::BadRequest => e
219
+ warn "[WARN] Failed to save #{self.class} via #{new? ? save_uri : relative_uri} with " \
220
+ "'#{e.message}':\n#{saveable_data.to_yaml}\n\nReceived: #{e.inspect}"
212
221
  end
213
222
 
214
223
  def save_uri
@@ -11,7 +11,7 @@ module SkullIsland
11
11
  attr_reader :max_size, :keys
12
12
 
13
13
  # @raise [Exceptions::InvalidCacheSize] if the max_size isn't an Integer
14
- def initialize(max_size = 100)
14
+ def initialize(max_size = 10_000)
15
15
  raise Exceptions::InvalidCacheSize unless max_size.is_a?(Integer)
16
16
 
17
17
  @max_size = max_size
@@ -57,9 +57,10 @@ module SkullIsland
57
57
  define_method(method_name) do |value|
58
58
  raise Exceptions::ImmutableModification if immutable?
59
59
 
60
- if opts[:validate]
61
- raise Exceptions::InvalidArguments, name unless send("validate_#{name}".to_sym, value)
60
+ if opts[:validate] && !send("validate_#{name}".to_sym, value)
61
+ raise Exceptions::InvalidArguments, name
62
62
  end
63
+
63
64
  @entity[name.to_s] = if opts[:preprocess]
64
65
  send("preprocess_#{name}".to_sym, value)
65
66
  else
@@ -121,7 +122,7 @@ module SkullIsland
121
122
  )
122
123
  end
123
124
 
124
- def self.from_hash(hash)
125
+ def self.from_hash(hash, options = {})
125
126
  # TODO: better options validations
126
127
  raise Exceptions::InvalidOptions unless options.is_a?(Hash)
127
128
 
@@ -161,9 +161,10 @@ module SkullIsland
161
161
  # use #merge
162
162
  # @return [ResourceCollection]
163
163
  def +(other)
164
- if other.is_a?(self.class)
164
+ case other
165
+ when self.class
165
166
  self.class.new(@list + other.to_a, type: @type, api_client: @api_client)
166
- elsif other.is_a?(@type)
167
+ when @type
167
168
  self.class.new(@list + [other], type: @type, api_client: @api_client)
168
169
  else
169
170
  raise Exceptions::InvalidArguments
@@ -171,7 +172,7 @@ module SkullIsland
171
172
  end
172
173
 
173
174
  def <<(other)
174
- raise Exceptions::InvalidArguments, 'Resource Type Mismatch' unless other.class == @type
175
+ raise Exceptions::InvalidArguments, 'Resource Type Mismatch' unless other.instance_of?(@type)
175
176
 
176
177
  @list << other
177
178
  end
@@ -12,7 +12,10 @@ module SkullIsland
12
12
  property :cert, required: true, validate: true
13
13
  property :created_at, read_only: true, postprocess: true
14
14
  property :tags, validate: true, preprocess: true, postprocess: true
15
+ # property :name
15
16
 
17
+ # rubocop:disable Metrics/CyclomaticComplexity
18
+ # rubocop:disable Metrics/PerceivedComplexity
16
19
  def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
17
20
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
18
21
 
@@ -22,6 +25,7 @@ module SkullIsland
22
25
  resource = new
23
26
  resource.delayed_set(:cert, resource_data)
24
27
  resource.tags = resource_data['tags'] if resource_data['tags']
28
+ resource.name = resource_data['name'] if resource_data['name']
25
29
  resource.project = project if project
26
30
  resource.import_time = (time || Time.now.utc.to_i) if project
27
31
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
@@ -32,10 +36,13 @@ module SkullIsland
32
36
 
33
37
  known_ids
34
38
  end
39
+ # rubocop:enable Metrics/CyclomaticComplexity
40
+ # rubocop:enable Metrics/PerceivedComplexity
35
41
 
36
42
  def export(options = {})
37
43
  hash = { 'cert' => cert }
38
44
  hash['tags'] = tags unless tags.empty?
45
+ hash['name'] = name if name
39
46
  [*options[:exclude]].each do |exclude|
40
47
  hash.delete(exclude.to_s)
41
48
  end
@@ -48,10 +55,19 @@ module SkullIsland
48
55
  def modified_existing?
49
56
  return false unless new?
50
57
 
51
- # Find CA certs of the same cert
52
- same_cert = self.class.where(:cert, cert)
58
+ # Find CA certs of the same "name"
59
+ if name
60
+ same_name = self.class.where(:name, name)
53
61
 
54
- existing = same_cert.size == 1 ? same_cert.first : nil
62
+ existing = same_name.size == 1 ? same_name.first : nil
63
+ end
64
+
65
+ unless existing
66
+ # Find CA certs of the same cert
67
+ same_cert = self.class.where(:cert, cert)
68
+
69
+ existing = same_cert.size == 1 ? same_cert.first : nil
70
+ end
55
71
 
56
72
  if existing
57
73
  @entity['id'] = existing.id
@@ -61,6 +77,16 @@ module SkullIsland
61
77
  end
62
78
  end
63
79
 
80
+ # Simulates retrieving a #name property via a tag
81
+ def name
82
+ metatags['name']
83
+ end
84
+
85
+ # Simulates setting a #name property via a tag
86
+ def name=(value)
87
+ add_meta('name', value.to_s)
88
+ end
89
+
64
90
  private
65
91
 
66
92
  # Used to validate {#cert} on set
@@ -12,11 +12,12 @@ module SkullIsland
12
12
  property :cert, required: true, validate: true
13
13
  property :key, required: true, validate: true
14
14
  property :snis, validate: true
15
+ # property :name
15
16
  property :created_at, read_only: true, postprocess: true
16
17
  property :tags, validate: true, preprocess: true, postprocess: true
17
18
 
18
- # rubocop:disable Metrics/CyclomaticComplexity
19
19
  # rubocop:disable Metrics/PerceivedComplexity
20
+ # rubocop:disable Metrics/CyclomaticComplexity
20
21
  def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
21
22
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
22
23
 
@@ -28,6 +29,7 @@ module SkullIsland
28
29
  resource.delayed_set(:key, resource_data)
29
30
  resource.snis = resource_data['snis'] if resource_data['snis']
30
31
  resource.tags = resource_data['tags'] if resource_data['tags']
32
+ resource.name = resource_data['name'] if resource_data['name']
31
33
  resource.project = project if project
32
34
  resource.import_time = (time || Time.now.utc.to_i) if project
33
35
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
@@ -38,13 +40,15 @@ module SkullIsland
38
40
 
39
41
  known_ids
40
42
  end
41
- # rubocop:enable Metrics/CyclomaticComplexity
42
43
  # rubocop:enable Metrics/PerceivedComplexity
44
+ # rubocop:enable Metrics/CyclomaticComplexity
43
45
 
46
+ # rubocop:disable Metrics/AbcSize
44
47
  def export(options = {})
45
48
  hash = { 'cert' => cert, 'key' => key }
46
49
  hash['snis'] = snis if snis && !snis.empty?
47
50
  hash['tags'] = tags unless tags.empty?
51
+ hash['name'] = name if name
48
52
  [*options[:exclude]].each do |exclude|
49
53
  hash.delete(exclude.to_s)
50
54
  end
@@ -53,14 +57,24 @@ module SkullIsland
53
57
  end
54
58
  hash.reject { |_, value| value.nil? }
55
59
  end
60
+ # rubocop:enable Metrics/AbcSize
56
61
 
57
62
  def modified_existing?
58
63
  return false unless new?
59
64
 
60
- # Find certs of the same cert and key
61
- same_key = self.class.where(:key, key)
65
+ # Find certs of the same "name"
66
+ if name
67
+ same_name = self.class.where(:name, name)
68
+
69
+ existing = same_name.size == 1 ? same_name.first : nil
70
+ end
71
+
72
+ unless existing
73
+ # Find certs of the same cert and key
74
+ same_key = self.class.where(:key, key)
62
75
 
63
- existing = same_key.size == 1 ? same_key.first : nil
76
+ existing = same_key.size == 1 ? same_key.first : nil
77
+ end
64
78
 
65
79
  if existing
66
80
  @entity['id'] = existing.id
@@ -70,6 +84,16 @@ module SkullIsland
70
84
  end
71
85
  end
72
86
 
87
+ # Simulates retrieving a #name property via a tag
88
+ def name
89
+ metatags['name']
90
+ end
91
+
92
+ # Simulates setting a #name property via a tag
93
+ def name=(value)
94
+ add_meta('name', value.to_s)
95
+ end
96
+
73
97
  private
74
98
 
75
99
  # Used to validate {#cert} on set
@@ -60,7 +60,7 @@ module SkullIsland
60
60
 
61
61
  known_acls = AccessControlList.batch_import(
62
62
  (
63
- resource_data.dig('acls') || []
63
+ resource_data['acls'] || []
64
64
  ).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
65
65
  verbose: verbose,
66
66
  test: test
@@ -105,9 +105,10 @@ module SkullIsland
105
105
  end
106
106
 
107
107
  def add_acl!(details)
108
- r = if details.is_a?(AccessControlList)
108
+ r = case details
109
+ when AccessControlList
109
110
  details
110
- elsif details.is_a?(String)
111
+ when String
111
112
  resource = AccessControlList.new(api_client: api_client)
112
113
  resource.group = details
113
114
  resource
@@ -164,6 +165,7 @@ module SkullIsland
164
165
  Plugin.where(:consumer, self, api_client: api_client)
165
166
  end
166
167
 
168
+ # rubocop:disable Metrics/AbcSize
167
169
  def export(options = {})
168
170
  hash = { 'username' => username, 'custom_id' => custom_id }
169
171
  creds = credentials_for_export
@@ -178,6 +180,7 @@ module SkullIsland
178
180
  end
179
181
  hash.reject { |_, value| value.nil? }
180
182
  end
183
+ # rubocop:enable Metrics/AbcSize
181
184
 
182
185
  def modified_existing?
183
186
  return false unless new?
@@ -48,6 +48,7 @@ module SkullIsland
48
48
  consumer ? "#{consumer.relative_uri}/jwt" : nil
49
49
  end
50
50
 
51
+ # rubocop:disable Metrics/AbcSize
51
52
  def export(options = {})
52
53
  hash = { 'algorithm' => algorithm }
53
54
  hash['key'] = key if key
@@ -62,6 +63,7 @@ module SkullIsland
62
63
  end
63
64
  hash.reject { |_, value| value.nil? }
64
65
  end
66
+ # rubocop:enable Metrics/AbcSize
65
67
 
66
68
  # Keys can't be updated, only created or deleted
67
69
  def modified_existing?
@@ -21,6 +21,7 @@ module SkullIsland
21
21
 
22
22
  # rubocop:disable Metrics/CyclomaticComplexity
23
23
  # rubocop:disable Metrics/PerceivedComplexity
24
+ # rubocop:disable Metrics/AbcSize
24
25
  def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
25
26
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
26
27
 
@@ -48,6 +49,7 @@ module SkullIsland
48
49
  end
49
50
  # rubocop:enable Metrics/CyclomaticComplexity
50
51
  # rubocop:enable Metrics/PerceivedComplexity
52
+ # rubocop:enable Metrics/AbcSize
51
53
 
52
54
  def self.enabled_names(api_client: APIClient.instance)
53
55
  api_client.get("#{relative_uri}/enabled")['enabled_plugins']
@@ -123,14 +125,15 @@ module SkullIsland
123
125
  end
124
126
 
125
127
  def postprocess_consumer(value)
126
- if value.is_a?(Hash)
128
+ case value
129
+ when Hash
127
130
  Consumer.new(
128
131
  entity: value,
129
132
  lazy: true,
130
133
  tainted: false,
131
134
  api_client: api_client
132
135
  )
133
- elsif value.is_a?(String)
136
+ when String
134
137
  Consumer.new(
135
138
  entity: { 'id' => value },
136
139
  lazy: true,
@@ -143,9 +146,10 @@ module SkullIsland
143
146
  end
144
147
 
145
148
  def preprocess_consumer(input)
146
- if input.is_a?(Hash)
149
+ case input
150
+ when Hash
147
151
  input
148
- elsif input.is_a?(Consumer)
152
+ when Consumer
149
153
  { 'id' => input.id }
150
154
  else
151
155
  input
@@ -153,14 +157,15 @@ module SkullIsland
153
157
  end
154
158
 
155
159
  def postprocess_route(value)
156
- if value.is_a?(Hash)
160
+ case value
161
+ when Hash
157
162
  Route.new(
158
163
  entity: value,
159
164
  lazy: true,
160
165
  tainted: false,
161
166
  api_client: api_client
162
167
  )
163
- elsif value.is_a?(String)
168
+ when String
164
169
  Route.new(
165
170
  entity: { 'id' => value },
166
171
  lazy: true,
@@ -173,9 +178,10 @@ module SkullIsland
173
178
  end
174
179
 
175
180
  def preprocess_route(input)
176
- if input.is_a?(Hash)
181
+ case input
182
+ when Hash
177
183
  input
178
- elsif input.is_a?(Route)
184
+ when Route
179
185
  { 'id' => input.id }
180
186
  else
181
187
  input
@@ -183,14 +189,15 @@ module SkullIsland
183
189
  end
184
190
 
185
191
  def postprocess_service(value)
186
- if value.is_a?(Hash)
192
+ case value
193
+ when Hash
187
194
  Service.new(
188
195
  entity: value,
189
196
  lazy: true,
190
197
  tainted: false,
191
198
  api_client: api_client
192
199
  )
193
- elsif value.is_a?(String)
200
+ when String
194
201
  Service.new(
195
202
  entity: { 'id' => value },
196
203
  lazy: true,
@@ -203,9 +210,10 @@ module SkullIsland
203
210
  end
204
211
 
205
212
  def preprocess_service(input)
206
- if input.is_a?(Hash)
213
+ case input
214
+ when Hash
207
215
  input
208
- elsif input.is_a?(Service)
216
+ when Service
209
217
  { 'id' => input.id }
210
218
  else
211
219
  input