app_rail-airtable 0.2.7 → 0.2.11

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
  SHA256:
3
- metadata.gz: 59112ddcce193bb297ccdb3cebd972445183c4a9e755a1ccb7c91c695f600bb9
4
- data.tar.gz: ee3d1ff83a53b53f367aa7c84781113457a037abf4257a9d7ccf2589a167e456
3
+ metadata.gz: 4042e0d7f3f72204f26f22d018c4e6fff171a76379e6961ac93511930566e43d
4
+ data.tar.gz: 95e44a95a516a1ef1afdaf14f47ff145deae55021c4b939e874033567515f234
5
5
  SHA512:
6
- metadata.gz: 5099f41bc41cc4a744e49586c2f727cca97cb1054131144094f1c3bbe3cbaac8acb020909acae4903d92920348a738f70ebac45f18a9150a1b3c6246b8e17807
7
- data.tar.gz: 4afb93f8f41cd9a306b1a5262fafcc30127f7c0df95c51e82b76fabf0a04b8e8e114381a432d44fb382e835021edbc5dcdc2727bee2bda12c6b23fdc5aad1b6e
6
+ metadata.gz: 71120e0e952456e41fb9f950d45b763306a038571694f37976c72e23824b4501bc8f87e141b765878e76dca4e438f6a12440da4112ba9803957902706865964d
7
+ data.tar.gz: 1da004d48fb6e02c0871a941423d191efcccf0b6a56d2c34123bf556e6b12756c589fab1ebca055ce6f5cd7eb0003cff19e815743bb2b7afc130bc0868674f13
data/Gemfile.lock CHANGED
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- app_rail-airtable (0.2.7)
4
+ app_rail-airtable (0.2.11)
5
5
  activesupport
6
6
  airrecord
7
+ bcrypt
7
8
  sinatra
8
9
  thor
9
10
 
@@ -19,6 +20,7 @@ GEM
19
20
  airrecord (1.0.7)
20
21
  faraday (>= 0.10, < 2.0)
21
22
  net-http-persistent
23
+ bcrypt (3.1.16)
22
24
  byebug (11.1.3)
23
25
  concurrent-ruby (1.1.9)
24
26
  connection_pool (2.2.5)
data/README.md CHANGED
@@ -31,7 +31,9 @@ You should create a model class for each table you want to use in your App. Mode
31
31
  To provide support for routes, models can implement
32
32
  * ar_list_item (index)
33
33
  * ar_stack (show)
34
- * self.create_from_params (create)
34
+ * self.create_as_json (create)
35
+
36
+ In order to support authentication you should create a class (normally `User`) and inherit from `AppRail::Airtable::AuthenticationRecord`. Your table needs `Email`, `Password Hash` and `Access Token` columns.
35
37
 
36
38
  ### Servers
37
39
  You should create a single server which extends `AppRail::Airtable::Sinatra`, then add routes with the `resources` macro to add `index`, `show` and `create` routes. You can also provide your own routes.
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'sinatra'
25
25
  spec.add_dependency 'airrecord'
26
26
  spec.add_dependency 'thor'
27
+ spec.add_dependency 'bcrypt'
27
28
 
28
29
  spec.add_development_dependency 'rspec'
29
30
  spec.add_development_dependency 'rack-test'
@@ -43,7 +43,7 @@ module AppRail
43
43
  # Customisable behaviour
44
44
 
45
45
  # Override to provide custom sorting or filtering for index
46
- def self.index(current_user)
46
+ def self.index(user:)
47
47
  all
48
48
  end
49
49
 
@@ -0,0 +1,56 @@
1
+ require 'bcrypt'
2
+ require 'securerandom'
3
+
4
+ module AppRail
5
+ module Airtable
6
+ module Authenticatable
7
+ include BCrypt
8
+
9
+ def self.included(klass)
10
+ klass.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ def create(email:, password:)
15
+ user = User.new("Email" => email, "Password Hash" => password_hash(password), "Access Token" => access_token)
16
+ user.create
17
+ user
18
+ end
19
+
20
+ def create_session_as_json(email:, password:)
21
+ user = find_by_email_and_password(email, password)
22
+ user&.oauth_session
23
+ end
24
+
25
+ def find_by_email_and_password(email, password)
26
+ user = all(filter: "AND({Email} = \"#{email}\"").first
27
+ user.valid_password? ? user : nil
28
+ end
29
+
30
+ def find_by_access_token(access_token)
31
+ all(filter: "{Access Token} = \"#{access_token}\"").first
32
+ end
33
+
34
+ def password_hash(password)
35
+ BCrypt::Password.create(password)
36
+ end
37
+
38
+ def access_token
39
+ SecureRandom.hex
40
+ end
41
+ end
42
+
43
+ def valid_password?(password)
44
+ BCrypt::Password.new(password_hash) == password
45
+ end
46
+
47
+ def password_hash
48
+ self["Password Hash"]
49
+ end
50
+
51
+ def oauth_session
52
+ { access_token: self["Access Token"], scope: :user, refresh_token: "", token_type: :bearer, expires_in: 60000 }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,27 @@
1
+ module AppRail
2
+ module Airtable
3
+ module AuthenticationHelpers
4
+ def current_user
5
+ @current_user ||= find_current_user
6
+ end
7
+
8
+ def find_current_user
9
+ authorization_header && bearer_token ? User.find_by_access_token(bearer_token) : nil
10
+ end
11
+
12
+ def bearer_token
13
+ authorization_values = authorization_header.split(" ")
14
+ return nil unless authorization_values.count > 1
15
+ authorization_values[1]
16
+ end
17
+
18
+ def authorization_header
19
+ request.env["HTTP_AUTHORIZATION"]
20
+ end
21
+
22
+ def authenticate!
23
+ halt 401 unless current_user
24
+ end
25
+ end
26
+ end
27
+ end
@@ -31,7 +31,7 @@ module AppRail
31
31
  JSON.parse(request.body.read)
32
32
  end
33
33
 
34
- def params_and_json_body
34
+ def params_and_body_as_json
35
35
  request_body_as_json.merge(params)
36
36
  end
37
37
  end
@@ -47,7 +47,7 @@ module AppRail
47
47
  def self.index_route(name, authenticated)
48
48
  get "/#{name.to_s}" do
49
49
  authenticate! if authenticated
50
- name.classify_constantize.index(authenticated ? current_user : nil).map(&:ar_list_item_as_json).to_json
50
+ name.classify_constantize.index(user: authenticated ? current_user : nil).map(&:ar_list_item_as_json).to_json
51
51
  end
52
52
  end
53
53
 
@@ -61,7 +61,7 @@ module AppRail
61
61
  def self.create_route(name, authenticated)
62
62
  post "/#{name.to_s}" do
63
63
  authenticate! if authenticated
64
- as_json = name.classify_constantize.create_with_params_as_json(params_and_json_body)
64
+ as_json = name.classify_constantize.create_as_json(current_user: authenticated ? current_user : nil, params: params_and_body_as_json)
65
65
  [201, as_json.to_json]
66
66
  end
67
67
  end
@@ -1,5 +1,5 @@
1
1
  module AppRail
2
2
  module Airtable
3
- VERSION = "0.2.7"
3
+ VERSION = "0.2.11"
4
4
  end
5
5
  end
@@ -1,8 +1,10 @@
1
1
  require "app_rail/airtable/version"
2
+ require "app_rail/airtable/string_ext"
2
3
  require "app_rail/airtable/application_record"
4
+ require "app_rail/airtable/authenticatable"
5
+ require "app_rail/airtable/authentication_helpers"
3
6
  require "app_rail/airtable/sinatra"
4
7
  require "app_rail/airtable/generator"
5
- require "app_rail/airtable/string_ext"
6
8
 
7
9
  module AppRail
8
10
  module Airtable
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_rail-airtable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Brooke-Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-04 00:00:00.000000000 Z
11
+ date: 2021-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bcrypt
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'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +130,8 @@ files:
116
130
  - bin/setup
117
131
  - lib/app_rail/airtable.rb
118
132
  - lib/app_rail/airtable/application_record.rb
133
+ - lib/app_rail/airtable/authenticatable.rb
134
+ - lib/app_rail/airtable/authentication_helpers.rb
119
135
  - lib/app_rail/airtable/generator.rb
120
136
  - lib/app_rail/airtable/sinatra.rb
121
137
  - lib/app_rail/airtable/string_ext.rb