stitches 4.0.1 → 4.2.0.RC2
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/.circleci/config.yml +29 -29
- data/.github/CODEOWNERS +1 -1
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/Gemfile.rails-6.1 +7 -0
- data/README.md +36 -4
- data/lib/stitches/add_disabled_at_to_api_clients_generator.rb +18 -0
- data/lib/stitches/allowlist_middleware.rb +20 -6
- data/lib/stitches/api_client_access_wrapper.rb +42 -11
- data/lib/stitches/api_key.rb +5 -5
- data/lib/stitches/configuration.rb +4 -0
- data/lib/stitches/generator_files/db/migrate/add_disabled_at_to_api_clients.rb +9 -0
- data/lib/stitches/generator_files/db/migrate/create_api_clients.rb +1 -0
- data/lib/stitches/valid_mime_type.rb +1 -1
- data/lib/stitches/version.rb +1 -1
- data/lib/stitches_norailtie.rb +1 -0
- data/owners.json +1 -1
- data/spec/api_key_middleware_spec.rb +368 -0
- data/spec/api_version_constraint_middleware_spec.rb +58 -0
- data/spec/configuration_spec.rb +1 -1
- data/spec/deprecation_spec.rb +1 -1
- data/spec/error_spec.rb +1 -1
- data/spec/errors_spec.rb +3 -3
- data/spec/fake_app/.rspec +1 -0
- data/spec/fake_app/.ruby-version +1 -0
- data/spec/fake_app/Gemfile +53 -0
- data/spec/fake_app/README.md +24 -0
- data/spec/fake_app/Rakefile +6 -0
- data/spec/fake_app/app/assets/config/manifest.js +2 -0
- data/spec/fake_app/app/assets/stylesheets/application.css +15 -0
- data/spec/fake_app/app/controllers/api.rb +2 -0
- data/spec/fake_app/app/controllers/api/api_controller.rb +31 -0
- data/spec/fake_app/app/controllers/api/v1.rb +2 -0
- data/spec/fake_app/app/controllers/api/v1/hellos_controller.rb +7 -0
- data/spec/fake_app/app/controllers/api/v1/pings_controller.rb +16 -0
- data/spec/fake_app/app/controllers/api/v2.rb +2 -0
- data/spec/fake_app/app/controllers/api/v2/hellos_controller.rb +7 -0
- data/spec/fake_app/app/controllers/api/v2/pings_controller.rb +16 -0
- data/spec/fake_app/app/controllers/application_controller.rb +2 -0
- data/spec/fake_app/app/helpers/application_helper.rb +2 -0
- data/spec/fake_app/app/models/api_client.rb +2 -0
- data/spec/fake_app/app/models/application_record.rb +3 -0
- data/spec/fake_app/bin/rails +4 -0
- data/spec/fake_app/bin/rake +4 -0
- data/spec/fake_app/bin/setup +33 -0
- data/spec/fake_app/config.ru +6 -0
- data/spec/fake_app/config/application.rb +35 -0
- data/spec/fake_app/config/boot.rb +3 -0
- data/spec/fake_app/config/credentials.yml.enc +1 -0
- data/spec/fake_app/config/database.yml +25 -0
- data/spec/fake_app/config/environment.rb +5 -0
- data/spec/fake_app/config/environments/development.rb +71 -0
- data/spec/fake_app/config/environments/production.rb +109 -0
- data/spec/fake_app/config/environments/test.rb +52 -0
- data/spec/fake_app/config/initializers/assets.rb +12 -0
- data/spec/fake_app/config/initializers/cookies_serializer.rb +5 -0
- data/spec/fake_app/config/initializers/filter_parameter_logging.rb +6 -0
- data/spec/fake_app/config/initializers/stitches.rb +24 -0
- data/spec/fake_app/config/locales/en.yml +33 -0
- data/spec/fake_app/config/master.key +1 -0
- data/spec/fake_app/config/puma.rb +43 -0
- data/spec/fake_app/config/routes.rb +17 -0
- data/spec/fake_app/config/storage.yml +34 -0
- data/spec/fake_app/db/development.sqlite3 +0 -0
- data/spec/fake_app/db/migrate/20210802153118_enable_uuid_ossp_extension.rb +7 -0
- data/spec/fake_app/db/migrate/20210802153119_create_api_clients.rb +14 -0
- data/spec/fake_app/db/schema_missing_disabled_at.rb +12 -0
- data/spec/fake_app/db/schema_missing_enabled.rb +11 -0
- data/spec/fake_app/db/schema_modern.rb +13 -0
- data/spec/fake_app/db/seeds.rb +7 -0
- data/spec/fake_app/db/test.sqlite3 +0 -0
- data/spec/fake_app/doc/api.md +4 -0
- data/spec/fake_app/lib/tasks/generate_api_key.rake +10 -0
- data/spec/fake_app/public/404.html +67 -0
- data/spec/fake_app/public/422.html +67 -0
- data/spec/fake_app/public/500.html +66 -0
- data/spec/fake_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/fake_app/public/apple-touch-icon.png +0 -0
- data/spec/fake_app/public/favicon.ico +0 -0
- data/spec/fake_app/public/javascripts/apitome/application.js +31 -0
- data/spec/fake_app/public/robots.txt +1 -0
- data/spec/fake_app/public/stylesheets/apitome/application.css +269 -0
- data/spec/fake_app/test/application_system_test_case.rb +5 -0
- data/spec/fake_app/test/test_helper.rb +13 -0
- data/spec/fake_app/tmp/development_secret.txt +1 -0
- data/spec/integration/add_to_rails_app_spec.rb +9 -1
- data/spec/rails_helper.rb +64 -0
- data/spec/valid_mime_type_middleware_spec.rb +59 -0
- data/spec/valid_mime_type_spec.rb +6 -4
- data/stitches.gemspec +2 -0
- metadata +168 -11
- data/spec/api_client_access_wrapper_spec.rb +0 -52
- data/spec/api_key_spec.rb +0 -208
- data/spec/api_version_constraint_spec.rb +0 -33
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 781cc5ec8996b5c726e7e214d69c5d780ddbf4818fb9b0cb5ce15de6bb6e829c
|
|
4
|
+
data.tar.gz: f482c0e9a21b84330add05e8c9a2bfd3ef5986ac60f7f22766f79f480d1e2a4b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d71dfb5cc76e1d753d1b25e3a8e278097167f07e8f43e7f276041c043960bf3ba551d47cd3ba90a4d94d56538a217d4c55156b5d5cb59273aa104086852d4a26
|
|
7
|
+
data.tar.gz: fb6c236f22a81f1cb7373f3d50d6dc907e7ba2c684a07dc1f5ce94ac7e9b6039dda780821d763912dbb39139fc00b27e2d254c525b7ac9da3d1011a5f4bec9b3
|
data/.circleci/config.yml
CHANGED
|
@@ -5,7 +5,7 @@ version: 2
|
|
|
5
5
|
jobs:
|
|
6
6
|
generate-and-push-docs:
|
|
7
7
|
docker:
|
|
8
|
-
- image: circleci/ruby:
|
|
8
|
+
- image: circleci/ruby:3.0.0
|
|
9
9
|
auth:
|
|
10
10
|
username: "$DOCKERHUB_USERNAME"
|
|
11
11
|
password: "$DOCKERHUB_PASSWORD"
|
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
docs:push; fi
|
|
27
27
|
release:
|
|
28
28
|
docker:
|
|
29
|
-
- image: circleci/ruby:
|
|
29
|
+
- image: circleci/ruby:3.0.0
|
|
30
30
|
auth:
|
|
31
31
|
username: "$DOCKERHUB_USERNAME"
|
|
32
32
|
password: "$DOCKERHUB_PASSWORD"
|
|
@@ -41,14 +41,14 @@ jobs:
|
|
|
41
41
|
- run:
|
|
42
42
|
name: Build/release gem to artifactory
|
|
43
43
|
command: bundle exec rake push_artifactory
|
|
44
|
-
ruby-
|
|
44
|
+
ruby-3.0.0-rails-6.1:
|
|
45
45
|
docker:
|
|
46
|
-
- image: circleci/ruby:
|
|
46
|
+
- image: circleci/ruby:3.0.0
|
|
47
47
|
auth:
|
|
48
48
|
username: "$DOCKERHUB_USERNAME"
|
|
49
49
|
password: "$DOCKERHUB_PASSWORD"
|
|
50
50
|
environment:
|
|
51
|
-
BUNDLE_GEMFILE: Gemfile.rails-6.
|
|
51
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.1
|
|
52
52
|
working_directory: "~/stitches"
|
|
53
53
|
steps:
|
|
54
54
|
- checkout
|
|
@@ -67,18 +67,18 @@ jobs:
|
|
|
67
67
|
fi
|
|
68
68
|
- run:
|
|
69
69
|
name: Notify Pager Duty
|
|
70
|
-
command: bundle exec y-notify "#
|
|
70
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
|
71
71
|
when: on_fail
|
|
72
72
|
- store_test_results:
|
|
73
73
|
path: "/tmp/test-results"
|
|
74
|
-
ruby-2.
|
|
74
|
+
ruby-2.7.2-rails-6.1:
|
|
75
75
|
docker:
|
|
76
|
-
- image: circleci/ruby:2.
|
|
76
|
+
- image: circleci/ruby:2.7.2
|
|
77
77
|
auth:
|
|
78
78
|
username: "$DOCKERHUB_USERNAME"
|
|
79
79
|
password: "$DOCKERHUB_PASSWORD"
|
|
80
80
|
environment:
|
|
81
|
-
BUNDLE_GEMFILE: Gemfile.rails-6.
|
|
81
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.1
|
|
82
82
|
working_directory: "~/stitches"
|
|
83
83
|
steps:
|
|
84
84
|
- checkout
|
|
@@ -97,18 +97,18 @@ jobs:
|
|
|
97
97
|
fi
|
|
98
98
|
- run:
|
|
99
99
|
name: Notify Pager Duty
|
|
100
|
-
command: bundle exec y-notify "#
|
|
100
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
|
101
101
|
when: on_fail
|
|
102
102
|
- store_test_results:
|
|
103
103
|
path: "/tmp/test-results"
|
|
104
|
-
ruby-
|
|
104
|
+
ruby-3.0.0-rails-6.0:
|
|
105
105
|
docker:
|
|
106
|
-
- image: circleci/ruby:
|
|
106
|
+
- image: circleci/ruby:3.0.0
|
|
107
107
|
auth:
|
|
108
108
|
username: "$DOCKERHUB_USERNAME"
|
|
109
109
|
password: "$DOCKERHUB_PASSWORD"
|
|
110
110
|
environment:
|
|
111
|
-
BUNDLE_GEMFILE: Gemfile.rails-
|
|
111
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.0
|
|
112
112
|
working_directory: "~/stitches"
|
|
113
113
|
steps:
|
|
114
114
|
- checkout
|
|
@@ -127,18 +127,18 @@ jobs:
|
|
|
127
127
|
fi
|
|
128
128
|
- run:
|
|
129
129
|
name: Notify Pager Duty
|
|
130
|
-
command: bundle exec y-notify "#
|
|
130
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
|
131
131
|
when: on_fail
|
|
132
132
|
- store_test_results:
|
|
133
133
|
path: "/tmp/test-results"
|
|
134
|
-
ruby-2.
|
|
134
|
+
ruby-2.7.2-rails-6.0:
|
|
135
135
|
docker:
|
|
136
|
-
- image: circleci/ruby:2.
|
|
136
|
+
- image: circleci/ruby:2.7.2
|
|
137
137
|
auth:
|
|
138
138
|
username: "$DOCKERHUB_USERNAME"
|
|
139
139
|
password: "$DOCKERHUB_PASSWORD"
|
|
140
140
|
environment:
|
|
141
|
-
BUNDLE_GEMFILE: Gemfile.rails-
|
|
141
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.0
|
|
142
142
|
working_directory: "~/stitches"
|
|
143
143
|
steps:
|
|
144
144
|
- checkout
|
|
@@ -157,7 +157,7 @@ jobs:
|
|
|
157
157
|
fi
|
|
158
158
|
- run:
|
|
159
159
|
name: Notify Pager Duty
|
|
160
|
-
command: bundle exec y-notify "#
|
|
160
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
|
161
161
|
when: on_fail
|
|
162
162
|
- store_test_results:
|
|
163
163
|
path: "/tmp/test-results"
|
|
@@ -168,10 +168,10 @@ workflows:
|
|
|
168
168
|
- release:
|
|
169
169
|
context: org-global
|
|
170
170
|
requires:
|
|
171
|
+
- ruby-3.0.0-rails-6.1
|
|
172
|
+
- ruby-2.7.2-rails-6.1
|
|
173
|
+
- ruby-3.0.0-rails-6.0
|
|
171
174
|
- ruby-2.7.2-rails-6.0
|
|
172
|
-
- ruby-2.6.6-rails-6.0
|
|
173
|
-
- ruby-2.7.2-rails-5.2
|
|
174
|
-
- ruby-2.6.6-rails-5.2
|
|
175
175
|
filters:
|
|
176
176
|
tags:
|
|
177
177
|
only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
|
|
@@ -186,22 +186,22 @@ workflows:
|
|
|
186
186
|
only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
|
|
187
187
|
branches:
|
|
188
188
|
ignore: /.*/
|
|
189
|
-
- ruby-
|
|
189
|
+
- ruby-3.0.0-rails-6.1:
|
|
190
190
|
context: org-global
|
|
191
191
|
filters:
|
|
192
192
|
tags:
|
|
193
193
|
only: &1 /.*/
|
|
194
|
-
- ruby-2.
|
|
194
|
+
- ruby-2.7.2-rails-6.1:
|
|
195
195
|
context: org-global
|
|
196
196
|
filters:
|
|
197
197
|
tags:
|
|
198
198
|
only: *1
|
|
199
|
-
- ruby-
|
|
199
|
+
- ruby-3.0.0-rails-6.0:
|
|
200
200
|
context: org-global
|
|
201
201
|
filters:
|
|
202
202
|
tags:
|
|
203
203
|
only: *1
|
|
204
|
-
- ruby-2.
|
|
204
|
+
- ruby-2.7.2-rails-6.0:
|
|
205
205
|
context: org-global
|
|
206
206
|
filters:
|
|
207
207
|
tags:
|
|
@@ -215,11 +215,11 @@ workflows:
|
|
|
215
215
|
only:
|
|
216
216
|
- master
|
|
217
217
|
jobs:
|
|
218
|
-
- ruby-
|
|
218
|
+
- ruby-3.0.0-rails-6.1:
|
|
219
219
|
context: org-global
|
|
220
|
-
- ruby-2.
|
|
220
|
+
- ruby-2.7.2-rails-6.1:
|
|
221
221
|
context: org-global
|
|
222
|
-
- ruby-
|
|
222
|
+
- ruby-3.0.0-rails-6.0:
|
|
223
223
|
context: org-global
|
|
224
|
-
- ruby-2.
|
|
224
|
+
- ruby-2.7.2-rails-6.0:
|
|
225
225
|
context: org-global
|
data/.github/CODEOWNERS
CHANGED
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.7.2
|
|
1
|
+
ruby-2.7.2
|
data/Gemfile.rails-6.1
ADDED
data/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Then, set it up:
|
|
|
35
35
|
|
|
36
36
|
### Upgrading from an older version
|
|
37
37
|
|
|
38
|
-
- When upgrading to version 4.0.0 you may now take advantage of an in-memory cache
|
|
38
|
+
- When upgrading to version 4.0.0 and above you may now take advantage of an in-memory cache
|
|
39
39
|
|
|
40
40
|
You can enabled it like so
|
|
41
41
|
|
|
@@ -46,18 +46,46 @@ Stitches.configure do |config|
|
|
|
46
46
|
end
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
You can also set a leniency for disabled API keys, which will allow old API keys to continue to be used if they have a
|
|
50
|
+
`disabled_at` field set as long as the leniency is not exceeded. Note that if the `disabled_at` field is not populated
|
|
51
|
+
the behavior will remain the same as it always was, and the request will be denied when the `enabled` field is set to
|
|
52
|
+
`true`. If Stitches allows a call due to leniency settings, a log message will be generated with a severity depending on
|
|
53
|
+
how long ago the API key was disabled.
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
Stitches.configure do |config|
|
|
57
|
+
config.disabled_key_leniency_in_seconds = 3 * 24 * 60 * 60 # Time in seconds, defaults to three days
|
|
58
|
+
config.disabled_key_leniency_error_log_threshold_in_seconds = 2 * 24 * 60 * 60 # Time in seconds, defaults to two days
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If a disabled key is used within the `disabled_key_leniency_in_seconds`, it will be allowed.
|
|
63
|
+
|
|
64
|
+
Anytime a disabled key is used a log will be generated. If it is before the
|
|
65
|
+
`disabled_key_leniency_error_log_threshold_in_seconds` it will be a warning log message, if it is after that, it will be
|
|
66
|
+
an error message. `disabled_key_leniency_error_log_threshold_in_seconds` should never be a greater number than
|
|
67
|
+
`disabled_key_leniency_in_seconds`, as this provides an escallating series of warnings before finally disabling access.
|
|
68
|
+
|
|
69
|
+
- If you are upgrading from a version older than 3.3.0 you need to run three generators, two of which create database
|
|
70
|
+
migrations on your `api_clients` table:
|
|
51
71
|
|
|
52
72
|
```
|
|
53
73
|
> bin/rails generate stitches:add_enabled_to_api_clients
|
|
54
74
|
> bin/rails generate stitches:add_deprecation
|
|
75
|
+
> bin/rails generate stitches:add_disabled_at_to_api_clients
|
|
55
76
|
```
|
|
56
77
|
|
|
57
|
-
- If you
|
|
78
|
+
- If you are upgrading from a version between 3.3.0 and 3.5.0 you need to run two generators:
|
|
58
79
|
|
|
59
80
|
```
|
|
60
81
|
> bin/rails generate stitches:add_deprecation
|
|
82
|
+
> bin/rails generate stitches:add_disabled_at_to_api_clients
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- If you are upgrading from a version between 3.6.0 and 4.0.2 you need to run one generator:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
> bin/rails generate stitches:add_disabled_at_to_api_clients
|
|
61
89
|
```
|
|
62
90
|
|
|
63
91
|
## Example Microservice Endpoint
|
|
@@ -143,6 +171,10 @@ Also, the integration test does a lot of "testing the implementation", but since
|
|
|
143
171
|
failing with a successful result, we have to make sure that the various `inject_into_file` calls are actually working. Do not do
|
|
144
172
|
any fancy refactors here, just keep it up to date.
|
|
145
173
|
|
|
174
|
+
## Releases
|
|
175
|
+
|
|
176
|
+
See the release process for open source gems in the Stitch Fix engineering wiki under technical topics.
|
|
177
|
+
|
|
146
178
|
---
|
|
147
179
|
|
|
148
180
|
Provided with love by your friends at [Stitch Fix Engineering](http://technology.stitchfix.com)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'rails/generators'
|
|
2
|
+
|
|
3
|
+
module Stitches
|
|
4
|
+
class AddDisabledAtToApiClientsGenerator < Rails::Generators::Base
|
|
5
|
+
include Rails::Generators::Migration
|
|
6
|
+
|
|
7
|
+
source_root(File.expand_path(File.join(File.dirname(__FILE__),"generator_files")))
|
|
8
|
+
|
|
9
|
+
def self.next_migration_number(path)
|
|
10
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc "Upgrade your api_clients table so it includes the `disabled_at` field"
|
|
14
|
+
def update_api_clients_table
|
|
15
|
+
migration_template "db/migrate/add_disabled_at_to_api_clients.rb", "db/migrate/add_disabled_at_to_api_clients.rb"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -3,15 +3,14 @@ module Stitches
|
|
|
3
3
|
class AllowlistMiddleware
|
|
4
4
|
def initialize(app, options={})
|
|
5
5
|
@app = app
|
|
6
|
-
@configuration = options[:configuration]
|
|
7
|
-
@except = options[:except]
|
|
6
|
+
@configuration = options[:configuration]
|
|
7
|
+
@except = options[:except]
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
raise ":except must be a Regexp"
|
|
11
|
-
end
|
|
9
|
+
allowlist_regex
|
|
12
10
|
end
|
|
11
|
+
|
|
13
12
|
def call(env)
|
|
14
|
-
if
|
|
13
|
+
if allowlist_regex && allowlist_regex.match(env["PATH_INFO"])
|
|
15
14
|
@app.call(env)
|
|
16
15
|
else
|
|
17
16
|
do_call(env)
|
|
@@ -24,5 +23,20 @@ module Stitches
|
|
|
24
23
|
raise 'subclass must implement'
|
|
25
24
|
end
|
|
26
25
|
|
|
26
|
+
def configuration
|
|
27
|
+
@configuration || Stitches.configuration
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def allowlist_regex
|
|
33
|
+
regex = @except || configuration.allowlist_regexp
|
|
34
|
+
|
|
35
|
+
if !regex.nil? && !regex.is_a?(Regexp)
|
|
36
|
+
raise ":except must be a Regexp"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
regex
|
|
40
|
+
end
|
|
27
41
|
end
|
|
28
42
|
end
|
|
@@ -2,26 +2,57 @@ require 'lru_redux'
|
|
|
2
2
|
|
|
3
3
|
module Stitches::ApiClientAccessWrapper
|
|
4
4
|
|
|
5
|
-
def self.fetch_for_key(key)
|
|
5
|
+
def self.fetch_for_key(key, configuration)
|
|
6
6
|
if cache_enabled
|
|
7
|
-
fetch_for_key_from_cache(key)
|
|
7
|
+
fetch_for_key_from_cache(key, configuration)
|
|
8
8
|
else
|
|
9
|
-
fetch_for_key_from_db(key)
|
|
9
|
+
fetch_for_key_from_db(key, configuration)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def self.fetch_for_key_from_cache(key)
|
|
13
|
+
def self.fetch_for_key_from_cache(key, configuration)
|
|
14
14
|
api_key_cache.getset(key) do
|
|
15
|
-
fetch_for_key_from_db(key)
|
|
15
|
+
fetch_for_key_from_db(key, configuration)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def self.fetch_for_key_from_db(key)
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
def self.fetch_for_key_from_db(key, configuration)
|
|
20
|
+
api_client = ::ApiClient.find_by(key: key)
|
|
21
|
+
return unless api_client
|
|
22
|
+
|
|
23
|
+
unless api_client.respond_to?(:enabled?)
|
|
24
|
+
logger.warn('api_keys is missing "enabled" column. Run "rails g stitches:add_enabled_to_api_clients"')
|
|
25
|
+
return api_client
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
unless api_client.respond_to?(:disabled_at)
|
|
29
|
+
logger.warn('api_keys is missing "disabled_at" column. Run "rails g stitches:add_disabled_at_to_api_clients"')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
return api_client if api_client.enabled?
|
|
33
|
+
|
|
34
|
+
disabled_at = api_client.respond_to?(:disabled_at) ? api_client.disabled_at : nil
|
|
35
|
+
if disabled_at && disabled_at > configuration.disabled_key_leniency_in_seconds.seconds.ago
|
|
36
|
+
message = "Allowing disabled ApiClient: #{api_client.name} with key #{api_client.key} disabled at #{disabled_at}"
|
|
37
|
+
if disabled_at > configuration.disabled_key_leniency_error_log_threshold_in_seconds.seconds.ago
|
|
38
|
+
logger.warn(message)
|
|
39
|
+
else
|
|
40
|
+
logger.error(message)
|
|
41
|
+
end
|
|
42
|
+
return api_client
|
|
43
|
+
else
|
|
44
|
+
logger.error("Rejecting disabled ApiClient: #{api_client.name} with key #{api_client.key}")
|
|
45
|
+
end
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.logger
|
|
50
|
+
if defined?(StitchFix::Logger::LogWriter)
|
|
51
|
+
StitchFix::Logger::LogWriter
|
|
52
|
+
elsif defined?(Rails.logger)
|
|
53
|
+
Rails.logger
|
|
22
54
|
else
|
|
23
|
-
|
|
24
|
-
::ApiClient.find_by(key: key)
|
|
55
|
+
::Logger.new('/dev/null')
|
|
25
56
|
end
|
|
26
57
|
end
|
|
27
58
|
|
|
@@ -39,4 +70,4 @@ module Stitches::ApiClientAccessWrapper
|
|
|
39
70
|
def self.cache_enabled
|
|
40
71
|
Stitches.configuration.max_cache_ttl.positive?
|
|
41
72
|
end
|
|
42
|
-
end
|
|
73
|
+
end
|
data/lib/stitches/api_key.rb
CHANGED
|
@@ -25,12 +25,12 @@ module Stitches
|
|
|
25
25
|
def do_call(env)
|
|
26
26
|
authorization = env["HTTP_AUTHORIZATION"]
|
|
27
27
|
if authorization
|
|
28
|
-
if authorization =~ /#{
|
|
28
|
+
if authorization =~ /#{configuration.custom_http_auth_scheme}\s+key=(.*)\s*$/
|
|
29
29
|
key = $1
|
|
30
|
-
client = Stitches::ApiClientAccessWrapper.fetch_for_key(key)
|
|
30
|
+
client = Stitches::ApiClientAccessWrapper.fetch_for_key(key, configuration)
|
|
31
31
|
if client.present?
|
|
32
|
-
env[
|
|
33
|
-
env[
|
|
32
|
+
env[configuration.env_var_to_hold_api_client_primary_key] = client.id
|
|
33
|
+
env[configuration.env_var_to_hold_api_client] = client
|
|
34
34
|
@app.call(env)
|
|
35
35
|
else
|
|
36
36
|
unauthorized_response("key invalid")
|
|
@@ -59,7 +59,7 @@ module Stitches
|
|
|
59
59
|
def unauthorized_response(reason)
|
|
60
60
|
status = 401
|
|
61
61
|
body = "Unauthorized - #{reason}"
|
|
62
|
-
header = { "WWW-Authenticate" => "#{
|
|
62
|
+
header = { "WWW-Authenticate" => "#{configuration.custom_http_auth_scheme} realm=#{rails_app_module}" }
|
|
63
63
|
Rack::Response.new(body, status, header).finish
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -15,8 +15,12 @@ class Stitches::Configuration
|
|
|
15
15
|
@env_var_to_hold_api_client= NonNullString.new("env_var_to_hold_api_client","STITCHES_API_CLIENT")
|
|
16
16
|
@max_cache_ttl = NonNullInteger.new("max_cache_ttl", 0)
|
|
17
17
|
@max_cache_size = NonNullInteger.new("max_cache_size", 0)
|
|
18
|
+
@disabled_key_leniency_in_seconds = ActiveSupport::Duration.days(3)
|
|
19
|
+
@disabled_key_leniency_error_log_threshold_in_seconds = ActiveSupport::Duration.days(2)
|
|
18
20
|
end
|
|
19
21
|
|
|
22
|
+
attr_accessor :disabled_key_leniency_in_seconds, :disabled_key_leniency_error_log_threshold_in_seconds
|
|
23
|
+
|
|
20
24
|
# A RegExp that allows URLS around the mime type and api key requirements.
|
|
21
25
|
# nil means that ever request must have a proper mime type and api key.
|
|
22
26
|
attr_reader :allowlist_regexp
|