discretion 0.4.0.pre.alpha → 1.0.0.pre.alpha
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 +4 -4
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/README.md +4 -2
- data/Rakefile +4 -1
- data/discretion.gemspec +6 -0
- data/lib/discretion.rb +1 -1
- data/lib/discretion/can.rb +6 -4
- data/lib/discretion/current_viewer.rb +3 -0
- data/lib/discretion/discreet_model.rb +5 -1
- data/lib/discretion/helpers.rb +22 -2
- data/lib/discretion/railtie.rb +2 -0
- data/lib/discretion/version.rb +1 -1
- metadata +87 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a56b9cc6109e4904c4c4ffa1569af797b4e043a7
|
4
|
+
data.tar.gz: 77a3f57cd1628eee0ed41ca2ae4c71f032309829
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ec9587ef19c98cd89b9ed107c16907a9a7c3fe1316f58b86b6ac66e38c4bef621c959e1286d2f04466e6b4dea1168e12a8e20959b8b33a5395eaa9816c2bd7a
|
7
|
+
data.tar.gz: e3b5fcad23ef87209535356e5ea6d5c4c9d2bc3d60d4cc722c1a772ab05e92a420a6d4cb74fc2d87adcca341b44d61b80d44e2b13fa3db736d3b85ef88f89c01
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Discretion
|
2
2
|
|
3
|
+
**tldr; Discretion is a simple privacy/authorization framework for Rails projects. You define `can_see?(viewer)` methods in a model class to determine if a given viewer is allowed to view/load/read the model (record). If so, you can query and load the record as you normally would in Rails (e.g. using `find`, `where`, `limit`, ...). If not, then Discretion will throw an exception when you try to fetch the record. Something similar is done for writes as well.**
|
4
|
+
|
3
5
|
## Installation
|
4
6
|
|
5
7
|
Add this line to your application's Gemfile:
|
@@ -25,7 +27,7 @@ Or install it yourself as:
|
|
25
27
|
|
26
28
|
The idea is simple: we colocate the read and write policies with the model definitions themselves by defining `can_see?(viewer)` and optionally `can_write?(viewer)`. The semantics are straightforward: given a `viewer` (typically a `User` but can be anything you want -- more on this below), can that viewer see the record encapsulated by the model class?
|
27
29
|
|
28
|
-
For example, let's say we have a web app for a large non-profit organization which has staff who have to raise money from donors. So we might have models like `Donor`, `Staff`, and `Donation
|
30
|
+
For example, let's say we have a web app for a large non-profit organization which has staff who have to raise money from donors. So we might have models like `Donor`, `Staff`, and `Donation`. Below we will describe how we would set up authorization/privacy policies for these models using Discretion.
|
29
31
|
|
30
32
|
### Opt-In
|
31
33
|
|
@@ -185,7 +187,7 @@ Discretion is totally opaque and should not require any changes in how you query
|
|
185
187
|
|
186
188
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
187
189
|
|
188
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
190
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
189
191
|
|
190
192
|
## Contributing
|
191
193
|
|
data/Rakefile
CHANGED
data/discretion.gemspec
CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = 'https://github.com/abeland/discretion'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
|
+
spec.add_dependency 'activesupport'
|
17
18
|
spec.add_dependency 'rails', '~>5'
|
18
19
|
spec.add_dependency 'request_store', '~>1.3'
|
19
20
|
spec.required_ruby_version = '>= 2.2.2'
|
@@ -25,6 +26,11 @@ Gem::Specification.new do |spec|
|
|
25
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
27
|
spec.require_paths = ['lib']
|
27
28
|
|
29
|
+
spec.add_development_dependency 'activerecord'
|
28
30
|
spec.add_development_dependency 'bundler', '~> 1.15'
|
31
|
+
spec.add_development_dependency 'factory_bot_rails'
|
29
32
|
spec.add_development_dependency 'rake', '~> 10.0'
|
33
|
+
spec.add_development_dependency 'rspec'
|
34
|
+
spec.add_development_dependency 'rspec-rails'
|
35
|
+
spec.add_development_dependency 'sqlite3'
|
30
36
|
end
|
data/lib/discretion.rb
CHANGED
@@ -5,7 +5,7 @@ require 'discretion/errors'
|
|
5
5
|
require 'discretion/helpers'
|
6
6
|
require 'discretion/meta'
|
7
7
|
require 'discretion/middleware'
|
8
|
-
require 'discretion/railtie'
|
8
|
+
require 'discretion/railtie' if defined?(Rails)
|
9
9
|
require 'discretion/version'
|
10
10
|
|
11
11
|
ActiveRecord::Base.send(:include, Discretion::Meta) if defined?(ActiveRecord)
|
data/lib/discretion/can.rb
CHANGED
@@ -2,6 +2,7 @@ module Discretion
|
|
2
2
|
class << self
|
3
3
|
def can_see_record?(viewer, record)
|
4
4
|
return true unless record.is_a?(Discretion::DiscreetModel)
|
5
|
+
return true if Discretion::OMNISCIENT_VIEWER == viewer || Discretion::OMNIPOTENT_VIEWER == viewer
|
5
6
|
|
6
7
|
record.send(:can_see?, viewer)
|
7
8
|
end
|
@@ -10,16 +11,17 @@ module Discretion
|
|
10
11
|
can_see_record?(Discretion.current_viewer, record)
|
11
12
|
end
|
12
13
|
|
13
|
-
def can_write_record?(viewer, record)
|
14
|
+
def can_write_record?(viewer, record, changes, new_record)
|
14
15
|
return true unless record.is_a?(Discretion::DiscreetModel)
|
16
|
+
return true if Discretion::OMNIPOTENT_VIEWER == viewer
|
15
17
|
|
16
18
|
record.respond_to?(:can_write?, true) ?
|
17
|
-
record.send(:can_write?, viewer) :
|
19
|
+
record.send(:can_write?, viewer, changes, new_record) :
|
18
20
|
can_see_record?(viewer, record)
|
19
21
|
end
|
20
22
|
|
21
|
-
def current_viewer_can_write_record?(record)
|
22
|
-
can_write_record?(Discretion.current_viewer, record)
|
23
|
+
def current_viewer_can_write_record?(record, changes, new_record)
|
24
|
+
can_write_record?(Discretion.current_viewer, record, changes, new_record)
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
1
3
|
module Discretion
|
2
4
|
module DiscreetModel
|
3
5
|
extend ActiveSupport::Concern
|
@@ -8,7 +10,9 @@ module Discretion
|
|
8
10
|
end
|
9
11
|
|
10
12
|
before_save do |record|
|
11
|
-
|
13
|
+
unless Discretion.current_viewer_can_write_record?(record, changes, new_record?)
|
14
|
+
raise Discretion::CannotWriteError
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
data/lib/discretion/helpers.rb
CHANGED
@@ -12,8 +12,28 @@ module Discretion
|
|
12
12
|
records.all? { |record| Discretion.can_see_record?(viewer, record) }
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def omnisciently
|
16
|
+
# Calling Proc.new will create a Proc from the implicitly given block to
|
17
|
+
# the current method.
|
18
|
+
# cf. http://ruby-doc.org/core-2.5.0/Proc.html#method-c-new
|
19
|
+
with_viewer(Discretion::OMNISCIENT_VIEWER, &Proc.new)
|
20
|
+
end
|
21
|
+
|
22
|
+
def omnipotently
|
23
|
+
# Calling Proc.new will create a Proc from the implicitly given block to
|
24
|
+
# the current method.
|
25
|
+
# cf. http://ruby-doc.org/core-2.5.0/Proc.html#method-c-new
|
26
|
+
with_viewer(Discretion::OMNIPOTENT_VIEWER, &Proc.new)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def with_viewer(viewer)
|
32
|
+
orig_viewer = Discretion.current_viewer
|
33
|
+
Discretion.set_current_viewer(viewer)
|
34
|
+
yield
|
35
|
+
ensure
|
36
|
+
Discretion.set_current_viewer(orig_viewer)
|
17
37
|
end
|
18
38
|
end
|
19
39
|
end
|
data/lib/discretion/railtie.rb
CHANGED
data/lib/discretion/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: discretion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abe Land
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rails
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,20 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activerecord
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: bundler
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +80,20 @@ dependencies:
|
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
82
|
version: '1.15'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: factory_bot_rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
55
97
|
- !ruby/object:Gem::Dependency
|
56
98
|
name: rake
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +108,48 @@ dependencies:
|
|
66
108
|
- - "~>"
|
67
109
|
- !ruby/object:Gem::Version
|
68
110
|
version: '10.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec-rails
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sqlite3
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
69
153
|
description: A simple privacy/authorization framework for Rails projects.
|
70
154
|
email:
|
71
155
|
- codeclimbcoffee@gmail.com
|
@@ -74,6 +158,7 @@ extensions: []
|
|
74
158
|
extra_rdoc_files: []
|
75
159
|
files:
|
76
160
|
- ".gitignore"
|
161
|
+
- ".rspec"
|
77
162
|
- CODE_OF_CONDUCT.md
|
78
163
|
- Gemfile
|
79
164
|
- LICENSE.txt
|