forest_liana 6.0.0.pre.beta.4 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|