crows 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +149 -0
- data/crows.gemspec +20 -0
- data/lib/crows.rb +76 -0
- data/test/test_crows.rb +121 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 45a31cd6e8c73b9a5ea6b587986da193074bc2d6
|
4
|
+
data.tar.gz: e51b2f94197a437e4dec56e166c99eec206bfa88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9cac3c422c581712a967212b6a3516bd7fa915766fe62c4737ae38c69dfcd3bd6721eac17a993a48d72d1be5dede1172e424a826379c10e9ab4681660bb887fb
|
7
|
+
data.tar.gz: 1d24ab84eaa80027896b71cf58d54e3d65577b4b38602eb0c03c858efabe7d5189149375ca1b13d33bb47f8c2d1f98fcc9a7e7a23099a58368debdc7e404c70f
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Julio Lopez
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# Crows
|
2
|
+
|
3
|
+
Inspired by [Pundit](https://github.com/elabs/pundit), Crows is a micro framework-agnostic library for authorization in Ruby classes.
|
4
|
+
|
5
|
+
A set of crows to authorized your users, because the night is dark and full of terrors...
|
6
|
+
|
7
|
+
Crows provide you with a few helpers to check if `current_user` can make operations into some records. This gives you the freedom to build your own plain Ruby classes to make authorization works easily, without the painful of bigs DSLs or something like that.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Installing Crows is as simple as running:
|
12
|
+
|
13
|
+
```
|
14
|
+
$ gem install crows
|
15
|
+
```
|
16
|
+
|
17
|
+
Include Crows in your Gemfile with gem 'crows' or require it with require 'crows'.
|
18
|
+
|
19
|
+
Usage
|
20
|
+
-----
|
21
|
+
|
22
|
+
Include Crows in your main class, can be your controller, your API class, etc.
|
23
|
+
|
24
|
+
``` ruby
|
25
|
+
class ApplicationController < ActionController::Base
|
26
|
+
include Crows
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
Crows exist around the notion of Crow classes.
|
31
|
+
|
32
|
+
``` ruby
|
33
|
+
class PostCrow
|
34
|
+
attr_reader :user, :post
|
35
|
+
|
36
|
+
def initialize(user, post)
|
37
|
+
@user = user
|
38
|
+
@post = post
|
39
|
+
end
|
40
|
+
|
41
|
+
def destroy?
|
42
|
+
user.admin? and post.draft?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
In the above example:
|
48
|
+
|
49
|
+
- We define a Crow class, its name is composed by a name of a class whose authorization you want to check, plus the suffix "Crow".
|
50
|
+
- In its `initialize` the class receive as first argument the user(captured by your method `current_user`) and as second argument your instance of the class for which was created the current crow.
|
51
|
+
- Finally the Crow class implements methods to check if user can be authorized to do a particular action.
|
52
|
+
|
53
|
+
Lastly, you have the `authorize` method for use your Crow class.
|
54
|
+
|
55
|
+
``` ruby
|
56
|
+
authorize @post, :destroy?
|
57
|
+
```
|
58
|
+
|
59
|
+
The above line will check your PostCrow class to authorize if current user can destroy the @post
|
60
|
+
|
61
|
+
Raising an exception if is not true the result of `destroy?`
|
62
|
+
|
63
|
+
``` ruby
|
64
|
+
Crows::NotAuthorizedError: not allowed to destroy? this #<Post:0x007fd1831adc48>
|
65
|
+
```
|
66
|
+
|
67
|
+
Also, you have a method `crow` to receive the instance of your Crow class for handle the checks manually, useful in the views:
|
68
|
+
|
69
|
+
``` erb
|
70
|
+
<% if crow(@post).destroy? %>
|
71
|
+
<%= link_to "Delete post", post_path(@post), method: :delete %>
|
72
|
+
<% end %>
|
73
|
+
```
|
74
|
+
|
75
|
+
## Scopes
|
76
|
+
|
77
|
+
You can also declare a Scope in your Crow class, use it when you need to check if the user can access to a list of records, looks like this:
|
78
|
+
|
79
|
+
``` ruby
|
80
|
+
class PostCrow
|
81
|
+
class Scope
|
82
|
+
attr_reader :user, :scope
|
83
|
+
|
84
|
+
def initialize(user, scope)
|
85
|
+
@user = user
|
86
|
+
@scope = scope
|
87
|
+
end
|
88
|
+
|
89
|
+
def resolve
|
90
|
+
if user.admin?
|
91
|
+
scope.all
|
92
|
+
else
|
93
|
+
scope.select{|post| post.published }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
To make the Scope class works:
|
101
|
+
- You need to create it nested in your Crow class.
|
102
|
+
- In its `initialize` the class Scope receive as first argument the `current_user`(similar as works the Crow classes) and as second argument the scope(a class name) that you'll pass later to the `authorize` method
|
103
|
+
- And you need to declare the `resolve` method, which should check the authorization and return something that can be iterated(that's why is called scope, isn't it?)
|
104
|
+
|
105
|
+
Now, you can use your scopes like this:
|
106
|
+
|
107
|
+
``` erb
|
108
|
+
<% crow_scope(Post).each do |post| %>
|
109
|
+
<p><%= link_to post.title, post_path(post) %></p>
|
110
|
+
<% end %>
|
111
|
+
```
|
112
|
+
|
113
|
+
This example will return all the posts if the user is admin, if not it will return just the published posts, as we indicated in the `resolve` method.
|
114
|
+
|
115
|
+
## Customize your current user
|
116
|
+
|
117
|
+
Sometimes, you'll need to authorize users outside your main class(your controller, API class, etc), in that case you simply need to Crows call other method than `current_user` and we give you for that, the option of define the `crow_user`
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
def crow_user
|
121
|
+
#grab here the user that you want to check his authorization
|
122
|
+
User.find(params[:user_id])
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
## Get and Set Crows
|
127
|
+
|
128
|
+
For other purposes you can get the hash of all crows and scopes defined with `crows` and `crows_scope` methods (use them in the class where you include Crows)
|
129
|
+
|
130
|
+
Following the previous examples:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
class ApplicationController
|
134
|
+
puts crows
|
135
|
+
#=>{<Post:instance> => <PostCrow:instance>}
|
136
|
+
|
137
|
+
puts crows_scope
|
138
|
+
#=>{Post => #result of PostCrow::Scope.resolve}
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
And you can set manually the crows with a hash syntax:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
class ApplicationController
|
146
|
+
crows[@post] = crow(@post)
|
147
|
+
crows_scope[Post] = crow_scope(Post)
|
148
|
+
end
|
149
|
+
```
|
data/crows.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "./lib/crows"
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "crows"
|
5
|
+
s.version = Crows::VERSION
|
6
|
+
s.summary = "Micro library for authorization in Ruby classes."
|
7
|
+
s.description = "Crows is a micro framework-agnostic library for authorization in Ruby classes. A set of crows to authorized your users, because the night is dark and full of terrors... Crows provide you with a few helpers to check if `current_user` can make operations into some records. This gives you the freedom to build your own plain Ruby classes to make authorization works easily, without the painful of bigs DSLs or something like that."
|
8
|
+
s.authors = ["Julio Lopez"]
|
9
|
+
s.email = ["ljuliom@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/TheBlasfem/crows"
|
11
|
+
s.files = Dir[
|
12
|
+
"LICENSE",
|
13
|
+
"README.md",
|
14
|
+
"lib/**/*.rb",
|
15
|
+
"*.gemspec",
|
16
|
+
"test/**/*.rb"
|
17
|
+
]
|
18
|
+
s.license = "MIT"
|
19
|
+
s.add_development_dependency "cutest", "1.1.3"
|
20
|
+
end
|
data/lib/crows.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Copyright (c) 2015 Julio Lopez
|
2
|
+
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
module Crows
|
21
|
+
VERSION = "0.1.0"
|
22
|
+
SUFFIX = "Crow"
|
23
|
+
|
24
|
+
class NotDefinedError < StandardError; end
|
25
|
+
class NotAuthorizedError < StandardError
|
26
|
+
def initialize(options = {})
|
27
|
+
query = options[:query]
|
28
|
+
record = options[:record]
|
29
|
+
message = "not allowed to #{query} this #{record.inspect}"
|
30
|
+
super(message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def crow(record)
|
35
|
+
instance = find_crowclass(record).new(crow_user, record)
|
36
|
+
crows[record] = instance unless record.is_a? Class
|
37
|
+
instance
|
38
|
+
end
|
39
|
+
|
40
|
+
def crow_scope(klass)
|
41
|
+
crows_scope[klass] = crow(klass)
|
42
|
+
crows_scope[klass].resolve
|
43
|
+
end
|
44
|
+
|
45
|
+
def authorize(record, query)
|
46
|
+
crow = crow(record)
|
47
|
+
unless crow.public_send(query)
|
48
|
+
raise NotAuthorizedError.new(query: query, record: record)
|
49
|
+
end
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def crow_user
|
54
|
+
current_user
|
55
|
+
end
|
56
|
+
|
57
|
+
def crows
|
58
|
+
@crows ||= {}
|
59
|
+
end
|
60
|
+
|
61
|
+
def crows_scope
|
62
|
+
@crows_scope ||= {}
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def find_crowclass(record)
|
68
|
+
klass = if record.is_a? Class
|
69
|
+
Object.const_get(record.to_s + SUFFIX)::Scope
|
70
|
+
else
|
71
|
+
Object.const_get(record.class.to_s + SUFFIX)
|
72
|
+
end
|
73
|
+
rescue NameError
|
74
|
+
raise NotDefinedError, "unable to find crow #{klass} for #{record.inspect}"
|
75
|
+
end
|
76
|
+
end
|
data/test/test_crows.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require File.expand_path("../lib/crows", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
scope do
|
4
|
+
class User; end
|
5
|
+
|
6
|
+
class Post
|
7
|
+
def self.all
|
8
|
+
['post 1', 'post 2']
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class PostCrow
|
13
|
+
attr_reader :user, :post
|
14
|
+
|
15
|
+
def initialize(user, post)
|
16
|
+
@user = user
|
17
|
+
@post = post
|
18
|
+
end
|
19
|
+
|
20
|
+
def update?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
class Scope
|
29
|
+
attr_reader :user, :scope
|
30
|
+
|
31
|
+
def initialize(user, scope)
|
32
|
+
@user = user
|
33
|
+
@scope = scope
|
34
|
+
end
|
35
|
+
|
36
|
+
def resolve
|
37
|
+
if true
|
38
|
+
scope.all
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Controller
|
45
|
+
include Crows
|
46
|
+
attr_reader :current_user
|
47
|
+
def initialize(user)
|
48
|
+
@current_user = user
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@user = User.new
|
53
|
+
@controller = Controller.new @user
|
54
|
+
@post = Post.new
|
55
|
+
|
56
|
+
test "return true if authorization passes" do
|
57
|
+
action = @controller.authorize(@post, :update?)
|
58
|
+
assert_equal action, true
|
59
|
+
end
|
60
|
+
|
61
|
+
test "throw an exception if authorization fails" do
|
62
|
+
assert_raise(Crows::NotAuthorizedError) do
|
63
|
+
@controller.authorize(@post, :destroy?)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
test "throws an exception when a crow class cannot be found" do
|
68
|
+
assert_raise(Crows::NotDefinedError) do
|
69
|
+
@controller.authorize(@user, :update?)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
test "returns an instantiated crow" do
|
74
|
+
crow = @controller.crow(@post)
|
75
|
+
assert_equal crow.post, @post
|
76
|
+
end
|
77
|
+
|
78
|
+
test "throws an exception when a crow class cannot be found in #crow" do
|
79
|
+
assert_raise(Crows::NotDefinedError) do
|
80
|
+
@controller.crow(@user)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
test "save the crow" do
|
85
|
+
assert_equal @controller.crows[Post.new], nil
|
86
|
+
crow = @controller.crow(@post)
|
87
|
+
assert_equal @controller.crows[@post], crow
|
88
|
+
end
|
89
|
+
|
90
|
+
test "allow crow to be injected" do
|
91
|
+
crow = @controller.crow(@post)
|
92
|
+
@controller.crows[@post] = crow
|
93
|
+
assert_equal @controller.crows[@post], crow
|
94
|
+
end
|
95
|
+
|
96
|
+
test "returns an instantiated crow scope" do
|
97
|
+
scope = @controller.crow_scope(Post)
|
98
|
+
assert_equal scope, ['post 1', 'post 2']
|
99
|
+
end
|
100
|
+
|
101
|
+
test "throws an exception when a crow scope class cannot be found" do
|
102
|
+
assert_raise(Crows::NotDefinedError) do
|
103
|
+
@controller.crow_scope(User)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
test "save the crow scope" do
|
108
|
+
scope = @controller.crow_scope(Post)
|
109
|
+
assert_equal @controller.crows_scope[Post].resolve, scope
|
110
|
+
end
|
111
|
+
|
112
|
+
test "allow crow scope to be injected" do
|
113
|
+
scope = @controller.crow_scope(Post)
|
114
|
+
@controller.crows_scope[Post] = scope
|
115
|
+
assert_equal @controller.crows_scope[Post], scope
|
116
|
+
end
|
117
|
+
|
118
|
+
test "crow_user return the same current_user of controller" do
|
119
|
+
assert_equal @controller.crow_user, @controller.current_user
|
120
|
+
end
|
121
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crows
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Julio Lopez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cutest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.1.3
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.1.3
|
27
|
+
description: Crows is a micro framework-agnostic library for authorization in Ruby
|
28
|
+
classes. A set of crows to authorized your users, because the night is dark and
|
29
|
+
full of terrors... Crows provide you with a few helpers to check if `current_user`
|
30
|
+
can make operations into some records. This gives you the freedom to build your
|
31
|
+
own plain Ruby classes to make authorization works easily, without the painful of
|
32
|
+
bigs DSLs or something like that.
|
33
|
+
email:
|
34
|
+
- ljuliom@gmail.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- LICENSE
|
40
|
+
- README.md
|
41
|
+
- crows.gemspec
|
42
|
+
- lib/crows.rb
|
43
|
+
- test/test_crows.rb
|
44
|
+
homepage: http://github.com/TheBlasfem/crows
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 2.4.6
|
65
|
+
signing_key:
|
66
|
+
specification_version: 4
|
67
|
+
summary: Micro library for authorization in Ruby classes.
|
68
|
+
test_files: []
|