eligible 1.0 → 3.0.0.beta17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +76 -0
- data/.codeclimate.yml +23 -0
- data/.gitignore +3 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1158 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +170 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +66 -0
- data/LICENSE +1 -1
- data/README.md +700 -93
- data/Rakefile +12 -2
- data/eligible.gemspec +14 -16
- data/lib/eligible/api_resource.rb +49 -5
- data/lib/eligible/calculator_deploy_url.rb +7 -0
- data/lib/eligible/claim.rb +22 -6
- data/lib/eligible/coverage.rb +19 -0
- data/lib/eligible/coverage_resource.rb +23 -0
- data/lib/eligible/customer.rb +19 -0
- data/lib/eligible/demographic.rb +6 -35
- data/lib/eligible/eligible_object.rb +12 -15
- data/lib/eligible/encryptor.rb +121 -0
- data/lib/eligible/enrollment.rb +23 -0
- data/lib/eligible/errors/eligible_error.rb +6 -3
- data/lib/eligible/errors/invalid_request_error.rb +4 -0
- data/lib/eligible/icd.rb +16 -0
- data/lib/eligible/json.rb +5 -15
- data/lib/eligible/lockbox.rb +39 -0
- data/lib/eligible/medicare.rb +11 -0
- data/lib/eligible/oauth_token.rb +9 -0
- data/lib/eligible/ocr.rb +15 -0
- data/lib/eligible/original_signature_pdf.rb +45 -0
- data/lib/eligible/payer.rb +17 -0
- data/lib/eligible/payer_mapping.rb +37 -0
- data/lib/eligible/payment.rb +11 -0
- data/lib/eligible/preauth_resource.rb +11 -0
- data/lib/eligible/precert.rb +15 -0
- data/lib/eligible/provider_model.rb +7 -0
- data/lib/eligible/public_key.rb +27 -0
- data/lib/eligible/received_pdf.rb +26 -0
- data/lib/eligible/referral.rb +11 -0
- data/lib/eligible/risk_assessment.rb +15 -0
- data/lib/eligible/session_token.rb +11 -0
- data/lib/eligible/ticket.rb +40 -0
- data/lib/eligible/util.rb +29 -38
- data/lib/eligible/v1_0/action.rb +9 -0
- data/lib/eligible/v1_0/attribute.rb +9 -0
- data/lib/eligible/v1_0/charge.rb +13 -0
- data/lib/eligible/v1_0/claim.rb +25 -0
- data/lib/eligible/v1_0/claim_service_line.rb +9 -0
- data/lib/eligible/v1_0/contract.rb +9 -0
- data/lib/eligible/v1_0/device.rb +9 -0
- data/lib/eligible/v1_0/discount.rb +9 -0
- data/lib/eligible/v1_0/enrollment.rb +17 -0
- data/lib/eligible/v1_0/estimate.rb +29 -0
- data/lib/eligible/v1_0/estimate_service_line.rb +17 -0
- data/lib/eligible/v1_0/fee.rb +21 -0
- data/lib/eligible/v1_0/fee_refund.rb +29 -0
- data/lib/eligible/v1_0/file.rb +17 -0
- data/lib/eligible/v1_0/file_link.rb +13 -0
- data/lib/eligible/v1_0/insurance_company.rb +21 -0
- data/lib/eligible/v1_0/insurance_company_alias.rb +9 -0
- data/lib/eligible/v1_0/insurance_policy.rb +9 -0
- data/lib/eligible/v1_0/patient_question.rb +9 -0
- data/lib/eligible/v1_0/patient_questionnaire.rb +9 -0
- data/lib/eligible/v1_0/patient_record.rb +9 -0
- data/lib/eligible/v1_0/patient_statement.rb +54 -0
- data/lib/eligible/v1_0/patient_statement_service_line.rb +13 -0
- data/lib/eligible/v1_0/payment_report.rb +21 -0
- data/lib/eligible/v1_0/product.rb +9 -0
- data/lib/eligible/v1_0/provider.rb +9 -0
- data/lib/eligible/v1_0/remark.rb +21 -0
- data/lib/eligible/v1_0/reports/accuracy_stats.rb +23 -0
- data/lib/eligible/v1_0/reports/estimate_friction.rb +23 -0
- data/lib/eligible/v1_0/reports/in_scope_distribution.rb +23 -0
- data/lib/eligible/v1_0/rest_api_base.rb +44 -0
- data/lib/eligible/v1_0/rule.rb +13 -0
- data/lib/eligible/v1_0/session.rb +21 -0
- data/lib/eligible/v1_0/transaction.rb +21 -0
- data/lib/eligible/v1_0/treatment.rb +9 -0
- data/lib/eligible/v1_0/value_list.rb +9 -0
- data/lib/eligible/v1_0/value_list_item.rb +9 -0
- data/lib/eligible/v1_0/verification.rb +17 -0
- data/lib/eligible/version.rb +1 -1
- data/lib/eligible/visit_type.rb +11 -0
- data/lib/eligible/x12.rb +8 -0
- data/lib/eligible.rb +320 -110
- metadata +148 -67
- data/CONTRIBUTORS +0 -1
- data/lib/eligible/plan.rb +0 -42
- data/lib/eligible/service.rb +0 -39
- data/test/test_eligible.rb +0 -279
- data/test/test_helper.rb +0 -67
data/Rakefile
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
2
|
require 'rake/testtask'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
require 'rspec/core/rake_task'
|
3
5
|
|
4
|
-
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
task default: [:spec]
|
9
|
+
|
10
|
+
desc 'Runs code coverage'
|
11
|
+
task :rcov do
|
12
|
+
ENV['COVERAGE'] = 'true'
|
13
|
+
Rake::Task[:spec].invoke
|
14
|
+
end
|
data/eligible.gemspec
CHANGED
@@ -4,25 +4,23 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'eligible/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
|
-
gem.name =
|
7
|
+
gem.name = 'eligible'
|
8
8
|
gem.version = Eligible::VERSION
|
9
|
-
gem.authors = [
|
10
|
-
gem.email = [
|
11
|
-
gem.description = 'Eligible is a developer-friendly way to process health care eligibility checks. Learn more at https://
|
9
|
+
gem.authors = ['Katelyn Gleaon', 'Rodrigo Dominguez', 'Aaron Bedra']
|
10
|
+
gem.email = ['k@eligible.com', 'rod@eligible.com', 'abedra@eligible.com']
|
11
|
+
gem.description = 'Eligible is a developer-friendly way to process health care eligibility checks. Learn more at https://eligible.com'
|
12
12
|
gem.summary = 'Ruby wrapper for the Eligible API'
|
13
|
-
gem.homepage =
|
14
|
-
gem.license =
|
13
|
+
gem.homepage = 'https://github.com/eligible/eligible-ruby'
|
14
|
+
gem.license = 'MIT'
|
15
15
|
|
16
|
-
gem.files = `git ls-files`.split(
|
17
|
-
|
18
|
-
gem.test_files = `git ls-files -- test/*`.split("\n")
|
19
|
-
gem.require_paths = ["lib"]
|
16
|
+
gem.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
gem.require_paths = ['lib']
|
20
18
|
|
21
|
-
gem.
|
22
|
-
gem.
|
23
|
-
gem.add_development_dependency('test-unit')
|
24
|
-
gem.add_development_dependency('rake')
|
19
|
+
gem.add_dependency('rest-client', '~> 2.0.0')
|
20
|
+
gem.add_dependency('multi_json', '~> 1.7')
|
25
21
|
|
26
|
-
gem.
|
27
|
-
gem.
|
22
|
+
gem.add_development_dependency('rake', '~> 12.0')
|
23
|
+
gem.add_development_dependency('rspec', '~> 3.4')
|
24
|
+
gem.add_development_dependency('rspec_junit_formatter', '~> 0.3.0')
|
25
|
+
gem.add_development_dependency('simplecov', '~> 0.11')
|
28
26
|
end
|
@@ -1,14 +1,58 @@
|
|
1
1
|
module Eligible
|
2
2
|
class APIResource < EligibleObject
|
3
3
|
def self.class_name
|
4
|
-
|
4
|
+
name.split('::').last
|
5
5
|
end
|
6
6
|
|
7
|
-
def self.
|
7
|
+
def self.api_url(base, params = nil, param_id = nil)
|
8
|
+
if params.nil?
|
9
|
+
"/#{base}"
|
10
|
+
else
|
11
|
+
id = Util.value(params, param_id)
|
12
|
+
"/#{base}/#{id}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.url
|
8
17
|
if self == APIResource
|
9
|
-
|
18
|
+
fail NotImplementedError, 'APIResource is an abstract class. You should perform actions on its subclasses (Plan, Service, etc.)'
|
10
19
|
end
|
11
|
-
"/#{CGI.escape(class_name.downcase)}/
|
20
|
+
"/#{CGI.escape(class_name.downcase)}/"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.endpoint_name
|
24
|
+
self.const_get('ENDPOINT_NAME')
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.require_param(value, name)
|
28
|
+
fail ArgumentError, "#{name} of the #{class_name} is required" if value.nil? || (value.is_a?(String) && value.empty?)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.required_param_validation(params:, required_params:)
|
32
|
+
return if required_params.nil? || !required_params.is_a?(Array)
|
33
|
+
|
34
|
+
required_params.each do |required_param_name|
|
35
|
+
required_param = Util.value(params, required_param_name)
|
36
|
+
require_param(required_param, required_param_name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.rest_api_params(id_or_params)
|
41
|
+
id_or_params.is_a?(Hash) ? id_or_params : { id: id_or_params }
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.send_request(method, url, params, opts)
|
45
|
+
headers = opts.clone
|
46
|
+
client_secret = headers.delete(:client_secret)
|
47
|
+
api_key = headers.delete(:api_key)
|
48
|
+
api_key = client_secret unless client_secret.nil?
|
49
|
+
|
50
|
+
required_param_validation(params: params, required_params: headers.delete(:required_params))
|
51
|
+
|
52
|
+
# Here rest_api_version is related to New REST API Endpoints
|
53
|
+
params = self.const_defined?(:REST_API_VERSION) ? params.merge(rest_api_version: self::REST_API_VERSION) : params
|
54
|
+
response, api_key = Eligible.request(method, url, api_key, params, headers)
|
55
|
+
Util.convert_to_eligible_object(response, api_key)
|
12
56
|
end
|
13
57
|
end
|
14
|
-
end
|
58
|
+
end
|
data/lib/eligible/claim.rb
CHANGED
@@ -1,12 +1,28 @@
|
|
1
1
|
module Eligible
|
2
2
|
class Claim < APIResource
|
3
|
-
def self.
|
4
|
-
|
5
|
-
|
3
|
+
def self.ack(params, opts = {})
|
4
|
+
reference_id = Util.value(params, :reference_id)
|
5
|
+
send_request :get, "/claims/#{reference_id}/acknowledgements.json", params, opts.merge(required_params: [:reference_id])
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def self.post(params, opts = {})
|
9
|
+
send_request :post, '/claims.json', params, opts
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.acks(params, opts = {})
|
13
|
+
send_request :get, '/claims/acknowledgements.json', params, opts
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.payment_report(params, opts = {})
|
17
|
+
reference_id = Util.value(params, :reference_id)
|
18
|
+
require_param(reference_id, 'Reference id')
|
19
|
+
id = Util.value(params, :id)
|
20
|
+
url = id.nil? ? "/claims/#{reference_id}/payment_reports" : "/claims/#{reference_id}/payment_reports/#{id}"
|
21
|
+
send_request :get, url, params, opts
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.payment_reports(params, opts = {})
|
25
|
+
send_request :get, '/claims/payment_reports.json', params, opts
|
10
26
|
end
|
11
27
|
end
|
12
|
-
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Eligible
|
2
|
+
class Coverage < CoverageResource
|
3
|
+
def self.get_uri
|
4
|
+
return '/coverage/all.json'
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.post_uri
|
8
|
+
return '/coverage/all/batch.json'
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.cost_estimate(params, opts = {})
|
12
|
+
send_request :get, '/coverage/cost_estimates.json', params, opts
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.batch_medicare_post(params, opts = {})
|
16
|
+
send_request :post, '/medicare/coverage/batch.json', params, opts
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Eligible
|
2
|
+
class CoverageResource < APIResource
|
3
|
+
def self.get(params, opts = {})
|
4
|
+
send_request :get, get_uri, params, opts
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.post(params, opts = {})
|
8
|
+
send_request :post, post_uri, params, opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.get_uri
|
12
|
+
fail NotImplementedError, "Please implement class method #{self}.get_uri"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.post_uri
|
16
|
+
fail NotImplementedError, "Please implement class method #{self}.post_uri"
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
alias_method :batch_post, :post
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Eligible
|
2
|
+
class Customer < APIResource
|
3
|
+
def self.get(params, opts = {})
|
4
|
+
send_request :get, api_url('customers', params, :customer_id), params, opts.merge(required_params: [:customer_id])
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.post(params, opts = {})
|
8
|
+
send_request :post, api_url('customers'), params, opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.update(params, opts = {})
|
12
|
+
send_request :put, api_url('customers', params, :customer_id), params, opts.merge(required_params: [:customer_id])
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.all(params, opts = {})
|
16
|
+
send_request :get, api_url('customers'), params, opts
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/eligible/demographic.rb
CHANGED
@@ -1,40 +1,11 @@
|
|
1
1
|
module Eligible
|
2
|
-
class Demographic <
|
3
|
-
|
4
|
-
|
5
|
-
EMPLOYER_ATTRIBUTES = [:group_id, :group_name]
|
6
|
-
ADDRESS_ATTRIBUTES = [:address]
|
7
|
-
DOB_ATTRIBUTES = [:dob]
|
8
|
-
|
9
|
-
def self.get(params, api_key=nil)
|
10
|
-
response, api_key = Eligible.request(:get, url, api_key, params)
|
11
|
-
Util.convert_to_eligible_object(response, api_key)
|
12
|
-
end
|
13
|
-
|
14
|
-
def all
|
15
|
-
error ? nil : to_hash
|
16
|
-
end
|
17
|
-
|
18
|
-
def zip
|
19
|
-
keys = COMMON_ATTRIBUTES
|
20
|
-
h = to_hash.select { |k, v| keys.include?(k) }
|
21
|
-
h[:zip] = to_hash[:address][:zip]
|
22
|
-
error ? nil : h
|
23
|
-
end
|
24
|
-
|
25
|
-
def employer
|
26
|
-
keys = COMMON_ATTRIBUTES + EMPLOYER_ATTRIBUTES
|
27
|
-
error ? nil : to_hash.select { |k, v| keys.include?(k) }
|
28
|
-
end
|
29
|
-
|
30
|
-
def address
|
31
|
-
keys = COMMON_ATTRIBUTES + ADDRESS_ATTRIBUTES
|
32
|
-
error ? nil : to_hash.select { |k, v| keys.include?(k) }
|
2
|
+
class Demographic < CoverageResource
|
3
|
+
def self.get_uri
|
4
|
+
return '/demographic/all.json'
|
33
5
|
end
|
34
6
|
|
35
|
-
def
|
36
|
-
|
37
|
-
error ? nil : to_hash.select { |k, v| keys.include?(k) }
|
7
|
+
def self.post_uri
|
8
|
+
return '/demographic/all/batch.json'
|
38
9
|
end
|
39
10
|
end
|
40
|
-
end
|
11
|
+
end
|
@@ -1,18 +1,16 @@
|
|
1
1
|
module Eligible
|
2
|
-
|
3
2
|
class EligibleObject
|
4
3
|
include Enumerable
|
5
4
|
|
6
5
|
attr_accessor :api_key
|
7
6
|
attr_accessor :eligible_id
|
7
|
+
|
8
8
|
@@permanent_attributes = Set.new([:api_key, :error, :balance, :address, :dob])
|
9
9
|
|
10
10
|
# The default :id method is deprecated and isn't useful to us
|
11
|
-
if method_defined?(:id)
|
12
|
-
undef :id
|
13
|
-
end
|
11
|
+
undef :id if method_defined?(:id)
|
14
12
|
|
15
|
-
def initialize(id=nil, api_key=nil)
|
13
|
+
def initialize(id = nil, api_key = nil)
|
16
14
|
@api_key = api_key
|
17
15
|
@values = {}
|
18
16
|
# This really belongs in APIResource, but not putting it there allows us
|
@@ -22,13 +20,13 @@ module Eligible
|
|
22
20
|
self.eligible_id = id if id
|
23
21
|
end
|
24
22
|
|
25
|
-
def self.construct_from(values, api_key=nil)
|
26
|
-
obj =
|
23
|
+
def self.construct_from(values, api_key = nil)
|
24
|
+
obj = new(values[:eligible_id], api_key)
|
27
25
|
obj.refresh_from(values, api_key)
|
28
26
|
obj
|
29
27
|
end
|
30
28
|
|
31
|
-
def refresh_from(values, api_key, partial=false)
|
29
|
+
def refresh_from(values, api_key, partial = false)
|
32
30
|
@api_key = api_key
|
33
31
|
|
34
32
|
removed = partial ? Set.new : Set.new(@values.keys - values.keys)
|
@@ -47,14 +45,14 @@ module Eligible
|
|
47
45
|
@unsaved_values.delete(k)
|
48
46
|
end
|
49
47
|
values.each do |k, v|
|
50
|
-
@values[k] = v
|
48
|
+
@values[k] = v
|
51
49
|
@transient_values.delete(k)
|
52
50
|
@unsaved_values.delete(k)
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
56
54
|
def [](k)
|
57
|
-
k = k.to_sym if k.
|
55
|
+
k = k.to_sym if k.is_a?(String)
|
58
56
|
@values[k]
|
59
57
|
end
|
60
58
|
|
@@ -70,7 +68,7 @@ module Eligible
|
|
70
68
|
@values.values
|
71
69
|
end
|
72
70
|
|
73
|
-
def to_json
|
71
|
+
def to_json
|
74
72
|
Eligible::JSON.dump(@values)
|
75
73
|
end
|
76
74
|
|
@@ -90,7 +88,7 @@ module Eligible
|
|
90
88
|
|
91
89
|
def metaclass
|
92
90
|
class << self; self; end
|
93
|
-
end
|
91
|
+
end
|
94
92
|
|
95
93
|
def remove_accessors(keys)
|
96
94
|
metaclass.instance_eval do
|
@@ -115,7 +113,6 @@ module Eligible
|
|
115
113
|
end
|
116
114
|
end
|
117
115
|
end
|
118
|
-
end
|
116
|
+
end
|
119
117
|
end
|
120
|
-
|
121
|
-
end
|
118
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Eligible
|
4
|
+
# A simple wrapper for the standard OpenSSL library
|
5
|
+
module Encryptor
|
6
|
+
extend self
|
7
|
+
# The default options to use when calling the <tt>encrypt</tt> and <tt>decrypt</tt> methods
|
8
|
+
#
|
9
|
+
# Defaults to { algorithm: 'aes-256-gcm',
|
10
|
+
# auth_data: '',
|
11
|
+
# insecure_mode: false,
|
12
|
+
# hmac_iterations: 2000,
|
13
|
+
# v2_gcm_iv: false }
|
14
|
+
#
|
15
|
+
# Run 'openssl list-cipher-commands' in your terminal to view a list all cipher algorithms that are supported on your platform
|
16
|
+
def default_options
|
17
|
+
@default_options ||= {
|
18
|
+
algorithm: 'aes-256-cbc',
|
19
|
+
auth_data: '',
|
20
|
+
insecure_mode: false,
|
21
|
+
hmac_iterations: 2000,
|
22
|
+
v2_gcm_iv: false
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Encrypts a <tt>:value</tt> with a specified <tt>:key</tt> and <tt>:iv</tt>.
|
27
|
+
#
|
28
|
+
# Optionally accepts <tt>:salt</tt>, <tt>:auth_data</tt>, <tt>:algorithm</tt>, <tt>:hmac_iterations</tt>, and <tt>:insecure_mode</tt> options.
|
29
|
+
#
|
30
|
+
# Example
|
31
|
+
#
|
32
|
+
# encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
33
|
+
# # or
|
34
|
+
# encrypted_value = Encryptor.encrypt('some string to encrypt', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
35
|
+
def encrypt(*args, &block)
|
36
|
+
crypt :encrypt, *args, &block
|
37
|
+
end
|
38
|
+
|
39
|
+
# Decrypts a <tt>:value</tt> with a specified <tt>:key</tt> and <tt>:iv</tt>.
|
40
|
+
#
|
41
|
+
# Optionally accepts <tt>:salt</tt>, <tt>:auth_data</tt>, <tt>:algorithm</tt>, <tt>:hmac_iterations</tt>, and <tt>:insecure_mode</tt> options.
|
42
|
+
#
|
43
|
+
# Example
|
44
|
+
#
|
45
|
+
# decrypted_value = Encryptor.decrypt(value: 'some encrypted string', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
46
|
+
# # or
|
47
|
+
# decrypted_value = Encryptor.decrypt('some encrypted string', key: 'some secret key', iv: 'some unique value', salt: 'another unique value')
|
48
|
+
def decrypt(*args, &block)
|
49
|
+
crypt :decrypt, *args, &block
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def crypt(cipher_method, *args) #:nodoc:
|
55
|
+
options = default_options.merge(value: args.first).merge(args.last.is_a?(Hash) ? args.last : {})
|
56
|
+
raise ArgumentError.new('must specify a key') if options[:key].to_s.empty?
|
57
|
+
cipher = OpenSSL::Cipher.new(options[:algorithm])
|
58
|
+
cipher.send(cipher_method)
|
59
|
+
|
60
|
+
unless options[:insecure_mode]
|
61
|
+
raise ArgumentError.new("key must be #{cipher.key_len} bytes or longer") if options[:key].bytesize < cipher.key_len
|
62
|
+
raise ArgumentError.new('must specify an iv') if options[:iv].to_s.empty?
|
63
|
+
raise ArgumentError.new("iv must be #{cipher.iv_len} bytes or longer") if options[:iv].bytesize < cipher.iv_len
|
64
|
+
end
|
65
|
+
|
66
|
+
if options[:iv]
|
67
|
+
# This is here for backwards compatibility for Encryptor v2.0.0.
|
68
|
+
cipher.iv = options[:iv] if options[:v2_gcm_iv]
|
69
|
+
if options[:salt].nil?
|
70
|
+
# Use a non-salted cipher.
|
71
|
+
# This behaviour is retained for backwards compatibility. This mode
|
72
|
+
# is not secure and new deployments should use the :salt options
|
73
|
+
# wherever possible.
|
74
|
+
cipher.key = options[:key]
|
75
|
+
else
|
76
|
+
# Use an explicit salt (which can be persisted into a database on a
|
77
|
+
# per-column basis, for example). This is the preferred (and more
|
78
|
+
# secure) mode of operation.
|
79
|
+
cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(options[:key], options[:salt], options[:hmac_iterations], cipher.key_len)
|
80
|
+
end
|
81
|
+
cipher.iv = options[:iv] unless options[:v2_gcm_iv]
|
82
|
+
else
|
83
|
+
# This is deprecated and needs to be changed.
|
84
|
+
cipher.pkcs5_keyivgen(options[:key])
|
85
|
+
end
|
86
|
+
|
87
|
+
yield cipher, options if block_given?
|
88
|
+
|
89
|
+
value = options[:value]
|
90
|
+
|
91
|
+
if cipher.authenticated?
|
92
|
+
if encryption?(cipher_method)
|
93
|
+
cipher.auth_data = options[:auth_data]
|
94
|
+
else
|
95
|
+
value = extract_cipher_text(options[:value])
|
96
|
+
cipher.auth_tag = extract_auth_tag(options[:value])
|
97
|
+
# auth_data must be set after auth_tag has been set when decrypting
|
98
|
+
# See http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-auth_data-3D
|
99
|
+
cipher.auth_data = options[:auth_data]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
result = cipher.update(value)
|
104
|
+
result << cipher.final
|
105
|
+
result << cipher.auth_tag if cipher.authenticated? && encryption?(cipher_method)
|
106
|
+
result
|
107
|
+
end
|
108
|
+
|
109
|
+
def encryption?(cipher_method)
|
110
|
+
cipher_method == :encrypt
|
111
|
+
end
|
112
|
+
|
113
|
+
def extract_cipher_text(value)
|
114
|
+
value[0..-17]
|
115
|
+
end
|
116
|
+
|
117
|
+
def extract_auth_tag(value)
|
118
|
+
value[-16..-1]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Eligible
|
2
|
+
class Enrollment < APIResource
|
3
|
+
def self.get(params, opts = {})
|
4
|
+
send_request :get, api_url('enrollment_npis', params, :enrollment_npi_id), params, opts.merge(required_params: [:enrollment_npi_id])
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.list(params, opts = {})
|
8
|
+
send_request :get, api_url('enrollment_npis'), params, opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.post(params, opts = {})
|
12
|
+
send_request :post, api_url('enrollment_npis'), params, opts
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.update(params, opts = {})
|
16
|
+
send_request :put, api_url('enrollment_npis', params, :enrollment_npi_id), params, opts.merge(required_params: [:enrollment_npi_id])
|
17
|
+
end
|
18
|
+
|
19
|
+
def enrollment_npis
|
20
|
+
values.first[:enrollment_npis]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -4,17 +4,20 @@ module Eligible
|
|
4
4
|
attr_reader :http_status
|
5
5
|
attr_reader :http_body
|
6
6
|
attr_reader :json_body
|
7
|
+
attr_reader :errors
|
7
8
|
|
8
|
-
def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
|
9
|
+
def initialize(message = nil, http_status = nil, http_body = nil, json_body = nil)
|
9
10
|
@message = message
|
10
11
|
@http_status = http_status
|
11
12
|
@http_body = http_body
|
12
13
|
@json_body = json_body
|
14
|
+
@errors = (@json_body || {}).fetch(:errors, [])
|
13
15
|
end
|
14
16
|
|
15
17
|
def to_s
|
16
|
-
status_string = @http_status.nil? ?
|
17
|
-
|
18
|
+
status_string = @http_status.nil? ? '' : "(Status #{@http_status}) "
|
19
|
+
json_errors = errors.presence || (json_body&.key?(:error) ? [json_body] : [])
|
20
|
+
"#{status_string}#{@message}: #{json_errors.to_json}"
|
18
21
|
end
|
19
22
|
end
|
20
23
|
end
|
data/lib/eligible/icd.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Eligible
|
2
|
+
class Icd < APIResource
|
3
|
+
|
4
|
+
def self.list(params, opts = {})
|
5
|
+
send_request :get, "/icds/#{Util.value(params, :type)}", params, opts
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.describe(params, opts = {})
|
9
|
+
send_request :get, "/icds/#{Util.value(params, :type)}/describe/#{Util.value(params, :code)}", params, opts
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.crosswalk(params, opts = {})
|
13
|
+
send_request :get, "/icds/#{Util.value(params, :type)}/crosswalk/#{Util.value(params, :code)}", params, opts
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/eligible/json.rb
CHANGED
@@ -1,21 +1,11 @@
|
|
1
1
|
module Eligible
|
2
2
|
module JSON
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.load(*args)
|
9
|
-
MultiJson.load(*args)
|
10
|
-
end
|
11
|
-
else
|
12
|
-
def self.dump(*args)
|
13
|
-
MultiJson.encode(*args)
|
14
|
-
end
|
3
|
+
def self.dump(*args)
|
4
|
+
MultiJson.dump(*args)
|
5
|
+
end
|
15
6
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
7
|
+
def self.load(*args)
|
8
|
+
MultiJson.load(*args)
|
19
9
|
end
|
20
10
|
end
|
21
11
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Eligible
|
5
|
+
class Lockbox < APIResource
|
6
|
+
def self.get(params, opts = {})
|
7
|
+
send_request :get, api_url('lockboxes', params, :lockbox_id), params, opts.merge(required_params: [:lockbox_id])
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.all(params, opts = {})
|
11
|
+
send_request :get, api_url('lockboxes'), params, opts
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.extract_private_key(params)
|
15
|
+
private_key = Util.value(params, :private_key)
|
16
|
+
fail ArgumentError, "Private key is required for decryption" if private_key.nil?
|
17
|
+
private_key
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.delete_private_key!(params)
|
21
|
+
params.delete('private_key')
|
22
|
+
params.delete(:private_key)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.decrypt_data(data, encrypted_data_key, private_key)
|
26
|
+
pkey = OpenSSL::PKey::RSA.new(private_key)
|
27
|
+
aes_key = pkey.private_decrypt(Base64.decode64(encrypted_data_key))
|
28
|
+
sha_key = Digest::SHA256.hexdigest(aes_key)
|
29
|
+
Encryptor.decrypt(value: Base64.decode64(data), key: sha_key, insecure_mode: true)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.get_and_decrypt_from_lockbox(params, opts = {})
|
33
|
+
private_key = extract_private_key(params)
|
34
|
+
delete_private_key!(params)
|
35
|
+
req = get(params, opts).to_hash
|
36
|
+
decrypt_data(req[:encrypted_data], req[:encrypted_key], private_key)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/eligible/ocr.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Eligible
|
2
|
+
class Ocr < APIResource
|
3
|
+
def self.setup_file(params)
|
4
|
+
file = Util.value(params, :file)
|
5
|
+
params[:file] = File.new(file, 'rb') if file.is_a?(String)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.post(params, opts = {})
|
9
|
+
setup_file(params)
|
10
|
+
send_request :post, '/card_scans.json', params, opts
|
11
|
+
end
|
12
|
+
|
13
|
+
private_class_method :setup_file
|
14
|
+
end
|
15
|
+
end
|