da-user-auth 0.1.1 → 0.1.2

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 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