verifica 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8df98ff228b89e7701f41df3d5617d93183e83c32cdae5c879e347c615f367d7
4
- data.tar.gz: 956259725d32e5a6208a03f2a07d682d6facbb1dcaae107687ce59cd1cd8363c
3
+ metadata.gz: ccea0b2769fa053006c2ec3d0b4cd0d3cc65a3a4b4375ce390dabe3a093f490d
4
+ data.tar.gz: 0bb0dd63b30f08a1df1af771671312182cde2c159613094f9fd0c664201b6e24
5
5
  SHA512:
6
- metadata.gz: d3329c9e126220d43a8e9b4a7923541b30139e74f565387bed6012acea9760239d1b5850d19ee2963e63252ddde3008e39486ac66438e6e9215afe18de0d4256
7
- data.tar.gz: 1dab1e7bab877e5f63298240db13270c6f46c238643f508037e81f524a99a54f3613e3515690e54886ac032b371d394622e51d5d33d92528ddab8560d7babb2e
6
+ metadata.gz: 5c3bfab0ce9ccd36cd91baadcc4454e462c9a5d098c6295d3073040d3291030e516d7ae90d200b55b84d4cafd51cd0118c51a1e5a5e0ee075d54e18528033d01
7
+ data.tar.gz: 6f6011eaec5b7f8a1d810233350a8a68cb7fdf7cf86d8bdc069d51478826ce847461c9d53e5c5f7e83922ac956cb3c1546fd957cb973c5dfee1a71cbc7258726
data/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.0.1] - 2023-04-15
11
+
12
+ ### Added
13
+
14
+ - `Sid#country_sid` and `Sid#group_sid` helper methods
15
+
10
16
  ## [1.0.0] - 2023-01-19
11
17
 
12
18
  Initial public release
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
+ [![Gem Version](https://badge.fury.io/rb/verifica.svg)](https://badge.fury.io/rb/verifica)
1
2
  [![CI](https://github.com/maximgurin/verifica/actions/workflows/ci.yml/badge.svg)](https://github.com/maximgurin/verifica/actions/workflows/ci.yml)
3
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/maximgurin/verifica)
2
4
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/457e56b0bb514539844a94d85abe99f9)](https://www.codacy.com/gh/maximgurin/verifica/dashboard?utm_source=github.com&utm_medium=referral&utm_content=maximgurin/verifica&utm_campaign=Badge_Grade)
3
5
  [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/457e56b0bb514539844a94d85abe99f9)](https://www.codacy.com/gh/maximgurin/verifica/dashboard?utm_source=github.com&utm_medium=referral&utm_content=maximgurin/verifica&utm_campaign=Badge_Coverage)
4
6
  ![GitHub](https://img.shields.io/github/license/maximgurin/verifica)
@@ -22,7 +24,7 @@ But anyway, trust nothing. DYOR.*
22
24
 
23
25
  ## Why Verifica? Isn't Pundit or CanCanCan enough?
24
26
 
25
- Let's say you working on a video platform application:
27
+ Let's say you are working on a video platform application:
26
28
 
27
29
  - You have 10M videos in the database
28
30
  - 7 types of user roles
@@ -70,7 +72,7 @@ authorizer = Verifica.authorizer do |config|
70
72
  end
71
73
 
72
74
  public_video = Video.new(id: 1, author_id: 1000, public: true)
73
- private_video = Video.new(id: 2, author_id: 1000, public: true)
75
+ private_video = Video.new(id: 2, author_id: 1000, public: false)
74
76
 
75
77
  superuser = User.new(id: 777, role: "root")
76
78
  video_author = User.new(id: 1000, role: "user")
@@ -184,9 +186,9 @@ end
184
186
 
185
187
  video_acl.to_a
186
188
  # =>
187
- # [#<Verifica::Ace:0x00007fab1955dd60 @action=:view, @allow=true, @sid="authenticated">,
188
- # #<Verifica::Ace:0x00007fab1955dd10 @action=:comment, @allow=true, @sid="authenticated">,
189
- # #<Verifica::Ace:0x00007fab1955dc48 @action=:view, @allow=false, @sid="country:US">]
189
+ # [#<Verifica::Ace:0x00007fab1955dd60 @action=:read, @allow=true, @sid="authenticated">,
190
+ # #<Verifica::Ace:0x00007fab1955dd10 @action=:comment, @allow=true, @sid="authenticated">,
191
+ # #<Verifica::Ace:0x00007fab1955dc48 @action=:read, @allow=false, @sid="country:US">]
190
192
  ```
191
193
 
192
194
  ### AclProvider
@@ -210,8 +212,8 @@ end
210
212
  ### Authorizer
211
213
 
212
214
  And finally, Authorizer, the heart of Verifica. It couples all concepts above into an isolated container with no global state.
213
- Each Authorizer has a list of resource types registered with their companion AclProviders.
214
- And most importantly, Authorizer has several methods to check the Subject's rights to perform a specific action on a given resource.
215
+ Each Authorizer has a list of resource types registered with their companion AclProviders and
216
+ several methods to check the Subject's rights to perform a specific action on a given resource.
215
217
 
216
218
  Check the [Basic example](#basic-example) above to see how it all plays together.
217
219
 
@@ -318,11 +320,11 @@ class User < ApplicationRecord
318
320
  when "moderator"
319
321
  [user_sid(id), role_sid("moderator")]
320
322
  when "user"
321
- sids = [authenticated_sid, user_sid(id), "country:#{country}"]
323
+ sids = [authenticated_sid, user_sid(id), country_sid(country)]
322
324
  organization_id.try { |org_id| sids.push(organization_sid(org_id)) }
323
325
  sids
324
326
  when "organization_admin"
325
- sids = [authenticated_sid, user_sid(id), "country:#{country}"]
327
+ sids = [authenticated_sid, user_sid(id), country_sid(country)]
326
328
  sids.push(organization_sid(organization_id))
327
329
  sids.push(role_sid("organization_admin:#{organization_id}"))
328
330
  else
@@ -354,7 +356,7 @@ end
354
356
  ```
355
357
 
356
358
  ```ruby
357
- # app/models/user.rb
359
+ # app/models/video.rb
358
360
 
359
361
  class Video < ApplicationRecord
360
362
  attr_accessor :allowed_actions
@@ -383,7 +385,11 @@ end
383
385
 
384
386
  class VideosController
385
387
  def index
386
- @videos = Video.available_for(current_user).order(:name).limit(50)
388
+ @videos = Video
389
+ .includes(:distribution_setting, author: [:organization])
390
+ .available_for(current_user)
391
+ .order(:name)
392
+ .limit(50)
387
393
  end
388
394
 
389
395
  def show
@@ -415,8 +421,6 @@ run a background job to find all affected videos and update `read_allow_sids`, `
415
421
  Same applies to Distribution Settings and other dependencies.
416
422
  - **Rules change handling.** If implementation of `VideoAclProvider` changed you need to run a background job
417
423
  to update `read_allow_sids`, `read_deny_sids` columns for all videos.
418
- - **Cache, N+1 problem.** `VideoAclProvider` retrieves a chain of records associated with each video which leads to
419
- N+1 problem in a naive implementation.
420
424
 
421
425
  See also:
422
426
 
data/lib/verifica/acl.rb CHANGED
@@ -54,7 +54,6 @@ module Verifica
54
54
 
55
55
  allow_deny[:allowed_sids].freeze
56
56
  allow_deny[:denied_sids].freeze
57
- allow_deny.freeze
58
57
  end
59
58
 
60
59
  @allowed_actions.freeze
@@ -154,7 +153,7 @@ module Verifica
154
153
 
155
154
  # @example
156
155
  # acl = Verifica::Acl.build { |acl| acl.allow "root", [:read, :write] }
157
- # acl.to_a.map(:to_h)
156
+ # acl.to_a.map(&:to_h)
158
157
  # # => [{:sid=>"root", :action=>:read, :allow=>true}, {:sid=>"root", :action=>:write, :allow=>true}]
159
158
  #
160
159
  # @return [Array<Ace>] a new array representing +self+
@@ -141,6 +141,7 @@ module Verifica
141
141
  def resource_acl(resource, **context)
142
142
  config = config_by_resource(resource)
143
143
  acl = config.acl_provider.call(resource, **context)
144
+ # trade-off flexibility to increase robustness here by requiring a specific type
144
145
  unless acl.is_a?(Verifica::Acl)
145
146
  type = resource.resource_type
146
147
  raise Error, "'#{type}' resource acl_provider should respond to #call with Acl object but got '#{acl.class}'"
data/lib/verifica/sid.rb CHANGED
@@ -211,5 +211,66 @@ module Verifica
211
211
 
212
212
  "org:#{organization_id}".freeze
213
213
  end
214
+
215
+ # Security Identifier of the subject who is a member of the group with given +group_id+
216
+ #
217
+ # @note (see #user_sid)
218
+ #
219
+ # @example
220
+ # class PostAclProvider
221
+ # include Verifica::Sid
222
+ #
223
+ # def call(post, **)
224
+ # Verifica::Acl.build do |acl|
225
+ # post.editor_groups.each do |group_id|
226
+ # acl.allow group_sid(group_id), [:edit, :delete]
227
+ # end
228
+ #
229
+ # # ...
230
+ # end
231
+ # end
232
+ # end
233
+ #
234
+ # @return [String]
235
+ #
236
+ # @api public
237
+ def group_sid(group_id)
238
+ if group_id.nil?
239
+ raise ArgumentError, "Nil 'group_id' is unsafe. Use empty string if you absolutely need this behavior"
240
+ end
241
+
242
+ "group:#{group_id}".freeze
243
+ end
244
+
245
+ # Security Identifier of the subject whose country is the country with given +country_id+
246
+ #
247
+ # @note (see #user_sid)
248
+ #
249
+ # @example
250
+ # class PostAclProvider
251
+ # include Verifica::Sid
252
+ #
253
+ # def call(post, **)
254
+ # Verifica::Acl.build do |acl|
255
+ # acl.allow authenticated_sid, [:read, :comment]
256
+ # post.banned_countries.each do |country_id|
257
+ # acl.deny country_sid(country_id), [:read, :comment]
258
+ # end
259
+ #
260
+ # # ...
261
+ # end
262
+ # end
263
+ # end
264
+ #
265
+ # @return [String]
266
+ #
267
+ # @api public
268
+ def country_sid(country_id)
269
+ if country_id.nil?
270
+ raise ArgumentError, "Nil 'country_id' is unsafe. Use empty string if you absolutely need this behavior"
271
+ end
272
+
273
+ "country:#{country_id}".freeze
274
+ end
214
275
  end
215
276
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Verifica
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.1"
5
5
  end
data/lib/verifica.rb CHANGED
@@ -54,7 +54,7 @@ require_relative "verifica/version"
54
54
  # end
55
55
  #
56
56
  # public_video = Video.new(id: 1, author_id: 1000, public: true)
57
- # private_video = Video.new(id: 2, author_id: 1000, public: true)
57
+ # private_video = Video.new(id: 2, author_id: 1000, public: false)
58
58
  #
59
59
  # superuser = User.new(id: 777, role: "root")
60
60
  # video_author = User.new(id: 1000, role: "user")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: verifica
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxim Gurin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-19 00:00:00.000000000 Z
11
+ date: 2023-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -105,7 +105,7 @@ metadata:
105
105
  source_code_uri: https://github.com/maximgurin/verifica
106
106
  bug_tracker_uri: https://github.com/maximgurin/verifica/issues
107
107
  rubygems_mfa_required: 'true'
108
- post_install_message:
108
+ post_install_message:
109
109
  rdoc_options: []
110
110
  require_paths:
111
111
  - lib
@@ -120,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  - !ruby/object:Gem::Version
121
121
  version: '0'
122
122
  requirements: []
123
- rubygems_version: 3.4.3
124
- signing_key:
123
+ rubygems_version: 3.4.12
124
+ signing_key:
125
125
  specification_version: 4
126
126
  summary: The most scalable authorization solution for Ruby
127
127
  test_files: []