cable_room 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 020faa2e6a7e8cd1027b4d5c7303d57ef1282ab4f298800df26d6336587082dc
4
- data.tar.gz: fae6de782ad1a15d7e065fbef53e71665ebb4606ecd75748fa7e574bd63ae393
3
+ metadata.gz: 319532a2546c5bbd96b89ca34c9a44ba963a5bc97bc62e5faacf8417cb815783
4
+ data.tar.gz: 2d1c92b8e36af65a69182537ba25b2ba5652569e21d398f9bccbd91011e6e411
5
5
  SHA512:
6
- metadata.gz: 24de44e3b78d19d72af29783069bf8ddd6ed87d03bb185c4e2fae9b79e159f6c2da7701f2a575cf54cb2a6baaf0a66ea4e4d65c7e84048694f33c8d6c19e2dd4
7
- data.tar.gz: 178caf0566a1420f7cb705d9076ae39a5cd664cd42da23619f9312f1feccc34b8afb55563aeb5acf8af700fe4046b6cad5f901b34c6d9bf2947d8c2f6ff08529
6
+ metadata.gz: 25afc8414cc55c14d41a72c2d8898c026d442f204744a1a67721e2fd6e6b6b9ea9013bfe727ba98984475c504b00eb95bda324fdf2c60a6e2b9269d5e3fb4e17
7
+ data.tar.gz: 903fa66437dec42ba12b87c49a0864b561b0b8b2f302de05f80482d8a086a1e7971ba5f03e04146e4905b6854f017c2d311e222393ba977cca9936d5b656f306
@@ -13,6 +13,22 @@ module CableRoom
13
13
  end
14
14
  end
15
15
 
16
+ def inbound_tag_policy(**kwargs, &blk)
17
+ if blk
18
+ self._port_policy_blocks = [*(_port_policy_blocks || []), {
19
+ **kwargs,
20
+ block: blk,
21
+ }]
22
+ else
23
+ @_tag_policy ||= TagPolicy.new().tap do |pol|
24
+ (_port_policy_blocks || []).each do |p|
25
+ pol.evaluate(**p.except(:block), &p[:block])
26
+ end
27
+ end
28
+ @_tag_policy
29
+ end
30
+ end
31
+
16
32
  def on_port_connected(...)
17
33
  set_callback(:port_connected, :before, ...)
18
34
  end
@@ -23,6 +39,8 @@ module CableRoom
23
39
  end
24
40
 
25
41
  included do
42
+ class_attribute :_port_policy_blocks, instance_writer: false, default: {}
43
+
26
44
  periodically :check_port_inactivity, every: PORT_TIMEOUT
27
45
 
28
46
  define_callbacks :port_connected, :port_disconnected
@@ -37,6 +55,16 @@ module CableRoom
37
55
  @current_message_origin = previous_mtok
38
56
  end
39
57
  end
58
+
59
+ authorize_inbound do |message|
60
+ msg_type = message['type'].to_s.underscore.to_sym
61
+ next true if %i[port_connected port_disconnected].include?(msg_type)
62
+ policy_allows?(msg_type)
63
+ end
64
+
65
+ inbound_tag_policy(priority: -10) do
66
+ allow :*, :connect
67
+ end
40
68
  end
41
69
 
42
70
  def initialize(...)
@@ -68,6 +96,10 @@ module CableRoom
68
96
 
69
97
  protected
70
98
 
99
+ def policy_allows?(method)
100
+ self.class.inbound_tag_policy.pass?(method, origin_tags)
101
+ end
102
+
71
103
  def on_port_disconnected(); end
72
104
 
73
105
  def on_port_connected(); end
@@ -93,6 +125,11 @@ module CableRoom
93
125
  origin_tags.include?(tag)
94
126
  end
95
127
 
128
+ def tag_origin!(*tags)
129
+ port_data[:tags] ||= Set.new
130
+ port_data[:tags].merge(tags.flatten.map(&:to_sym))
131
+ end
132
+
96
133
  def handle_received_message(message)
97
134
  case message['type']
98
135
  when 'port_connected'
@@ -101,14 +138,20 @@ module CableRoom
101
138
  touch_port_activity
102
139
 
103
140
  mdata.merge! ::ActiveJob::Arguments.deserialize(message['extra'])[0] if message['extra'].present?
104
- mdata[:tags] = Array(message['tags']).map(&:to_sym) if message['tags'].present?
141
+ tag_origin!(message['tags'])
105
142
 
106
- run_callbacks :port_connected do
107
- on_port_connected
143
+ if self.class.inbound_tag_policy.pass?(message['type'].to_sym, origin_tags)
144
+ run_callbacks :port_connected do
145
+ on_port_connected
146
+ end
147
+ else
148
+ @port_data.delete(origin_port)
108
149
  end
109
150
  when 'port_disconnected'
110
- run_callbacks :port_disconnected do
111
- on_port_disconnected
151
+ if self.class.inbound_tag_policy.pass?(message['type'].to_sym, origin_tags)
152
+ run_callbacks :port_disconnected do
153
+ on_port_disconnected
154
+ end
112
155
  end
113
156
  @port_data.delete(origin_port)
114
157
  when 'port_ping'
@@ -131,6 +174,122 @@ module CableRoom
131
174
  @port_data.delete(mtok)
132
175
  end
133
176
  end
177
+
178
+ class TagPolicy
179
+ ALIASES = {}
180
+
181
+ def self.define_tag_alias(key, implies)
182
+ Array(implies).each do |i|
183
+ ALIASES[i] ||= Set.new
184
+ ALIASES[i] << key
185
+ end
186
+ end
187
+
188
+ define_tag_alias :connect, [:port_connected, :port_ping, :port_disconnected]
189
+
190
+ def initialize()
191
+ @policy_rules = []
192
+ @fallback_rule = { action: :allow, priority: -100, tag: :*, methods: :* }
193
+ append_rule(@fallback_rule)
194
+ end
195
+
196
+ def pass?(method, user_tags)
197
+ user_tags = Set.new(Array(user_tags).map(&:to_sym))
198
+ find_rules_for(method).each do |r|
199
+ if r[:tag] == :* || user_tags.include?(r[:tag])
200
+ return r[:action] == :allow
201
+ end
202
+ end
203
+
204
+ false
205
+ end
206
+
207
+ def evaluate(priority: 10, &blk)
208
+ @fallback_rule[:action] = :deny if priority > 0
209
+
210
+ p = @rule_priority
211
+ @rule_priority = priority
212
+ instance_exec(&blk)
213
+ ensure
214
+ @rule_priority = p
215
+ end
216
+
217
+ protected
218
+
219
+ def allow(tag = :*, methods = :*)
220
+ append_rule({
221
+ action: :allow,
222
+ tag: tag,
223
+ methods: methods,
224
+ })
225
+ end
226
+
227
+ def deny(tag = :*, methods = :*)
228
+ append_rule({
229
+ action: :deny,
230
+ tag: tag,
231
+ methods: methods,
232
+ })
233
+ end
234
+
235
+ private
236
+
237
+ def append_rule(rule)
238
+ rule[:methods] = Set.new(Array(rule[:methods]).map(&:to_sym))
239
+ rule[:priority] ||= @rule_priority || 10
240
+ @policy_rules << rule
241
+ end
242
+
243
+ def find_rules_for(method)
244
+ rules ||= select_ruleset(@policy_rules, method).presence
245
+ rules ||= []
246
+
247
+ rules.sort_by! { |r| -r[:priority] }
248
+
249
+ rules
250
+ end
251
+
252
+ def select_ruleset(set, method)
253
+ all_aliases = Set.new
254
+ all_aliases << method
255
+
256
+ bfs(method) do |m|
257
+ all_aliases.merge(ALIASES[m] || [])
258
+ ALIASES[m]
259
+ end
260
+
261
+ all_aliases << :*
262
+
263
+ rules = set.select { |r| (Set.new(r[:methods]) & all_aliases).count > 0 }.sort_by { |r| -r[:priority] }
264
+
265
+ rules
266
+ end
267
+
268
+ def bfs(base, children = nil)
269
+ q = [base]
270
+ seen = Set.new
271
+ until q.empty?
272
+ n = q.shift
273
+ next if seen.include?(n)
274
+ seen << n
275
+
276
+ catch :end_branch do
277
+ value = catch :found do
278
+ result = yield n
279
+ next_set = children ? children.call(n) : Array(result)
280
+ (next_set || []).each do |c|
281
+ q << c unless seen.include?(c)
282
+ end
283
+ throw :end_branch
284
+ end
285
+
286
+ return value || n
287
+ end
288
+ end
289
+
290
+ nil
291
+ end
292
+ end
134
293
  end
135
294
  end
136
295
  end
@@ -18,10 +18,16 @@ module CableRoom
18
18
  set_callback(:port_disconnected, :after, :_handle_user_cleanup_after_disconnection)
19
19
 
20
20
  define_callbacks :user_joined, :user_left
21
+
22
+ inbound_tag_policy(priority: -10) do
23
+ allow :*, :join
24
+ end
25
+
26
+ PortManagement::TagPolicy.define_tag_alias :join, [:connect, :user_joined, :user_left]
21
27
  end
22
28
 
23
29
  def initialize(...)
24
- @_user_state_map = {}c
30
+ @_user_state_map = {}
25
31
  @_user_map_mutex = Monitor.new
26
32
  super
27
33
  end
@@ -93,6 +99,8 @@ module CableRoom
93
99
 
94
100
  def _user_state_transaction(user = origin_user)
95
101
  return unless user.present?
102
+ return unless policy_allows?(:join)
103
+
96
104
  @_user_map_mutex.synchronize do
97
105
  usm = @_user_state_map[user]
98
106
  yield usm, user
@@ -1,3 +1,3 @@
1
1
  module CableRoom
2
- VERSION = "0.2.0".freeze
2
+ VERSION = "0.3.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cable_room
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan Knapp