evoleap-licensing 1.0.0.12
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 +7 -0
- data/README.md +480 -0
- data/lib/evoleap_licensing/configuration.rb +34 -0
- data/lib/evoleap_licensing/control_logic.rb +38 -0
- data/lib/evoleap_licensing/control_manager_helper.rb +230 -0
- data/lib/evoleap_licensing/control_strategy.rb +16 -0
- data/lib/evoleap_licensing/encryption_handler.rb +42 -0
- data/lib/evoleap_licensing/errors.rb +9 -0
- data/lib/evoleap_licensing/identity/instance_identity.rb +39 -0
- data/lib/evoleap_licensing/identity/user_identity.rb +32 -0
- data/lib/evoleap_licensing/platform_info.rb +75 -0
- data/lib/evoleap_licensing/results/component_checkin_result.rb +16 -0
- data/lib/evoleap_licensing/results/component_checkout_result.rb +18 -0
- data/lib/evoleap_licensing/results/components_status.rb +18 -0
- data/lib/evoleap_licensing/results/instance_validity.rb +46 -0
- data/lib/evoleap_licensing/results/license_info.rb +19 -0
- data/lib/evoleap_licensing/results/registration_result.rb +16 -0
- data/lib/evoleap_licensing/results/session_validity.rb +47 -0
- data/lib/evoleap_licensing/server_control_manager.rb +50 -0
- data/lib/evoleap_licensing/state/server_state.rb +78 -0
- data/lib/evoleap_licensing/state/session_state.rb +68 -0
- data/lib/evoleap_licensing/state/user_state.rb +78 -0
- data/lib/evoleap_licensing/types/component_license_model.rb +22 -0
- data/lib/evoleap_licensing/types/invalid_reason.rb +49 -0
- data/lib/evoleap_licensing/types/validation_status.rb +91 -0
- data/lib/evoleap_licensing/user_control_manager.rb +198 -0
- data/lib/evoleap_licensing/version.rb +6 -0
- data/lib/evoleap_licensing/web_client.rb +65 -0
- data/lib/evoleap_licensing/web_service.rb +168 -0
- data/lib/evoleap_licensing.rb +41 -0
- metadata +129 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
module EvoleapLicensing
|
|
6
|
+
class ServerState
|
|
7
|
+
attr_accessor :instance_guid, :first_launch_time, :registered_at,
|
|
8
|
+
:grace_period_for_validation_failures,
|
|
9
|
+
:last_successful_validation_time, :last_validation_status,
|
|
10
|
+
:number_of_failed_validation_attempts, :features
|
|
11
|
+
|
|
12
|
+
attr_reader :failed_registration_times, :failed_validation_times
|
|
13
|
+
|
|
14
|
+
def initialize(hash = nil)
|
|
15
|
+
hash = (hash || {}).transform_keys(&:to_s)
|
|
16
|
+
@instance_guid = hash["instance_guid"]
|
|
17
|
+
@first_launch_time = parse_time(hash["first_launch_time"])
|
|
18
|
+
@registered_at = parse_time(hash["registered_at"])
|
|
19
|
+
@grace_period_for_validation_failures = hash["grace_period_for_validation_failures"]
|
|
20
|
+
@last_successful_validation_time = parse_time(hash["last_successful_validation_time"])
|
|
21
|
+
@last_validation_status = hash["last_validation_status"]
|
|
22
|
+
@number_of_failed_validation_attempts = hash["number_of_failed_validation_attempts"] || 0
|
|
23
|
+
@features = hash["features"] || []
|
|
24
|
+
@failed_registration_times = (hash["failed_registration_times"] || []).map { |t| parse_time(t) }.compact
|
|
25
|
+
@failed_validation_times = (hash["failed_validation_times"] || []).map { |t| parse_time(t) }.compact
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def registered?
|
|
29
|
+
!@registered_at.nil?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def add_registration_failure(time = Time.now.utc)
|
|
33
|
+
@failed_registration_times.unshift(time)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def reset_registration_failures
|
|
37
|
+
@failed_registration_times = []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_validation_failure(time = Time.now.utc)
|
|
41
|
+
@failed_validation_times.unshift(time)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reset_validation_failures
|
|
45
|
+
@failed_validation_times = []
|
|
46
|
+
@number_of_failed_validation_attempts = 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def take_registration_params(response)
|
|
50
|
+
@instance_guid = response["instance_guid"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_h
|
|
54
|
+
{
|
|
55
|
+
"instance_guid" => @instance_guid,
|
|
56
|
+
"first_launch_time" => @first_launch_time&.iso8601,
|
|
57
|
+
"registered_at" => @registered_at&.iso8601,
|
|
58
|
+
"grace_period_for_validation_failures" => @grace_period_for_validation_failures,
|
|
59
|
+
"last_successful_validation_time" => @last_successful_validation_time&.iso8601,
|
|
60
|
+
"last_validation_status" => @last_validation_status,
|
|
61
|
+
"number_of_failed_validation_attempts" => @number_of_failed_validation_attempts,
|
|
62
|
+
"features" => @features,
|
|
63
|
+
"failed_registration_times" => @failed_registration_times.map(&:iso8601),
|
|
64
|
+
"failed_validation_times" => @failed_validation_times.map(&:iso8601)
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def parse_time(value)
|
|
71
|
+
return nil if value.nil?
|
|
72
|
+
return value if value.is_a?(Time)
|
|
73
|
+
Time.parse(value.to_s)
|
|
74
|
+
rescue ArgumentError
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvoleapLicensing
|
|
4
|
+
class SessionState
|
|
5
|
+
attr_accessor :auth_token, :session_key, :session_duration,
|
|
6
|
+
:features, :feature_groups,
|
|
7
|
+
:components, :component_entitlements
|
|
8
|
+
|
|
9
|
+
def initialize(hash = nil)
|
|
10
|
+
hash = (hash || {}).transform_keys(&:to_s)
|
|
11
|
+
@auth_token = hash["auth_token"]
|
|
12
|
+
@session_key = hash["session_key"]
|
|
13
|
+
@session_duration = hash["session_duration"]
|
|
14
|
+
@features = hash["features"] || []
|
|
15
|
+
@feature_groups = hash["feature_groups"] || []
|
|
16
|
+
@components = hash["components"] || []
|
|
17
|
+
@component_entitlements = hash["component_entitlements"] || []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def active?
|
|
21
|
+
!@auth_token.nil? && !@session_key.nil?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def clear!
|
|
25
|
+
@auth_token = nil
|
|
26
|
+
@session_key = nil
|
|
27
|
+
@session_duration = nil
|
|
28
|
+
@features = []
|
|
29
|
+
@feature_groups = []
|
|
30
|
+
@components = []
|
|
31
|
+
@component_entitlements = []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def update_from_session_response(response)
|
|
35
|
+
@auth_token = response["token"] if response["token"]
|
|
36
|
+
@session_key = response["session_key"] if response["session_key"]
|
|
37
|
+
@session_duration = response["session_duration"] if response["session_duration"]
|
|
38
|
+
@features = response["features"] if response["features"]
|
|
39
|
+
@feature_groups = response["feature_groups"] if response["feature_groups"]
|
|
40
|
+
update_components_from_response(response)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def update_from_extend_response(response)
|
|
44
|
+
@auth_token = response["token"] if response["token"]
|
|
45
|
+
@session_duration = response["session_duration"] if response["session_duration"]
|
|
46
|
+
@features = response["features"] if response["features"]
|
|
47
|
+
@feature_groups = response["feature_groups"] if response["feature_groups"]
|
|
48
|
+
update_components_from_response(response)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def update_components_from_response(response)
|
|
52
|
+
@components = response["components"] if response["components"]
|
|
53
|
+
@component_entitlements = response["component_entitlements"] if response["component_entitlements"]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_h
|
|
57
|
+
{
|
|
58
|
+
"auth_token" => @auth_token,
|
|
59
|
+
"session_key" => @session_key,
|
|
60
|
+
"session_duration" => @session_duration,
|
|
61
|
+
"features" => @features,
|
|
62
|
+
"feature_groups" => @feature_groups,
|
|
63
|
+
"components" => @components,
|
|
64
|
+
"component_entitlements" => @component_entitlements
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
module EvoleapLicensing
|
|
6
|
+
class UserState
|
|
7
|
+
attr_accessor :user_guid, :first_launch_time, :registered_at,
|
|
8
|
+
:grace_period_for_validation_failures,
|
|
9
|
+
:last_successful_validation_time, :last_validation_status,
|
|
10
|
+
:number_of_failed_validation_attempts, :features
|
|
11
|
+
|
|
12
|
+
attr_reader :failed_registration_times, :failed_validation_times
|
|
13
|
+
|
|
14
|
+
def initialize(hash = nil)
|
|
15
|
+
hash = (hash || {}).transform_keys(&:to_s)
|
|
16
|
+
@user_guid = hash["user_guid"]
|
|
17
|
+
@first_launch_time = parse_time(hash["first_launch_time"])
|
|
18
|
+
@registered_at = parse_time(hash["registered_at"])
|
|
19
|
+
@grace_period_for_validation_failures = hash["grace_period_for_validation_failures"]
|
|
20
|
+
@last_successful_validation_time = parse_time(hash["last_successful_validation_time"])
|
|
21
|
+
@last_validation_status = hash["last_validation_status"]
|
|
22
|
+
@number_of_failed_validation_attempts = hash["number_of_failed_validation_attempts"] || 0
|
|
23
|
+
@features = hash["features"] || []
|
|
24
|
+
@failed_registration_times = (hash["failed_registration_times"] || []).map { |t| parse_time(t) }.compact
|
|
25
|
+
@failed_validation_times = (hash["failed_validation_times"] || []).map { |t| parse_time(t) }.compact
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def registered?
|
|
29
|
+
!@registered_at.nil?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def add_registration_failure(time = Time.now.utc)
|
|
33
|
+
@failed_registration_times.unshift(time)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def reset_registration_failures
|
|
37
|
+
@failed_registration_times = []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_validation_failure(time = Time.now.utc)
|
|
41
|
+
@failed_validation_times.unshift(time)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reset_validation_failures
|
|
45
|
+
@failed_validation_times = []
|
|
46
|
+
@number_of_failed_validation_attempts = 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def take_registration_params(response)
|
|
50
|
+
@user_guid = response["user_guid"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_h
|
|
54
|
+
{
|
|
55
|
+
"user_guid" => @user_guid,
|
|
56
|
+
"first_launch_time" => @first_launch_time&.iso8601,
|
|
57
|
+
"registered_at" => @registered_at&.iso8601,
|
|
58
|
+
"grace_period_for_validation_failures" => @grace_period_for_validation_failures,
|
|
59
|
+
"last_successful_validation_time" => @last_successful_validation_time&.iso8601,
|
|
60
|
+
"last_validation_status" => @last_validation_status,
|
|
61
|
+
"number_of_failed_validation_attempts" => @number_of_failed_validation_attempts,
|
|
62
|
+
"features" => @features,
|
|
63
|
+
"failed_registration_times" => @failed_registration_times.map(&:iso8601),
|
|
64
|
+
"failed_validation_times" => @failed_validation_times.map(&:iso8601)
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def parse_time(value)
|
|
71
|
+
return nil if value.nil?
|
|
72
|
+
return value if value.is_a?(Time)
|
|
73
|
+
Time.parse(value.to_s)
|
|
74
|
+
rescue ArgumentError
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvoleapLicensing
|
|
4
|
+
module ComponentLicenseModel
|
|
5
|
+
NONE = :none
|
|
6
|
+
TOKEN = :token
|
|
7
|
+
SESSION = :session
|
|
8
|
+
CONSUMABLE_TOKEN = :consumable_token
|
|
9
|
+
UNKNOWN = :unknown
|
|
10
|
+
|
|
11
|
+
FROM_STRING = {
|
|
12
|
+
"None" => NONE,
|
|
13
|
+
"Token" => TOKEN,
|
|
14
|
+
"Session" => SESSION,
|
|
15
|
+
"ConsumableToken" => CONSUMABLE_TOKEN
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
def self.from_string(str)
|
|
19
|
+
FROM_STRING[str] || UNKNOWN
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvoleapLicensing
|
|
4
|
+
module InvalidReason
|
|
5
|
+
REGISTRATION_REQUIRED = :registration_required
|
|
6
|
+
USER_TAMPERING_DETECTED = :user_tampering_detected
|
|
7
|
+
SERVICE_UNREACHABLE = :service_unreachable
|
|
8
|
+
LICENSE_EXPIRED = :license_expired
|
|
9
|
+
INSTANCE_DISABLED = :instance_disabled
|
|
10
|
+
USER_DISABLED = :user_disabled
|
|
11
|
+
INVALID_LICENSE_KEY = :invalid_license_key
|
|
12
|
+
INVALID_PRODUCT_ID = :invalid_product_id
|
|
13
|
+
INSTANCE_NOT_REGISTERED = :instance_not_registered
|
|
14
|
+
USER_NOT_REGISTERED = :user_not_registered
|
|
15
|
+
INCONSISTENT_REGISTRATION = :inconsistent_registration
|
|
16
|
+
INCONSISTENT_USER = :inconsistent_user
|
|
17
|
+
NO_SEATS_AVAILABLE = :no_seats_available
|
|
18
|
+
SESSION_REVOKED = :session_revoked
|
|
19
|
+
ACTIVATION_PENDING = :activation_pending
|
|
20
|
+
INSUFFICIENT_TOKENS = :insufficient_tokens
|
|
21
|
+
INVALID_COMPONENT = :invalid_component
|
|
22
|
+
|
|
23
|
+
# Map ValidationStatus integers to InvalidReason symbols
|
|
24
|
+
FROM_VALIDATION_STATUS = {
|
|
25
|
+
ValidationStatus::REGISTRATION_REQUIRED => REGISTRATION_REQUIRED,
|
|
26
|
+
ValidationStatus::USER_TAMPERING_DETECTED => USER_TAMPERING_DETECTED,
|
|
27
|
+
ValidationStatus::SERVICE_UNREACHABLE => SERVICE_UNREACHABLE,
|
|
28
|
+
ValidationStatus::LICENSE_EXPIRED => LICENSE_EXPIRED,
|
|
29
|
+
ValidationStatus::INSTANCE_DISABLED => INSTANCE_DISABLED,
|
|
30
|
+
ValidationStatus::USER_DISABLED => USER_DISABLED,
|
|
31
|
+
ValidationStatus::INVALID_LICENSE_KEY => INVALID_LICENSE_KEY,
|
|
32
|
+
ValidationStatus::INVALID_PRODUCT_ID => INVALID_PRODUCT_ID,
|
|
33
|
+
ValidationStatus::INSTANCE_NOT_REGISTERED => INSTANCE_NOT_REGISTERED,
|
|
34
|
+
ValidationStatus::USER_NOT_REGISTERED => USER_NOT_REGISTERED,
|
|
35
|
+
ValidationStatus::INCONSISTENT_REGISTRATION => INCONSISTENT_REGISTRATION,
|
|
36
|
+
ValidationStatus::INCONSISTENT_USER => INCONSISTENT_USER,
|
|
37
|
+
ValidationStatus::NO_SEATS_AVAILABLE => NO_SEATS_AVAILABLE,
|
|
38
|
+
ValidationStatus::SESSION_REVOKED => SESSION_REVOKED,
|
|
39
|
+
ValidationStatus::ACTIVATION_PENDING => ACTIVATION_PENDING,
|
|
40
|
+
ValidationStatus::INSUFFICIENT_TOKENS => INSUFFICIENT_TOKENS,
|
|
41
|
+
ValidationStatus::INVALID_COMPONENT => INVALID_COMPONENT,
|
|
42
|
+
ValidationStatus::GENERAL_ERROR => SERVICE_UNREACHABLE
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
def self.from_validation_status(status)
|
|
46
|
+
FROM_VALIDATION_STATUS[status] || SERVICE_UNREACHABLE
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvoleapLicensing
|
|
4
|
+
module ValidationStatus
|
|
5
|
+
# Client-only statuses
|
|
6
|
+
REGISTRATION_REQUIRED = -101
|
|
7
|
+
USER_TAMPERING_DETECTED = -100
|
|
8
|
+
SERVICE_UNREACHABLE = -99
|
|
9
|
+
|
|
10
|
+
# Server-provided statuses
|
|
11
|
+
FULL_LICENSE_ALREADY_CHECKED_OUT = -17
|
|
12
|
+
OFFLINE_CHECKOUT_NOT_SUPPORTED = -16
|
|
13
|
+
INVALID_COMPONENT = -15
|
|
14
|
+
INSUFFICIENT_TOKENS = -14
|
|
15
|
+
ACTIVATION_PENDING = -13
|
|
16
|
+
SESSION_REVOKED = -12
|
|
17
|
+
NO_SEATS_AVAILABLE = -11
|
|
18
|
+
INCONSISTENT_REGISTRATION = -10
|
|
19
|
+
INCONSISTENT_USER = -9
|
|
20
|
+
INSTANCE_NOT_REGISTERED = -8
|
|
21
|
+
USER_NOT_REGISTERED = -7
|
|
22
|
+
INVALID_LICENSE_KEY = -6
|
|
23
|
+
INVALID_PRODUCT_ID = -5
|
|
24
|
+
INSTANCE_DISABLED = -4
|
|
25
|
+
USER_DISABLED = -3
|
|
26
|
+
LICENSE_EXPIRED = -2
|
|
27
|
+
GENERAL_ERROR = -1
|
|
28
|
+
SUCCESS = 0
|
|
29
|
+
|
|
30
|
+
ALL = {
|
|
31
|
+
registration_required: REGISTRATION_REQUIRED,
|
|
32
|
+
user_tampering_detected: USER_TAMPERING_DETECTED,
|
|
33
|
+
service_unreachable: SERVICE_UNREACHABLE,
|
|
34
|
+
full_license_already_checked_out: FULL_LICENSE_ALREADY_CHECKED_OUT,
|
|
35
|
+
offline_checkout_not_supported: OFFLINE_CHECKOUT_NOT_SUPPORTED,
|
|
36
|
+
invalid_component: INVALID_COMPONENT,
|
|
37
|
+
insufficient_tokens: INSUFFICIENT_TOKENS,
|
|
38
|
+
activation_pending: ACTIVATION_PENDING,
|
|
39
|
+
session_revoked: SESSION_REVOKED,
|
|
40
|
+
no_seats_available: NO_SEATS_AVAILABLE,
|
|
41
|
+
inconsistent_registration: INCONSISTENT_REGISTRATION,
|
|
42
|
+
inconsistent_user: INCONSISTENT_USER,
|
|
43
|
+
instance_not_registered: INSTANCE_NOT_REGISTERED,
|
|
44
|
+
user_not_registered: USER_NOT_REGISTERED,
|
|
45
|
+
invalid_license_key: INVALID_LICENSE_KEY,
|
|
46
|
+
invalid_product_id: INVALID_PRODUCT_ID,
|
|
47
|
+
instance_disabled: INSTANCE_DISABLED,
|
|
48
|
+
user_disabled: USER_DISABLED,
|
|
49
|
+
license_expired: LICENSE_EXPIRED,
|
|
50
|
+
general_error: GENERAL_ERROR,
|
|
51
|
+
success: SUCCESS
|
|
52
|
+
}.freeze
|
|
53
|
+
|
|
54
|
+
BY_VALUE = ALL.invert.freeze
|
|
55
|
+
|
|
56
|
+
def self.name_for(value)
|
|
57
|
+
BY_VALUE[value]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Convenience class methods matching old Enum API
|
|
61
|
+
def self.registration_required; REGISTRATION_REQUIRED; end
|
|
62
|
+
def self.user_tampering_detected; USER_TAMPERING_DETECTED; end
|
|
63
|
+
def self.service_unreachable; SERVICE_UNREACHABLE; end
|
|
64
|
+
def self.activation_pending; ACTIVATION_PENDING; end
|
|
65
|
+
def self.session_revoked; SESSION_REVOKED; end
|
|
66
|
+
def self.no_seats_available; NO_SEATS_AVAILABLE; end
|
|
67
|
+
def self.inconsistent_registration; INCONSISTENT_REGISTRATION; end
|
|
68
|
+
def self.inconsistent_user; INCONSISTENT_USER; end
|
|
69
|
+
def self.instance_not_registered; INSTANCE_NOT_REGISTERED; end
|
|
70
|
+
def self.user_not_registered; USER_NOT_REGISTERED; end
|
|
71
|
+
def self.invalid_license_key; INVALID_LICENSE_KEY; end
|
|
72
|
+
def self.invalid_product_id; INVALID_PRODUCT_ID; end
|
|
73
|
+
def self.instance_disabled; INSTANCE_DISABLED; end
|
|
74
|
+
def self.user_disabled; USER_DISABLED; end
|
|
75
|
+
def self.license_expired; LICENSE_EXPIRED; end
|
|
76
|
+
def self.general_error; GENERAL_ERROR; end
|
|
77
|
+
def self.success; SUCCESS; end
|
|
78
|
+
def self.insufficient_tokens; INSUFFICIENT_TOKENS; end
|
|
79
|
+
def self.invalid_component; INVALID_COMPONENT; end
|
|
80
|
+
def self.offline_checkout_not_supported; OFFLINE_CHECKOUT_NOT_SUPPORTED; end
|
|
81
|
+
def self.full_license_already_checked_out; FULL_LICENSE_ALREADY_CHECKED_OUT; end
|
|
82
|
+
|
|
83
|
+
def self.success?(value)
|
|
84
|
+
value == SUCCESS
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.client_only?(value)
|
|
88
|
+
value <= SERVICE_UNREACHABLE
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvoleapLicensing
|
|
4
|
+
class UserControlManager
|
|
5
|
+
attr_reader :product_id, :version, :instance_id, :public_key,
|
|
6
|
+
:strategy, :user_state, :session_state
|
|
7
|
+
|
|
8
|
+
def initialize(product_id:, version:, instance_id:, public_key:,
|
|
9
|
+
strategy: nil, user_state: nil, session_state: nil)
|
|
10
|
+
@product_id = product_id
|
|
11
|
+
@version = version
|
|
12
|
+
@instance_id = instance_id
|
|
13
|
+
@public_key = public_key
|
|
14
|
+
@strategy = strategy || ControlStrategy.default
|
|
15
|
+
@user_state = user_state || UserState.new
|
|
16
|
+
@session_state = session_state || SessionState.new
|
|
17
|
+
@client = WebClient.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Register a user against the server instance.
|
|
21
|
+
# Returns a RegistrationResult.
|
|
22
|
+
def register(user_info:, user_identity:)
|
|
23
|
+
ControlManagerHelper.register(@user_state) do
|
|
24
|
+
WebService.register_user(
|
|
25
|
+
product_id: @product_id,
|
|
26
|
+
instance_id: @instance_id,
|
|
27
|
+
user_info: user_info,
|
|
28
|
+
user_identity: user_identity.to_api_format,
|
|
29
|
+
public_key: @public_key,
|
|
30
|
+
client: @client
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Begin or extend a user session.
|
|
36
|
+
# Returns a SessionValidity.
|
|
37
|
+
def validate_session(user_identity:, requested_duration: nil)
|
|
38
|
+
ControlManagerHelper.validate_session(@strategy, @user_state, @session_state,
|
|
39
|
+
-> { make_session_call(user_identity, requested_duration) })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# End the active session.
|
|
43
|
+
def end_session
|
|
44
|
+
raise NoActiveSessionError, "No active session to end" unless @session_state.active?
|
|
45
|
+
|
|
46
|
+
response = WebService.end_session(
|
|
47
|
+
product_id: @product_id,
|
|
48
|
+
auth_token: @session_state.auth_token,
|
|
49
|
+
session_key: @session_state.session_key,
|
|
50
|
+
public_key: @public_key,
|
|
51
|
+
client: @client
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@session_state.clear!
|
|
55
|
+
!response.key?("error")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Check out named components for the active session.
|
|
59
|
+
# Returns a ComponentCheckoutResult.
|
|
60
|
+
def check_out_components(*component_names)
|
|
61
|
+
raise NoActiveSessionError, "No active session" unless @session_state.active?
|
|
62
|
+
|
|
63
|
+
response = WebService.check_out_components(
|
|
64
|
+
product_id: @product_id,
|
|
65
|
+
auth_token: @session_state.auth_token,
|
|
66
|
+
session_key: @session_state.session_key,
|
|
67
|
+
component_names: component_names.flatten,
|
|
68
|
+
public_key: @public_key,
|
|
69
|
+
client: @client
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if response["status"] == ValidationStatus::SUCCESS
|
|
73
|
+
@session_state.update_components_from_response(response)
|
|
74
|
+
ComponentCheckoutResult.new(
|
|
75
|
+
success: true,
|
|
76
|
+
components: response["components"] || [],
|
|
77
|
+
component_entitlements: response["component_entitlements"] || []
|
|
78
|
+
)
|
|
79
|
+
else
|
|
80
|
+
ComponentCheckoutResult.new(
|
|
81
|
+
success: false,
|
|
82
|
+
failure_reason: InvalidReason.from_validation_status(response["status"])
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Check in named components.
|
|
88
|
+
# Returns a ComponentCheckinResult.
|
|
89
|
+
def check_in_components(*component_names)
|
|
90
|
+
raise NoActiveSessionError, "No active session" unless @session_state.active?
|
|
91
|
+
|
|
92
|
+
response = WebService.check_in_components(
|
|
93
|
+
product_id: @product_id,
|
|
94
|
+
auth_token: @session_state.auth_token,
|
|
95
|
+
session_key: @session_state.session_key,
|
|
96
|
+
component_names: component_names.flatten,
|
|
97
|
+
public_key: @public_key,
|
|
98
|
+
client: @client
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if response["status"] == ValidationStatus::SUCCESS
|
|
102
|
+
@session_state.update_components_from_response(response)
|
|
103
|
+
ComponentCheckinResult.new(success: true)
|
|
104
|
+
else
|
|
105
|
+
ComponentCheckinResult.new(
|
|
106
|
+
success: false,
|
|
107
|
+
failure_reason: InvalidReason.from_validation_status(response["status"])
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Get status of all components.
|
|
113
|
+
# Returns a ComponentsStatus.
|
|
114
|
+
def components_status
|
|
115
|
+
raise NoActiveSessionError, "No active session" unless @session_state.active?
|
|
116
|
+
|
|
117
|
+
response = WebService.components_status(
|
|
118
|
+
product_id: @product_id,
|
|
119
|
+
auth_token: @session_state.auth_token,
|
|
120
|
+
session_key: @session_state.session_key,
|
|
121
|
+
public_key: @public_key,
|
|
122
|
+
client: @client
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if response["status"] == ValidationStatus::SUCCESS
|
|
126
|
+
ComponentsStatus.new(
|
|
127
|
+
success: true,
|
|
128
|
+
components: response["components"] || [],
|
|
129
|
+
component_entitlements: response["component_entitlements"] || []
|
|
130
|
+
)
|
|
131
|
+
else
|
|
132
|
+
ComponentsStatus.new(
|
|
133
|
+
success: false,
|
|
134
|
+
error_message: response["error"]
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Get license info for the active session.
|
|
140
|
+
# Returns a LicenseInfo.
|
|
141
|
+
def license_info
|
|
142
|
+
raise NoActiveSessionError, "No active session" unless @session_state.active?
|
|
143
|
+
|
|
144
|
+
response = WebService.get_license_info(
|
|
145
|
+
product_id: @product_id,
|
|
146
|
+
auth_token: @session_state.auth_token,
|
|
147
|
+
session_key: @session_state.session_key,
|
|
148
|
+
public_key: @public_key,
|
|
149
|
+
client: @client
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if response["status"] == ValidationStatus::SUCCESS
|
|
153
|
+
LicenseInfo.new(
|
|
154
|
+
success: true,
|
|
155
|
+
owner_name: response["owner_name"],
|
|
156
|
+
owner_logo_url: response["owner_logo_url"],
|
|
157
|
+
expiry: response["expiry"]
|
|
158
|
+
)
|
|
159
|
+
else
|
|
160
|
+
LicenseInfo.new(
|
|
161
|
+
success: false,
|
|
162
|
+
error_message: response["error"]
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# For testing: allow injecting a custom web client
|
|
168
|
+
def web_client=(client)
|
|
169
|
+
@client = client
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
def make_session_call(user_identity, requested_duration)
|
|
175
|
+
if @session_state.active?
|
|
176
|
+
# Extend existing session
|
|
177
|
+
WebService.extend_session(
|
|
178
|
+
product_id: @product_id,
|
|
179
|
+
auth_token: @session_state.auth_token,
|
|
180
|
+
session_key: @session_state.session_key,
|
|
181
|
+
public_key: @public_key,
|
|
182
|
+
client: @client,
|
|
183
|
+
session_duration: requested_duration
|
|
184
|
+
)
|
|
185
|
+
else
|
|
186
|
+
# Begin new session
|
|
187
|
+
WebService.begin_user_session(
|
|
188
|
+
product_id: @product_id,
|
|
189
|
+
instance_id: @instance_id,
|
|
190
|
+
user_identity: user_identity.to_api_format,
|
|
191
|
+
public_key: @public_key,
|
|
192
|
+
client: @client,
|
|
193
|
+
session_duration: requested_duration
|
|
194
|
+
)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module EvoleapLicensing
|
|
8
|
+
class WebClient
|
|
9
|
+
ENDPOINTS = {
|
|
10
|
+
register_instance: "register_instance",
|
|
11
|
+
validate_instance: "validate_instance",
|
|
12
|
+
register_user: "register_user",
|
|
13
|
+
begin_user_session: "begin_user_session",
|
|
14
|
+
extend_session: "extend_session",
|
|
15
|
+
end_session: "end_session",
|
|
16
|
+
check_out_components: "check_out_components",
|
|
17
|
+
check_in_components: "check_in_components",
|
|
18
|
+
components_status: "components_status",
|
|
19
|
+
get_license_info: "get_license_info"
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
attr_accessor :base_url, :timeout
|
|
23
|
+
|
|
24
|
+
def initialize(base_url: nil, timeout: nil)
|
|
25
|
+
config = EvoleapLicensing.configuration
|
|
26
|
+
@base_url = base_url || config.api_base_url
|
|
27
|
+
@timeout = timeout || config.timeout
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
ENDPOINTS.each do |method_name, _endpoint|
|
|
31
|
+
define_method(method_name) do |key, encrypted_params|
|
|
32
|
+
post(method_name, key, encrypted_params)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def post(action, key, encrypted_params)
|
|
39
|
+
url = URI("#{@base_url}/#{ENDPOINTS[action]}")
|
|
40
|
+
http = Net::HTTP.new(url.host, url.port)
|
|
41
|
+
http.use_ssl = url.scheme == "https"
|
|
42
|
+
http.open_timeout = @timeout
|
|
43
|
+
http.read_timeout = @timeout
|
|
44
|
+
|
|
45
|
+
request = Net::HTTP::Post.new(url)
|
|
46
|
+
request["Content-Type"] = "application/json"
|
|
47
|
+
request["User-Agent"] = EvoleapLicensing.configuration.user_agent
|
|
48
|
+
request.body = { key: key, data: encrypted_params }.to_json
|
|
49
|
+
|
|
50
|
+
response = http.request(request)
|
|
51
|
+
|
|
52
|
+
case response
|
|
53
|
+
when Net::HTTPSuccess
|
|
54
|
+
response.body
|
|
55
|
+
when Net::HTTPInternalServerError
|
|
56
|
+
raise ServerError, "Server error: #{response.code} #{response.message}"
|
|
57
|
+
else
|
|
58
|
+
raise ApiError, "API error: #{response.code} #{response.message}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class ServerError < EvoleapLicensing::Error; end
|
|
63
|
+
class ApiError < EvoleapLicensing::Error; end
|
|
64
|
+
end
|
|
65
|
+
end
|