forest_liana 6.0.0.pre.beta.4 → 6.0.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/app/controllers/forest_liana/actions_controller.rb +12 -2
- data/app/controllers/forest_liana/authentication_controller.rb +2 -2
- data/app/serializers/forest_liana/stripe_invoice_serializer.rb +5 -5
- data/app/services/forest_liana/authentication.rb +0 -2
- data/app/services/forest_liana/authorization_getter.rb +23 -21
- data/app/services/forest_liana/resource_creator.rb +1 -1
- data/app/services/forest_liana/resource_updater.rb +3 -3
- data/app/services/forest_liana/schema_utils.rb +8 -3
- data/app/services/forest_liana/stripe_invoice_getter.rb +1 -1
- data/app/services/forest_liana/stripe_invoices_getter.rb +1 -1
- data/app/services/forest_liana/stripe_source_getter.rb +1 -1
- data/app/services/forest_liana/stripe_sources_getter.rb +1 -1
- data/config/initializers/error-messages.rb +3 -0
- data/config/initializers/errors.rb +21 -2
- data/config/routes.rb +0 -4
- data/lib/forest_liana/bootstrapper.rb +5 -5
- data/lib/forest_liana/version.rb +1 -1
- data/spec/requests/actions_controller_spec.rb +49 -1
- data/test/routing/route_test.rb +0 -12
- data/test/services/forest_liana/resources_getter_test.rb +3 -3
- metadata +113 -148
- data/app/controllers/forest_liana/sessions_controller.rb +0 -95
- data/app/serializers/forest_liana/session_serializer.rb +0 -33
- data/app/services/forest_liana/login_handler.rb +0 -99
- data/app/services/forest_liana/two_factor_registration_confirmer.rb +0 -36
- data/app/services/forest_liana/user_secret_creator.rb +0 -26
- data/spec/requests/sessions_spec.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 407abbfa6e112f59b3e951e0b29d9660fa3845606cbaff9db24238e09bde8f08
|
4
|
+
data.tar.gz: 1778138ca8558ea3c66c5acc86171493af707948eacc61b400ebcec31966b6ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b71a26a73298e82533e6a25282e0964214360d8c4c6b7774919b4421c778eef9ab28d31a260d85a83706367a3fd85b6be4169b84f28cc3e8a45b88c79d78cbc
|
7
|
+
data.tar.gz: efcde59108053f294bb2128205d347af6261f42bcaec0df8c4336631cbb3f7af34fa8940556863421f79c57b0c1ee88336c0586f4f06360ecc42d59310954ac0
|
@@ -55,10 +55,20 @@ module ForestLiana
|
|
55
55
|
# Apply result on fields (transform the object back to an array), preserve order.
|
56
56
|
fields = action.fields.map do |field|
|
57
57
|
updated_field = result[field[:field]]
|
58
|
+
|
58
59
|
# Reset `value` when not present in `enums` (which means `enums` has changed).
|
59
|
-
if updated_field[:enums].is_a?(Array)
|
60
|
-
|
60
|
+
if updated_field[:enums].is_a?(Array)
|
61
|
+
# `value` can be an array if the type of fields is `[x]`
|
62
|
+
if updated_field[:type].is_a?(Array) && updated_field[:value].is_a?(Array) && !(updated_field[:value] - updated_field[:enums]).empty?
|
63
|
+
updated_field[:value] = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# `value` can be any other value
|
67
|
+
if !updated_field[:type].is_a?(Array) && !updated_field[:enums].include?(updated_field[:value])
|
68
|
+
updated_field[:value] = nil
|
69
|
+
end
|
61
70
|
end
|
71
|
+
|
62
72
|
updated_field
|
63
73
|
end
|
64
74
|
|
@@ -86,8 +86,8 @@ module ForestLiana
|
|
86
86
|
render json: response_body, status: 200
|
87
87
|
|
88
88
|
rescue => error
|
89
|
-
render json: { errors: [{ status: 500, detail: error.message }] },
|
90
|
-
status: :internal_server_error, serializer: nil
|
89
|
+
render json: { errors: [{ status: error.error_code || 500, detail: error.message }] },
|
90
|
+
status: error.status || :internal_server_error, serializer: nil
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -3,20 +3,20 @@ module ForestLiana
|
|
3
3
|
include JSONAPI::Serializer
|
4
4
|
|
5
5
|
attribute :amount_due
|
6
|
+
attribute :amount_paid
|
7
|
+
attribute :amount_remaining
|
8
|
+
attribute :application_fee_amount
|
6
9
|
attribute :attempt_count
|
7
10
|
attribute :attempted
|
8
|
-
attribute :closed
|
9
11
|
attribute :currency
|
10
|
-
attribute :
|
11
|
-
attribute :forgiven
|
12
|
+
attribute :due_date
|
12
13
|
attribute :paid
|
13
14
|
attribute :period_end
|
14
15
|
attribute :period_start
|
16
|
+
attribute :status
|
15
17
|
attribute :subtotal
|
16
18
|
attribute :total
|
17
|
-
attribute :application_fee
|
18
19
|
attribute :tax
|
19
|
-
attribute :tax_percent
|
20
20
|
|
21
21
|
has_one :customer
|
22
22
|
|
@@ -26,9 +26,7 @@ module ForestLiana
|
|
26
26
|
|
27
27
|
user = ForestLiana::AuthorizationGetter.authenticate(
|
28
28
|
rendering_id,
|
29
|
-
true,
|
30
29
|
{ :forest_token => access_token_instance.instance_variable_get(:@access_token) },
|
31
|
-
nil,
|
32
30
|
)
|
33
31
|
|
34
32
|
return ForestLiana::Token.create_token(user, rendering_id)
|
@@ -1,23 +1,12 @@
|
|
1
1
|
module ForestLiana
|
2
2
|
class AuthorizationGetter
|
3
|
-
def self.authenticate(rendering_id,
|
3
|
+
def self.authenticate(rendering_id, auth_data)
|
4
4
|
begin
|
5
5
|
route = "/liana/v2/renderings/#{rendering_id.to_s}/authorization"
|
6
|
-
|
7
|
-
if !use_google_authentication.nil?
|
8
|
-
headers = { 'forest-token' => auth_data[:forest_token] }
|
9
|
-
elsif !auth_data[:email].nil?
|
10
|
-
headers = { 'email' => auth_data[:email], 'password' => auth_data[:password] }
|
11
|
-
end
|
12
|
-
|
13
|
-
query_parameters = {}
|
14
|
-
|
15
|
-
unless two_factor_registration.nil?
|
16
|
-
query_parameters['two-factor-registration'] = true
|
17
|
-
end
|
6
|
+
headers = { 'forest-token' => auth_data[:forest_token] }
|
18
7
|
|
19
8
|
response = ForestLiana::ForestApiRequester
|
20
|
-
.get(route, query:
|
9
|
+
.get(route, query: {}, headers: headers)
|
21
10
|
|
22
11
|
if response.code.to_i == 200
|
23
12
|
body = JSON.parse(response.body, :symbolize_names => false)
|
@@ -25,15 +14,28 @@ module ForestLiana
|
|
25
14
|
user['id'] = body['data']['id']
|
26
15
|
user
|
27
16
|
else
|
28
|
-
|
29
|
-
raise "Cannot authorize the user using this google account. Forest API returned an #{Errors::HTTPErrorHelper.format(response)}"
|
30
|
-
else
|
31
|
-
raise "Cannot authorize the user using this email/password. Forest API returned an #{Errors::HTTPErrorHelper.format(response)}"
|
32
|
-
end
|
17
|
+
raise generate_authentication_error response
|
33
18
|
end
|
34
|
-
rescue
|
35
|
-
raise ForestLiana::Errors::HTTP401Error
|
36
19
|
end
|
37
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def self.generate_authentication_error(error)
|
24
|
+
case error[:message]
|
25
|
+
when ForestLiana::MESSAGES[:SERVER_TRANSACTION][:SECRET_AND_RENDERINGID_INCONSISTENT]
|
26
|
+
return ForestLiana::Errors::InconsistentSecretAndRenderingError.new()
|
27
|
+
when ForestLiana::MESSAGES[:SERVER_TRANSACTION][:SECRET_NOT_FOUND]
|
28
|
+
return ForestLiana::Errors::SecretNotFoundError.new()
|
29
|
+
else
|
30
|
+
end
|
31
|
+
|
32
|
+
serverError = error[:jse_cause][:response][:body][:errors][0] || nil
|
33
|
+
|
34
|
+
if !serverError.nil? && serverError[:name] == ForestLiana::MESSAGES[:SERVER_TRANSACTION][:names][:TWO_FACTOR_AUTHENTICATION_REQUIRED]
|
35
|
+
return ForestLiana::Errors::TwoFactorAuthenticationRequiredError.new()
|
36
|
+
end
|
37
|
+
|
38
|
+
return StandardError.new(error)
|
39
|
+
end
|
38
40
|
end
|
39
41
|
end
|
@@ -14,9 +14,9 @@ module ForestLiana
|
|
14
14
|
@record = @resource.find(@params[:id])
|
15
15
|
|
16
16
|
if has_strong_parameter
|
17
|
-
@record.
|
17
|
+
@record.update(resource_params)
|
18
18
|
else
|
19
|
-
@record.
|
19
|
+
@record.update(resource_params, without_protection: true)
|
20
20
|
end
|
21
21
|
rescue ActiveRecord::StatementInvalid => exception
|
22
22
|
# NOTICE: SQL request cannot be executed properly
|
@@ -33,7 +33,7 @@ module ForestLiana
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def has_strong_parameter
|
36
|
-
Rails::VERSION::MAJOR > 5 || @resource.instance_method(:
|
36
|
+
Rails::VERSION::MAJOR > 5 || @resource.instance_method(:update!).arity == 1
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -2,9 +2,14 @@ module ForestLiana
|
|
2
2
|
class SchemaUtils
|
3
3
|
|
4
4
|
def self.associations(active_record_class)
|
5
|
-
active_record_class
|
6
|
-
|
7
|
-
|
5
|
+
active_record_class.reflect_on_all_associations.select do |association|
|
6
|
+
begin
|
7
|
+
!polymorphic?(association) && !is_active_type?(association.klass)
|
8
|
+
rescue
|
9
|
+
FOREST_LOGGER.warn "Unknown association #{association.name} on class #{active_record_class.name}"
|
10
|
+
false
|
11
|
+
end
|
12
|
+
end
|
8
13
|
end
|
9
14
|
|
10
15
|
def self.one_associations(active_record_class)
|
@@ -11,7 +11,7 @@ module ForestLiana
|
|
11
11
|
query = {}
|
12
12
|
@record = ::Stripe::Invoice.retrieve(@params[:invoice_id])
|
13
13
|
|
14
|
-
@record.
|
14
|
+
@record.due_date = Time.at(@record.due_date).to_datetime unless @record.due_date.nil?
|
15
15
|
@record.period_start = Time.at(@record.period_start).to_datetime
|
16
16
|
@record.period_end = Time.at(@record.period_end).to_datetime
|
17
17
|
@record.subtotal /= 100.00
|
@@ -32,7 +32,7 @@ module ForestLiana
|
|
32
32
|
end
|
33
33
|
|
34
34
|
@records = @invoices.data.map do |d|
|
35
|
-
d.date = Time.at(d.
|
35
|
+
d.date = Time.at(d.created).to_datetime
|
36
36
|
d.period_start = Time.at(d.period_start).to_datetime
|
37
37
|
d.period_end = Time.at(d.period_end).to_datetime
|
38
38
|
d.subtotal /= 100.00
|
@@ -32,7 +32,7 @@ module ForestLiana
|
|
32
32
|
|
33
33
|
def fetch_bank_accounts(customer, params)
|
34
34
|
begin
|
35
|
-
@cards = ::Stripe::Customer.retrieve(customer).sources.list(params)
|
35
|
+
@cards = ::Stripe::Customer.retrieve({ id: customer, expand: ['sources'] }).sources.list(params)
|
36
36
|
if @cards.blank?
|
37
37
|
@records = []
|
38
38
|
return
|
@@ -15,6 +15,9 @@ module ForestLiana
|
|
15
15
|
INVALID_RENDERING_ID: "The parameter renderingId is not valid",
|
16
16
|
REGISTRATION_FAILED: "The registration to the authentication API failed, response: ",
|
17
17
|
OIDC_CONFIGURATION_RETRIEVAL_FAILED: "Failed to retrieve the provider's configuration.",
|
18
|
+
names: {
|
19
|
+
TWO_FACTOR_AUTHENTICATION_REQUIRED: 'TwoFactorAuthenticationRequiredForbiddenError',
|
20
|
+
}
|
18
21
|
}
|
19
22
|
}
|
20
23
|
end
|
@@ -14,12 +14,13 @@ module ForestLiana
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class ExpectedError < StandardError
|
17
|
-
attr_reader :error_code, :status, :message
|
17
|
+
attr_reader :error_code, :status, :message, :name
|
18
18
|
|
19
|
-
def initialize(error_code, status, message)
|
19
|
+
def initialize(error_code, status, message, name = nil)
|
20
20
|
@error_code = error_code
|
21
21
|
@status = status
|
22
22
|
@message = message
|
23
|
+
@name = name
|
23
24
|
end
|
24
25
|
|
25
26
|
def display_error
|
@@ -45,6 +46,24 @@ module ForestLiana
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
class InconsistentSecretAndRenderingError < ExpectedError
|
50
|
+
def initialize(message=ForestLiana::MESSAGES[:SERVER_TRANSACTION][:SECRET_AND_RENDERINGID_INCONSISTENT])
|
51
|
+
super(500, :internal_server_error, message, 'InconsistentSecretAndRenderingError')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class SecretNotFoundError < ExpectedError
|
56
|
+
def initialize(message=ForestLiana::MESSAGES[:SERVER_TRANSACTION][:SECRET_NOT_FOUND])
|
57
|
+
super(500, :internal_server_error, message, 'SecretNotFoundError')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class TwoFactorAuthenticationRequiredError < ExpectedError
|
62
|
+
def initialize(message='Two factor authentication required')
|
63
|
+
super(403, :forbidden, message, 'TwoFactorAuthenticationRequiredError')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
48
67
|
class ExceptionHelper
|
49
68
|
def self.recursively_print(error, margin: '', is_error: false)
|
50
69
|
logger = is_error ?
|
data/config/routes.rb
CHANGED
@@ -9,10 +9,6 @@ ForestLiana::Engine.routes.draw do
|
|
9
9
|
get 'authentication/callback' => 'authentication#authentication_callback'
|
10
10
|
post 'authentication/logout' => 'authentication#logout'
|
11
11
|
|
12
|
-
# Session
|
13
|
-
post 'sessions' => 'sessions#create_with_password'
|
14
|
-
post 'sessions-google' => 'sessions#create_with_google'
|
15
|
-
|
16
12
|
# Associations
|
17
13
|
get ':collection/:id/relationships/:association_name' => 'associations#index'
|
18
14
|
get ':collection/:id/relationships/:association_name/count' => 'associations#count'
|
@@ -430,19 +430,19 @@ module ForestLiana
|
|
430
430
|
fields: [
|
431
431
|
{ field: :id, type: 'String', is_filterable: false },
|
432
432
|
{ field: :amount_due, type: 'Number', is_filterable: false },
|
433
|
+
{ field: :amount_paid, type: 'Number', is_filterable: false },
|
434
|
+
{ field: :amount_remaining, type: 'Number', is_filterable: false },
|
435
|
+
{ field: :application_fee_amount, type: 'Number', is_filterable: false },
|
433
436
|
{ field: :attempt_count, type: 'Number', is_filterable: false },
|
434
437
|
{ field: :attempted, type: 'Boolean', is_filterable: false },
|
435
|
-
{ field: :closed, type: 'Boolean', is_filterable: false },
|
436
438
|
{ field: :currency, type: 'String', is_filterable: false },
|
437
|
-
{ field: :
|
438
|
-
{ field: :forgiven, type: 'Boolean', is_filterable: false },
|
439
|
+
{ field: :due_date, type: 'Date', is_filterable: false },
|
439
440
|
{ field: :period_start, type: 'Date', is_filterable: false },
|
440
441
|
{ field: :period_end, type: 'Date', is_filterable: false },
|
442
|
+
{ field: :status, type: 'String', enums: ['draft', 'open', 'paid', 'uncollectible', 'void'], is_filterable: false },
|
441
443
|
{ field: :subtotal, type: 'Number', is_filterable: false },
|
442
444
|
{ field: :total, type: 'Number', is_filterable: false },
|
443
|
-
{ field: :application_fee, type: 'Number', is_filterable: false },
|
444
445
|
{ field: :tax, type: 'Number', is_filterable: false },
|
445
|
-
{ field: :tax_percent, type: 'Number', is_filterable: false },
|
446
446
|
{
|
447
447
|
field: :customer,
|
448
448
|
type: 'String',
|
data/lib/forest_liana/version.rb
CHANGED
@@ -35,6 +35,11 @@ describe 'Requesting Actions routes', :type => :request do
|
|
35
35
|
type: 'Enum',
|
36
36
|
enums: %w[a b c],
|
37
37
|
}
|
38
|
+
multiple_enum = {
|
39
|
+
field: 'multipleEnum',
|
40
|
+
type: ['Enum'],
|
41
|
+
enums: %w[a b c],
|
42
|
+
}
|
38
43
|
|
39
44
|
action_definition = {
|
40
45
|
name: 'my_action',
|
@@ -95,12 +100,28 @@ describe 'Requesting Actions routes', :type => :request do
|
|
95
100
|
}
|
96
101
|
}
|
97
102
|
}
|
103
|
+
|
104
|
+
multiple_enums_action_definition = {
|
105
|
+
name: 'multiple_enums_action',
|
106
|
+
fields: [foo, multiple_enum],
|
107
|
+
hooks: {
|
108
|
+
:change => {
|
109
|
+
'foo' => -> (context) {
|
110
|
+
fields = context[:fields]
|
111
|
+
fields['multipleEnum'][:enums] = %w[c d z]
|
112
|
+
return fields
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
98
118
|
action = ForestLiana::Model::Action.new(action_definition)
|
99
119
|
fail_action = ForestLiana::Model::Action.new(fail_action_definition)
|
100
120
|
cheat_action = ForestLiana::Model::Action.new(cheat_action_definition)
|
101
121
|
enums_action = ForestLiana::Model::Action.new(enums_action_definition)
|
122
|
+
multiple_enums_action = ForestLiana::Model::Action.new(multiple_enums_action_definition)
|
102
123
|
island = ForestLiana.apimap.find {|collection| collection.name.to_s == ForestLiana.name_for(Island)}
|
103
|
-
island.actions = [action, fail_action, cheat_action, enums_action]
|
124
|
+
island.actions = [action, fail_action, cheat_action, enums_action, multiple_enums_action]
|
104
125
|
|
105
126
|
describe 'call /load' do
|
106
127
|
params = {recordIds: [1], collectionName: 'Island'}
|
@@ -169,6 +190,33 @@ describe 'Requesting Actions routes', :type => :request do
|
|
169
190
|
expect(JSON.parse(response.body)).to eq({'fields' => [expected_foo.stringify_keys, expected_enum.stringify_keys]})
|
170
191
|
end
|
171
192
|
|
193
|
+
it 'should not reset value when every enum values are in the enums definition' do
|
194
|
+
updated_multiple_enum = multiple_enum.clone.merge({:previousValue => nil, :value => %w[c]})
|
195
|
+
p = {recordIds: [1], fields: [foo, updated_multiple_enum], collectionName: 'Island', changedField: 'foo'}
|
196
|
+
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers: { 'CONTENT_TYPE' => 'application/json' }
|
197
|
+
expect(response.status).to eq(200)
|
198
|
+
|
199
|
+
expected_multiple_enum = updated_multiple_enum.clone.merge({ :enums => %w[c d z], :widgetEdit => nil, :value => %w[c]})
|
200
|
+
expected_multiple_enum.delete(:widget)
|
201
|
+
expected_foo = foo.clone.merge({ :widgetEdit => nil})
|
202
|
+
expected_foo.delete(:widget)
|
203
|
+
|
204
|
+
expect(JSON.parse(response.body)).to eq({'fields' => [expected_foo.stringify_keys, expected_multiple_enum.stringify_keys]})
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should reset value when one of the enum values is not in the enums definition' do
|
208
|
+
wrongly_updated_multiple_enum = multiple_enum.clone.merge({:previousValue => nil, :value => %w[a b]})
|
209
|
+
p = {recordIds: [1], fields: [foo, wrongly_updated_multiple_enum], collectionName: 'Island', changedField: 'foo'}
|
210
|
+
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers: { 'CONTENT_TYPE' => 'application/json' }
|
211
|
+
expect(response.status).to eq(200)
|
212
|
+
|
213
|
+
expected_multiple_enum = wrongly_updated_multiple_enum.clone.merge({ :enums => %w[c d z], :widgetEdit => nil, :value => nil })
|
214
|
+
expected_multiple_enum.delete(:widget)
|
215
|
+
expected_foo = foo.clone.merge({ :widgetEdit => nil})
|
216
|
+
expected_foo.delete(:widget)
|
217
|
+
|
218
|
+
expect(JSON.parse(response.body)).to eq({'fields' => [expected_foo.stringify_keys, expected_multiple_enum.stringify_keys]})
|
219
|
+
end
|
172
220
|
end
|
173
221
|
end
|
174
222
|
end
|
data/test/routing/route_test.rb
CHANGED
@@ -12,18 +12,6 @@ module ForestLiana
|
|
12
12
|
controller: 'forest_liana/apimaps', action: 'index'
|
13
13
|
})
|
14
14
|
|
15
|
-
# Session
|
16
|
-
assert_routing({
|
17
|
-
method: 'post', path: 'sessions'
|
18
|
-
}, {
|
19
|
-
controller: 'forest_liana/sessions', action: 'create_with_password'
|
20
|
-
})
|
21
|
-
assert_routing({
|
22
|
-
method: 'post', path: 'sessions-google'
|
23
|
-
}, {
|
24
|
-
controller: 'forest_liana/sessions', action: 'create_with_google'
|
25
|
-
})
|
26
|
-
|
27
15
|
# Associations
|
28
16
|
assert_routing({
|
29
17
|
method: 'get', path: ':collection/:id/relationships/:association_name'
|
@@ -106,7 +106,7 @@ module ForestLiana
|
|
106
106
|
conditions: [{
|
107
107
|
field: 'created_at',
|
108
108
|
operator: 'after',
|
109
|
-
value:
|
109
|
+
value: "#{Time.now.year - 5}-06-18 08:00:00",
|
110
110
|
}, {
|
111
111
|
field: 'owner:name',
|
112
112
|
operator: 'equal',
|
@@ -119,8 +119,8 @@ module ForestLiana
|
|
119
119
|
records = getter.records
|
120
120
|
count = getter.count
|
121
121
|
|
122
|
-
assert records.count ==
|
123
|
-
assert count =
|
122
|
+
assert records.count == 1
|
123
|
+
assert count = 1
|
124
124
|
assert records.first.id == 4
|
125
125
|
assert records.first.name == 'Oak'
|
126
126
|
assert records.first.owner.name == 'Arnaud Besnier'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forest_liana
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.0
|
4
|
+
version: 6.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sandro Munda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -122,34 +122,6 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: rotp
|
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'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: base32
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - ">="
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :runtime
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
153
125
|
- !ruby/object:Gem::Dependency
|
154
126
|
name: httparty
|
155
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -246,7 +218,6 @@ files:
|
|
246
218
|
- app/controllers/forest_liana/mixpanel_controller.rb
|
247
219
|
- app/controllers/forest_liana/resources_controller.rb
|
248
220
|
- app/controllers/forest_liana/router.rb
|
249
|
-
- app/controllers/forest_liana/sessions_controller.rb
|
250
221
|
- app/controllers/forest_liana/smart_actions_controller.rb
|
251
222
|
- app/controllers/forest_liana/stats_controller.rb
|
252
223
|
- app/controllers/forest_liana/stripe_controller.rb
|
@@ -267,7 +238,6 @@ files:
|
|
267
238
|
- app/serializers/forest_liana/mixpanel_event_serializer.rb
|
268
239
|
- app/serializers/forest_liana/schema_serializer.rb
|
269
240
|
- app/serializers/forest_liana/serializer_factory.rb
|
270
|
-
- app/serializers/forest_liana/session_serializer.rb
|
271
241
|
- app/serializers/forest_liana/stat_serializer.rb
|
272
242
|
- app/serializers/forest_liana/stripe_bank_account_serializer.rb
|
273
243
|
- app/serializers/forest_liana/stripe_card_serializer.rb
|
@@ -294,7 +264,6 @@ files:
|
|
294
264
|
- app/services/forest_liana/leaderboard_stat_getter.rb
|
295
265
|
- app/services/forest_liana/line_stat_getter.rb
|
296
266
|
- app/services/forest_liana/live_query_checker.rb
|
297
|
-
- app/services/forest_liana/login_handler.rb
|
298
267
|
- app/services/forest_liana/mixpanel_last_events_getter.rb
|
299
268
|
- app/services/forest_liana/objective_stat_getter.rb
|
300
269
|
- app/services/forest_liana/oidc_client_manager.rb
|
@@ -326,8 +295,6 @@ files:
|
|
326
295
|
- app/services/forest_liana/stripe_subscription_getter.rb
|
327
296
|
- app/services/forest_liana/stripe_subscriptions_getter.rb
|
328
297
|
- app/services/forest_liana/token.rb
|
329
|
-
- app/services/forest_liana/two_factor_registration_confirmer.rb
|
330
|
-
- app/services/forest_liana/user_secret_creator.rb
|
331
298
|
- app/services/forest_liana/utils/beta_schema_utils.rb
|
332
299
|
- app/services/forest_liana/value_stat_getter.rb
|
333
300
|
- app/views/layouts/forest_liana/application.html.erb
|
@@ -397,7 +364,6 @@ files:
|
|
397
364
|
- spec/requests/actions_controller_spec.rb
|
398
365
|
- spec/requests/authentications_spec.rb
|
399
366
|
- spec/requests/resources_spec.rb
|
400
|
-
- spec/requests/sessions_spec.rb
|
401
367
|
- spec/services/forest_liana/apimap_sorter_spec.rb
|
402
368
|
- spec/services/forest_liana/filters_parser_spec.rb
|
403
369
|
- spec/services/forest_liana/ip_whitelist_checker_spec.rb
|
@@ -514,162 +480,161 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
514
480
|
version: '0'
|
515
481
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
516
482
|
requirements:
|
517
|
-
- - "
|
483
|
+
- - ">="
|
518
484
|
- !ruby/object:Gem::Version
|
519
|
-
version:
|
485
|
+
version: '0'
|
520
486
|
requirements: []
|
521
|
-
rubygems_version: 3.
|
487
|
+
rubygems_version: 3.1.2
|
522
488
|
signing_key:
|
523
489
|
specification_version: 4
|
524
490
|
summary: Official Rails Liana for Forest
|
525
491
|
test_files:
|
526
|
-
- test/
|
527
|
-
- test/
|
528
|
-
- test/
|
529
|
-
- test/fixtures/tree.yml
|
530
|
-
- test/fixtures/has_one_field.yml
|
531
|
-
- test/fixtures/reference.yml
|
532
|
-
- test/fixtures/serialize_field.yml
|
533
|
-
- test/fixtures/has_many_field.yml
|
534
|
-
- test/fixtures/string_field.yml
|
535
|
-
- test/services/forest_liana/resources_getter_test.rb
|
536
|
-
- test/services/forest_liana/scope_validator_test.rb
|
537
|
-
- test/services/forest_liana/schema_adapter_test.rb
|
538
|
-
- test/services/forest_liana/has_many_getter_test.rb
|
539
|
-
- test/services/forest_liana/value_stat_getter_test.rb
|
540
|
-
- test/services/forest_liana/resource_updater_test.rb
|
541
|
-
- test/services/forest_liana/pie_stat_getter_test.rb
|
542
|
-
- test/test_helper.rb
|
543
|
-
- test/dummy/README.rdoc
|
492
|
+
- test/dummy/app/assets/stylesheets/application.css
|
493
|
+
- test/dummy/app/assets/config/manifest.js
|
494
|
+
- test/dummy/app/assets/javascripts/application.js
|
544
495
|
- test/dummy/app/views/layouts/application.html.erb
|
496
|
+
- test/dummy/app/controllers/application_controller.rb
|
497
|
+
- test/dummy/app/helpers/application_helper.rb
|
498
|
+
- test/dummy/app/models/reference.rb
|
499
|
+
- test/dummy/app/models/float_field.rb
|
545
500
|
- test/dummy/app/models/has_many_field.rb
|
501
|
+
- test/dummy/app/models/polymorphic_field.rb
|
502
|
+
- test/dummy/app/models/decimal_field.rb
|
546
503
|
- test/dummy/app/models/string_field.rb
|
547
|
-
- test/dummy/app/models/
|
504
|
+
- test/dummy/app/models/serialize_field.rb
|
505
|
+
- test/dummy/app/models/tree.rb
|
506
|
+
- test/dummy/app/models/boolean_field.rb
|
507
|
+
- test/dummy/app/models/date_field.rb
|
548
508
|
- test/dummy/app/models/has_many_through_field.rb
|
549
|
-
- test/dummy/app/models/
|
509
|
+
- test/dummy/app/models/owner.rb
|
550
510
|
- test/dummy/app/models/has_one_field.rb
|
551
|
-
- test/dummy/app/models/
|
552
|
-
- test/dummy/app/models/boolean_field.rb
|
553
|
-
- test/dummy/app/models/float_field.rb
|
554
|
-
- test/dummy/app/models/reference.rb
|
511
|
+
- test/dummy/app/models/has_many_class_name_field.rb
|
555
512
|
- test/dummy/app/models/belongs_to_class_name_field.rb
|
556
|
-
- test/dummy/app/models/polymorphic_field.rb
|
557
|
-
- test/dummy/app/models/tree.rb
|
558
|
-
- test/dummy/app/models/decimal_field.rb
|
559
|
-
- test/dummy/app/models/serialize_field.rb
|
560
513
|
- test/dummy/app/models/integer_field.rb
|
561
514
|
- test/dummy/app/models/belongs_to_field.rb
|
562
|
-
- test/dummy/app/models/
|
563
|
-
- test/dummy/
|
564
|
-
- test/dummy/app/assets/javascripts/application.js
|
565
|
-
- test/dummy/app/assets/stylesheets/application.css
|
566
|
-
- test/dummy/app/assets/config/manifest.js
|
567
|
-
- test/dummy/app/controllers/application_controller.rb
|
568
|
-
- test/dummy/Rakefile
|
569
|
-
- test/dummy/bin/rake
|
570
|
-
- test/dummy/bin/bundle
|
571
|
-
- test/dummy/bin/rails
|
572
|
-
- test/dummy/bin/setup
|
573
|
-
- test/dummy/public/404.html
|
574
|
-
- test/dummy/public/500.html
|
575
|
-
- test/dummy/public/422.html
|
576
|
-
- test/dummy/public/favicon.ico
|
577
|
-
- test/dummy/config.ru
|
578
|
-
- test/dummy/db/migrate/20181111162121_create_references_table.rb
|
579
|
-
- test/dummy/db/migrate/20150608131430_create_integer_field.rb
|
580
|
-
- test/dummy/db/migrate/20160628173505_add_timestamps.rb
|
581
|
-
- test/dummy/db/migrate/20160627172810_create_owner.rb
|
582
|
-
- test/dummy/db/migrate/20150814081918_create_has_many_through_field.rb
|
515
|
+
- test/dummy/app/models/has_and_belongs_to_many_field.rb
|
516
|
+
- test/dummy/db/migrate/20160627172951_create_tree.rb
|
583
517
|
- test/dummy/db/migrate/20150608132159_create_boolean_field.rb
|
584
|
-
- test/dummy/db/migrate/20150608131603_create_decimal_field.rb
|
585
|
-
- test/dummy/db/migrate/20150616150629_create_polymorphic_field.rb
|
586
518
|
- test/dummy/db/migrate/20150612112520_create_has_and_belongs_to_many_field.rb
|
587
|
-
- test/dummy/db/migrate/
|
588
|
-
- test/dummy/db/migrate/20150608133038_create_belongs_to_field.rb
|
589
|
-
- test/dummy/db/migrate/20150608150016_create_has_many_field.rb
|
519
|
+
- test/dummy/db/migrate/20160627172810_create_owner.rb
|
590
520
|
- test/dummy/db/migrate/20150609114636_create_belongs_to_class_name_field.rb
|
521
|
+
- test/dummy/db/migrate/20150608130516_create_date_field.rb
|
522
|
+
- test/dummy/db/migrate/20160628173505_add_timestamps.rb
|
523
|
+
- test/dummy/db/migrate/20150608131610_create_float_field.rb
|
591
524
|
- test/dummy/db/migrate/20170614141921_create_serialize_field.rb
|
525
|
+
- test/dummy/db/migrate/20150608150016_create_has_many_field.rb
|
526
|
+
- test/dummy/db/migrate/20150608131430_create_integer_field.rb
|
527
|
+
- test/dummy/db/migrate/20150608133038_create_belongs_to_field.rb
|
528
|
+
- test/dummy/db/migrate/20150616150629_create_polymorphic_field.rb
|
592
529
|
- test/dummy/db/migrate/20150608132621_create_string_field.rb
|
593
|
-
- test/dummy/db/migrate/
|
530
|
+
- test/dummy/db/migrate/20181111162121_create_references_table.rb
|
594
531
|
- test/dummy/db/migrate/20150623115554_create_has_many_class_name_field.rb
|
595
|
-
- test/dummy/db/migrate/
|
596
|
-
- test/dummy/db/migrate/
|
532
|
+
- test/dummy/db/migrate/20150608133044_create_has_one_field.rb
|
533
|
+
- test/dummy/db/migrate/20150814081918_create_has_many_through_field.rb
|
534
|
+
- test/dummy/db/migrate/20150608131603_create_decimal_field.rb
|
597
535
|
- test/dummy/db/schema.rb
|
598
|
-
- test/dummy/config
|
599
|
-
- test/dummy/
|
536
|
+
- test/dummy/config.ru
|
537
|
+
- test/dummy/README.rdoc
|
600
538
|
- test/dummy/config/secrets.yml
|
601
|
-
- test/dummy/config/application.rb
|
602
|
-
- test/dummy/config/boot.rb
|
603
|
-
- test/dummy/config/environments/test.rb
|
604
|
-
- test/dummy/config/environments/development.rb
|
605
|
-
- test/dummy/config/environments/production.rb
|
606
539
|
- test/dummy/config/locales/en.yml
|
540
|
+
- test/dummy/config/routes.rb
|
541
|
+
- test/dummy/config/database.yml
|
607
542
|
- test/dummy/config/initializers/wrap_parameters.rb
|
608
|
-
- test/dummy/config/initializers/mime_types.rb
|
609
|
-
- test/dummy/config/initializers/filter_parameter_logging.rb
|
610
543
|
- test/dummy/config/initializers/assets.rb
|
544
|
+
- test/dummy/config/initializers/filter_parameter_logging.rb
|
611
545
|
- test/dummy/config/initializers/session_store.rb
|
546
|
+
- test/dummy/config/initializers/backtrace_silencers.rb
|
612
547
|
- test/dummy/config/initializers/inflections.rb
|
613
548
|
- test/dummy/config/initializers/cookies_serializer.rb
|
614
|
-
- test/dummy/config/initializers/
|
615
|
-
- test/dummy/config/
|
549
|
+
- test/dummy/config/initializers/mime_types.rb
|
550
|
+
- test/dummy/config/application.rb
|
551
|
+
- test/dummy/config/environments/development.rb
|
552
|
+
- test/dummy/config/environments/production.rb
|
553
|
+
- test/dummy/config/environments/test.rb
|
554
|
+
- test/dummy/config/environment.rb
|
555
|
+
- test/dummy/config/boot.rb
|
556
|
+
- test/dummy/public/500.html
|
557
|
+
- test/dummy/public/favicon.ico
|
558
|
+
- test/dummy/public/404.html
|
559
|
+
- test/dummy/public/422.html
|
560
|
+
- test/dummy/Rakefile
|
561
|
+
- test/dummy/bin/rake
|
562
|
+
- test/dummy/bin/setup
|
563
|
+
- test/dummy/bin/rails
|
564
|
+
- test/dummy/bin/bundle
|
616
565
|
- test/forest_liana_test.rb
|
566
|
+
- test/services/forest_liana/schema_adapter_test.rb
|
567
|
+
- test/services/forest_liana/pie_stat_getter_test.rb
|
568
|
+
- test/services/forest_liana/value_stat_getter_test.rb
|
569
|
+
- test/services/forest_liana/has_many_getter_test.rb
|
570
|
+
- test/services/forest_liana/resource_updater_test.rb
|
571
|
+
- test/services/forest_liana/scope_validator_test.rb
|
572
|
+
- test/services/forest_liana/resources_getter_test.rb
|
573
|
+
- test/test_helper.rb
|
617
574
|
- test/routing/route_test.rb
|
618
|
-
-
|
619
|
-
-
|
620
|
-
-
|
621
|
-
-
|
622
|
-
-
|
623
|
-
-
|
624
|
-
-
|
625
|
-
-
|
626
|
-
-
|
627
|
-
- spec/
|
628
|
-
- spec/requests/sessions_spec.rb
|
629
|
-
- spec/requests/authentications_spec.rb
|
630
|
-
- spec/requests/resources_spec.rb
|
631
|
-
- spec/dummy/README.rdoc
|
632
|
-
- spec/dummy/app/views/layouts/application.html.erb
|
633
|
-
- spec/dummy/app/models/island.rb
|
634
|
-
- spec/dummy/app/models/user.rb
|
635
|
-
- spec/dummy/app/models/tree.rb
|
636
|
-
- spec/dummy/app/helpers/application_helper.rb
|
637
|
-
- spec/dummy/app/assets/javascripts/application.js
|
575
|
+
- test/fixtures/reference.yml
|
576
|
+
- test/fixtures/has_many_through_field.yml
|
577
|
+
- test/fixtures/has_many_field.yml
|
578
|
+
- test/fixtures/tree.yml
|
579
|
+
- test/fixtures/belongs_to_field.yml
|
580
|
+
- test/fixtures/owner.yml
|
581
|
+
- test/fixtures/serialize_field.yml
|
582
|
+
- test/fixtures/string_field.yml
|
583
|
+
- test/fixtures/has_one_field.yml
|
584
|
+
- spec/rails_helper.rb
|
638
585
|
- spec/dummy/app/assets/stylesheets/application.css
|
639
586
|
- spec/dummy/app/assets/config/manifest.js
|
587
|
+
- spec/dummy/app/assets/javascripts/application.js
|
588
|
+
- spec/dummy/app/views/layouts/application.html.erb
|
640
589
|
- spec/dummy/app/config/routes.rb
|
641
590
|
- spec/dummy/app/controllers/application_controller.rb
|
642
|
-
- spec/dummy/
|
643
|
-
- spec/dummy/
|
644
|
-
- spec/dummy/
|
645
|
-
- spec/dummy/
|
646
|
-
- spec/dummy/bin/setup
|
647
|
-
- spec/dummy/config.ru
|
648
|
-
- spec/dummy/db/migrate/20190226174951_create_tree.rb
|
649
|
-
- spec/dummy/db/migrate/20190716135241_add_type_to_user.rb
|
591
|
+
- spec/dummy/app/helpers/application_helper.rb
|
592
|
+
- spec/dummy/app/models/user.rb
|
593
|
+
- spec/dummy/app/models/island.rb
|
594
|
+
- spec/dummy/app/models/tree.rb
|
650
595
|
- spec/dummy/db/migrate/20190226173051_create_isle.rb
|
651
596
|
- spec/dummy/db/migrate/20190716130830_add_age_to_tree.rb
|
597
|
+
- spec/dummy/db/migrate/20190226174951_create_tree.rb
|
598
|
+
- spec/dummy/db/migrate/20190716135241_add_type_to_user.rb
|
652
599
|
- spec/dummy/db/migrate/20190226172951_create_user.rb
|
653
600
|
- spec/dummy/db/schema.rb
|
654
|
-
- spec/dummy/config
|
655
|
-
- spec/dummy/
|
601
|
+
- spec/dummy/config.ru
|
602
|
+
- spec/dummy/README.rdoc
|
656
603
|
- spec/dummy/config/secrets.yml
|
657
|
-
- spec/dummy/config/
|
658
|
-
- spec/dummy/config/
|
659
|
-
- spec/dummy/config/environments/test.rb
|
660
|
-
- spec/dummy/config/environments/development.rb
|
661
|
-
- spec/dummy/config/environments/production.rb
|
604
|
+
- spec/dummy/config/routes.rb
|
605
|
+
- spec/dummy/config/database.yml
|
662
606
|
- spec/dummy/config/initializers/wrap_parameters.rb
|
607
|
+
- spec/dummy/config/initializers/assets.rb
|
663
608
|
- spec/dummy/config/initializers/forest_liana.rb
|
664
|
-
- spec/dummy/config/initializers/mime_types.rb
|
665
609
|
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
666
|
-
- spec/dummy/config/initializers/assets.rb
|
667
610
|
- spec/dummy/config/initializers/session_store.rb
|
611
|
+
- spec/dummy/config/initializers/backtrace_silencers.rb
|
668
612
|
- spec/dummy/config/initializers/inflections.rb
|
669
613
|
- spec/dummy/config/initializers/cookies_serializer.rb
|
670
|
-
- spec/dummy/config/initializers/
|
671
|
-
- spec/dummy/config/
|
614
|
+
- spec/dummy/config/initializers/mime_types.rb
|
615
|
+
- spec/dummy/config/application.rb
|
616
|
+
- spec/dummy/config/environments/development.rb
|
617
|
+
- spec/dummy/config/environments/production.rb
|
618
|
+
- spec/dummy/config/environments/test.rb
|
619
|
+
- spec/dummy/config/environment.rb
|
620
|
+
- spec/dummy/config/boot.rb
|
621
|
+
- spec/dummy/Rakefile
|
622
|
+
- spec/dummy/bin/rake
|
623
|
+
- spec/dummy/bin/setup
|
624
|
+
- spec/dummy/bin/rails
|
625
|
+
- spec/dummy/bin/bundle
|
626
|
+
- spec/services/forest_liana/schema_adapter_spec.rb
|
627
|
+
- spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb
|
628
|
+
- spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb
|
629
|
+
- spec/services/forest_liana/permissions_formatter_spec.rb
|
630
|
+
- spec/services/forest_liana/apimap_sorter_spec.rb
|
631
|
+
- spec/services/forest_liana/permissions_getter_spec.rb
|
632
|
+
- spec/services/forest_liana/ip_whitelist_checker_spec.rb
|
633
|
+
- spec/services/forest_liana/filters_parser_spec.rb
|
634
|
+
- spec/helpers/forest_liana/query_helper_spec.rb
|
672
635
|
- spec/helpers/forest_liana/schema_helper_spec.rb
|
673
636
|
- spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb
|
674
|
-
- spec/
|
675
|
-
- spec/
|
637
|
+
- spec/requests/actions_controller_spec.rb
|
638
|
+
- spec/requests/authentications_spec.rb
|
639
|
+
- spec/requests/resources_spec.rb
|
640
|
+
- spec/spec_helper.rb
|
@@ -1,95 +0,0 @@
|
|
1
|
-
module ForestLiana
|
2
|
-
class SessionsController < ForestLiana::BaseController
|
3
|
-
def create_with_password
|
4
|
-
@error_message = nil
|
5
|
-
rendering_id = params['renderingId']
|
6
|
-
project_id = params['projectId']
|
7
|
-
email = params['email']
|
8
|
-
password = params['password']
|
9
|
-
two_factor_token = params['token']
|
10
|
-
two_factor_registration = params['twoFactorRegistration']
|
11
|
-
|
12
|
-
process_login(
|
13
|
-
use_google_authentication: false,
|
14
|
-
rendering_id: rendering_id,
|
15
|
-
project_id: project_id,
|
16
|
-
auth_data: { email: email, password: password },
|
17
|
-
two_factor_registration: two_factor_registration,
|
18
|
-
two_factor_token: two_factor_token,
|
19
|
-
)
|
20
|
-
end
|
21
|
-
|
22
|
-
def create_with_google
|
23
|
-
@error_message = nil
|
24
|
-
|
25
|
-
forest_token = params['forestToken']
|
26
|
-
rendering_id = params['renderingId']
|
27
|
-
project_id = params['projectId']
|
28
|
-
two_factor_token = params['token']
|
29
|
-
two_factor_registration = params['twoFactorRegistration']
|
30
|
-
|
31
|
-
process_login(
|
32
|
-
use_google_authentication: true,
|
33
|
-
rendering_id: rendering_id,
|
34
|
-
project_id: project_id,
|
35
|
-
auth_data: { forest_token: forest_token },
|
36
|
-
two_factor_registration: two_factor_registration,
|
37
|
-
two_factor_token: two_factor_token,
|
38
|
-
)
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def process_login(
|
44
|
-
use_google_authentication:,
|
45
|
-
rendering_id:,
|
46
|
-
project_id:,
|
47
|
-
auth_data:,
|
48
|
-
two_factor_registration:,
|
49
|
-
two_factor_token:
|
50
|
-
)
|
51
|
-
begin
|
52
|
-
if two_factor_registration && two_factor_token.nil?
|
53
|
-
raise ForestLiana::Errors::HTTP401Error
|
54
|
-
end
|
55
|
-
|
56
|
-
# NOTICE: The IP Whitelist is retrieved on any request if it was not retrieved yet, or when
|
57
|
-
# an IP is rejected, to ensure the IP is still rejected (meaning the configuration
|
58
|
-
# on the projects has not changed). To handle the last case, which is rejecting an
|
59
|
-
# IP which was not initaliy rejected, we need periodically refresh the whitelist.
|
60
|
-
# This is done here on the login of any user.
|
61
|
-
ForestLiana::IpWhitelist.retrieve
|
62
|
-
|
63
|
-
reponse_data = ForestLiana::LoginHandler.new(
|
64
|
-
rendering_id,
|
65
|
-
auth_data,
|
66
|
-
use_google_authentication,
|
67
|
-
two_factor_registration,
|
68
|
-
project_id,
|
69
|
-
two_factor_token
|
70
|
-
).perform
|
71
|
-
|
72
|
-
rescue ForestLiana::Errors::ExpectedError => error
|
73
|
-
error.display_error
|
74
|
-
error_data = JSONAPI::Serializer.serialize_errors([{
|
75
|
-
status: error.error_code,
|
76
|
-
detail: error.message
|
77
|
-
}])
|
78
|
-
render(serializer: nil, json: error_data, status: error.status)
|
79
|
-
rescue StandardError => error
|
80
|
-
FOREST_LOGGER.error error
|
81
|
-
FOREST_LOGGER.error error.backtrace.join("\n")
|
82
|
-
|
83
|
-
render(serializer: nil, json: nil, status: :internal_server_error)
|
84
|
-
else
|
85
|
-
# NOTICE: Set a cookie to ensure secure authentication using export feature.
|
86
|
-
# NOTICE: The token is empty at first authentication step if the 2FA option is active.
|
87
|
-
if reponse_data[:token]
|
88
|
-
response.set_cookie("forest_session_token", { value: reponse_data[:token], expires: (ForestLiana::Token.expiration_in_days) })
|
89
|
-
end
|
90
|
-
|
91
|
-
render(json: reponse_data, serializer: nil)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module ForestLiana
|
2
|
-
class SessionSerializer
|
3
|
-
include JSONAPI::Serializer
|
4
|
-
|
5
|
-
attribute :first_name
|
6
|
-
attribute :last_name
|
7
|
-
attribute :email
|
8
|
-
|
9
|
-
def type
|
10
|
-
'users'
|
11
|
-
end
|
12
|
-
|
13
|
-
def format_name(attribute_name)
|
14
|
-
attribute_name.to_s
|
15
|
-
end
|
16
|
-
|
17
|
-
def unformat_name(attribute_name)
|
18
|
-
attribute_name.to_s.underscore
|
19
|
-
end
|
20
|
-
|
21
|
-
def self_link
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
def relationship_self_link(attribute_name)
|
26
|
-
nil
|
27
|
-
end
|
28
|
-
|
29
|
-
def relationship_related_link(attribute_name)
|
30
|
-
nil
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
require 'rotp'
|
2
|
-
|
3
|
-
module ForestLiana
|
4
|
-
class LoginHandler
|
5
|
-
def initialize(
|
6
|
-
rendering_id,
|
7
|
-
auth_data,
|
8
|
-
use_google_authentication,
|
9
|
-
two_factor_registration,
|
10
|
-
project_id,
|
11
|
-
two_factor_token
|
12
|
-
)
|
13
|
-
@rendering_id = rendering_id
|
14
|
-
@auth_data = auth_data
|
15
|
-
@use_google_authentication = use_google_authentication
|
16
|
-
@two_factor_registration = two_factor_registration
|
17
|
-
@project_id = project_id
|
18
|
-
@two_factor_token = two_factor_token
|
19
|
-
end
|
20
|
-
|
21
|
-
def perform
|
22
|
-
user = ForestLiana::AuthorizationGetter.authenticate(
|
23
|
-
@rendering_id,
|
24
|
-
@use_google_authentication,
|
25
|
-
@auth_data,
|
26
|
-
@two_factor_registration
|
27
|
-
)
|
28
|
-
|
29
|
-
if user['two_factor_authentication_enabled']
|
30
|
-
if !@two_factor_token.nil?
|
31
|
-
if is_two_factor_token_valid(user, @two_factor_token)
|
32
|
-
ForestLiana::TwoFactorRegistrationConfirmer
|
33
|
-
.new(@project_id, @use_google_authentication, @auth_data)
|
34
|
-
.perform
|
35
|
-
|
36
|
-
return { 'token' => create_token(user, @rendering_id) }
|
37
|
-
else
|
38
|
-
raise ForestLiana::Errors::HTTP401Error.new('Your token is invalid, please try again.')
|
39
|
-
end
|
40
|
-
else
|
41
|
-
return get_two_factor_response(user)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
return { token: create_token(user, @rendering_id) }
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def check_two_factor_secret_salt
|
51
|
-
if ENV['FOREST_2FA_SECRET_SALT'].nil?
|
52
|
-
FOREST_LOGGER.error 'Cannot use the two factor authentication because the environment variable "FOREST_2FA_SECRET_SALT" is not set.'
|
53
|
-
FOREST_LOGGER.error 'You can generate it using this command: `$ openssl rand -hex 10`'
|
54
|
-
|
55
|
-
raise Errors::HTTP401Error.new('Invalid 2FA configuration, please ask more information to your admin')
|
56
|
-
end
|
57
|
-
|
58
|
-
if ENV['FOREST_2FA_SECRET_SALT'].length != 20
|
59
|
-
FOREST_LOGGER.error 'The FOREST_2FA_SECRET_SALT environment variable must be 20 characters long.'
|
60
|
-
FOREST_LOGGER.error 'You can generate it using this command: `$ openssl rand -hex 10`'
|
61
|
-
|
62
|
-
raise ForestLiana::Errors::HTTP401Error.new('Invalid 2FA configuration, please ask more information to your admin')
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def get_two_factor_response(user)
|
67
|
-
check_two_factor_secret_salt
|
68
|
-
|
69
|
-
return { 'twoFactorAuthenticationEnabled' => true } if user['two_factor_authentication_active']
|
70
|
-
|
71
|
-
two_factor_authentication_secret = user['two_factor_authentication_secret']
|
72
|
-
user_secret = ForestLiana::UserSecretCreator
|
73
|
-
.new(two_factor_authentication_secret, ENV['FOREST_2FA_SECRET_SALT'])
|
74
|
-
.perform
|
75
|
-
|
76
|
-
{
|
77
|
-
twoFactorAuthenticationEnabled: true,
|
78
|
-
userSecret: user_secret,
|
79
|
-
}
|
80
|
-
end
|
81
|
-
|
82
|
-
def is_two_factor_token_valid(user, two_factor_token)
|
83
|
-
check_two_factor_secret_salt
|
84
|
-
|
85
|
-
two_factor_authentication_secret = user['two_factor_authentication_secret']
|
86
|
-
|
87
|
-
user_secret = ForestLiana::UserSecretCreator
|
88
|
-
.new(two_factor_authentication_secret, ENV['FOREST_2FA_SECRET_SALT'])
|
89
|
-
.perform
|
90
|
-
|
91
|
-
totp = ROTP::TOTP.new(user_secret)
|
92
|
-
totp.verify(two_factor_token)
|
93
|
-
end
|
94
|
-
|
95
|
-
def create_token(user, rendering_id)
|
96
|
-
ForestLiana::Token.create_token(user, rendering_id)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module ForestLiana
|
2
|
-
class TwoFactorRegistrationConfirmer
|
3
|
-
def initialize(
|
4
|
-
project_id,
|
5
|
-
use_google_authentication,
|
6
|
-
auth_data
|
7
|
-
)
|
8
|
-
@project_id = project_id
|
9
|
-
@use_google_authentication = use_google_authentication
|
10
|
-
@auth_data = auth_data
|
11
|
-
end
|
12
|
-
|
13
|
-
def perform
|
14
|
-
begin
|
15
|
-
body_data = { 'useGoogleAuthentication' => @use_google_authentication }
|
16
|
-
|
17
|
-
if @use_google_authentication
|
18
|
-
body_data['forestToken'] = @auth_data[:forest_token]
|
19
|
-
else
|
20
|
-
body_data['email'] = @auth_data[:email]
|
21
|
-
end
|
22
|
-
|
23
|
-
response = ForestLiana::ForestApiRequester.post(
|
24
|
-
"/liana/v2/projects/#{@project_id}/two-factor-registration-confirm",
|
25
|
-
body: body_data,
|
26
|
-
)
|
27
|
-
|
28
|
-
unless response.is_a?(Net::HTTPOK)
|
29
|
-
raise "Cannot retrieve the data from the Forest server. Forest API returned an #{ForestLiana::Errors::HTTPErrorHelper.format(response)}"
|
30
|
-
end
|
31
|
-
rescue
|
32
|
-
raise ForestLiana::Errors::HTTP401Error
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'base32'
|
2
|
-
|
3
|
-
module ForestLiana
|
4
|
-
# NOTICE: This service combines the 2FA secret stored on the forest server to the local secret
|
5
|
-
# salt. This guarantees that only the owner of the server and the concerned end user can
|
6
|
-
# know the final key.
|
7
|
-
# This is done by using a bitwise exclusive or operation, which guarantees the key to stay
|
8
|
-
# unique, so it is impossible for two users to have the same key.
|
9
|
-
class UserSecretCreator
|
10
|
-
def initialize(two_factor_authentication_secret, two_factor_secret_salt)
|
11
|
-
@two_factor_authentication_secret = two_factor_authentication_secret
|
12
|
-
@two_factor_secret_salt = two_factor_secret_salt
|
13
|
-
end
|
14
|
-
|
15
|
-
def perform
|
16
|
-
hash = (@two_factor_authentication_secret.to_i(16) ^ @two_factor_secret_salt.to_i(16)).to_s(16)
|
17
|
-
bin_hash = hex_to_bin(hash)
|
18
|
-
|
19
|
-
Base32.encode(bin_hash).tr('=', '')
|
20
|
-
end
|
21
|
-
|
22
|
-
def hex_to_bin(hex_string)
|
23
|
-
hex_string.scan(/../).map { |x| x.hex.chr }.join
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'rails_helper'
|
2
|
-
require 'openid_connect'
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
RSpec.describe "Authentications", type: :request do
|
6
|
-
before() do
|
7
|
-
allow(ForestLiana::IpWhitelist).to receive(:retrieve) { true }
|
8
|
-
allow(ForestLiana::IpWhitelist).to receive(:is_ip_whitelist_retrieved) { true }
|
9
|
-
allow(ForestLiana::IpWhitelist).to receive(:is_ip_valid) { true }
|
10
|
-
|
11
|
-
body = '{"data":{"id":"654","type":"users","attributes":{"email":"user@email.com","first_name":"FirstName","last_name":"LastName","teams":["Operations"]}},"relationships":{"renderings":{"data":[{"id":1,"type":"renderings"}]}}}'
|
12
|
-
allow(ForestLiana::ForestApiRequester).to receive(:get).with(
|
13
|
-
"/liana/v2/renderings/42/authorization", { :headers => { "forest-token" => "google-access-token" }, :query=> {} }
|
14
|
-
).and_return(
|
15
|
-
instance_double(HTTParty::Response, :body => body, :code => 200)
|
16
|
-
)
|
17
|
-
end
|
18
|
-
|
19
|
-
after() do
|
20
|
-
Rails.cache.delete(URI.join(ForestLiana.application_url, ForestLiana::Engine.routes.url_helpers.authentication_callback_path).to_s)
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "POST /forest/sessions-google" do
|
24
|
-
before() do
|
25
|
-
post ForestLiana::Engine.routes.url_helpers.sessions_google_path, params: '{ "renderingId": "42", "forestToken": "google-access-token" }', headers: {
|
26
|
-
'Accept' => 'application/json',
|
27
|
-
'Content-Type' => 'application/json',
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should respond with a 200 code" do
|
32
|
-
expect(response).to have_http_status(200)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should return a valid authentication token" do
|
36
|
-
response_body = JSON.parse(response.body, :symbolize_names => true)
|
37
|
-
expect(response_body).to have_key(:token)
|
38
|
-
|
39
|
-
token = response_body[:token]
|
40
|
-
decoded = JWT.decode(token, ForestLiana.auth_secret, true, { algorithm: 'HS256' })[0]
|
41
|
-
|
42
|
-
expected_token_data = {
|
43
|
-
"id" => '654',
|
44
|
-
"email" => 'user@email.com',
|
45
|
-
"first_name" => 'FirstName',
|
46
|
-
"last_name" => 'LastName',
|
47
|
-
"rendering_id" => "42",
|
48
|
-
"team" => 'Operations'
|
49
|
-
}
|
50
|
-
expect(decoded).to include(expected_token_data);
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|