alfred 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -1
- data/README.textile +120 -0
- data/alfred.gemspec +3 -2
- data/lib/alfred.rb +1 -2
- data/lib/alfred/mass_assignment_security.rb +150 -0
- data/lib/alfred/orm/active_record.rb +30 -1
- data/lib/alfred/version.rb +1 -1
- metadata +51 -15
- data/.rvmrc +0 -1
- data/lib/alfred/models.rb +0 -53
data/.travis.yml
CHANGED
data/README.textile
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
h1. Alfred - the unobtrusive butler who takes care of the uninvited guests "!https://secure.travis-ci.org/parcydo/alfred.png?branch=master!":http://travis-ci.org/parcydo/alfred
|
2
|
+
|
3
|
+
Travis is an attempt to create an open-source, distributed build system for the Ruby community that:
|
4
|
+
|
5
|
+
1. allows open-source projects to register their repository and have their test-suites run on demand
|
6
|
+
2. allows users to contribute build capacities by connecting a VM that runs a build agent somewhere on their underused servers
|
7
|
+
|
8
|
+
h2. Contact
|
9
|
+
* "Github":http://github.com/parcydo
|
10
|
+
* "Twitter":http://twitter.com/parcydo
|
11
|
+
|
12
|
+
h2. Documentation
|
13
|
+
|
14
|
+
* "Wiki":http://github.com/parcydo/alfred/wiki
|
15
|
+
* "YARD":http://rdoc.info/github/parcydo/alfred
|
16
|
+
|
17
|
+
h2. Preview
|
18
|
+
|
19
|
+
h3. Without Alfred, and with much mess:
|
20
|
+
|
21
|
+
<pre>
|
22
|
+
# app/models/user.rb
|
23
|
+
class User < ActiveRecord::Base
|
24
|
+
attr_accessible :email, :password, :password_confirmation
|
25
|
+
attr_accessible :email, :password, :password_confirmation, :username, as: :admin
|
26
|
+
attr_accessible :email, :password, :password_confirmation, :username, as: :on_create
|
27
|
+
end
|
28
|
+
</pre>
|
29
|
+
|
30
|
+
Have to use a special role:
|
31
|
+
|
32
|
+
<pre>
|
33
|
+
# app/controllers/users_controlelr.rb
|
34
|
+
class UsersController < ApplicationController
|
35
|
+
def create
|
36
|
+
@user = User.create(params[:user], as: :on_create)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
</pre>
|
40
|
+
|
41
|
+
h3. With Alfred and no hassles:
|
42
|
+
|
43
|
+
<pre>
|
44
|
+
# app/models/user.rb
|
45
|
+
class User < ActiveRecord::Base
|
46
|
+
alfred_accessible :email, :password
|
47
|
+
alfred_accessible :username, as: :admin
|
48
|
+
alfred_accessible :username, on: :create
|
49
|
+
end
|
50
|
+
</pre>
|
51
|
+
|
52
|
+
Nothing special here:
|
53
|
+
|
54
|
+
<pre>
|
55
|
+
# app/controllers/users_controlelr.rb
|
56
|
+
class UsersController < ApplicationController
|
57
|
+
def create
|
58
|
+
@user = User.create(params[:user])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
</pre>
|
62
|
+
|
63
|
+
h2. Usage
|
64
|
+
|
65
|
+
alfred_accessible and alfred_protected behaves just like attr_accessible and attr_protected on steroids.
|
66
|
+
|
67
|
+
h3. accessible and protected
|
68
|
+
|
69
|
+
<pre>
|
70
|
+
class User < ActiveRecord::Base
|
71
|
+
alfred_accessible :a, :b
|
72
|
+
alfred_protected :c, :d
|
73
|
+
end
|
74
|
+
</pre>
|
75
|
+
|
76
|
+
h3. roles
|
77
|
+
|
78
|
+
Custom inherits from default role:
|
79
|
+
|
80
|
+
<pre>
|
81
|
+
class User < ActiveRecord::Base
|
82
|
+
alfred_accessible :a, :b
|
83
|
+
alfred_accessible :c, :d, as: :custom
|
84
|
+
end
|
85
|
+
</pre>
|
86
|
+
|
87
|
+
h3. custom inheritance
|
88
|
+
|
89
|
+
<pre>
|
90
|
+
class User < ActiveRecord::Base
|
91
|
+
alfred_accessible :a, :b
|
92
|
+
alfred_accessible :c, :d, as: :custom
|
93
|
+
alfred_accessible :e, :f, as: :custom2, inherit: :custom
|
94
|
+
end
|
95
|
+
</pre>
|
96
|
+
|
97
|
+
h3. events
|
98
|
+
|
99
|
+
<pre>
|
100
|
+
class User < ActiveRecord::Base
|
101
|
+
alfred_accessible :a, :b
|
102
|
+
alfred_accessible :c, :d, on: :create
|
103
|
+
alfred_accessible :e, :f, on: :update
|
104
|
+
end
|
105
|
+
</pre>
|
106
|
+
|
107
|
+
h3. passwords
|
108
|
+
|
109
|
+
password_confirmation will automatically added by default.
|
110
|
+
|
111
|
+
<pre>
|
112
|
+
class User < ActiveRecord::Base
|
113
|
+
alfred_accessible :password
|
114
|
+
end
|
115
|
+
</pre>
|
116
|
+
|
117
|
+
h2. Requirements
|
118
|
+
|
119
|
+
* Ruby 1.9.2 (Ruby 1.9.1 is not supported).
|
120
|
+
* Rails 3.1.x (Rails 3.0.x is not supported).
|
data/alfred.gemspec
CHANGED
@@ -13,7 +13,8 @@ Gem::Specification.new do |s|
|
|
13
13
|
|
14
14
|
s.rubyforge_project = "alfred"
|
15
15
|
|
16
|
-
s.add_dependency "rails", "
|
16
|
+
s.add_dependency "rails", ">= 3.1.0"
|
17
|
+
s.add_development_dependency "activemodel"
|
17
18
|
s.add_development_dependency "activerecord"
|
18
19
|
s.add_development_dependency "rr"
|
19
20
|
s.add_development_dependency "rspec"
|
@@ -22,4 +23,4 @@ Gem::Specification.new do |s|
|
|
22
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
24
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
25
|
s.require_paths = ["lib"]
|
25
|
-
end
|
26
|
+
end
|
data/lib/alfred.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'rails'
|
2
2
|
|
3
3
|
module Alfred
|
4
|
-
autoload :Models, 'alfred/models'
|
5
|
-
|
6
4
|
# Automaticly add password_confirmation if password exists.
|
7
5
|
mattr_accessor :auto_password_confirmation
|
8
6
|
@@auto_password_confirmation = true
|
@@ -15,4 +13,5 @@ module Alfred
|
|
15
13
|
end
|
16
14
|
|
17
15
|
require 'alfred/engine'
|
16
|
+
require 'alfred/mass_assignment_security'
|
18
17
|
require 'alfred/orm/active_record' if defined?(ActiveRecord)
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module Alfred
|
4
|
+
module ActiveModel
|
5
|
+
module MassAssignmentSecurity
|
6
|
+
module ClassMethods
|
7
|
+
# Attributes named in this macro are protected from mass-assignment
|
8
|
+
# whenever attributes are sanitized before assignment. A role for the
|
9
|
+
# attributes is optional, if no role is provided then :default is used.
|
10
|
+
# A role can be defined by using the :as option.
|
11
|
+
#
|
12
|
+
# Mass-assignment to these attributes will simply be ignored, to assign
|
13
|
+
# to them you can use direct writer methods. This is meant to protect
|
14
|
+
# sensitive attributes from being overwritten by malicious users
|
15
|
+
# tampering with URLs or forms. Example:
|
16
|
+
#
|
17
|
+
# class Customer
|
18
|
+
# include ActiveModel::MassAssignmentSecurity
|
19
|
+
# extend Alfred::ActiveModel::MassAssignmentSecurity
|
20
|
+
#
|
21
|
+
# attr_accessor :name, :credit_rating
|
22
|
+
#
|
23
|
+
# alfred_protected :credit_rating
|
24
|
+
# alfred_protected :last_login, as: :trainee
|
25
|
+
#
|
26
|
+
# def assign_attributes(values, options = {})
|
27
|
+
# sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
28
|
+
# send("#{k}=", v)
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# When using the :default role :
|
34
|
+
#
|
35
|
+
# customer = Customer.new
|
36
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
|
37
|
+
# customer.name # => "Daniel"
|
38
|
+
# customer.credit_rating # => nil
|
39
|
+
# customer.last_login # => nil
|
40
|
+
#
|
41
|
+
# customer.credit_rating = "Average"
|
42
|
+
# customer.credit_rating # => "Average"
|
43
|
+
#
|
44
|
+
# And using the :admin role :
|
45
|
+
#
|
46
|
+
# customer = Customer.new
|
47
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :trainee)
|
48
|
+
# customer.name # => "Daniel"
|
49
|
+
# customer.credit_rating # => "Excellent"
|
50
|
+
# customer.last_login # => nil
|
51
|
+
#
|
52
|
+
# To start from an all-closed default and enable attributes as needed,
|
53
|
+
# have a look at +alfred_accessible+.
|
54
|
+
#
|
55
|
+
# Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_protected+
|
56
|
+
# to sanitize attributes won't provide sufficient protection.
|
57
|
+
def alfred_protected(*args)
|
58
|
+
alfred(:protected, *args)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Specifies a white list of model attributes that can be set via
|
62
|
+
# mass-assignment.
|
63
|
+
#
|
64
|
+
# Like +alfred_protected+, a role for the attributes is optional,
|
65
|
+
# if no role is provided then :default is used. A role can be defined by
|
66
|
+
# using the :as option.
|
67
|
+
#
|
68
|
+
# This is the opposite of the +alfred_protected+ macro: Mass-assignment
|
69
|
+
# will only set attributes in this list, to assign to the rest of
|
70
|
+
# attributes you can use direct writer methods. This is meant to protect
|
71
|
+
# sensitive attributes from being overwritten by malicious users
|
72
|
+
# tampering with URLs or forms. If you'd rather start from an all-open
|
73
|
+
# default and restrict attributes as needed, have a look at
|
74
|
+
# +alfred_protected+.
|
75
|
+
#
|
76
|
+
# class Customer
|
77
|
+
# include ActiveModel::MassAssignmentSecurity
|
78
|
+
# extend Alfred::ActiveModel::MassAssignmentSecurity
|
79
|
+
#
|
80
|
+
# attr_accessor :name, :credit_rating
|
81
|
+
#
|
82
|
+
# alfred_accessible :name
|
83
|
+
# alfred_accessible :credit_rating, as: :admin
|
84
|
+
#
|
85
|
+
# def assign_attributes(values, options = {})
|
86
|
+
# sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
87
|
+
# send("#{k}=", v)
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# When using the :default role :
|
93
|
+
#
|
94
|
+
# customer = Customer.new
|
95
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
|
96
|
+
# customer.name # => "Daniel"
|
97
|
+
# customer.credit_rating # => nil
|
98
|
+
#
|
99
|
+
# customer.credit_rating = "Average"
|
100
|
+
# customer.credit_rating # => "Average"
|
101
|
+
#
|
102
|
+
# And using the :admin role :
|
103
|
+
#
|
104
|
+
# customer = Customer.new
|
105
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :admin)
|
106
|
+
# customer.name # => "Daniel"
|
107
|
+
# customer.credit_rating # => "Excellent"
|
108
|
+
#
|
109
|
+
# Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_accessible+
|
110
|
+
# to sanitize attributes won't provide sufficient protection.
|
111
|
+
def alfred_accessible(*args)
|
112
|
+
alfred(:accessible, *args)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def alfred(method, *args)
|
117
|
+
options = args.extract_options!
|
118
|
+
|
119
|
+
if args.include?(:password) && Alfred.auto_password_confirmation
|
120
|
+
args = args + [:password_confirmation]
|
121
|
+
end
|
122
|
+
|
123
|
+
[nil, :create, :update].each do |action|
|
124
|
+
if options[:on]
|
125
|
+
next unless options[:on] == action
|
126
|
+
end
|
127
|
+
|
128
|
+
action_args = args.dup
|
129
|
+
|
130
|
+
role = (options[:as] || :default).to_s
|
131
|
+
role << "_#{action}" if action
|
132
|
+
role = role.to_sym
|
133
|
+
|
134
|
+
action_args = action_args + [{ as: role }]
|
135
|
+
|
136
|
+
action_args = action_args + send("#{method}_attributes", role).to_a.compact.reject { |s| s.blank? }
|
137
|
+
|
138
|
+
send("attr_#{method}", *action_args)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
include ClassMethods
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
module ActiveModel::MassAssignmentSecurity::ClassMethods
|
149
|
+
include Alfred::ActiveModel::MassAssignmentSecurity
|
150
|
+
end
|
@@ -1,3 +1,32 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
|
3
|
-
|
3
|
+
module Alfred
|
4
|
+
module ActiveRecord
|
5
|
+
module Base
|
6
|
+
def assign_attributes(new_attributes, options = {})
|
7
|
+
role = (options[:as] || :default).to_s
|
8
|
+
role << "_#{options[:action]}" if options[:action]
|
9
|
+
|
10
|
+
options[:as] = role.to_sym
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(attributes = nil, options = {})
|
16
|
+
options[:action] = :create
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_attributes(attributes, options = {})
|
22
|
+
options[:action] = :update
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class ActiveRecord::Base
|
31
|
+
include Alfred::ActiveRecord::Base
|
32
|
+
end
|
data/lib/alfred/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alfred
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,43 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-04-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 3.1.0
|
21
|
+
version: 3.1.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.1.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activemodel
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
25
46
|
- !ruby/object:Gem::Dependency
|
26
47
|
name: activerecord
|
27
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
28
49
|
none: false
|
29
50
|
requirements:
|
30
51
|
- - ! '>='
|
@@ -32,10 +53,15 @@ dependencies:
|
|
32
53
|
version: '0'
|
33
54
|
type: :development
|
34
55
|
prerelease: false
|
35
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
36
62
|
- !ruby/object:Gem::Dependency
|
37
63
|
name: rr
|
38
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
39
65
|
none: false
|
40
66
|
requirements:
|
41
67
|
- - ! '>='
|
@@ -43,10 +69,15 @@ dependencies:
|
|
43
69
|
version: '0'
|
44
70
|
type: :development
|
45
71
|
prerelease: false
|
46
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
47
78
|
- !ruby/object:Gem::Dependency
|
48
79
|
name: rspec
|
49
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
50
81
|
none: false
|
51
82
|
requirements:
|
52
83
|
- - ! '>='
|
@@ -54,7 +85,12 @@ dependencies:
|
|
54
85
|
version: '0'
|
55
86
|
type: :development
|
56
87
|
prerelease: false
|
57
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
58
94
|
description: Alfred provides better attr_accessor handling on your application.
|
59
95
|
email:
|
60
96
|
- daniel.spangenberg@parcydo.com
|
@@ -64,16 +100,16 @@ extra_rdoc_files: []
|
|
64
100
|
files:
|
65
101
|
- .gitignore
|
66
102
|
- .rspec
|
67
|
-
- .rvmrc
|
68
103
|
- .travis.yml
|
69
104
|
- Gemfile
|
105
|
+
- README.textile
|
70
106
|
- Rakefile
|
71
107
|
- alfred.gemspec
|
72
108
|
- lib/alfred.rb
|
73
109
|
- lib/alfred/engine.rb
|
74
110
|
- lib/alfred/generators/alfred/install_generator.rb
|
75
111
|
- lib/alfred/generators/templates/alfred.rb
|
76
|
-
- lib/alfred/
|
112
|
+
- lib/alfred/mass_assignment_security.rb
|
77
113
|
- lib/alfred/orm/active_record.rb
|
78
114
|
- lib/alfred/version.rb
|
79
115
|
- spec/models_spec.rb
|
@@ -98,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
134
|
version: '0'
|
99
135
|
requirements: []
|
100
136
|
rubyforge_project: alfred
|
101
|
-
rubygems_version: 1.8.
|
137
|
+
rubygems_version: 1.8.21
|
102
138
|
signing_key:
|
103
139
|
specification_version: 3
|
104
140
|
summary: Alfred is the unobtrusive butler who takes care of the uninvited guests.
|
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm 1.9.2@alfred --create
|
data/lib/alfred/models.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
module Alfred
|
2
|
-
module Models
|
3
|
-
def alfred_accessible(*args)
|
4
|
-
alfred(:accessible, *args)
|
5
|
-
end
|
6
|
-
|
7
|
-
def alfred_protected(*args)
|
8
|
-
alfred(:protected, *args)
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def alfred(method, *args)
|
14
|
-
options = args.extract_options!
|
15
|
-
|
16
|
-
if options[:as]
|
17
|
-
if method == :accessible
|
18
|
-
args = args + accessible_attributes(options[:inherit] || :default).to_a
|
19
|
-
else
|
20
|
-
args = args + protected_attributes(options[:inherit] || :default).to_a
|
21
|
-
end
|
22
|
-
args = args + [{ as: options[:as] }]
|
23
|
-
end
|
24
|
-
|
25
|
-
if args.include?(:password) && Alfred.auto_password_confirmation
|
26
|
-
args = args + [:password_confirmation]
|
27
|
-
end
|
28
|
-
|
29
|
-
if options[:on] && [:create, :update].include?(options[:on])
|
30
|
-
if options[:on] == :create
|
31
|
-
before = :before_create
|
32
|
-
else
|
33
|
-
before = :before_update
|
34
|
-
end
|
35
|
-
if method == :accessible
|
36
|
-
self.class.send(:define_method, before) do
|
37
|
-
attr_accessible(*args)
|
38
|
-
end
|
39
|
-
else
|
40
|
-
self.class.send(:define_method, before) do
|
41
|
-
attr_protected(*args)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
else
|
45
|
-
if method == :accessible
|
46
|
-
attr_accessible(*args)
|
47
|
-
else
|
48
|
-
attr_protected(*args)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|