sorcery 0.6.1 → 0.7.1
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.
- data/Gemfile +1 -0
- data/Gemfile.lock +52 -45
- data/README.rdoc +26 -54
- data/Rakefile +26 -0
- data/VERSION +1 -1
- data/lib/generators/sorcery/USAGE +22 -0
- data/lib/generators/sorcery/install_generator.rb +71 -0
- data/lib/{sorcery/initializers → generators/sorcery/templates}/initializer.rb +82 -61
- data/lib/generators/sorcery/templates/migration/activity_logging.rb +17 -0
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +11 -0
- data/lib/generators/{sorcery_migration/templates → sorcery/templates/migration}/core.rb +3 -3
- data/lib/generators/{sorcery_migration/templates → sorcery/templates/migration}/external.rb +1 -1
- data/lib/generators/sorcery/templates/migration/remember_me.rb +15 -0
- data/lib/generators/sorcery/templates/migration/reset_password.rb +17 -0
- data/lib/generators/sorcery/templates/migration/user_activation.rb +17 -0
- data/lib/sorcery/controller/submodules/activity_logging.rb +23 -9
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +2 -1
- data/lib/sorcery/controller/submodules/external/protocols/certs/ca-bundle.crt +5182 -0
- data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +27 -8
- data/lib/sorcery/controller/submodules/external/providers/github.rb +80 -0
- data/lib/sorcery/controller/submodules/external/providers/twitter.rb +5 -0
- data/lib/sorcery/controller/submodules/external.rb +10 -3
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +1 -1
- data/lib/sorcery/controller/submodules/remember_me.rb +15 -5
- data/lib/sorcery/controller/submodules/session_timeout.rb +1 -1
- data/lib/sorcery/controller.rb +59 -38
- data/lib/sorcery/crypto_providers/aes256.rb +7 -3
- data/lib/sorcery/engine.rb +1 -0
- data/lib/sorcery/model/adapters/active_record.rb +2 -1
- data/lib/sorcery/model/adapters/mongo_mapper.rb +49 -0
- data/lib/sorcery/model/adapters/mongoid.rb +7 -2
- data/lib/sorcery/model/submodules/brute_force_protection.rb +13 -3
- data/lib/sorcery/model/submodules/remember_me.rb +9 -2
- data/lib/sorcery/model/submodules/reset_password.rb +11 -2
- data/lib/sorcery/model/submodules/user_activation.rb +13 -2
- data/lib/sorcery/model/temporary_token.rb +5 -0
- data/lib/sorcery/model.rb +34 -15
- data/lib/sorcery/test_helpers/internal/rails.rb +1 -1
- data/lib/sorcery/test_helpers/rails.rb +2 -2
- data/lib/sorcery.rb +6 -7
- data/sorcery.gemspec +86 -203
- data/spec/Gemfile.lock +23 -12
- data/spec/README.md +31 -0
- data/spec/rails3/Gemfile +3 -1
- data/spec/rails3/Gemfile.lock +45 -28
- data/spec/rails3/app/controllers/application_controller.rb +40 -22
- data/spec/rails3/app/views/application/index.html.erb +17 -0
- data/spec/rails3/spec/controller_activity_logging_spec.rb +23 -0
- data/spec/rails3/spec/controller_oauth2_spec.rb +59 -16
- data/spec/rails3/spec/controller_remember_me_spec.rb +37 -6
- data/spec/rails3/spec/controller_spec.rb +30 -0
- data/spec/rails3/spec/integration_spec.rb +23 -0
- data/spec/rails3/spec/spec_helper.rb +6 -5
- data/spec/rails3_mongo_mapper/.gitignore +4 -0
- data/spec/rails3_mongo_mapper/.rspec +1 -0
- data/spec/{sinatra_modular → rails3_mongo_mapper}/Gemfile +5 -5
- data/spec/rails3_mongo_mapper/Gemfile.lock +159 -0
- data/spec/{sinatra → rails3_mongo_mapper}/Rakefile +3 -3
- data/spec/rails3_mongo_mapper/app/controllers/application_controller.rb +108 -0
- data/spec/rails3_mongo_mapper/app/helpers/application_helper.rb +2 -0
- data/spec/rails3_mongo_mapper/app/models/authentication.rb +6 -0
- data/spec/rails3_mongo_mapper/app/models/user.rb +5 -0
- data/spec/rails3_mongo_mapper/app/views/layouts/application.html.erb +14 -0
- data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_email.html.erb +17 -0
- data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_email.text.erb +9 -0
- data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
- data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
- data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
- data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
- data/spec/rails3_mongo_mapper/config/application.rb +51 -0
- data/spec/rails3_mongo_mapper/config/boot.rb +13 -0
- data/spec/rails3_mongo_mapper/config/environment.rb +5 -0
- data/spec/rails3_mongo_mapper/config/environments/development.rb +30 -0
- data/spec/rails3_mongo_mapper/config/environments/in_memory.rb +0 -0
- data/spec/rails3_mongo_mapper/config/environments/production.rb +49 -0
- data/spec/rails3_mongo_mapper/config/environments/test.rb +35 -0
- data/spec/rails3_mongo_mapper/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails3_mongo_mapper/config/initializers/inflections.rb +10 -0
- data/spec/rails3_mongo_mapper/config/initializers/mime_types.rb +5 -0
- data/spec/rails3_mongo_mapper/config/initializers/mongo.rb +2 -0
- data/spec/rails3_mongo_mapper/config/initializers/secret_token.rb +7 -0
- data/spec/rails3_mongo_mapper/config/initializers/session_store.rb +8 -0
- data/spec/rails3_mongo_mapper/config/locales/en.yml +5 -0
- data/spec/rails3_mongo_mapper/config/routes.rb +59 -0
- data/spec/rails3_mongo_mapper/config.ru +4 -0
- data/spec/rails3_mongo_mapper/db/schema.rb +23 -0
- data/spec/rails3_mongo_mapper/db/seeds.rb +7 -0
- data/spec/rails3_mongo_mapper/lib/tasks/.gitkeep +0 -0
- data/spec/rails3_mongo_mapper/public/404.html +26 -0
- data/spec/rails3_mongo_mapper/public/422.html +26 -0
- data/spec/rails3_mongo_mapper/public/500.html +26 -0
- data/spec/rails3_mongo_mapper/public/favicon.ico +0 -0
- data/spec/rails3_mongo_mapper/public/images/rails.png +0 -0
- data/spec/rails3_mongo_mapper/public/javascripts/application.js +2 -0
- data/spec/rails3_mongo_mapper/public/javascripts/controls.js +965 -0
- data/spec/rails3_mongo_mapper/public/javascripts/dragdrop.js +974 -0
- data/spec/rails3_mongo_mapper/public/javascripts/effects.js +1123 -0
- data/spec/rails3_mongo_mapper/public/javascripts/prototype.js +6001 -0
- data/spec/rails3_mongo_mapper/public/javascripts/rails.js +175 -0
- data/spec/rails3_mongo_mapper/public/robots.txt +5 -0
- data/spec/rails3_mongo_mapper/public/stylesheets/.gitkeep +0 -0
- data/spec/rails3_mongo_mapper/script/rails +6 -0
- data/spec/{sinatra → rails3_mongo_mapper}/spec/controller_spec.rb +51 -41
- data/spec/rails3_mongo_mapper/spec/spec_helper.orig.rb +27 -0
- data/spec/rails3_mongo_mapper/spec/spec_helper.rb +55 -0
- data/spec/rails3_mongo_mapper/spec/user_activation_spec.rb +9 -0
- data/spec/rails3_mongo_mapper/spec/user_activity_logging_spec.rb +8 -0
- data/spec/rails3_mongo_mapper/spec/user_brute_force_protection_spec.rb +8 -0
- data/spec/rails3_mongo_mapper/spec/user_oauth_spec.rb +8 -0
- data/spec/rails3_mongo_mapper/spec/user_remember_me_spec.rb +8 -0
- data/spec/rails3_mongo_mapper/spec/user_reset_password_spec.rb +8 -0
- data/spec/rails3_mongo_mapper/spec/user_spec.rb +37 -0
- data/spec/rails3_mongo_mapper/vendor/plugins/.gitkeep +0 -0
- data/spec/rails3_mongoid/Gemfile +1 -1
- data/spec/rails3_mongoid/Gemfile.lock +41 -34
- data/spec/rails3_mongoid/spec/controller_activity_logging_spec.rb +98 -0
- data/spec/rails3_mongoid/spec/controller_spec.rb +130 -0
- data/spec/rails3_mongoid/spec/user_spec.rb +1 -0
- data/spec/shared_examples/user_remember_me_shared_examples.rb +1 -0
- data/spec/shared_examples/user_shared_examples.rb +36 -8
- metadata +128 -234
- data/lib/generators/sorcery_migration/sorcery_migration_generator.rb +0 -24
- data/lib/generators/sorcery_migration/templates/activity_logging.rb +0 -17
- data/lib/generators/sorcery_migration/templates/brute_force_protection.rb +0 -11
- data/lib/generators/sorcery_migration/templates/remember_me.rb +0 -15
- data/lib/generators/sorcery_migration/templates/reset_password.rb +0 -13
- data/lib/generators/sorcery_migration/templates/user_activation.rb +0 -17
- data/lib/sorcery/controller/adapters/sinatra.rb +0 -104
- data/lib/sorcery/sinatra.rb +0 -4
- data/lib/sorcery/test_helpers/internal/sinatra.rb +0 -74
- data/lib/sorcery/test_helpers/internal/sinatra_modular.rb +0 -74
- data/lib/sorcery/test_helpers/sinatra.rb +0 -88
- data/spec/rails3/Rakefile.unused +0 -7
- data/spec/rails3/public/index.html +0 -239
- data/spec/sinatra/Gemfile +0 -15
- data/spec/sinatra/Gemfile.lock +0 -117
- data/spec/sinatra/authentication.rb +0 -3
- data/spec/sinatra/db/migrate/activation/20101224223622_add_activation_to_users.rb +0 -17
- data/spec/sinatra/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +0 -17
- data/spec/sinatra/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +0 -11
- data/spec/sinatra/db/migrate/core/20101224223620_create_users.rb +0 -16
- data/spec/sinatra/db/migrate/external/20101224223628_create_authentications.rb +0 -14
- data/spec/sinatra/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +0 -15
- data/spec/sinatra/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +0 -13
- data/spec/sinatra/filters.rb +0 -27
- data/spec/sinatra/modular.rb +0 -157
- data/spec/sinatra/myapp.rb +0 -133
- data/spec/sinatra/spec/controller_activity_logging_spec.rb +0 -85
- data/spec/sinatra/spec/controller_brute_force_protection_spec.rb +0 -70
- data/spec/sinatra/spec/controller_http_basic_auth_spec.rb +0 -53
- data/spec/sinatra/spec/controller_oauth2_spec.rb +0 -99
- data/spec/sinatra/spec/controller_oauth_spec.rb +0 -100
- data/spec/sinatra/spec/controller_remember_me_spec.rb +0 -64
- data/spec/sinatra/spec/controller_session_timeout_spec.rb +0 -57
- data/spec/sinatra/spec/spec_helper.rb +0 -45
- data/spec/sinatra/user.rb +0 -6
- data/spec/sinatra/views/test_login.erb +0 -4
- data/spec/sinatra_modular/Gemfile.lock +0 -117
- data/spec/sinatra_modular/Rakefile +0 -11
- data/spec/sinatra_modular/authentication.rb +0 -3
- data/spec/sinatra_modular/db/migrate/activation/20101224223622_add_activation_to_users.rb +0 -17
- data/spec/sinatra_modular/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +0 -17
- data/spec/sinatra_modular/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +0 -11
- data/spec/sinatra_modular/db/migrate/core/20101224223620_create_users.rb +0 -16
- data/spec/sinatra_modular/db/migrate/external/20101224223628_create_authentications.rb +0 -14
- data/spec/sinatra_modular/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +0 -15
- data/spec/sinatra_modular/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +0 -13
- data/spec/sinatra_modular/filters.rb +0 -27
- data/spec/sinatra_modular/modular.rb +0 -157
- data/spec/sinatra_modular/myapp.rb +0 -133
- data/spec/sinatra_modular/sorcery_mailer.rb +0 -25
- data/spec/sinatra_modular/spec_modular/controller_activity_logging_spec.rb +0 -85
- data/spec/sinatra_modular/spec_modular/controller_brute_force_protection_spec.rb +0 -70
- data/spec/sinatra_modular/spec_modular/controller_http_basic_auth_spec.rb +0 -53
- data/spec/sinatra_modular/spec_modular/controller_oauth2_spec.rb +0 -99
- data/spec/sinatra_modular/spec_modular/controller_oauth_spec.rb +0 -100
- data/spec/sinatra_modular/spec_modular/controller_remember_me_spec.rb +0 -64
- data/spec/sinatra_modular/spec_modular/controller_session_timeout_spec.rb +0 -57
- data/spec/sinatra_modular/spec_modular/controller_spec.rb +0 -116
- data/spec/sinatra_modular/spec_modular/spec.opts +0 -2
- data/spec/sinatra_modular/spec_modular/spec_helper.rb +0 -51
- data/spec/sinatra_modular/user.rb +0 -6
- data/spec/sinatra_modular/views/test_login.erb +0 -4
- /data/spec/{sinatra → rails3_mongo_mapper/app/mailers}/sorcery_mailer.rb +0 -0
- /data/spec/{sinatra → rails3_mongo_mapper}/spec/spec.opts +0 -0
data/spec/rails3/Gemfile.lock
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
|
-
remote:
|
|
2
|
+
remote: ../../
|
|
3
3
|
specs:
|
|
4
|
-
sorcery (0.
|
|
4
|
+
sorcery (0.7.0)
|
|
5
5
|
bcrypt-ruby (~> 3.0.0)
|
|
6
|
-
|
|
7
|
-
oauth (
|
|
8
|
-
|
|
9
|
-
oauth2 (
|
|
6
|
+
mongo_mapper
|
|
7
|
+
oauth (~> 0.4.4)
|
|
8
|
+
oauth (~> 0.4.4)
|
|
9
|
+
oauth2 (~> 0.4.1)
|
|
10
|
+
oauth2 (~> 0.4.1)
|
|
10
11
|
|
|
11
12
|
GEM
|
|
12
13
|
remote: http://rubygems.org/
|
|
@@ -40,37 +41,48 @@ GEM
|
|
|
40
41
|
activesupport (3.0.3)
|
|
41
42
|
addressable (2.2.6)
|
|
42
43
|
archive-tar-minitar (0.5.2)
|
|
43
|
-
arel (2.0.
|
|
44
|
-
bcrypt-ruby (3.0.
|
|
44
|
+
arel (2.0.10)
|
|
45
|
+
bcrypt-ruby (3.0.1)
|
|
46
|
+
bson (1.4.1)
|
|
45
47
|
builder (2.1.2)
|
|
46
|
-
columnize (0.3.
|
|
47
|
-
diff-lcs (1.1.
|
|
48
|
+
columnize (0.3.4)
|
|
49
|
+
diff-lcs (1.1.3)
|
|
48
50
|
erubis (2.6.6)
|
|
49
51
|
abstract (>= 1.0.0)
|
|
50
52
|
faraday (0.6.1)
|
|
51
53
|
addressable (~> 2.2.4)
|
|
52
54
|
multipart-post (~> 1.1.0)
|
|
53
|
-
rack (
|
|
54
|
-
i18n (0.
|
|
55
|
-
|
|
55
|
+
rack (>= 1.1.0, < 2)
|
|
56
|
+
i18n (0.6.0)
|
|
57
|
+
launchy (2.0.5)
|
|
58
|
+
addressable (~> 2.2.6)
|
|
59
|
+
linecache19 (0.5.12)
|
|
56
60
|
ruby_core_source (>= 0.1.4)
|
|
57
|
-
mail (2.2.
|
|
61
|
+
mail (2.2.19)
|
|
58
62
|
activesupport (>= 2.3.6)
|
|
59
63
|
i18n (>= 0.4.0)
|
|
60
64
|
mime-types (~> 1.16)
|
|
61
65
|
treetop (~> 1.4.8)
|
|
62
66
|
mime-types (1.16)
|
|
67
|
+
mongo (1.4.1)
|
|
68
|
+
bson (= 1.4.1)
|
|
69
|
+
mongo_mapper (0.9.2)
|
|
70
|
+
activemodel (~> 3.0)
|
|
71
|
+
activesupport (~> 3.0)
|
|
72
|
+
plucky (~> 0.3.8)
|
|
63
73
|
multi_json (1.0.3)
|
|
64
74
|
multipart-post (1.1.3)
|
|
65
75
|
oauth (0.4.5)
|
|
66
76
|
oauth2 (0.4.1)
|
|
67
77
|
faraday (~> 0.6.1)
|
|
68
78
|
multi_json (>= 0.0.5)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
plucky (0.3.8)
|
|
80
|
+
mongo (~> 1.3)
|
|
81
|
+
polyglot (0.3.2)
|
|
82
|
+
rack (1.2.4)
|
|
83
|
+
rack-mount (0.6.14)
|
|
72
84
|
rack (>= 1.0.0)
|
|
73
|
-
rack-test (0.5.
|
|
85
|
+
rack-test (0.5.7)
|
|
74
86
|
rack (>= 1.0)
|
|
75
87
|
rails (3.0.3)
|
|
76
88
|
actionmailer (= 3.0.3)
|
|
@@ -85,12 +97,12 @@ GEM
|
|
|
85
97
|
activesupport (= 3.0.3)
|
|
86
98
|
rake (>= 0.8.7)
|
|
87
99
|
thor (~> 0.14.4)
|
|
88
|
-
rake (0.
|
|
100
|
+
rake (0.9.2)
|
|
89
101
|
rspec (2.5.0)
|
|
90
102
|
rspec-core (~> 2.5.0)
|
|
91
103
|
rspec-expectations (~> 2.5.0)
|
|
92
104
|
rspec-mocks (~> 2.5.0)
|
|
93
|
-
rspec-core (2.5.
|
|
105
|
+
rspec-core (2.5.2)
|
|
94
106
|
rspec-expectations (2.5.0)
|
|
95
107
|
diff-lcs (~> 1.1.2)
|
|
96
108
|
rspec-mocks (2.5.0)
|
|
@@ -99,7 +111,7 @@ GEM
|
|
|
99
111
|
activesupport (~> 3.0)
|
|
100
112
|
railties (~> 3.0)
|
|
101
113
|
rspec (~> 2.5.0)
|
|
102
|
-
ruby-debug-base19 (0.11.
|
|
114
|
+
ruby-debug-base19 (0.11.25)
|
|
103
115
|
columnize (>= 0.3.1)
|
|
104
116
|
linecache19 (>= 0.5.11)
|
|
105
117
|
ruby_core_source (>= 0.1.4)
|
|
@@ -107,22 +119,27 @@ GEM
|
|
|
107
119
|
columnize (>= 0.3.1)
|
|
108
120
|
linecache19 (>= 0.5.11)
|
|
109
121
|
ruby-debug-base19 (>= 0.11.19)
|
|
110
|
-
ruby_core_source (0.1.
|
|
122
|
+
ruby_core_source (0.1.5)
|
|
111
123
|
archive-tar-minitar (>= 0.5.2)
|
|
112
|
-
simplecov (0.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
124
|
+
simplecov (0.5.4)
|
|
125
|
+
multi_json (~> 1.0.3)
|
|
126
|
+
simplecov-html (~> 0.5.3)
|
|
127
|
+
simplecov-html (0.5.3)
|
|
128
|
+
sqlite3 (1.3.4)
|
|
129
|
+
sqlite3-ruby (1.3.3)
|
|
130
|
+
sqlite3 (>= 1.3.3)
|
|
116
131
|
thor (0.14.6)
|
|
117
132
|
timecop (0.3.5)
|
|
118
|
-
treetop (1.4.
|
|
133
|
+
treetop (1.4.10)
|
|
134
|
+
polyglot
|
|
119
135
|
polyglot (>= 0.3.1)
|
|
120
|
-
tzinfo (0.3.
|
|
136
|
+
tzinfo (0.3.30)
|
|
121
137
|
|
|
122
138
|
PLATFORMS
|
|
123
139
|
ruby
|
|
124
140
|
|
|
125
141
|
DEPENDENCIES
|
|
142
|
+
launchy (~> 2.0.5)
|
|
126
143
|
rails (= 3.0.3)
|
|
127
144
|
rspec (~> 2.5.0)
|
|
128
145
|
rspec-rails (~> 2.5.0)
|
|
@@ -2,78 +2,88 @@ require 'oauth'
|
|
|
2
2
|
|
|
3
3
|
class ApplicationController < ActionController::Base
|
|
4
4
|
protect_from_forgery
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
#before_filter :validate_session, :only => [:test_should_be_logged_in] if defined?(:validate_session)
|
|
7
7
|
before_filter :require_login_from_http_basic, :only => [:test_http_basic_auth]
|
|
8
8
|
before_filter :require_login, :only => [:test_logout, :test_should_be_logged_in, :some_action]
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
def index
|
|
11
|
-
render :text => ""
|
|
12
11
|
end
|
|
13
12
|
|
|
14
13
|
def some_action
|
|
15
14
|
render :nothing => true
|
|
16
15
|
end
|
|
17
|
-
|
|
16
|
+
|
|
18
17
|
def test_login
|
|
19
18
|
@user = login(params[:username], params[:password])
|
|
20
19
|
render :text => ""
|
|
21
20
|
end
|
|
22
21
|
|
|
22
|
+
def test_auto_login
|
|
23
|
+
@user = User.find(:first)
|
|
24
|
+
auto_login(@user)
|
|
25
|
+
@result = current_user
|
|
26
|
+
render :text => ""
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
def test_return_to
|
|
24
30
|
@user = login(params[:username], params[:password])
|
|
25
31
|
redirect_back_or_to(:index, :notice => 'haha!')
|
|
26
32
|
end
|
|
27
|
-
|
|
33
|
+
|
|
28
34
|
def test_logout
|
|
29
35
|
logout
|
|
30
36
|
render :text => ""
|
|
31
37
|
end
|
|
32
|
-
|
|
38
|
+
|
|
33
39
|
def test_logout_with_remember
|
|
34
40
|
remember_me!
|
|
35
41
|
logout
|
|
36
42
|
render :text => ""
|
|
37
43
|
end
|
|
38
|
-
|
|
44
|
+
|
|
39
45
|
def test_login_with_remember
|
|
40
46
|
@user = login(params[:username], params[:password])
|
|
41
47
|
remember_me!
|
|
42
|
-
|
|
48
|
+
|
|
43
49
|
render :text => ""
|
|
44
50
|
end
|
|
45
|
-
|
|
51
|
+
|
|
46
52
|
def test_login_with_remember_in_login
|
|
47
53
|
@user = login(params[:username], params[:password], params[:remember])
|
|
48
|
-
|
|
54
|
+
|
|
49
55
|
render :text => ""
|
|
50
56
|
end
|
|
51
|
-
|
|
57
|
+
|
|
52
58
|
def test_login_from_cookie
|
|
53
59
|
@user = current_user
|
|
54
60
|
render :text => ""
|
|
55
61
|
end
|
|
56
|
-
|
|
62
|
+
|
|
57
63
|
def test_not_authenticated_action
|
|
58
64
|
render :text => "test_not_authenticated_action"
|
|
59
65
|
end
|
|
60
|
-
|
|
66
|
+
|
|
61
67
|
def test_should_be_logged_in
|
|
62
68
|
render :text => ""
|
|
63
69
|
end
|
|
64
|
-
|
|
70
|
+
|
|
65
71
|
def test_http_basic_auth
|
|
66
72
|
render :text => "HTTP Basic Auth"
|
|
67
73
|
end
|
|
68
|
-
|
|
74
|
+
|
|
69
75
|
def login_at_test
|
|
70
76
|
login_at(:twitter)
|
|
71
77
|
end
|
|
72
|
-
|
|
78
|
+
|
|
73
79
|
def login_at_test2
|
|
74
80
|
login_at(:facebook)
|
|
75
81
|
end
|
|
76
|
-
|
|
82
|
+
|
|
83
|
+
def login_at_test3
|
|
84
|
+
login_at(:github)
|
|
85
|
+
end
|
|
86
|
+
|
|
77
87
|
def test_login_from
|
|
78
88
|
if @user = login_from(:twitter)
|
|
79
89
|
redirect_to "bla", :notice => "Success!"
|
|
@@ -81,7 +91,7 @@ class ApplicationController < ActionController::Base
|
|
|
81
91
|
redirect_to "blu", :alert => "Failed!"
|
|
82
92
|
end
|
|
83
93
|
end
|
|
84
|
-
|
|
94
|
+
|
|
85
95
|
def test_login_from2
|
|
86
96
|
if @user = login_from(:facebook)
|
|
87
97
|
redirect_to "bla", :notice => "Success!"
|
|
@@ -89,7 +99,15 @@ class ApplicationController < ActionController::Base
|
|
|
89
99
|
redirect_to "blu", :alert => "Failed!"
|
|
90
100
|
end
|
|
91
101
|
end
|
|
92
|
-
|
|
102
|
+
|
|
103
|
+
def test_login_from3
|
|
104
|
+
if @user = login_from(:github)
|
|
105
|
+
redirect_to "bla", :notice => "Success!"
|
|
106
|
+
else
|
|
107
|
+
redirect_to "blu", :alert => "Failed!"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
93
111
|
def test_create_from_provider
|
|
94
112
|
provider = params[:provider]
|
|
95
113
|
login_from(provider)
|
|
@@ -99,9 +117,9 @@ class ApplicationController < ActionController::Base
|
|
|
99
117
|
redirect_to "blu", :alert => "Failed!"
|
|
100
118
|
end
|
|
101
119
|
end
|
|
102
|
-
|
|
120
|
+
|
|
103
121
|
protected
|
|
104
|
-
|
|
105
|
-
|
|
122
|
+
|
|
123
|
+
|
|
106
124
|
|
|
107
125
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%= form_tag :action => :test_login, :method => :post do %>
|
|
2
|
+
<div class="field">
|
|
3
|
+
<%= label_tag :username %><br />
|
|
4
|
+
<%= text_field_tag :username %>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="field">
|
|
7
|
+
<%= label_tag :password %><br />
|
|
8
|
+
<%= password_field_tag :password %>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="actions">
|
|
11
|
+
<%= submit_tag "Login" %>
|
|
12
|
+
</div>
|
|
13
|
+
<div>
|
|
14
|
+
<%= label_tag "keep me logged in" %><br />
|
|
15
|
+
<%= check_box_tag :remember %>
|
|
16
|
+
</div>
|
|
17
|
+
<% end %>
|
|
@@ -78,5 +78,28 @@ describe ApplicationController do
|
|
|
78
78
|
subject.current_users[1].should == user2
|
|
79
79
|
subject.current_users[2].should == user3
|
|
80
80
|
end
|
|
81
|
+
|
|
82
|
+
it "should not register login time if configured so" do
|
|
83
|
+
sorcery_controller_property_set(:register_login_time, false)
|
|
84
|
+
now = Time.now.utc
|
|
85
|
+
login_user
|
|
86
|
+
@user.last_login_at.should be_nil
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should not register logout time if configured so" do
|
|
90
|
+
sorcery_controller_property_set(:register_logout_time, false)
|
|
91
|
+
now = Time.now.utc
|
|
92
|
+
login_user
|
|
93
|
+
logout_user
|
|
94
|
+
@user.last_logout_at.should be_nil
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "should not register last activity time if configured so" do
|
|
98
|
+
sorcery_controller_property_set(:register_last_activity_time, false)
|
|
99
|
+
now = Time.now.utc
|
|
100
|
+
login_user
|
|
101
|
+
get :some_action
|
|
102
|
+
@user.last_activity_at.should be_nil
|
|
103
|
+
end
|
|
81
104
|
end
|
|
82
105
|
end
|
|
@@ -15,78 +15,107 @@ describe ApplicationController do
|
|
|
15
15
|
before(:all) do
|
|
16
16
|
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/external")
|
|
17
17
|
sorcery_reload!([:external])
|
|
18
|
-
sorcery_controller_property_set(:external_providers, [:facebook])
|
|
18
|
+
sorcery_controller_property_set(:external_providers, [:facebook, :github])
|
|
19
19
|
sorcery_controller_external_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
|
|
20
20
|
sorcery_controller_external_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
21
21
|
sorcery_controller_external_property_set(:facebook, :callback_url, "http://blabla.com")
|
|
22
|
+
sorcery_controller_external_property_set(:github, :key, "eYVNBjBDi33aa9GkA3w")
|
|
23
|
+
sorcery_controller_external_property_set(:github, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
24
|
+
sorcery_controller_external_property_set(:github, :callback_url, "http://blabla.com")
|
|
22
25
|
end
|
|
23
|
-
|
|
26
|
+
|
|
24
27
|
after(:all) do
|
|
25
28
|
ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/external")
|
|
26
29
|
end
|
|
27
30
|
# ----------------- OAuth -----------------------
|
|
28
31
|
describe ApplicationController, "with OAuth features" do
|
|
29
|
-
|
|
32
|
+
|
|
30
33
|
before(:each) do
|
|
31
34
|
stub_all_oauth2_requests!
|
|
32
35
|
end
|
|
33
|
-
|
|
36
|
+
|
|
34
37
|
after(:each) do
|
|
35
38
|
User.delete_all
|
|
36
39
|
Authentication.delete_all
|
|
37
40
|
end
|
|
38
|
-
|
|
41
|
+
|
|
39
42
|
it "login_at redirects correctly" do
|
|
40
43
|
create_new_user
|
|
41
44
|
get :login_at_test2
|
|
42
45
|
response.should be_a_redirect
|
|
43
|
-
#response.should redirect_to("http://myapi.com/oauth/authorize?client_id=key&redirect_uri=http%3A%2F%2Fblabla.com&scope=email%2Coffline_access&type=web_server")
|
|
44
46
|
response.should redirect_to("http://myapi.com/oauth/authorize?client_id=key&redirect_uri=http%3A%2F%2Fblabla.com&scope=email%2Coffline_access&response_type=code")
|
|
45
47
|
end
|
|
46
|
-
|
|
48
|
+
|
|
47
49
|
it "'login_from' logins if user exists" do
|
|
48
50
|
sorcery_model_property_set(:authentications_class, Authentication)
|
|
49
51
|
create_new_external_user(:facebook)
|
|
50
52
|
get :test_login_from2
|
|
51
53
|
flash[:notice].should == "Success!"
|
|
52
54
|
end
|
|
53
|
-
|
|
55
|
+
|
|
54
56
|
it "'login_from' fails if user doesn't exist" do
|
|
55
57
|
sorcery_model_property_set(:authentications_class, Authentication)
|
|
56
58
|
create_new_user
|
|
57
59
|
get :test_login_from2
|
|
58
60
|
flash[:alert].should == "Failed!"
|
|
59
61
|
end
|
|
62
|
+
|
|
63
|
+
# provider: github
|
|
64
|
+
it "login_at redirects correctly (github)" do
|
|
65
|
+
create_new_user
|
|
66
|
+
get :login_at_test3
|
|
67
|
+
response.should be_a_redirect
|
|
68
|
+
response.should redirect_to("http://myapi.com/oauth/authorize?client_id=key&redirect_uri=http%3A%2F%2Fblabla.com&scope=&response_type=code")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "'login_from' logins if user exists (github)" do
|
|
72
|
+
sorcery_model_property_set(:authentications_class, Authentication)
|
|
73
|
+
create_new_external_user(:github)
|
|
74
|
+
get :test_login_from3
|
|
75
|
+
flash[:notice].should == "Success!"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "'login_from' fails if user doesn't exist (github)" do
|
|
79
|
+
sorcery_model_property_set(:authentications_class, Authentication)
|
|
80
|
+
create_new_user
|
|
81
|
+
get :test_login_from3
|
|
82
|
+
flash[:alert].should == "Failed!"
|
|
83
|
+
end
|
|
84
|
+
|
|
60
85
|
end
|
|
61
|
-
|
|
86
|
+
|
|
87
|
+
|
|
62
88
|
describe ApplicationController do
|
|
63
89
|
it_behaves_like "oauth2_controller"
|
|
64
90
|
end
|
|
65
|
-
|
|
91
|
+
|
|
66
92
|
describe ApplicationController, "OAuth with User Activation features" do
|
|
67
93
|
before(:all) do
|
|
68
94
|
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/activation")
|
|
69
95
|
sorcery_reload!([:user_activation,:external], :user_activation_mailer => ::SorceryMailer)
|
|
70
|
-
sorcery_controller_property_set(:external_providers, [:facebook])
|
|
96
|
+
sorcery_controller_property_set(:external_providers, [:facebook, :github])
|
|
71
97
|
sorcery_controller_external_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
|
|
72
98
|
sorcery_controller_external_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
73
99
|
sorcery_controller_external_property_set(:facebook, :callback_url, "http://blabla.com")
|
|
100
|
+
sorcery_controller_external_property_set(:github, :key, "eYVNBjBDi33aa9GkA3w")
|
|
101
|
+
sorcery_controller_external_property_set(:github, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
102
|
+
sorcery_controller_external_property_set(:github, :callback_url, "http://blabla.com")
|
|
74
103
|
end
|
|
75
|
-
|
|
104
|
+
|
|
76
105
|
after(:all) do
|
|
77
106
|
ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/activation")
|
|
78
107
|
end
|
|
79
|
-
|
|
108
|
+
|
|
80
109
|
after(:each) do
|
|
81
110
|
User.delete_all
|
|
82
111
|
end
|
|
83
|
-
|
|
112
|
+
|
|
84
113
|
it "should not send activation email to external users" do
|
|
85
114
|
old_size = ActionMailer::Base.deliveries.size
|
|
86
115
|
create_new_external_user(:facebook)
|
|
87
116
|
ActionMailer::Base.deliveries.size.should == old_size
|
|
88
117
|
end
|
|
89
|
-
|
|
118
|
+
|
|
90
119
|
it "should not send external users an activation success email" do
|
|
91
120
|
sorcery_model_property_set(:activation_success_email_method_name, nil)
|
|
92
121
|
create_new_external_user(:facebook)
|
|
@@ -94,6 +123,20 @@ describe ApplicationController do
|
|
|
94
123
|
@user.activate!
|
|
95
124
|
ActionMailer::Base.deliveries.size.should == old_size
|
|
96
125
|
end
|
|
126
|
+
|
|
127
|
+
# provider: github
|
|
128
|
+
it "should not send activation email to external users (github)" do
|
|
129
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
130
|
+
create_new_external_user(:github)
|
|
131
|
+
ActionMailer::Base.deliveries.size.should == old_size
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "should not send external users an activation success email (github)" do
|
|
135
|
+
sorcery_model_property_set(:activation_success_email_method_name, nil)
|
|
136
|
+
create_new_external_user(:github)
|
|
137
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
138
|
+
@user.activate!
|
|
139
|
+
ActionMailer::Base.deliveries.size.should == old_size
|
|
140
|
+
end
|
|
97
141
|
end
|
|
98
|
-
|
|
99
142
|
end
|
|
@@ -4,6 +4,7 @@ describe ApplicationController do
|
|
|
4
4
|
|
|
5
5
|
# ----------------- REMEMBER ME -----------------------
|
|
6
6
|
describe ApplicationController, "with remember me features" do
|
|
7
|
+
|
|
7
8
|
before(:all) do
|
|
8
9
|
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/remember_me")
|
|
9
10
|
sorcery_reload!([:remember_me])
|
|
@@ -25,25 +26,29 @@ describe ApplicationController do
|
|
|
25
26
|
|
|
26
27
|
it "should set cookie on remember_me!" do
|
|
27
28
|
post :test_login_with_remember, :username => 'gizmo', :password => 'secret'
|
|
28
|
-
cookies
|
|
29
|
+
@request.cookies.merge!(cookies)
|
|
30
|
+
cookies = ActionDispatch::Cookies::CookieJar.build(@request)
|
|
31
|
+
cookies.signed["remember_me_token"].should == assigns[:current_user].remember_me_token
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
it "should clear cookie on forget_me!" do
|
|
32
35
|
cookies["remember_me_token"] == {:value => 'asd54234dsfsd43534', :expires => 3600}
|
|
33
36
|
get :test_logout
|
|
34
|
-
cookies["remember_me_token"].should
|
|
37
|
+
cookies["remember_me_token"].should be_nil
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
it "login(username,password,remember_me) should login and remember" do
|
|
38
41
|
post :test_login_with_remember_in_login, :username => 'gizmo', :password => 'secret', :remember => "1"
|
|
39
|
-
cookies
|
|
40
|
-
cookies
|
|
42
|
+
@request.cookies.merge!(cookies)
|
|
43
|
+
cookies = ActionDispatch::Cookies::CookieJar.build(@request)
|
|
44
|
+
cookies.signed["remember_me_token"].should_not be_nil
|
|
45
|
+
cookies.signed["remember_me_token"].should == assigns[:user].remember_me_token
|
|
41
46
|
end
|
|
42
47
|
|
|
43
48
|
it "logout should also forget_me!" do
|
|
44
49
|
session[:user_id] = @user.id
|
|
45
50
|
get :test_logout_with_remember
|
|
46
|
-
cookies["remember_me_token"].should
|
|
51
|
+
cookies["remember_me_token"].should be_nil
|
|
47
52
|
end
|
|
48
53
|
|
|
49
54
|
it "should login_from_cookie" do
|
|
@@ -57,9 +62,35 @@ describe ApplicationController do
|
|
|
57
62
|
assigns[:current_user].should == @user
|
|
58
63
|
end
|
|
59
64
|
|
|
65
|
+
it "should not remember_me! when not asked to, even if third parameter is used" do
|
|
66
|
+
post :test_login_with_remember_in_login, :username => 'gizmo', :password => 'secret', :remember => "0"
|
|
67
|
+
cookies["remember_me_token"].should be_nil
|
|
68
|
+
end
|
|
69
|
+
|
|
60
70
|
it "should not remember_me! when not asked to" do
|
|
61
71
|
post :test_login, :username => 'gizmo', :password => 'secret'
|
|
62
|
-
cookies["remember_me_token"].should
|
|
72
|
+
cookies["remember_me_token"].should be_nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# --- login_user(user) ---
|
|
76
|
+
specify { should respond_to(:auto_login) }
|
|
77
|
+
|
|
78
|
+
it "auto_login(user) should login a user instance without remembering" do
|
|
79
|
+
create_new_user
|
|
80
|
+
session[:user_id] = nil
|
|
81
|
+
subject.auto_login(@user)
|
|
82
|
+
get :test_login_from_cookie
|
|
83
|
+
assigns[:current_user].should == @user
|
|
84
|
+
cookies["remember_me_token"].should be_nil
|
|
63
85
|
end
|
|
86
|
+
|
|
87
|
+
it "auto_login(user, true) should login a user instance with remembering" do
|
|
88
|
+
create_new_user
|
|
89
|
+
session[:user_id] = nil
|
|
90
|
+
subject.auto_login(@user, true)
|
|
91
|
+
get :test_login_from_cookie
|
|
92
|
+
assigns[:current_user].should == @user
|
|
93
|
+
cookies["remember_me_token"].should_not be_nil
|
|
94
|
+
end
|
|
64
95
|
end
|
|
65
96
|
end
|
|
@@ -28,13 +28,20 @@ describe ApplicationController do
|
|
|
28
28
|
# ----------------- PLUGIN ACTIVATED -----------------------
|
|
29
29
|
describe ApplicationController, "when activated with sorcery" do
|
|
30
30
|
before(:all) do
|
|
31
|
+
sorcery_reload!
|
|
31
32
|
User.delete_all
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
before(:each) do
|
|
32
36
|
create_new_user
|
|
33
37
|
end
|
|
34
38
|
|
|
35
39
|
after(:each) do
|
|
36
40
|
Sorcery::Controller::Config.reset!
|
|
41
|
+
sorcery_reload!
|
|
42
|
+
User.delete_all
|
|
37
43
|
sorcery_controller_property_set(:user_class, User)
|
|
44
|
+
sorcery_model_property_set(:username_attribute_names, [:username, :email])
|
|
38
45
|
end
|
|
39
46
|
|
|
40
47
|
specify { should respond_to(:login) }
|
|
@@ -50,6 +57,12 @@ describe ApplicationController do
|
|
|
50
57
|
assigns[:user].should == @user
|
|
51
58
|
session[:user_id].should == @user.id
|
|
52
59
|
end
|
|
60
|
+
|
|
61
|
+
it "login(email,password) should return the user when success and set the session with user.id" do
|
|
62
|
+
get :test_login, :username => 'bla@bla.com', :password => 'secret'
|
|
63
|
+
assigns[:user].should == @user
|
|
64
|
+
session[:user_id].should == @user.id
|
|
65
|
+
end
|
|
53
66
|
|
|
54
67
|
it "login(username,password) should return nil and not set the session when failure" do
|
|
55
68
|
get :test_login, :username => 'gizmo', :password => 'opensesame!'
|
|
@@ -107,6 +120,23 @@ describe ApplicationController do
|
|
|
107
120
|
flash[:notice].should == "haha!"
|
|
108
121
|
end
|
|
109
122
|
|
|
123
|
+
|
|
124
|
+
# --- auto_login(user) ---
|
|
125
|
+
specify { should respond_to(:auto_login) }
|
|
126
|
+
|
|
127
|
+
it "auto_login(user) should login a user instance" do
|
|
128
|
+
session[:user_id] = nil
|
|
129
|
+
subject.auto_login(@user)
|
|
130
|
+
subject.logged_in?.should be_true
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "auto_login(user) should work even if current_user was already set to false" do
|
|
134
|
+
get :test_logout
|
|
135
|
+
session[:user_id].should be_nil
|
|
136
|
+
subject.current_user.should be_false
|
|
137
|
+
get :test_auto_login
|
|
138
|
+
assigns[:result].should == User.find(:first)
|
|
139
|
+
end
|
|
110
140
|
end
|
|
111
141
|
|
|
112
142
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
#
|
|
3
|
+
# describe "the login process", :type => :request do
|
|
4
|
+
# before(:all) do
|
|
5
|
+
# sorcery_reload!
|
|
6
|
+
# create_new_user
|
|
7
|
+
# end
|
|
8
|
+
#
|
|
9
|
+
# after(:all) do
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# it "handles unverified request" do
|
|
13
|
+
# visit root_path
|
|
14
|
+
# # save_and_open_page
|
|
15
|
+
# fill_in 'Username', :with => 'gizmo'
|
|
16
|
+
# fill_in 'Password', :with => 'secret'
|
|
17
|
+
# # <input name="authenticity_token" type="hidden" value="+8M9lXnjnhAW/mAuzwI9Mmy6hM+00qZJa8VMQUg+NmM=">
|
|
18
|
+
# #page.execute_script("$$('hidden').value='mezuza'")
|
|
19
|
+
# #save_and_open_page
|
|
20
|
+
# click_button 'Login'
|
|
21
|
+
# save_and_open_page
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
$: << File.join(File.dirname(__FILE__), '..', '..', 'lib' )
|
|
2
2
|
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
|
3
|
+
|
|
3
4
|
# Set the default environment to sqlite3's in_memory database
|
|
4
|
-
ENV[
|
|
5
|
-
require File.expand_path("../../config/environment", __FILE__)
|
|
6
|
-
require 'rspec/rails'
|
|
5
|
+
ENV["RAILS_ENV"] ||= 'in_memory'
|
|
6
|
+
require File.expand_path("../../config/environment", __FILE__)
|
|
7
|
+
require 'rspec/rails'
|
|
8
|
+
#require 'capybara/rspec'
|
|
7
9
|
require 'timecop'
|
|
8
10
|
# require 'simplecov'
|
|
9
11
|
# SimpleCov.root File.join(File.dirname(__FILE__), "..", "..", "rails3" )
|
|
@@ -22,8 +24,6 @@ require 'timecop'
|
|
|
22
24
|
# in spec/support/ and its subdirectories.
|
|
23
25
|
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
27
|
RSpec.configure do |config|
|
|
28
28
|
config.include RSpec::Rails::ControllerExampleGroup, :example_group => { :file_path => /controller(.)*_spec.rb$/ }
|
|
29
29
|
# == Mock Framework
|
|
@@ -43,6 +43,7 @@ RSpec.configure do |config|
|
|
|
43
43
|
# instead of true.
|
|
44
44
|
config.use_transactional_fixtures = true
|
|
45
45
|
|
|
46
|
+
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
46
47
|
config.before(:suite) do
|
|
47
48
|
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/core")
|
|
48
49
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--colour
|