stitches 3.6.1 → 3.7.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/.travis.yml +2 -2
- data/lib/stitches/allowlist_middleware.rb +29 -0
- data/lib/stitches/api_key.rb +2 -2
- data/lib/stitches/configuration.rb +12 -7
- data/lib/stitches/generator_files/config/initializers/stitches.rb +1 -1
- data/lib/stitches/update_configuration_generator.rb +16 -0
- data/lib/stitches/valid_mime_type.rb +3 -3
- data/lib/stitches/version.rb +1 -1
- data/lib/stitches/whitelisting_middleware.rb +4 -28
- data/lib/stitches_norailtie.rb +1 -0
- data/spec/api_key_spec.rb +9 -9
- data/spec/configuration_spec.rb +25 -10
- data/spec/integration/add_to_rails_app_spec.rb +33 -1
- data/spec/valid_mime_type_spec.rb +9 -9
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e779533d1ae845c15bec064ad589e32d2e29bca1b3b966144358735d26026248
|
4
|
+
data.tar.gz: f9af71cd6d2bab7e70ef1d963c25f66a41aa76107b032dc409bb611c30bf7819
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5145e91908d5cd6f685b7389cf3cf2a17bca9f5355eb513c26f6bb5f2e66270ebdf9c649796b683f470014e12dae4b98b3c2b2ce151afc2c984c96f94aa38a2f
|
7
|
+
data.tar.gz: 921734574b5e142f5786c1c7088e389e0d8d243111d5fcbfe7fded4f6e8dbb85fee11b1a25ffc2017f58c8b270ee46c41a6e0a554c130f9f09fa9c4c960cb544
|
data/.travis.yml
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Stitches
|
2
|
+
# A middleware that will skip its behavior if the path matches an allowed URL
|
3
|
+
class AllowlistMiddleware
|
4
|
+
def initialize(app, options={})
|
5
|
+
|
6
|
+
@app = app
|
7
|
+
@configuration = options[:configuration] || Stitches.configuration
|
8
|
+
@except = options[:except] || @configuration.allowlist_regexp
|
9
|
+
|
10
|
+
unless @except.nil? || @except.is_a?(Regexp)
|
11
|
+
raise ":except must be a Regexp"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
def call(env)
|
15
|
+
if @except && @except.match(env["PATH_INFO"])
|
16
|
+
@app.call(env)
|
17
|
+
else
|
18
|
+
do_call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def do_call(env)
|
25
|
+
raise 'subclass must implement'
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/stitches/api_key.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'allowlist_middleware'
|
2
2
|
|
3
3
|
module Stitches
|
4
4
|
# A middleware that requires an API key for certain transactions, and makes its id available
|
@@ -18,7 +18,7 @@ module Stitches
|
|
18
18
|
#
|
19
19
|
# If that is the case, env[Stitches.configuration.env_var_to_hold_api_client_primary_key] will be the primary key of the
|
20
20
|
# ApiClient that it maps to.
|
21
|
-
class ApiKey < Stitches::
|
21
|
+
class ApiKey < Stitches::AllowlistMiddleware
|
22
22
|
|
23
23
|
def initialize(app,options = {})
|
24
24
|
super(app,options)
|
@@ -9,20 +9,25 @@ class Stitches::Configuration
|
|
9
9
|
|
10
10
|
# Mainly for testing, this resets all configuration to the default value
|
11
11
|
def reset_to_defaults!
|
12
|
-
@
|
12
|
+
@allowlist_regexp = nil
|
13
13
|
@custom_http_auth_scheme = UnsetString.new("custom_http_auth_scheme")
|
14
14
|
@env_var_to_hold_api_client_primary_key = NonNullString.new("env_var_to_hold_api_client_primary_key","STITCHES_API_CLIENT_ID")
|
15
15
|
@env_var_to_hold_api_client= NonNullString.new("env_var_to_hold_api_client","STITCHES_API_CLIENT")
|
16
16
|
end
|
17
17
|
|
18
|
-
# A RegExp that
|
18
|
+
# A RegExp that allows URLS around the mime type and api key requirements.
|
19
19
|
# nil means that ever request must have a proper mime type and api key.
|
20
|
-
attr_reader :
|
21
|
-
def
|
22
|
-
unless
|
23
|
-
raise "
|
20
|
+
attr_reader :allowlist_regexp
|
21
|
+
def allowlist_regexp=(new_allowlist_regexp)
|
22
|
+
unless new_allowlist_regexp.nil? || new_allowlist_regexp.is_a?(Regexp)
|
23
|
+
raise "allowlist_regexp must be a Regexp, not a #{new_allowlist_regexp.class}"
|
24
24
|
end
|
25
|
-
@
|
25
|
+
@allowlist_regexp = new_allowlist_regexp
|
26
|
+
end
|
27
|
+
|
28
|
+
def whitelist_regexp=(new_allowlist_regexp)
|
29
|
+
self.allowlist_regexp = new_allowlist_regexp
|
30
|
+
warn("⚠️ 'whitelist' is deprecated in stitches configuration, please use 'allowlist' or auto-update with:\n\n bin/rails g stitches:update_configuration\n\n⚠️ 'whitelist' will be removed in 4.0")
|
26
31
|
end
|
27
32
|
|
28
33
|
# The name of your custom http auth scheme. This must be set, and has no default
|
@@ -2,7 +2,7 @@ require 'stitches'
|
|
2
2
|
|
3
3
|
Stitches.configure do |configuration|
|
4
4
|
# Regexp of urls that do not require ApiKeys or valid, versioned mime types
|
5
|
-
configuration.
|
5
|
+
configuration.allowlist_regexp = %r{\A/(resque|docs|assets)(\Z|/.*\Z)}
|
6
6
|
|
7
7
|
# Name of the custom Authorization scheme. See http://www.ietf.org/rfc/rfc2617.txt for details,
|
8
8
|
# but generally should be a string with no spaces or special characters.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Stitches
|
4
|
+
class UpdateConfigurationGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
source_root(File.expand_path(File.join(File.dirname(__FILE__),"generator_files")))
|
8
|
+
|
9
|
+
desc "Change your configuration to use 'allowlist' so you'll be ready for 4.x"
|
10
|
+
def update_to_allowlist
|
11
|
+
gsub_file "config/initializers/stitches.rb", /whitelist/, "allowlist"
|
12
|
+
puts "🎉 You are now good to go!"
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'allowlist_middleware'
|
2
2
|
module Stitches
|
3
3
|
# A middleware that requires all API calls to be for versioned JSON. This means that the Accept
|
4
4
|
# header (available to Rack apps as HTTP_ACCEPT) should be like so:
|
@@ -7,7 +7,7 @@ module Stitches
|
|
7
7
|
#
|
8
8
|
# This just checks that you've specified some numeric version. ApiVersionConstraint should be used
|
9
9
|
# to "lock down" the versions you accept.
|
10
|
-
class ValidMimeType < Stitches::
|
10
|
+
class ValidMimeType < Stitches::AllowlistMiddleware
|
11
11
|
|
12
12
|
protected
|
13
13
|
|
@@ -29,4 +29,4 @@ module Stitches
|
|
29
29
|
end
|
30
30
|
|
31
31
|
end
|
32
|
-
end
|
32
|
+
end
|
data/lib/stitches/version.rb
CHANGED
@@ -1,29 +1,5 @@
|
|
1
|
-
|
2
|
-
# A middleware that will skip its behavior if the path matches a white-listed URL
|
3
|
-
class WhitelistingMiddleware
|
4
|
-
def initialize(app, options={})
|
5
|
-
|
6
|
-
@app = app
|
7
|
-
@configuration = options[:configuration] || Stitches.configuration
|
8
|
-
@except = options[:except] || @configuration.whitelist_regexp
|
9
|
-
|
10
|
-
unless @except.nil? || @except.is_a?(Regexp)
|
11
|
-
raise ":except must be a Regexp"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
def call(env)
|
15
|
-
if @except && @except.match(env["PATH_INFO"])
|
16
|
-
@app.call(env)
|
17
|
-
else
|
18
|
-
do_call(env)
|
19
|
-
end
|
20
|
-
end
|
1
|
+
require_relative "allowlist_middleware"
|
21
2
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
raise 'subclass must implement'
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
3
|
+
module Stitches
|
4
|
+
WhitelistingMiddleware = AllowlistMiddleware
|
5
|
+
end
|
data/lib/stitches_norailtie.rb
CHANGED
@@ -14,6 +14,7 @@ require 'stitches/errors'
|
|
14
14
|
require 'stitches/api_generator'
|
15
15
|
require 'stitches/add_deprecation_generator'
|
16
16
|
require 'stitches/add_enabled_to_api_clients_generator'
|
17
|
+
require 'stitches/update_configuration_generator'
|
17
18
|
require 'stitches/api_version_constraint'
|
18
19
|
require 'stitches/api_key'
|
19
20
|
require 'stitches/deprecation'
|
data/spec/api_key_spec.rb
CHANGED
@@ -49,7 +49,7 @@ describe Stitches::ApiKey do
|
|
49
49
|
|
50
50
|
describe "#call" do
|
51
51
|
context "not in namespace" do
|
52
|
-
context "not
|
52
|
+
context "not allowlisted" do
|
53
53
|
let(:env) {
|
54
54
|
{
|
55
55
|
"PATH_INFO" => "/index/apifoolingyou/home",
|
@@ -64,12 +64,12 @@ describe Stitches::ApiKey do
|
|
64
64
|
let(:expected_body) { "Unauthorized - no authorization header" }
|
65
65
|
end
|
66
66
|
end
|
67
|
-
context "
|
68
|
-
context "
|
67
|
+
context "allowlisting" do
|
68
|
+
context "allowlist is explicit in middleware usage" do
|
69
69
|
before do
|
70
70
|
@response = middleware.call(env)
|
71
71
|
end
|
72
|
-
context "passes the
|
72
|
+
context "passes the allowlist" do
|
73
73
|
subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
|
74
74
|
let(:env) {
|
75
75
|
{
|
@@ -81,7 +81,7 @@ describe Stitches::ApiKey do
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
context "fails the
|
84
|
+
context "fails the allowlist" do
|
85
85
|
subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
|
86
86
|
let(:env) {
|
87
87
|
{
|
@@ -105,14 +105,14 @@ describe Stitches::ApiKey do
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
108
|
-
context "
|
108
|
+
context "allowlist is implicit from the configuration" do
|
109
109
|
|
110
110
|
before do
|
111
|
-
Stitches.configuration.
|
111
|
+
Stitches.configuration.allowlist_regexp = %r{\A/resque/.*\Z}
|
112
112
|
@response = middleware.call(env)
|
113
113
|
end
|
114
114
|
|
115
|
-
context "passes the
|
115
|
+
context "passes the allowlist" do
|
116
116
|
subject(:middleware) { described_class.new(app) }
|
117
117
|
let(:env) {
|
118
118
|
{
|
@@ -124,7 +124,7 @@ describe Stitches::ApiKey do
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
-
context "fails the
|
127
|
+
context "fails the allowlist" do
|
128
128
|
subject(:middleware) { described_class.new(app) }
|
129
129
|
let(:env) {
|
130
130
|
{
|
data/spec/configuration_spec.rb
CHANGED
@@ -6,24 +6,24 @@ describe Stitches::Configuration do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe "global configuration" do
|
9
|
-
let(:
|
9
|
+
let(:allowlist_regexp) { %r{foo} }
|
10
10
|
let(:custom_http_auth_scheme) { "Blah" }
|
11
11
|
let(:env_var_to_hold_api_client_primary_key) { "FOOBAR" }
|
12
12
|
|
13
13
|
it "can be configured globally" do
|
14
14
|
Stitches.configure do |config|
|
15
|
-
config.
|
15
|
+
config.allowlist_regexp = allowlist_regexp
|
16
16
|
config.custom_http_auth_scheme = custom_http_auth_scheme
|
17
17
|
config.env_var_to_hold_api_client_primary_key = env_var_to_hold_api_client_primary_key
|
18
18
|
end
|
19
19
|
|
20
|
-
expect(Stitches.configuration.
|
20
|
+
expect(Stitches.configuration.allowlist_regexp).to eq(allowlist_regexp)
|
21
21
|
expect(Stitches.configuration.custom_http_auth_scheme).to eq(custom_http_auth_scheme)
|
22
22
|
expect(Stitches.configuration.env_var_to_hold_api_client_primary_key).to eq(env_var_to_hold_api_client_primary_key)
|
23
23
|
end
|
24
24
|
|
25
|
-
it "defaults to nil for
|
26
|
-
expect(Stitches.configuration.
|
25
|
+
it "defaults to nil for allowlist_regexp" do
|
26
|
+
expect(Stitches.configuration.allowlist_regexp).to be_nil
|
27
27
|
end
|
28
28
|
|
29
29
|
it "sets a default for env_var_to_hold_api_client_primary_key" do
|
@@ -36,21 +36,21 @@ describe Stitches::Configuration do
|
|
36
36
|
}.to raise_error(/you must set a value for custom_http_auth_scheme/i)
|
37
37
|
end
|
38
38
|
end
|
39
|
-
describe "
|
39
|
+
describe "allowlist_regexp" do
|
40
40
|
let(:config) { Stitches::Configuration.new }
|
41
41
|
it "must be a regexp" do
|
42
42
|
expect {
|
43
|
-
config.
|
44
|
-
}.to raise_error(/
|
43
|
+
config.allowlist_regexp = "foo"
|
44
|
+
}.to raise_error(/allowlist_regexp must be a Regexp/i)
|
45
45
|
end
|
46
46
|
it "may be nil" do
|
47
47
|
expect {
|
48
|
-
config.
|
48
|
+
config.allowlist_regexp = nil
|
49
49
|
}.not_to raise_error
|
50
50
|
end
|
51
51
|
it "may be a regexp" do
|
52
52
|
expect {
|
53
|
-
config.
|
53
|
+
config.allowlist_regexp = /foo/
|
54
54
|
}.not_to raise_error
|
55
55
|
end
|
56
56
|
end
|
@@ -102,4 +102,19 @@ describe Stitches::Configuration do
|
|
102
102
|
}.not_to raise_error
|
103
103
|
end
|
104
104
|
end
|
105
|
+
context "deprecated options we want to support for backwards compatibility" do
|
106
|
+
|
107
|
+
let(:logger) { double("logger") }
|
108
|
+
before do
|
109
|
+
allow(Rails).to receive(:logger).and_return(logger)
|
110
|
+
allow(logger).to receive(:info)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "'whitelist' still works for allowlist" do
|
114
|
+
Stitches.configure do |config|
|
115
|
+
config.whitelist_regexp = /foo/
|
116
|
+
end
|
117
|
+
expect(Stitches.configuration.allowlist_regexp).to eq(/foo/)
|
118
|
+
end
|
119
|
+
end
|
105
120
|
end
|
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
require "fileutils"
|
3
3
|
require "open3"
|
4
4
|
|
5
|
-
RSpec.describe "Adding Stitches to a New Rails App" do
|
5
|
+
RSpec.describe "Adding Stitches to a New Rails App", :integration do
|
6
6
|
let(:work_dir) { Dir.mktmpdir }
|
7
7
|
let(:rails_app_name) { "swamp-thing" }
|
8
8
|
|
@@ -103,6 +103,38 @@ RSpec.describe "Adding Stitches to a New Rails App" do
|
|
103
103
|
expect(include_line).to_not be_nil,lines.inspect
|
104
104
|
end
|
105
105
|
|
106
|
+
it "inserts can update old configuration" do
|
107
|
+
run "bin/rails generate rspec:install"
|
108
|
+
run "bin/rails generate apitome:install"
|
109
|
+
run "bin/rails generate stitches:api"
|
110
|
+
|
111
|
+
rails_root = Pathname(work_dir) / rails_app_name
|
112
|
+
initializer = rails_root / "config" / "initializers" / "stitches.rb"
|
113
|
+
|
114
|
+
initializer_contents = File.read(initializer).split(/\n/)
|
115
|
+
found_initializer = false
|
116
|
+
File.open(initializer,"w") do |file|
|
117
|
+
initializer_contents.each do |line|
|
118
|
+
if line =~ /allowlist/
|
119
|
+
line = line.gsub("allowlist","whitelist")
|
120
|
+
found_initializer = true
|
121
|
+
end
|
122
|
+
file.puts line
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
raise "Didn't find 'allowlist' in the initializer?!" if !found_initializer
|
127
|
+
|
128
|
+
run "bin/rails generate stitches:update_configuration"
|
129
|
+
|
130
|
+
lines = File.read(initializer).split(/\n/)
|
131
|
+
include_line = lines.detect { |line|
|
132
|
+
line =~ /whitelist/
|
133
|
+
}
|
134
|
+
|
135
|
+
expect(include_line).to be_nil,lines.inspect
|
136
|
+
end
|
137
|
+
|
106
138
|
class RoutesFileAnalysis
|
107
139
|
attr_reader :routes_file
|
108
140
|
def initialize(routes_file, namespace: nil, module_scope: nil, resource: nil, mounted_engine: nil)
|
@@ -23,7 +23,7 @@ describe Stitches::ValidMimeType do
|
|
23
23
|
|
24
24
|
describe "#call" do
|
25
25
|
context "not in namespace" do
|
26
|
-
context "not in
|
26
|
+
context "not in allowlist" do
|
27
27
|
let(:env) {
|
28
28
|
{
|
29
29
|
"PATH_INFO" => "/index/home",
|
@@ -36,19 +36,19 @@ describe Stitches::ValidMimeType do
|
|
36
36
|
|
37
37
|
it_behaves_like "an unacceptable response"
|
38
38
|
end
|
39
|
-
context "
|
39
|
+
context "allowlisting" do
|
40
40
|
let(:env) {
|
41
41
|
{
|
42
42
|
"PATH_INFO" => "/index/home",
|
43
43
|
}
|
44
44
|
}
|
45
45
|
|
46
|
-
context "
|
46
|
+
context "allowlist is explicit in middleware usage" do
|
47
47
|
before do
|
48
48
|
@response = middleware.call(env)
|
49
49
|
end
|
50
50
|
|
51
|
-
context "passes the
|
51
|
+
context "passes the allowlist" do
|
52
52
|
subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
|
53
53
|
let(:env) {
|
54
54
|
{
|
@@ -60,7 +60,7 @@ describe Stitches::ValidMimeType do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
context "fails the
|
63
|
+
context "fails the allowlist" do
|
64
64
|
subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
|
65
65
|
let(:env) {
|
66
66
|
{
|
@@ -82,14 +82,14 @@ describe Stitches::ValidMimeType do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
85
|
-
context "
|
85
|
+
context "allowlist is implicit from the configuration" do
|
86
86
|
|
87
87
|
before do
|
88
|
-
Stitches.configuration.
|
88
|
+
Stitches.configuration.allowlist_regexp = %r{\A/resque/.*\Z}
|
89
89
|
@response = middleware.call(env)
|
90
90
|
end
|
91
91
|
|
92
|
-
context "passes the
|
92
|
+
context "passes the allowlist" do
|
93
93
|
subject(:middleware) { described_class.new(app) }
|
94
94
|
let(:env) {
|
95
95
|
{
|
@@ -101,7 +101,7 @@ describe Stitches::ValidMimeType do
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
context "fails the
|
104
|
+
context "fails the allowlist" do
|
105
105
|
subject(:middleware) { described_class.new(app) }
|
106
106
|
let(:env) {
|
107
107
|
{
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stitches
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stitch Fix Engineering
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2018-
|
14
|
+
date: 2018-08-26 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -141,6 +141,7 @@ files:
|
|
141
141
|
- lib/stitches.rb
|
142
142
|
- lib/stitches/add_deprecation_generator.rb
|
143
143
|
- lib/stitches/add_enabled_to_api_clients_generator.rb
|
144
|
+
- lib/stitches/allowlist_middleware.rb
|
144
145
|
- lib/stitches/api_generator.rb
|
145
146
|
- lib/stitches/api_key.rb
|
146
147
|
- lib/stitches/api_version_constraint.rb
|
@@ -171,6 +172,7 @@ files:
|
|
171
172
|
- lib/stitches/spec/have_api_error.rb
|
172
173
|
- lib/stitches/spec/show_deprecation.rb
|
173
174
|
- lib/stitches/spec/test_headers.rb
|
175
|
+
- lib/stitches/update_configuration_generator.rb
|
174
176
|
- lib/stitches/valid_mime_type.rb
|
175
177
|
- lib/stitches/version.rb
|
176
178
|
- lib/stitches/whitelisting_middleware.rb
|