castle_devise 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/castle_devise.svg)](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
|