da-user-auth 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 453ccd82ecf5380d0f1e2929d910d28849c4dee8
4
- data.tar.gz: 501f50f6df3b831bda592b2688b99f1422f8d7d9
3
+ metadata.gz: 688eaf232753fb14c940d1e28592868774a3d0e8
4
+ data.tar.gz: 237032e40e98382a550b0a0df2fc4b4240619f73
5
5
  SHA512:
6
- metadata.gz: 4d34bfd4e8358cf4ca8f9b3f457563c2a911ce0eed07293b6aab8f1b810da6308c81d24c338c7c35c4ddd9b7be510716ea6f07fcfcb8793ad8bbb567bf72b4fe
7
- data.tar.gz: fe6d6e5be9865cf432796b4ad3faf50a1ef32f41aecd2a479b386f06c58b644c9a64a8ec809f8d8ec79138e5c525163f9af0981435f85e97cb08bf1f4db8813a
6
+ metadata.gz: c9ea6553b7c07ad204cbcaa628e4f5edca7cedab3b7ec46ee8b1605d437ce95846715a609f69cdafeb97992b84143805d77adced4f0609d9819087564c33e7e4
7
+ data.tar.gz: bc7995fd435c7dc2218562c76aac3460646fce35fd3bbe37237fe28438c501594913c9c2e8510e0f980216cc5d38216de3c773f16eaea90a91ebf9fb1f87b033
@@ -1,5 +1,15 @@
1
1
  sudo: false
2
2
  language: ruby
3
+ cache: bundler
3
4
  rvm:
4
- - 2.4.0
5
+ - 2.4.1
6
+ addons:
7
+ postgresql: '9.4'
8
+ env:
9
+ - TEST_DATABASE_URL="postgres://localhost/travis_ci_test" JWT_SECRET_KEY=df4eb72858852f57d15d8d6dd53b305e
10
+ before_script:
11
+ - psql -c 'create database travis_ci_test;' -U postgres
5
12
  before_install: gem install bundler -v 1.15.0
13
+ script:
14
+ - bin/rake db:migrate APP_ENV=test
15
+ - bin/rake ci:all
data/Rakefile CHANGED
@@ -1,8 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
- require "da/rake_tasks"
3
2
 
4
3
  # Add current path and lib to the load path
5
4
  $: << File.expand_path('../', __FILE__)
6
5
  $: << File.expand_path('../lib', __FILE__)
7
6
 
7
+ Dir.glob('lib/tasks/*.rake').each { |r| import r }
8
+
8
9
  task default: ["ci:all"]
data/config.ru CHANGED
@@ -1,9 +1,7 @@
1
1
  require_relative "./config/boot"
2
2
  require_relative "./lib/user_auth/api"
3
- require "da/web/exception_handling"
4
3
  require "rack/cors"
5
4
 
6
- use DA::Web::ExceptionHandling
7
5
  use Rack::Deflater
8
6
  use Rack::Cors do
9
7
  allow do
@@ -5,6 +5,22 @@ $: << File.expand_path("../../lib", __FILE__)
5
5
  # Default ENV to dev if not present
6
6
  ENV["APP_ENV"] ||= "development"
7
7
 
8
- require "da/core/environment"
9
- require "da/db"
10
- require "da/web"
8
+ # Autoload common standard library features
9
+ require "json"
10
+
11
+ # Autoload gems from the Gemfile
12
+ require "bundler/setup"
13
+ require "dotenv"
14
+
15
+ require "active_support/core_ext/object/blank" # blank? and present?
16
+ require "active_support/core_ext/integer/time" # 1.week.ago etc
17
+ require "active_support/core_ext/hash/slice" # params.slice(:one, :other)
18
+ require "active_support/core_ext/hash/conversions" # params.symbolize_keys
19
+ require "active_support/core_ext/hash/indifferent_access"
20
+
21
+ # Load dev env vars
22
+ Dotenv.load if %w[development test].include? ENV["APP_ENV"]
23
+
24
+ # Autoload app dependencies
25
+ path = File.join(__dir__, "initializers", "*.rb")
26
+ (Dir[path].sort).uniq.each { |rb| require rb }
@@ -0,0 +1,28 @@
1
+ require "logger"
2
+ require "null_logger"
3
+
4
+ $logger = begin
5
+ case ENV["APP_ENV"]
6
+ when "test"
7
+ NullLogger.new
8
+ else
9
+ # Log to a file
10
+ # Logger.new(File.expand_path(File.join(__dir__, "..", "..", "log", ENV.fetch('APP_ENV', 'development')+".log")))
11
+
12
+ # Log to STDOUT
13
+ Logger.new(STDOUT)
14
+ end
15
+ end
16
+
17
+ $logger.level = begin
18
+ case String(ENV["LOG_LEVEL"]).downcase
19
+ when "info"
20
+ Logger::INFO
21
+ when "warn"
22
+ Logger::WARN
23
+ when "error"
24
+ Logger::ERROR
25
+ else
26
+ Logger::DEBUG
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ require "sequel"
2
+
3
+ DB = Sequel.connect(ENV["APP_ENV"] == "test" ? ENV["TEST_DATABASE_URL"] : ENV["DATABASE_URL"], max_connections: Integer(ENV.fetch('MAX_THREADS', 5)) + 1)
4
+ DB.extension :pg_array, :pg_json, :pagination
5
+ DB.loggers << $logger
6
+ DB.sql_log_level = :debug
7
+
8
+ Sequel::Model.plugin :timestamps, update_on_create: true
9
+ Sequel::Model.plugin :validation_helpers
10
+ Sequel::Model.plugin :defaults_setter
@@ -0,0 +1,30 @@
1
+ require "base64"
2
+ require "user_auth/token"
3
+ require "warden"
4
+ require "ostruct"
5
+
6
+ Warden::Manager.before_failure do |env,opts|
7
+ # Sinatra is very sensitive to the request method
8
+ # since authentication could fail on any type of method, we need
9
+ # to set it for the failure app so it is routed to the correct block
10
+ env["REQUEST_METHOD"] = "POST"
11
+ end
12
+
13
+ Warden::Strategies.add(:jwt) do
14
+ def valid?
15
+ env["HTTP_AUTHORIZATION"] || params["access_token"]
16
+ end
17
+
18
+ def authenticate!
19
+ token_str = params["access_token"]
20
+
21
+ if env["HTTP_AUTHORIZATION"]
22
+ token_str = env["HTTP_AUTHORIZATION"].sub(/^Bearer/, "").strip
23
+ end
24
+
25
+ payload = UserAuth::Token.new.parse(token_str)
26
+ success!(OpenStruct.new(payload))
27
+ rescue UserAuth::Token::ParseError => e
28
+ throw(:warden, message: "Auth token error: #{e.message}")
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ require "logger"
2
+
3
+ class NullLogger < Logger
4
+ def initialize
5
+ super("/dev/null")
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ begin
2
+ require "bundler/audit/task"
3
+ require "rspec/core/rake_task"
4
+ require "rubocop/rake_task"
5
+
6
+ Bundler::Audit::Task.new
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ namespace :ci do
11
+ task :all do
12
+ # Run rubocop on the current branches commit diff with master:
13
+ # rubocop:disable Metrics/LineLength
14
+ # system!("git diff-tree -r --no-commit-id --name-only master@\{u\} head | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs rubocop")
15
+ Rake::Task["rubocop"].invoke
16
+ Rake::Task["spec"].invoke
17
+ Rake::Task["bundle:audit"].invoke
18
+ end
19
+ end
20
+ rescue LoadError
21
+ puts "Can’t load CI task"
22
+ end
@@ -0,0 +1,88 @@
1
+ # rubocop:disable Metrics/BlockLength
2
+ namespace :db do
3
+ task :environment do
4
+ ENV["APP_ENV"] ||= "development"
5
+ require "bundler/setup"
6
+ require "dotenv"
7
+ Dotenv.load if %w[development test].include? ENV["APP_ENV"]
8
+ end
9
+
10
+ task connect_db: :environment do
11
+ @root_dir = File.expand_path(File.join(__dir__, "..", ".."))
12
+ @migrations_dir = File.join(@root_dir, "db", "migrations")
13
+ require_relative "../../config/boot"
14
+ Sequel.extension :migration
15
+ end
16
+
17
+ desc "Create databases"
18
+ task create: :environment do
19
+ %w[DATABASE_URL TEST_DATABASE_URL].each do |db_url|
20
+ db_url = ENV[db_url]
21
+ puts "CREATE: #{db_url}"
22
+
23
+ if db_url.nil?
24
+ puts "#{db_url} not set!"
25
+ next
26
+ end
27
+
28
+ dbname = URI.parse(db_url).path[1..-1]
29
+ system("createdb #{dbname}")
30
+ end
31
+ end
32
+
33
+ desc "Run migrations"
34
+ task :migrate, [:version] => :connect_db do |_, args|
35
+ if args[:version]
36
+ Sequel::Migrator.run(DB, @migrations_dir, target: args[:version].to_i)
37
+ else
38
+ Sequel::Migrator.run(DB, @migrations_dir)
39
+ end
40
+
41
+ if ENV["APP_ENV"] == "development"
42
+ system("sequel -d #{ENV['DATABASE_URL']} > #{@root_dir}/db/schema.rb")
43
+ end
44
+
45
+ Rake::Task["db:version"].execute
46
+ end
47
+
48
+ desc "Rollback to migration"
49
+ task rollback: :connect_db do
50
+ version = if DB.tables.include?(:schema_migrations)
51
+ previous = DB[:schema_migrations].order(Sequel.desc(:filename)).limit(2).all[1]
52
+ previous ? previous[:filename].split("_").first : nil
53
+ end || 0
54
+
55
+ Sequel::Migrator.run(DB, @migrations_dir, target: version.to_i)
56
+
57
+ if ENV["APP_ENV"] == "development"
58
+ system("sequel -d #{ENV['DATABASE_URL']} > #{@root_dir}/db/schema.rb")
59
+ end
60
+
61
+ Rake::Task["db:version"].execute
62
+ end
63
+
64
+ desc "Create a migration"
65
+ task :create_migration, [:name] => :connect_db do |_, args|
66
+ require "date"
67
+ raise("Name required") unless args[:name]
68
+
69
+ timestamp = DateTime.now.strftime("%Y%m%d%H%M%S")
70
+ path = "db/migrations/#{timestamp}_#{args[:name]}.rb"
71
+
72
+ File.open("#{@root_dir}/#{path}", "w") do |f|
73
+ f.write("Sequel.migration do\n up do\n end\n\n down do\n end\nend")
74
+ end
75
+
76
+ puts "MIGRATION CREATED: #{path}"
77
+ end
78
+
79
+ desc "Prints current schema version"
80
+ task version: :connect_db do
81
+ version = if DB.tables.include?(:schema_migrations)
82
+ latest = DB[:schema_migrations].order(:filename).last
83
+ latest ? latest[:filename] : nil
84
+ end || 0
85
+
86
+ puts "Schema Version: #{version}"
87
+ end
88
+ end
@@ -0,0 +1,18 @@
1
+ require "json"
2
+ require "sinatra/base"
3
+
4
+ class TokenFailureApp < ::Sinatra::Base
5
+ post "/unauthenticated" do
6
+ status :unauthorized
7
+ content_type :json
8
+ JSON.dump(error: "authentication_failed", message: error_message)
9
+ end
10
+
11
+ def error_message
12
+ if request.env["warden.options"]
13
+ message = request.env["warden.options"][:message]
14
+ end
15
+
16
+ message || request.env["warden.api.error"] || "Your credentials are invalid"
17
+ end
18
+ end
@@ -1,13 +1,25 @@
1
- require "da/web"
2
1
  require_relative "./models/refresh_token"
3
2
  require_relative "./models/user"
4
3
  require_relative "./web/helpers"
4
+ require_relative "./token"
5
5
  require_relative "./password_verifier"
6
+ require "rack/contrib"
7
+ require "sinatra/base"
8
+ require "token_failure_app"
6
9
 
7
10
  module UserAuth
8
- class Api < DA::Web::BaseRoute
11
+ class Api < Sinatra::Base
12
+ use Rack::PostBodyContentTypeParser
9
13
  include UserAuth::Models
10
14
 
15
+ enable :raise_errors
16
+ disable :dump_errors, :show_exceptions, :logging, :static
17
+
18
+ use Warden::Manager do |manager|
19
+ manager.default_strategies :jwt
20
+ manager.failure_app = ::TokenFailureApp # lib/token_failure_app.rb
21
+ end
22
+
11
23
  helpers Web::Helpers
12
24
 
13
25
  get "/" do
@@ -105,16 +117,16 @@ module UserAuth
105
117
  json_user_token(current_user)
106
118
  end
107
119
 
108
- error Sinatra::NotFound, Sequel::NoMatchingRow do
109
- halt_not_found("Endpoint '#{request.path_info}' not found")
110
- end
111
-
112
- error Sequel::ValidationFailed do |e|
113
- halt_unprocessible_entity(e)
120
+ error Sequel::ValidationFailed do |record|
121
+ halt 422, json(
122
+ errors: record.errors,
123
+ error_code: "validation_failed",
124
+ message: "Validation failed"
125
+ )
114
126
  end
115
127
 
116
- error AuthToken::ParseError do |e|
117
- halt_bad_request(e.message)
128
+ error Sinatra::NotFound, Sequel::NoMatchingRow do
129
+ halt 404, json(error_code: "not_found", message: "Endpoint '#{request.path}' not found")
118
130
  end
119
131
  end
120
132
  end
@@ -0,0 +1,23 @@
1
+ require "jwt"
2
+
3
+ module UserAuth
4
+ class Token
5
+ def initialize(secret = ENV["JWT_SECRET_KEY"])
6
+ @secret = secret
7
+ end
8
+
9
+ def create(payload)
10
+ JWT.encode(payload, @secret, "HS512")
11
+ end
12
+
13
+ def parse(token)
14
+ JWT.decode(token, @secret)[0]
15
+ rescue JWT::ExpiredSignature
16
+ raise ParseError.new("Token expired")
17
+ rescue JWT::DecodeError
18
+ raise ParseError.new("Invalid token")
19
+ end
20
+
21
+ class ParseError < StandardError; end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module UserAuth
2
- VERSION = "0.1.1".freeze
2
+ VERSION = "0.1.2".freeze
3
3
  end
@@ -1,12 +1,18 @@
1
- require "da/core/auth_token"
2
-
3
1
  module UserAuth
4
2
  module Web
5
3
  module Helpers
4
+ def warden
5
+ env["warden"]
6
+ end
7
+
6
8
  def current_user
7
9
  @current_user ||= UserAuth::Models::User.with_pk!(warden.user.user_id)
8
10
  end
9
11
 
12
+ def params
13
+ super.symbolize_keys.with_indifferent_access
14
+ end
15
+
10
16
  def deliver_email(options)
11
17
  UserAuth.configuration.deliver_mail.call(options)
12
18
  end
@@ -26,7 +32,7 @@ module UserAuth
26
32
 
27
33
  def build_jwt(data)
28
34
  exp = Time.now.to_i + UserAuth.configuration.jwt_exp
29
- AuthToken.new.create(data.merge(exp: exp))
35
+ Token.new.create(data.merge(exp: exp))
30
36
  end
31
37
  end
32
38
  end
@@ -21,12 +21,19 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_runtime_dependency "da-core", "~> 0.1.5"
24
+ spec.add_runtime_dependency "activesupport"
25
+ spec.add_runtime_dependency "dotenv"
26
+ spec.add_runtime_dependency "rack"
27
+ spec.add_runtime_dependency "rack-contrib"
28
+ spec.add_runtime_dependency "rack-cors"
29
+ spec.add_runtime_dependency "sinatra", "~> 2.0.0"
25
30
  spec.add_runtime_dependency "pg", "~> 0.20"
26
31
  spec.add_runtime_dependency "sequel", "~> 4.44.0"
32
+ spec.add_runtime_dependency "jwt"
27
33
  spec.add_runtime_dependency "bcrypt"
34
+ spec.add_runtime_dependency "warden"
28
35
 
29
- spec.add_development_dependency "bundler", ">= 1.14"
36
+ spec.add_development_dependency "bundler", "~> 1.15"
30
37
  spec.add_development_dependency "rake", "~> 10.0"
31
38
  spec.add_development_dependency "rspec", "~> 3.0"
32
39
  spec.add_development_dependency "rack-test"
metadata CHANGED
@@ -1,29 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: da-user-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pete Hawkins
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-12 00:00:00.000000000 Z
11
+ date: 2017-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: da-core
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack-contrib
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-cors
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sinatra
15
85
  requirement: !ruby/object:Gem::Requirement
16
86
  requirements:
17
87
  - - "~>"
18
88
  - !ruby/object:Gem::Version
19
- version: 0.1.5
89
+ version: 2.0.0
20
90
  type: :runtime
21
91
  prerelease: false
22
92
  version_requirements: !ruby/object:Gem::Requirement
23
93
  requirements:
24
94
  - - "~>"
25
95
  - !ruby/object:Gem::Version
26
- version: 0.1.5
96
+ version: 2.0.0
27
97
  - !ruby/object:Gem::Dependency
28
98
  name: pg
29
99
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +122,20 @@ dependencies:
52
122
  - - "~>"
53
123
  - !ruby/object:Gem::Version
54
124
  version: 4.44.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: jwt
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
55
139
  - !ruby/object:Gem::Dependency
56
140
  name: bcrypt
57
141
  requirement: !ruby/object:Gem::Requirement
@@ -67,19 +151,33 @@ dependencies:
67
151
  - !ruby/object:Gem::Version
68
152
  version: '0'
69
153
  - !ruby/object:Gem::Dependency
70
- name: bundler
154
+ name: warden
71
155
  requirement: !ruby/object:Gem::Requirement
72
156
  requirements:
73
157
  - - ">="
74
158
  - !ruby/object:Gem::Version
75
- version: '1.14'
76
- type: :development
159
+ version: '0'
160
+ type: :runtime
77
161
  prerelease: false
78
162
  version_requirements: !ruby/object:Gem::Requirement
79
163
  requirements:
80
164
  - - ">="
81
165
  - !ruby/object:Gem::Version
82
- version: '1.14'
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: bundler
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '1.15'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.15'
83
181
  - !ruby/object:Gem::Dependency
84
182
  name: rake
85
183
  requirement: !ruby/object:Gem::Requirement
@@ -204,9 +302,16 @@ files:
204
302
  - bin/setup
205
303
  - config.ru
206
304
  - config/boot.rb
305
+ - config/initializers/logger.rb
306
+ - config/initializers/sequel.rb
307
+ - config/initializers/warden.rb
207
308
  - config/puma.rb
208
309
  - db/migrations/20170602120030_create_users.rb
209
310
  - db/schema.rb
311
+ - lib/null_logger.rb
312
+ - lib/tasks/ci.rake
313
+ - lib/tasks/db.rake
314
+ - lib/token_failure_app.rb
210
315
  - lib/user_auth.rb
211
316
  - lib/user_auth/api.rb
212
317
  - lib/user_auth/configuration.rb
@@ -216,6 +321,7 @@ files:
216
321
  - lib/user_auth/password_verifier.rb
217
322
  - lib/user_auth/rake_tasks.rb
218
323
  - lib/user_auth/tasks/import_migrations.rake
324
+ - lib/user_auth/token.rb
219
325
  - lib/user_auth/version.rb
220
326
  - lib/user_auth/web/helpers.rb
221
327
  - user-auth.gemspec