simple-api-auth 0.1.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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +14 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +16 -0
  7. data/Gemfile +12 -0
  8. data/Guardfile +5 -0
  9. data/LICENSE +22 -0
  10. data/README.md +169 -0
  11. data/Rakefile +7 -0
  12. data/lib/simple-api-auth/authenticable.rb +72 -0
  13. data/lib/simple-api-auth/authenticator.rb +32 -0
  14. data/lib/simple-api-auth/config.rb +61 -0
  15. data/lib/simple-api-auth/hashers/sha1_hasher.rb +14 -0
  16. data/lib/simple-api-auth/helpers/auth_helpers.rb +49 -0
  17. data/lib/simple-api-auth/helpers/request_helpers.rb +18 -0
  18. data/lib/simple-api-auth/request.rb +34 -0
  19. data/lib/simple-api-auth/signer.rb +53 -0
  20. data/lib/simple-api-auth/version.rb +6 -0
  21. data/lib/simple-api-auth.rb +47 -0
  22. data/simple-api-auth.gemspec +25 -0
  23. data/spec/extensions/string_spec.rb +13 -0
  24. data/spec/internal/app/models/models.rb +13 -0
  25. data/spec/internal/config/database.yml +4 -0
  26. data/spec/internal/db/schema.rb +7 -0
  27. data/spec/lib/simple-api-auth/authenticable_spec.rb +106 -0
  28. data/spec/lib/simple-api-auth/authenticator_spec.rb +35 -0
  29. data/spec/lib/simple-api-auth/config_spec.rb +48 -0
  30. data/spec/lib/simple-api-auth/helpers/auth_helpers_spec.rb +61 -0
  31. data/spec/lib/simple-api-auth/helpers/request_helpers_spec.rb +39 -0
  32. data/spec/lib/simple-api-auth/request_spec.rb +49 -0
  33. data/spec/lib/simple-api-auth/signer_spec.rb +37 -0
  34. data/spec/lib/simple-api-auth_spec.rb +110 -0
  35. data/spec/spec_helper.rb +31 -0
  36. data/spec/support/auth.rb +13 -0
  37. data/spec/support/database.rb +14 -0
  38. data/spec/support/database_cleaner.rb +19 -0
  39. data/spec/support/extensions.rb +10 -0
  40. data/spec/support/mocks.rb +67 -0
  41. data/spec/support/requests.rb +51 -0
  42. metadata +189 -0
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'simple-api-auth/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'simple-api-auth'
7
+ spec.version = SimpleApiAuth::VERSION
8
+ spec.authors = ['Daniel Perez']
9
+ spec.email = ['daniel@claudetech.com']
10
+ spec.summary = 'Basic token based authentication for APIs'
11
+ spec.homepage = 'https://github.com/claude-tech/ruby-simple-api-auth'
12
+ spec.license = 'MIT'
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.test_files = Dir['specs/**/*']
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.add_development_dependency 'rake', '~> 10.0'
19
+ spec.add_development_dependency 'rspec', '~> 3.0'
20
+ spec.add_development_dependency 'rspec-its'
21
+ spec.add_development_dependency 'coveralls', '~> 0.7'
22
+ spec.add_development_dependency 'activerecord', ['>= 3', '< 5']
23
+ spec.add_development_dependency 'database_cleaner'
24
+ spec.add_development_dependency 'sqlite3'
25
+ end
@@ -0,0 +1,13 @@
1
+ describe String do
2
+ describe '#hexdecode' do
3
+ it 'should decode text' do
4
+ expect(Digest.hexencode('foo').hexdecode).to eq('foo')
5
+ end
6
+
7
+ it 'should decode binary' do
8
+ digest = OpenSSL::Digest.new('sha1')
9
+ binary_data = OpenSSL::HMAC.digest(digest, 'foo', 'bar')
10
+ expect(Digest.hexencode(binary_data).hexdecode).to eq(binary_data)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class AuthenticableModel < ActiveRecord::Base
2
+ acts_as_api_authenticable
3
+ end
4
+
5
+ class OverriddenAuthenticableModel < ActiveRecord::Base
6
+ acts_as_api_authenticable ssa_key: :ssa_key, ssa_secret: :ssa_secret
7
+ acts_as_api_authenticable ssa_key: :ssa_key, ssa_secret: :overriden_secret
8
+ end
9
+
10
+ class AuthenticableModelWithHooks < ActiveRecord::Base
11
+ self.table_name = 'authenticable_models'
12
+ acts_as_api_authenticable auto_generate: true
13
+ end
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ':memory:'
4
+ timeout: 500
@@ -0,0 +1,7 @@
1
+ ActiveRecord::Schema.define version: 0 do
2
+ create_table :authenticable_models do |t|
3
+ t.string :ssa_key
4
+ t.string :ssa_secret
5
+ end
6
+ add_index :authenticable_models, :ssa_key, unique: true
7
+ end
@@ -0,0 +1,106 @@
1
+ describe SimpleApiAuth do
2
+ describe SimpleApiAuth::Authenticable do
3
+
4
+ describe 'class extensions' do
5
+ subject(:clazz) { AuthenticableModel }
6
+
7
+ it { should respond_to(:ssa_options) }
8
+ it { should respond_to(:ssa_authenticate) }
9
+ it { should respond_to(:ssa_find) }
10
+
11
+ it 'should set options' do
12
+ expect(clazz.ssa_options[:ssa_key]).to eq(:ssa_key)
13
+ expect(clazz.ssa_options[:ssa_secret]).to eq(:ssa_secret)
14
+ end
15
+
16
+ context 'when included several times' do
17
+ subject(:clazz) { OverriddenAuthenticableModel }
18
+
19
+ it { should respond_to(:ssa_options) }
20
+ it 'should have overriden attributes' do
21
+ expect(clazz.ssa_options[:ssa_secret]).to eq(:overriden_secret)
22
+ end
23
+ end
24
+
25
+ describe '#ssa_find' do
26
+ let(:request) { mock_request }
27
+
28
+ subject { clazz.ssa_find(request) }
29
+
30
+ it 'should return nil when not found' do
31
+ expect(subject).to be_nil
32
+ end
33
+
34
+ it 'should return entity when present' do
35
+ entity = AuthenticableModel.create(ssa_key: 'user_personal_key')
36
+ expect(subject.id).to eq(entity.id)
37
+ end
38
+ end
39
+
40
+ describe '#ssa_authenticate' do
41
+ let(:request) { mock_request }
42
+ before(:each) do
43
+ request.headers[:authorization] = "Signature: #{mock_signature}"
44
+ end
45
+
46
+ subject { clazz.ssa_authenticate(request) }
47
+
48
+ it 'should return false when the entity does not exists' do
49
+ expect(subject).to be false
50
+ end
51
+
52
+ it 'should return false when the secret key does not match' do
53
+ clazz.create(ssa_key: 'user_personal_key', ssa_secret: 'something else')
54
+ expect(subject).to be false
55
+ end
56
+
57
+ it 'should return the resource when signature matches' do
58
+ entity = clazz.create(
59
+ ssa_key: 'user_personal_key', ssa_secret: 'ultra_secret_key')
60
+ expect(subject.id).to eq(entity.id)
61
+ end
62
+ end
63
+
64
+ { 'generate_ssa_key' => 5, 'generate_ssa_secret' => 64 }.each do |method, value|
65
+ describe "##{method}" do
66
+ let(:options) { {} }
67
+ let(:key) { clazz.send(method.to_sym, options) }
68
+ it 'should generate a long enough key' do
69
+ expect(key.length).to be > value
70
+ end
71
+
72
+ it 'should use options length' do
73
+ options[:length] = 1
74
+ expect(key.length).to be < 3
75
+ end
76
+ end
77
+ end
78
+
79
+ describe 'hooks' do
80
+ subject { AuthenticableModelWithHooks.new }
81
+ its(:ssa_key) { should_not be_nil }
82
+ its(:ssa_secret) { should_not be_nil }
83
+ end
84
+ end
85
+
86
+ describe 'instance extension' do
87
+ subject(:model) { AuthenticableModel.new }
88
+
89
+ it { should respond_to(:assign_ssa_key) }
90
+ it { should respond_to(:assign_ssa_secret) }
91
+ its(:ssa_key) { should be_nil }
92
+ its(:ssa_secret) { should be_nil }
93
+
94
+ [:assign_ssa_key, :assign_ssa_secret].each do |method|
95
+ field_name = method.to_s.gsub('assign_', '')
96
+ describe "##{method}" do
97
+ it "should assign #{field_name}" do
98
+ expect(model.send(field_name)).to be_nil
99
+ model.send(method)
100
+ expect(model.send(field_name)).not_to be_nil
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,35 @@
1
+ describe SimpleApiAuth do
2
+ describe SimpleApiAuth::Authenticator do
3
+ include SimpleApiAuth::Helpers::Request
4
+
5
+ let(:dummy_headers) { mock_headers }
6
+
7
+ let(:authenticator) { SimpleApiAuth::Authenticator.new(dummy_request, mock_secret_key) }
8
+
9
+ requests.each do |name, request|
10
+ context "with #{name}" do
11
+ before(:each) do
12
+ request.configure
13
+ setup_dummy_signer
14
+ end
15
+ let(:dummy_request) { request.new(headers: dummy_headers, method: 'GET') }
16
+
17
+ describe '#valid_signature?' do
18
+ it 'should fail on missing header' do
19
+ dummy_headers.delete 'X-Saa-Key'
20
+ expect(authenticator.valid_signature?).to be_falsy
21
+ end
22
+
23
+ it 'should fail on outdated request' do
24
+ dummy_headers[:x_saa_auth_time] = outdated_time.iso8601
25
+ expect(authenticator.valid_signature?).to be_falsy
26
+ end
27
+
28
+ it 'should compare signature otherwise' do
29
+ expect(authenticator.valid_signature?).to be_truthy
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,48 @@
1
+ describe SimpleApiAuth do
2
+ describe SimpleApiAuth::Config do
3
+ let(:config) { SimpleApiAuth::Config.new }
4
+
5
+ it 'should have default values' do
6
+ expect(config.request_fields[:headers]).to eq(:headers)
7
+ expect(config.request_fields[:http_verb]).to eq(:method)
8
+ end
9
+
10
+ it 'should be mutable' do
11
+ config.request_fields[:headers] = :env
12
+ expect(config.request_fields[:headers]).to eq(:env)
13
+ end
14
+
15
+ describe 'make_model_options' do
16
+ let(:model_options) { { ssa_key: :foobar } }
17
+ subject(:options) { config.make_model_options(model_options) }
18
+
19
+ it 'should merge options' do
20
+ expect(options[:ssa_key]).to eq(:foobar)
21
+ expect(options[:ssa_secret]).to eq(:ssa_secret)
22
+ expect(options[:auto_generate]).to eq([])
23
+ end
24
+
25
+ describe 'auto_generate configuration' do
26
+ it 'should handle symbol' do
27
+ model_options[:auto_generate] = :ssa_key
28
+ expect(options[:auto_generate]).to eq([:ssa_key])
29
+ end
30
+
31
+ it 'should handle true' do
32
+ model_options[:auto_generate] = true
33
+ expect(options[:auto_generate]).to eq([:ssa_key, :ssa_secret])
34
+ end
35
+
36
+ it 'should handle false' do
37
+ model_options[:auto_generate] = false
38
+ expect(options[:auto_generate]).to eq([])
39
+ end
40
+
41
+ it 'should handle arrays' do
42
+ model_options[:auto_generate] = [:ssa_secret]
43
+ expect(options[:auto_generate]).to eq([:ssa_secret])
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ describe SimpleApiAuth do
2
+ describe SimpleApiAuth::Helpers::Auth do
3
+ include SimpleApiAuth::Helpers::Request
4
+ include SimpleApiAuth::Helpers::Auth
5
+
6
+ let(:headers) { normalize_headers(mock_headers) }
7
+ let(:request) { SimpleApiAuth::Request.create(rails_request) }
8
+
9
+ describe '#extract_signature' do
10
+ it 'should return signature when present' do
11
+ expect(extract_signature(headers)).to eq('dummy_signature')
12
+ end
13
+
14
+ it 'should return nil otherwise' do
15
+ headers[:authorization] = 'Signatur: foobar'
16
+ expect(extract_signature(headers)).to be_nil
17
+ end
18
+ end
19
+
20
+ describe '#check_data' do
21
+ it 'should return true when headers are present and http verb is valid' do
22
+ expect(check_data(request)).to be_truthy
23
+ request.http_verb = :post
24
+ expect(check_data(request)).to be_truthy
25
+ end
26
+
27
+ it 'should fail when http verb is not valid' do
28
+ request.http_verb = nil
29
+ expect(check_data(request)).to be_falsy
30
+ request.http_verb = :forbidden_verb
31
+ expect(check_data(request)).to be_falsy
32
+ end
33
+
34
+ it 'should fail when header is missing' do
35
+ request.headers.delete :authorization
36
+ expect(check_data(request)).to be_falsy
37
+ end
38
+ end
39
+
40
+ describe '#too_old?' do
41
+ it 'should allow recent enough requests' do
42
+ expect(too_old?(request)).to be_falsy
43
+ end
44
+
45
+ it 'should reject old requests' do
46
+ request.headers[:x_saa_auth_time] = Time.new(2014, 11, 8).iso8601
47
+ expect(too_old?(request)).to be_truthy
48
+ end
49
+ end
50
+
51
+ describe '#secure_equals?' do
52
+ it 'should succeed on equal values' do
53
+ expect(secure_equals?('foo', 'foo', 'secret_key')).to be_truthy
54
+ end
55
+
56
+ it 'should fail on different values' do
57
+ expect(secure_equals?('foo', 'bar', 'secret_key')).to be_falsy
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,39 @@
1
+ describe SimpleApiAuth do
2
+ describe SimpleApiAuth::Helpers::Request do
3
+ include SimpleApiAuth::Helpers::Request
4
+
5
+ describe '#normalize_headers' do
6
+ let(:raw_headers) { mock_headers }
7
+ let(:headers) { normalize_headers(raw_headers) }
8
+
9
+ it 'should normalize headers keys' do
10
+ [:authorization, :x_saa_auth_time, :x_saa_key].each do |key|
11
+ expect(headers).to include(key)
12
+ end
13
+ expect(headers.values).to eq(raw_headers.values)
14
+ end
15
+ end
16
+
17
+ describe '#normalize' do
18
+ it 'should symbolize keys' do
19
+ expect(normalize('foo')).to eq(:foo)
20
+ end
21
+
22
+ it 'should work with symbols' do
23
+ expect(normalize(:foo)).to eq(:foo)
24
+ end
25
+
26
+ it 'should downcase' do
27
+ expect(normalize('FOO')).to eq(:foo)
28
+ end
29
+
30
+ it 'should replace hyphens' do
31
+ expect(normalize('foo-bar')).to eq(:foo_bar)
32
+ end
33
+
34
+ it 'should work with more complex keys' do
35
+ expect(normalize('FOO-BAR-BAZ')).to eq(:foo_bar_baz)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,49 @@
1
+ describe SimpleApiAuth do
2
+ describe SimpleApiAuth::Request do
3
+ include SimpleApiAuth::Helpers::Request
4
+
5
+ let(:base_request) { SimpleApiAuth::Request.create(rails_request) }
6
+
7
+ def check_request(request)
8
+ expect(request.headers).to eq(normalize_headers(mock_headers))
9
+ expect(request.http_verb).to eq(:get)
10
+ end
11
+
12
+ describe '#initialize' do
13
+ let(:request) { SimpleApiAuth::Request.create(rails_request) }
14
+
15
+ it 'should set headers and http verb' do
16
+ check_request(request)
17
+ end
18
+ end
19
+
20
+ describe '#create' do
21
+ context 'with third party requests' do
22
+ requests.each do |name, request|
23
+ before(:each) { request.configure }
24
+ let(:dummy_request) { request.new(headers: mock_headers, method: 'GET') }
25
+
26
+ it "should create normalized request from #{name}" do
27
+ normalized_request = SimpleApiAuth::Request.create(dummy_request)
28
+ check_request(normalized_request)
29
+ end
30
+ end
31
+ end
32
+
33
+ it 'should not modify already normalized requests' do
34
+ expect(SimpleApiAuth::Request.create(base_request).object_id).to eq(base_request.object_id)
35
+ end
36
+ end
37
+
38
+ describe '#time' do
39
+ it 'should return request time' do
40
+ expect(base_request.time).to eq(request_time)
41
+ end
42
+
43
+ it 'should return nil on wrong time' do
44
+ base_request.headers[:x_saa_auth_time] = 'foobar'
45
+ expect(base_request.time).to be_nil
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ describe SimpleApiAuth do
2
+ describe SimpleApiAuth::Signer do
3
+
4
+ let(:signer) { SimpleApiAuth::Signer.new }
5
+ let(:request) { mock_request }
6
+
7
+ describe '#make_hashed_request' do
8
+ it 'should make a hased canonical request' do
9
+ expect(signer.make_hashed_request(request)).to eq(mock_hashed_request)
10
+ end
11
+
12
+ it 'should encode payload' do
13
+ request.body = StringIO.new('abc')
14
+ expected = <<-EOF.unindent[0..-2]
15
+ hashed:get
16
+ /foobar
17
+ foo=bar&baz=qux
18
+ #{Digest.hexencode('hashed:abc')}
19
+ EOF
20
+ expect(signer.make_hashed_request(request)).to eq(Digest.hexencode(expected))
21
+ end
22
+ end
23
+
24
+ describe '#make_string_to_sign' do
25
+ it 'should generate correct string to sign' do
26
+ expect(signer.make_string_to_sign(request)).to eq(mock_string_to_sign)
27
+ end
28
+ end
29
+
30
+ describe '#sign' do
31
+ let(:secret_key) { 'ultra_secret_key' }
32
+ it 'should generate correct signature' do
33
+ expect(signer.sign(request, secret_key)).to eq(mock_signature)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,110 @@
1
+ describe SimpleApiAuth do
2
+ it 'should be configurable' do
3
+ expect(SimpleApiAuth.config.request_fields[:headers]).to eq(:headers)
4
+ SimpleApiAuth.configure do |config|
5
+ config.request_fields[:headers] = :env
6
+ end
7
+ expect(SimpleApiAuth.config.request_fields[:headers]).to eq(:env)
8
+ end
9
+
10
+ describe '#log' do
11
+ it 'should not fail on nil' do
12
+ SimpleApiAuth.log('foobar')
13
+ end
14
+
15
+ it 'should log when logger is present' do
16
+ s = StringIO.new('', 'a')
17
+ SimpleApiAuth.config.logger = Logger.new(s)
18
+ expect(s.string).not_to include('foobar')
19
+ SimpleApiAuth.log(Logger::WARN, 'foobar')
20
+ expect(s.string).to include('foobar')
21
+ end
22
+ end
23
+
24
+ describe '#extract_key' do
25
+ let(:request) { mock_request }
26
+ subject { SimpleApiAuth.extract_key(request) }
27
+
28
+ it 'should extract correct key' do
29
+ expect(subject).to eq('user_personal_key')
30
+ end
31
+
32
+ it 'should work with custom headers' do
33
+ SimpleApiAuth.config.header_keys[:key] = :key
34
+ request.headers[:key] = request.headers.delete(:x_saa_key)
35
+ expect(subject).to eq('user_personal_key')
36
+ end
37
+ end
38
+
39
+ describe '#valid_signature?' do
40
+ let(:request) { mock_request }
41
+ let(:result) { SimpleApiAuth.valid_signature?(request, mock_secret_key) }
42
+
43
+ it 'should fail with wrong request' do
44
+ expect(result).to be_falsy
45
+ end
46
+
47
+ it 'should succeed with correct signature' do
48
+ request.headers[:authorization] = "Signature: #{mock_signature}"
49
+ expect(result).to be_truthy
50
+ end
51
+
52
+ context 'with real world example' do
53
+ before(:each) do
54
+ SimpleApiAuth.config.hasher = SimpleApiAuth::Hasher::SHA1
55
+ end
56
+ let(:request) do
57
+ SimpleApiAuth::Request.new(
58
+ http_verb: 'GET',
59
+ uri: '/foo/bar',
60
+ query_string: 'foo=bar&bar=qux',
61
+ body: StringIO.new('somerandombody'),
62
+ headers: {
63
+ authorization: 'Signature: 7c171d095fd65b7078afd13a6b3bd4ecfe596552',
64
+ x_saa_auth_time: request_time.iso8601,
65
+ x_saa_key: 'wedontreallycarehere'
66
+ }
67
+ )
68
+ end
69
+
70
+ it 'should succeed with correct key' do
71
+ expect(SimpleApiAuth.valid_signature?(request, mock_secret_key)).to be_truthy
72
+ end
73
+
74
+ it 'should fail with wrong key' do
75
+ expect(SimpleApiAuth.valid_signature?(request, 'somerandomkey')).to be_falsy
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'signing methods' do
81
+ let(:request) { mock_request }
82
+ let(:base_secret) { 'a_very_secret_key' }
83
+ let(:secret_key) { base_secret }
84
+ subject { SimpleApiAuth.valid_signature?(request, secret_key) }
85
+
86
+ describe '#compute_signature' do
87
+ let(:signature) { SimpleApiAuth.compute_signature(request, secret_key) }
88
+
89
+ it 'should return correct signature' do
90
+ request.headers[:authorization] = "Signature: #{signature}"
91
+ expect(subject).to be_truthy
92
+ end
93
+
94
+ context 'with a different key' do
95
+ let(:secret_key) { 'another cool key' }
96
+ it 'should not return the same signature' do
97
+ request.headers[:authorization] = "Signature: #{signature}"
98
+ expect(SimpleApiAuth.valid_signature?(request, base_secret)).to be_falsy
99
+ end
100
+ end
101
+ end
102
+
103
+ describe '#sign!' do
104
+ before(:each) { SimpleApiAuth.sign!(request, secret_key) }
105
+ it 'should sign the current request' do
106
+ expect(subject).to be_truthy
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,31 @@
1
+ require 'coveralls'
2
+ require 'codeclimate-test-reporter'
3
+ Coveralls.wear!
4
+ CodeClimate::TestReporter.start
5
+
6
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
+ Coveralls::SimpleCov::Formatter,
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ CodeClimate::TestReporter::Formatter
10
+ ]
11
+
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
13
+
14
+ require 'active_record'
15
+ require 'database_cleaner'
16
+ require 'simple-api-auth'
17
+ require 'rspec/its'
18
+
19
+ support_glob = File.expand_path('support/**/*.rb', File.dirname(__FILE__))
20
+ Dir[support_glob].each { |f| require f }
21
+
22
+ RSpec.configure do |config|
23
+ config.include SpecHelpers::Dummy
24
+ config.extend SpecHelpers::Requests
25
+
26
+ config.before(:each) do
27
+ allow(Time).to receive(:now) { Time.utc(2014, 11, 8, 0, 7) }
28
+ SimpleApiAuth.config.reset!
29
+ SimpleApiAuth.config.hasher = SpecHelpers::Auth::DummyHasher
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ module SpecHelpers
2
+ module Auth
3
+ class DummyHasher
4
+ def hash(value)
5
+ "hashed:#{value}"
6
+ end
7
+
8
+ def hmac(key, message)
9
+ "#{key}:#{message}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ database_yml = File.expand_path('../../internal/config/database.yml', __FILE__)
2
+ ActiveRecord::Base.default_timezone = :utc
3
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), '../debug.log'))
4
+ ActiveRecord::Base.logger.level = ENV['TRAVIS'] ? ::Logger::ERROR : ::Logger::DEBUG
5
+ ActiveRecord::Base.configurations = YAML.load_file(database_yml)
6
+
7
+ begin
8
+ ActiveRecord::Base.establish_connection(:test)
9
+ rescue
10
+ ActiveRecord::Base.establish_connection('test')
11
+ end
12
+
13
+ load(File.dirname(__FILE__) + '/../internal/db/schema.rb')
14
+ load(File.dirname(__FILE__) + '/../internal/app/models/models.rb')
@@ -0,0 +1,19 @@
1
+ RSpec.configure do |config|
2
+ config.before(:suite) do
3
+ DatabaseCleaner.clean_with(:truncation)
4
+ DatabaseCleaner.strategy = :transaction
5
+ DatabaseCleaner.clean
6
+ end
7
+
8
+ config.after(:suite) do
9
+ DatabaseCleaner.clean
10
+ end
11
+
12
+ config.before(:each) do
13
+ DatabaseCleaner.start
14
+ end
15
+
16
+ config.after(:each) do
17
+ DatabaseCleaner.clean
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ class String
2
+ def unindent
3
+ first_line_spaces = self[/\A\s*/]
4
+ gsub(/^#{first_line_spaces}/, '')
5
+ end
6
+
7
+ def hexdecode
8
+ scan(/../).map(&:hex).map(&:chr).join
9
+ end
10
+ end