castle_devise 0.1.0 → 0.2.0
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/.github/workflows/specs.yml +24 -6
- data/.gitignore +6 -0
- data/.rspec +1 -1
- data/Appraisals +13 -0
- data/CHANGELOG.md +15 -2
- data/Gemfile +3 -1
- data/Gemfile.lock +63 -40
- data/README.md +20 -3
- data/castle_devise.gemspec +4 -4
- data/gemfiles/rails_5.2.gemfile +17 -0
- data/gemfiles/rails_6.0.gemfile +17 -0
- data/gemfiles/rails_6.1.gemfile +17 -0
- data/lib/castle_devise.rb +4 -2
- data/lib/castle_devise/models/castle_protectable.rb +6 -1
- data/lib/castle_devise/patches.rb +2 -1
- data/lib/castle_devise/patches/passwords_controller.rb +50 -0
- data/lib/castle_devise/patches/registrations_controller.rb +52 -3
- data/lib/castle_devise/sdk_facade.rb +18 -7
- data/lib/castle_devise/version.rb +1 -1
- metadata +34 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7cc0ef1100f1ceb942fa1be6553b6b7ca862656e3c7a6b9b57459285a69a46a7
|
4
|
+
data.tar.gz: 9222268f8c6e22fb367bbc0cc9a0ce52b5dc8854f8eefa0f2f34e2afaa4a92eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6a11b460114c2133776991e4cde4f11a9030e5b019ea0162712b070a72b9adbd50cfad1f866cf90a92b05f505464ded6d9727a474c22edd5f65a9ed6f4fb0d6
|
7
|
+
data.tar.gz: 292fe6b7dff6f11135c8e63b53ee4484cc8c1dd93dab449d58ef765b29935a8f4bbb925896bf4b4d06b21f1e44cc7ce748af8226287c832b9e8409026bc81c23
|
data/.github/workflows/specs.yml
CHANGED
@@ -1,25 +1,43 @@
|
|
1
1
|
name: Specs
|
2
2
|
|
3
|
-
on: [push
|
3
|
+
on: [push]
|
4
4
|
|
5
5
|
jobs:
|
6
6
|
build:
|
7
7
|
environment: tests
|
8
8
|
runs-on: ubuntu-latest
|
9
|
+
|
10
|
+
strategy:
|
11
|
+
fail-fast: false
|
12
|
+
matrix:
|
13
|
+
ruby: ["2.6", "2.7", "3.0"]
|
14
|
+
rails: ["5.2", "6.0", "6.1"]
|
15
|
+
exclude:
|
16
|
+
- ruby: "3.0"
|
17
|
+
rails: "5.2"
|
18
|
+
|
9
19
|
steps:
|
10
20
|
- uses: actions/checkout@v2
|
11
|
-
- name: Set up Ruby
|
21
|
+
- name: Set up Ruby ${{ matrix.ruby }}
|
12
22
|
uses: ruby/setup-ruby@v1
|
13
23
|
with:
|
14
|
-
ruby-version:
|
15
|
-
- name:
|
24
|
+
ruby-version: ${{ matrix.ruby }}
|
25
|
+
- name: Install depenencies
|
26
|
+
env:
|
27
|
+
BUNDLE_GEMFILE: gemfiles/rails_${{ matrix.rails }}.gemfile
|
16
28
|
run: |
|
17
|
-
gem
|
29
|
+
gem update --system
|
30
|
+
bundle config path vendor/bundle
|
18
31
|
bundle install
|
19
|
-
|
32
|
+
- name: Run specs
|
20
33
|
env:
|
34
|
+
BUNDLE_GEMFILE: gemfiles/rails_${{ matrix.rails }}.gemfile
|
21
35
|
CASTLE_API_SECRET: ${{ secrets.CASTLE_API_SECRET }}
|
36
|
+
run: |
|
37
|
+
bundle exec rake
|
22
38
|
- name: Simplecov Report
|
39
|
+
if:
|
40
|
+
${{ matrix.rails == '6.1' && matrix.ruby >= '3.0' }}
|
23
41
|
uses: aki77/simplecov-report-action@v1
|
24
42
|
with:
|
25
43
|
token: ${{ secrets.GITHUB_TOKEN }}
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/Appraisals
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
|
-
|
1
|
+
# Changelog
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [Unreleased][main]
|
4
|
+
|
5
|
+
## [0.2.0] - 2021-08-12
|
6
|
+
|
7
|
+
- Add Log action for $profile_update event with $succeeded and $failed statuses during reset password process
|
8
|
+
- Add Risk action for $profile_update event with $attempted status and Log action for $profile_update event with $succeeded and $failed statuses
|
9
|
+
- Add Log action for $password_reset_request event with $succeeded and $failed statuses
|
10
|
+
- Run specs in multiple ruby and rails versions.
|
11
|
+
|
12
|
+
## [0.1.0] - 2021-07-08
|
4
13
|
|
5
14
|
- Initial release
|
15
|
+
|
16
|
+
[main]: https://github.com/castle/castle_devise/compare/v0.2.0...HEAD
|
17
|
+
[0.2.0]: https://github.com/castle/castle_devise/compare/v0.1.0...v0.2.0
|
18
|
+
[0.1.0]: https://github.com/castle/castle_devise/releases/tag/v0.1.0
|
data/Gemfile
CHANGED
@@ -5,8 +5,10 @@ source "https://rubygems.org"
|
|
5
5
|
# Specify your gem's dependencies in castle-devise.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
+
gem "actionmailer"
|
8
9
|
gem "activerecord"
|
9
|
-
gem "
|
10
|
+
gem "byebug"
|
11
|
+
gem "railties", "~> 6.1"
|
10
12
|
gem "rake"
|
11
13
|
gem "rspec"
|
12
14
|
gem "rspec-rails"
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
castle_devise (0.
|
4
|
+
castle_devise (0.2.0)
|
5
5
|
activesupport (>= 5.0)
|
6
6
|
castle-rb (>= 7.0, < 8.0)
|
7
7
|
devise (>= 4.3.0, < 5.0)
|
@@ -9,36 +9,50 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
actionmailer (6.1.4)
|
13
|
+
actionpack (= 6.1.4)
|
14
|
+
actionview (= 6.1.4)
|
15
|
+
activejob (= 6.1.4)
|
16
|
+
activesupport (= 6.1.4)
|
17
|
+
mail (~> 2.5, >= 2.5.4)
|
18
|
+
rails-dom-testing (~> 2.0)
|
19
|
+
actionpack (6.1.4)
|
20
|
+
actionview (= 6.1.4)
|
21
|
+
activesupport (= 6.1.4)
|
22
|
+
rack (~> 2.0, >= 2.0.9)
|
16
23
|
rack-test (>= 0.6.3)
|
17
24
|
rails-dom-testing (~> 2.0)
|
18
|
-
rails-html-sanitizer (~> 1.0, >= 1.0
|
19
|
-
actionview (
|
20
|
-
activesupport (=
|
25
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
26
|
+
actionview (6.1.4)
|
27
|
+
activesupport (= 6.1.4)
|
21
28
|
builder (~> 3.1)
|
22
29
|
erubi (~> 1.4)
|
23
30
|
rails-dom-testing (~> 2.0)
|
24
|
-
rails-html-sanitizer (~> 1.
|
25
|
-
|
26
|
-
activesupport (=
|
27
|
-
|
28
|
-
|
29
|
-
activesupport (=
|
30
|
-
|
31
|
-
|
31
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
32
|
+
activejob (6.1.4)
|
33
|
+
activesupport (= 6.1.4)
|
34
|
+
globalid (>= 0.3.6)
|
35
|
+
activemodel (6.1.4)
|
36
|
+
activesupport (= 6.1.4)
|
37
|
+
activerecord (6.1.4)
|
38
|
+
activemodel (= 6.1.4)
|
39
|
+
activesupport (= 6.1.4)
|
40
|
+
activesupport (6.1.4)
|
32
41
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
33
|
-
i18n (>=
|
34
|
-
minitest (
|
35
|
-
tzinfo (~>
|
36
|
-
|
42
|
+
i18n (>= 1.6, < 2)
|
43
|
+
minitest (>= 5.1)
|
44
|
+
tzinfo (~> 2.0)
|
45
|
+
zeitwerk (~> 2.3)
|
46
|
+
addressable (2.8.0)
|
37
47
|
public_suffix (>= 2.0.2, < 5.0)
|
38
|
-
|
48
|
+
appraisal (2.3.0)
|
49
|
+
bundler
|
50
|
+
rake
|
51
|
+
thor (>= 0.14.0)
|
39
52
|
ast (2.4.2)
|
40
53
|
bcrypt (3.1.16)
|
41
54
|
builder (3.2.4)
|
55
|
+
byebug (11.1.3)
|
42
56
|
castle-rb (7.1.1)
|
43
57
|
concurrent-ruby (1.1.9)
|
44
58
|
crack (0.4.5)
|
@@ -53,19 +67,24 @@ GEM
|
|
53
67
|
diff-lcs (1.4.4)
|
54
68
|
docile (1.4.0)
|
55
69
|
erubi (1.10.0)
|
70
|
+
globalid (0.5.1)
|
71
|
+
activesupport (>= 5.0)
|
56
72
|
hashdiff (1.0.1)
|
57
73
|
i18n (1.8.10)
|
58
74
|
concurrent-ruby (~> 1.0)
|
59
75
|
loofah (2.10.0)
|
60
76
|
crass (~> 1.0.2)
|
61
77
|
nokogiri (>= 1.5.9)
|
78
|
+
mail (2.7.1)
|
79
|
+
mini_mime (>= 0.1.1)
|
62
80
|
method_source (1.0.0)
|
81
|
+
mini_mime (1.1.0)
|
63
82
|
minitest (5.14.4)
|
64
83
|
nokogiri (1.11.7-x86_64-darwin)
|
65
84
|
racc (~> 1.4)
|
66
85
|
orm_adapter (0.5.0)
|
67
86
|
parallel (1.20.1)
|
68
|
-
parser (3.0.
|
87
|
+
parser (3.0.2.0)
|
69
88
|
ast (~> 2.4.1)
|
70
89
|
public_suffix (4.0.6)
|
71
90
|
racc (1.5.2)
|
@@ -77,14 +96,14 @@ GEM
|
|
77
96
|
nokogiri (>= 1.6)
|
78
97
|
rails-html-sanitizer (1.3.0)
|
79
98
|
loofah (~> 2.3)
|
80
|
-
railties (
|
81
|
-
actionpack (=
|
82
|
-
activesupport (=
|
99
|
+
railties (6.1.4)
|
100
|
+
actionpack (= 6.1.4)
|
101
|
+
activesupport (= 6.1.4)
|
83
102
|
method_source
|
84
|
-
rake (>= 0.
|
85
|
-
thor (
|
103
|
+
rake (>= 0.13)
|
104
|
+
thor (~> 1.0)
|
86
105
|
rainbow (3.0.0)
|
87
|
-
rake (13.0.
|
106
|
+
rake (13.0.6)
|
88
107
|
regexp_parser (2.1.1)
|
89
108
|
responders (3.0.1)
|
90
109
|
actionpack (>= 5.0)
|
@@ -111,18 +130,18 @@ GEM
|
|
111
130
|
rspec-mocks (~> 3.10)
|
112
131
|
rspec-support (~> 3.10)
|
113
132
|
rspec-support (3.10.2)
|
114
|
-
rubocop (1.
|
133
|
+
rubocop (1.18.4)
|
115
134
|
parallel (~> 1.10)
|
116
135
|
parser (>= 3.0.0.0)
|
117
136
|
rainbow (>= 2.2.2, < 4.0)
|
118
137
|
regexp_parser (>= 1.8, < 3.0)
|
119
138
|
rexml
|
120
|
-
rubocop-ast (>= 1.
|
139
|
+
rubocop-ast (>= 1.8.0, < 2.0)
|
121
140
|
ruby-progressbar (~> 1.7)
|
122
141
|
unicode-display_width (>= 1.4.0, < 3.0)
|
123
|
-
rubocop-ast (1.
|
142
|
+
rubocop-ast (1.8.0)
|
124
143
|
parser (>= 3.0.1.1)
|
125
|
-
rubocop-performance (1.11.
|
144
|
+
rubocop-performance (1.11.4)
|
126
145
|
rubocop (>= 1.7.0, < 2.0)
|
127
146
|
rubocop-ast (>= 0.4.0)
|
128
147
|
ruby-progressbar (1.11.0)
|
@@ -133,13 +152,12 @@ GEM
|
|
133
152
|
simplecov-html (0.12.3)
|
134
153
|
simplecov_json_formatter (0.1.3)
|
135
154
|
sqlite3 (1.4.2)
|
136
|
-
standard (1.1.
|
137
|
-
rubocop (= 1.
|
138
|
-
rubocop-performance (= 1.11.
|
155
|
+
standard (1.1.6)
|
156
|
+
rubocop (= 1.18.4)
|
157
|
+
rubocop-performance (= 1.11.4)
|
139
158
|
thor (1.1.0)
|
140
|
-
|
141
|
-
|
142
|
-
thread_safe (~> 0.1)
|
159
|
+
tzinfo (2.0.4)
|
160
|
+
concurrent-ruby (~> 1.0)
|
143
161
|
unicode-display_width (2.0.0)
|
144
162
|
vcr (6.0.0)
|
145
163
|
warden (1.2.9)
|
@@ -148,14 +166,19 @@ GEM
|
|
148
166
|
addressable (>= 2.3.6)
|
149
167
|
crack (>= 0.3.2)
|
150
168
|
hashdiff (>= 0.4.0, < 2.0.0)
|
169
|
+
zeitwerk (2.4.2)
|
151
170
|
|
152
171
|
PLATFORMS
|
153
172
|
x86_64-darwin-18
|
173
|
+
x86_64-darwin-19
|
154
174
|
|
155
175
|
DEPENDENCIES
|
176
|
+
actionmailer
|
156
177
|
activerecord
|
178
|
+
appraisal (~> 2.3.0)
|
179
|
+
byebug
|
157
180
|
castle_devise!
|
158
|
-
railties (~>
|
181
|
+
railties (~> 6.1)
|
159
182
|
rake
|
160
183
|
rspec
|
161
184
|
rspec-rails
|
@@ -166,4 +189,4 @@ DEPENDENCIES
|
|
166
189
|
webmock
|
167
190
|
|
168
191
|
BUNDLED WITH
|
169
|
-
2.2.
|
192
|
+
2.2.23
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[](https://badge.fury.io/rb/castle_devise)
|
2
|
+
|
1
3
|
**Disclaimer:** CastleDevise is currently in beta. There might be some upcoming breaking changes to the gem before we stabilize the API.
|
2
4
|
|
3
5
|
---
|
@@ -9,6 +11,8 @@ CastleDevise is a [Devise](https://github.com/heartcombo/devise) plugin that int
|
|
9
11
|
It currently provides the following features:
|
10
12
|
- preventing bots from registration attacks using Castle's [Filter API](https://docs.castle.io/v1/reference/api-reference/#filter)
|
11
13
|
- preventing ATO attacks using Castle's [Risk API](https://docs.castle.io/v1/reference/api-reference/#risk)
|
14
|
+
- blocks attempts to update passwords for high-risk logged-in users
|
15
|
+
- logs attempts of password reset flows so that you can see them on the Castle dashboard
|
12
16
|
|
13
17
|
If you want to learn about all capabilities of Castle, please take a look at [our documentation](https://docs.castle.io/).
|
14
18
|
|
@@ -83,9 +87,19 @@ You're set! Now verify that everything works by logging in to your application a
|
|
83
87
|
|
84
88
|
#### Further steps if you're using Webpacker
|
85
89
|
|
86
|
-
Add `castle.js` to your package.json file
|
90
|
+
Add `castle.js` to your package.json file:
|
91
|
+
|
92
|
+
```
|
93
|
+
yarn add castle.js
|
94
|
+
```
|
95
|
+
|
96
|
+
Require castle.js in your application pack:
|
97
|
+
|
98
|
+
```javascript
|
99
|
+
require("castle.js");
|
87
100
|
|
88
|
-
|
101
|
+
_castle("setAppId", YOUR_APPLICATION_ID);
|
102
|
+
```
|
89
103
|
|
90
104
|
|
91
105
|
## How-Tos
|
@@ -161,7 +175,10 @@ class User < ApplicationRecord
|
|
161
175
|
before_registration: true,
|
162
176
|
# set it to false to prevent CastleDevise from
|
163
177
|
# sending risk($login) and log($login, $failed)
|
164
|
-
after_login: true
|
178
|
+
after_login: true,
|
179
|
+
# set it to false to prevent CastleDevise from
|
180
|
+
# sending log($password_reset_request)
|
181
|
+
after_password_reset_request: true
|
165
182
|
}
|
166
183
|
end
|
167
184
|
```
|
data/castle_devise.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.homepage = "https://github.com/castle/castle_devise"
|
12
12
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
13
13
|
|
14
|
-
spec.authors = ["Kacper Madej", "Johan Brissmyr"]
|
14
|
+
spec.authors = ["Kacper Madej", "Dawid Libiszewski", "Johan Brissmyr"]
|
15
15
|
spec.email = ["kacper@castle.io"]
|
16
16
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
@@ -27,9 +27,9 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
-
# Uncomment to register a new dependency of your gem
|
31
|
-
spec.add_dependency "castle-rb", ">= 7.0", "< 8.0"
|
32
30
|
spec.add_dependency "activesupport", ">= 5.0"
|
31
|
+
spec.add_dependency "castle-rb", ">= 7.0", "< 8.0"
|
32
|
+
spec.add_dependency "devise", ">= 4.3.0", "< 5.0"
|
33
33
|
|
34
|
-
spec.
|
34
|
+
spec.add_development_dependency "appraisal", "~> 2.3.0"
|
35
35
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "actionmailer"
|
6
|
+
gem "activerecord"
|
7
|
+
gem "railties", "~> 5.2.6"
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec"
|
10
|
+
gem "rspec-rails"
|
11
|
+
gem "simplecov"
|
12
|
+
gem "standard"
|
13
|
+
gem "sqlite3"
|
14
|
+
gem "vcr"
|
15
|
+
gem "webmock"
|
16
|
+
|
17
|
+
gemspec path: "../"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "actionmailer"
|
6
|
+
gem "activerecord"
|
7
|
+
gem "railties", "~> 6.0.4"
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec"
|
10
|
+
gem "rspec-rails"
|
11
|
+
gem "simplecov"
|
12
|
+
gem "standard"
|
13
|
+
gem "sqlite3"
|
14
|
+
gem "vcr"
|
15
|
+
gem "webmock"
|
16
|
+
|
17
|
+
gemspec path: "../"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "actionmailer"
|
6
|
+
gem "activerecord"
|
7
|
+
gem "railties", "~> 6.1.4"
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec"
|
10
|
+
gem "rspec-rails"
|
11
|
+
gem "simplecov"
|
12
|
+
gem "standard"
|
13
|
+
gem "sqlite3"
|
14
|
+
gem "vcr"
|
15
|
+
gem "webmock"
|
16
|
+
|
17
|
+
gemspec path: "../"
|
data/lib/castle_devise.rb
CHANGED
@@ -60,8 +60,8 @@ require_relative "castle_devise/controllers/helpers"
|
|
60
60
|
require_relative "castle_devise/helpers/castle_helper"
|
61
61
|
require_relative "castle_devise/hooks/castle_protectable"
|
62
62
|
require_relative "castle_devise/models/castle_protectable"
|
63
|
+
require_relative "castle_devise/patches/passwords_controller"
|
63
64
|
require_relative "castle_devise/patches/registrations_controller"
|
64
|
-
|
65
65
|
require_relative "castle_devise/rails"
|
66
66
|
|
67
67
|
# Monkey patching Devise module in order to add
|
@@ -71,7 +71,9 @@ module Devise
|
|
71
71
|
mattr_accessor :castle_hooks
|
72
72
|
@@castle_hooks = {
|
73
73
|
before_registration: true,
|
74
|
-
after_login: true
|
74
|
+
after_login: true,
|
75
|
+
after_password_reset_request: true,
|
76
|
+
profile_update: true
|
75
77
|
}
|
76
78
|
end
|
77
79
|
|
@@ -10,7 +10,12 @@ module Devise
|
|
10
10
|
# castle_hooks: configures which events trigger Castle API calls
|
11
11
|
# {
|
12
12
|
# after_login: true, # trigger risk($login) and log($login, $failed),
|
13
|
-
# before_registration: true # trigger filter($registration)
|
13
|
+
# before_registration: true, # trigger filter($registration)
|
14
|
+
# after_password_reset_request: true, # trigger log($password_reset_request, $succeeded)
|
15
|
+
# # and log($password_reset_request, $failed)
|
16
|
+
# profile_update: true # trigger risk($profile_update, $attempted),
|
17
|
+
# # log($profile_update, $succeeded)
|
18
|
+
# # and log($profile_update, $failed)
|
14
19
|
# }
|
15
20
|
module CastleProtectable
|
16
21
|
extend ActiveSupport::Concern
|
@@ -6,7 +6,8 @@ module CastleDevise
|
|
6
6
|
# Applies monkey-patches to Devise controllers
|
7
7
|
# @api private
|
8
8
|
def apply
|
9
|
-
Devise::RegistrationsController.send(:
|
9
|
+
Devise::RegistrationsController.send(:prepend, Patches::RegistrationsController)
|
10
|
+
Devise::PasswordsController.send(:prepend, Patches::PasswordsController)
|
10
11
|
end
|
11
12
|
end
|
12
13
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CastleDevise
|
4
|
+
module Patches
|
5
|
+
# Monkey-patch for
|
6
|
+
# {https://github.com/heartcombo/devise/blob/master/app/controllers/devise/passwords_controller.rb Devise::PasswordsController}
|
7
|
+
# which includes Castle to the password reset requests flow.
|
8
|
+
module PasswordsController
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
# PUT /resource/password
|
12
|
+
# @note Notice, this must happen within a block because before calling
|
13
|
+
# "reset_password_by_token" method we don't know what resource we operate on.
|
14
|
+
def update
|
15
|
+
super do |resource|
|
16
|
+
next unless resource_class.castle_hooks[:profile_update]
|
17
|
+
|
18
|
+
begin
|
19
|
+
CastleDevise.sdk_facade.log(
|
20
|
+
event: "$profile_update",
|
21
|
+
status: resource.errors.empty? ? "$succeeded" : "$failed",
|
22
|
+
context: CastleDevise::Context.from_rack_env(request.env, scope_name, resource)
|
23
|
+
)
|
24
|
+
rescue Castle::Error => e
|
25
|
+
# log API errors and pass-through it
|
26
|
+
CastleDevise.logger.error("[CastleDevise] log($password_reset_request): #{e}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# POST /resource/password
|
32
|
+
def create
|
33
|
+
super do |resource|
|
34
|
+
next unless resource_class.castle_hooks[:after_password_reset_request]
|
35
|
+
|
36
|
+
begin
|
37
|
+
CastleDevise.sdk_facade.log(
|
38
|
+
event: "$password_reset_request",
|
39
|
+
status: resource.persisted? ? "$succeeded" : "$failed",
|
40
|
+
context: CastleDevise::Context.from_rack_env(request.env, scope_name, resource)
|
41
|
+
)
|
42
|
+
rescue Castle::Error => e
|
43
|
+
# log API errors and pass-through it
|
44
|
+
CastleDevise.logger.error("[CastleDevise] log($password_reset_request): #{e}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -8,8 +8,56 @@ module CastleDevise
|
|
8
8
|
module RegistrationsController
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
# @param klass [self]
|
12
|
+
def self.prepended(klass)
|
13
|
+
klass.class_eval do
|
14
|
+
before_action :castle_filter, only: :create
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# PUT /resource
|
19
|
+
def update
|
20
|
+
context = CastleDevise::Context.from_rack_env(request.env, scope_name, resource)
|
21
|
+
|
22
|
+
if resource_class.castle_hooks[:profile_update]
|
23
|
+
begin
|
24
|
+
# TODO: Implement a verification mechanism for this action.
|
25
|
+
CastleDevise.sdk_facade.risk(
|
26
|
+
event: "$profile_update",
|
27
|
+
status: "$attempted",
|
28
|
+
context: context
|
29
|
+
)
|
30
|
+
rescue Castle::InvalidParametersError
|
31
|
+
# TODO: We should act differently if the error is about missing/invalid request token
|
32
|
+
# compared to any other validation errors. However, we can't do this with the
|
33
|
+
# current Castle SDK as it doesn't give us any way to differentiate these two cases.
|
34
|
+
CastleDevise.logger.warn(
|
35
|
+
"[CastleDevise] /v1/risk request contained invalid parameters." \
|
36
|
+
" This might mean that either you didn't configure Castle's Javascript properly," \
|
37
|
+
" or a request has been made without Javascript (eg. cURL/bot)." \
|
38
|
+
" Such a request is treated as if Castle responded with a 'deny' action in" \
|
39
|
+
" non-monitoring mode."
|
40
|
+
)
|
41
|
+
rescue Castle::Error => e
|
42
|
+
# log API errors and allow
|
43
|
+
CastleDevise.logger.error("[CastleDevise] risk($profile_update): #{e}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
super do |resource|
|
48
|
+
next unless resource_class.castle_hooks[:profile_update]
|
49
|
+
|
50
|
+
begin
|
51
|
+
CastleDevise.sdk_facade.log(
|
52
|
+
event: "$profile_update",
|
53
|
+
status: resource.saved_changes? ? "$succeeded" : "$failed",
|
54
|
+
context: context
|
55
|
+
)
|
56
|
+
rescue Castle::Error => e
|
57
|
+
# log API errors and pass-through it
|
58
|
+
CastleDevise.logger.error("[CastleDevise] log($password_reset_request): #{e}")
|
59
|
+
end
|
60
|
+
end
|
13
61
|
end
|
14
62
|
|
15
63
|
# Sends a /v1/filter request to Castle
|
@@ -40,7 +88,8 @@ module CastleDevise
|
|
40
88
|
"[CastleDevise] /v1/filter request contained invalid parameters." \
|
41
89
|
" This might mean that either you didn't configure Castle's Javascript properly, or" \
|
42
90
|
" a request has been made without Javascript (eg. cURL/bot)." \
|
43
|
-
" Such a request is treated as if Castle responded with a 'deny' action in
|
91
|
+
" Such a request is treated as if Castle responded with a 'deny' action in" \
|
92
|
+
" non-monitoring mode."
|
44
93
|
)
|
45
94
|
|
46
95
|
unless CastleDevise.monitoring_mode?
|
@@ -37,13 +37,14 @@ module CastleDevise
|
|
37
37
|
|
38
38
|
# Sends request to the /v1/risk endpoint.
|
39
39
|
# @param event [String]
|
40
|
+
# @param status [String]
|
40
41
|
# @param context [CastleDevise::Context]
|
41
42
|
# @return [Hash] Raw API response
|
42
43
|
# @see https://docs.castle.io/v1/reference/api-reference/#v1risk
|
43
|
-
def risk(event:, context:)
|
44
|
+
def risk(event:, context:, status: "$succeeded")
|
44
45
|
payload = {
|
45
46
|
event: event,
|
46
|
-
status:
|
47
|
+
status: status,
|
47
48
|
user: {
|
48
49
|
id: context.castle_id,
|
49
50
|
email: context.email,
|
@@ -68,15 +69,25 @@ module CastleDevise
|
|
68
69
|
# @return [Hash] Raw API response
|
69
70
|
# @see https://docs.castle.io/v1/reference/api-reference/#v1log
|
70
71
|
def log(event:, status:, context:)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
return if context.castle_id.blank? && context.email.blank?
|
73
|
+
|
74
|
+
user = if context.castle_id
|
75
|
+
{
|
75
76
|
id: context.castle_id,
|
76
77
|
email: context.email,
|
77
78
|
registered_at: format_time(context.registered_at),
|
78
79
|
traits: context.user_traits
|
79
|
-
}
|
80
|
+
}
|
81
|
+
else
|
82
|
+
{
|
83
|
+
email: context.email
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
payload = {
|
88
|
+
event: event,
|
89
|
+
status: status,
|
90
|
+
user: user,
|
80
91
|
context: payload_context(context.rack_request)
|
81
92
|
}
|
82
93
|
|
metadata
CHANGED
@@ -1,50 +1,51 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: castle_devise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kacper Madej
|
8
|
+
- Dawid Libiszewski
|
8
9
|
- Johan Brissmyr
|
9
10
|
autorequire:
|
10
11
|
bindir: exe
|
11
12
|
cert_chain: []
|
12
|
-
date: 2021-
|
13
|
+
date: 2021-08-12 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
+
name: activesupport
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
17
18
|
requirements:
|
18
19
|
- - ">="
|
19
20
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
21
|
-
- - "<"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: '8.0'
|
21
|
+
version: '5.0'
|
24
22
|
type: :runtime
|
25
23
|
prerelease: false
|
26
24
|
version_requirements: !ruby/object:Gem::Requirement
|
27
25
|
requirements:
|
28
26
|
- - ">="
|
29
27
|
- !ruby/object:Gem::Version
|
30
|
-
version: '
|
31
|
-
- - "<"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '8.0'
|
28
|
+
version: '5.0'
|
34
29
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
30
|
+
name: castle-rb
|
36
31
|
requirement: !ruby/object:Gem::Requirement
|
37
32
|
requirements:
|
38
33
|
- - ">="
|
39
34
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
35
|
+
version: '7.0'
|
36
|
+
- - "<"
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '8.0'
|
41
39
|
type: :runtime
|
42
40
|
prerelease: false
|
43
41
|
version_requirements: !ruby/object:Gem::Requirement
|
44
42
|
requirements:
|
45
43
|
- - ">="
|
46
44
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
45
|
+
version: '7.0'
|
46
|
+
- - "<"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '8.0'
|
48
49
|
- !ruby/object:Gem::Dependency
|
49
50
|
name: devise
|
50
51
|
requirement: !ruby/object:Gem::Requirement
|
@@ -65,6 +66,20 @@ dependencies:
|
|
65
66
|
- - "<"
|
66
67
|
- !ruby/object:Gem::Version
|
67
68
|
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: appraisal
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.3.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.3.0
|
68
83
|
description: castle_devise provides out-of-the-box protection against bot registrations
|
69
84
|
and account takeover attacks.
|
70
85
|
email:
|
@@ -77,6 +92,7 @@ files:
|
|
77
92
|
- ".github/workflows/specs.yml"
|
78
93
|
- ".gitignore"
|
79
94
|
- ".rspec"
|
95
|
+
- Appraisals
|
80
96
|
- CHANGELOG.md
|
81
97
|
- Gemfile
|
82
98
|
- Gemfile.lock
|
@@ -86,6 +102,9 @@ files:
|
|
86
102
|
- bin/console
|
87
103
|
- bin/setup
|
88
104
|
- castle_devise.gemspec
|
105
|
+
- gemfiles/rails_5.2.gemfile
|
106
|
+
- gemfiles/rails_6.0.gemfile
|
107
|
+
- gemfiles/rails_6.1.gemfile
|
89
108
|
- lib/castle_devise.rb
|
90
109
|
- lib/castle_devise/configuration.rb
|
91
110
|
- lib/castle_devise/context.rb
|
@@ -94,6 +113,7 @@ files:
|
|
94
113
|
- lib/castle_devise/hooks/castle_protectable.rb
|
95
114
|
- lib/castle_devise/models/castle_protectable.rb
|
96
115
|
- lib/castle_devise/patches.rb
|
116
|
+
- lib/castle_devise/patches/passwords_controller.rb
|
97
117
|
- lib/castle_devise/patches/registrations_controller.rb
|
98
118
|
- lib/castle_devise/rails.rb
|
99
119
|
- lib/castle_devise/sdk_facade.rb
|