incognia_api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5eb3f0cd63a0319c016e88eea0d86fd5892271befa4a28b8c5d8870c21cd27bb
4
+ data.tar.gz: 8439dfd8d7cefe7ee1b7d0c91687d8f062b8809afb7a76798e52de2c792c520a
5
+ SHA512:
6
+ metadata.gz: 88e070f8841a1410117cd527139be05ee19b8e73aea4d1190642f107f97dc181a086b56cbe1c0bfab2bc833d7a0000500b66fc2ce6a3c57b9b0d9e9d58979640
7
+ data.tar.gz: e7d396d6623a7b2f0965e6b430faa5d5aa28d22b137949a2b24c6956840f85787906d6739f342004381cb593f614af8ec5596443e64277a71e6aaf84a994df00
@@ -0,0 +1 @@
1
+ * @guiocavalcanti
@@ -0,0 +1,18 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - name: Set up Ruby
11
+ uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: 3.0.1
14
+ - name: Run the default task
15
+ run: |
16
+ gem install bundler -v 2.2.15
17
+ bundle install
18
+ bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2021-05-28
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in incognia_api.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
11
+
12
+ group :test do
13
+ gem "webmock"
14
+ gem "timecop"
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ incognia_api (0.1.0)
5
+ faraday
6
+ faraday_middleware
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.8.0)
12
+ public_suffix (>= 2.0.2, < 5.0)
13
+ crack (0.4.5)
14
+ rexml
15
+ diff-lcs (1.4.4)
16
+ faraday (1.4.2)
17
+ faraday-em_http (~> 1.0)
18
+ faraday-em_synchrony (~> 1.0)
19
+ faraday-excon (~> 1.1)
20
+ faraday-net_http (~> 1.0)
21
+ faraday-net_http_persistent (~> 1.1)
22
+ multipart-post (>= 1.2, < 3)
23
+ ruby2_keywords (>= 0.0.4)
24
+ faraday-em_http (1.0.0)
25
+ faraday-em_synchrony (1.0.0)
26
+ faraday-excon (1.1.0)
27
+ faraday-net_http (1.0.1)
28
+ faraday-net_http_persistent (1.1.0)
29
+ faraday_middleware (1.0.0)
30
+ faraday (~> 1.0)
31
+ hashdiff (1.0.1)
32
+ multipart-post (2.1.1)
33
+ public_suffix (4.0.6)
34
+ rake (13.0.3)
35
+ rexml (3.2.5)
36
+ rspec (3.10.0)
37
+ rspec-core (~> 3.10.0)
38
+ rspec-expectations (~> 3.10.0)
39
+ rspec-mocks (~> 3.10.0)
40
+ rspec-core (3.10.1)
41
+ rspec-support (~> 3.10.0)
42
+ rspec-expectations (3.10.1)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.10.0)
45
+ rspec-mocks (3.10.2)
46
+ diff-lcs (>= 1.2.0, < 2.0)
47
+ rspec-support (~> 3.10.0)
48
+ rspec-support (3.10.2)
49
+ ruby2_keywords (0.0.4)
50
+ timecop (0.9.4)
51
+ webmock (3.14.0)
52
+ addressable (>= 2.8.0)
53
+ crack (>= 0.3.2)
54
+ hashdiff (>= 0.4.0, < 2.0.0)
55
+
56
+ PLATFORMS
57
+ ruby
58
+ x86_64-darwin-20
59
+
60
+ DEPENDENCIES
61
+ incognia_api!
62
+ rake (~> 13.0)
63
+ rspec (~> 3.0)
64
+ timecop
65
+ webmock
66
+
67
+ BUNDLED WITH
68
+ 2.3.7
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Incognia Ruby Library
2
+
3
+ [![Ruby](https://github.com/inloco/incognia-ruby/actions/workflows/main.yml/badge.svg)](https://github.com/inloco/incognia-ruby/actions/workflows/main.yml)
4
+
5
+ Incognia Ruby library provides easy access to the Incogia API from Ruby
6
+ applications. It includes:
7
+
8
+ - Basic Access Token management (with transparent token refresh)
9
+ - API resounces dinamically built from API responses
10
+
11
+ For more information on how to integrate Incognia APIs, refer to one of the
12
+ following guides:
13
+
14
+ - Address verification on user onboarding
15
+ - Protecting app logins
16
+ - Secure and frictionless device change
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'incognia_api'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle install
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install incognia_api
33
+
34
+ ## Usage
35
+
36
+ ### Configuration
37
+
38
+ Before using the API client, you must initialize it using credentials obtained
39
+ from the [Incognia dashboard]():
40
+
41
+ ```ruby
42
+ api = Incognia::Api.new(client_id: "your-client-id", client_secret:
43
+ "your-client-secret")
44
+
45
+ ```
46
+
47
+ For sandbox credentials, refer to the [API testing guide]().
48
+
49
+
50
+ ### Registering a Signup
51
+
52
+ This method registers a new signup for the given installation and address, returning a signup assessment, containing the risk assessment and supporting evidence:
53
+
54
+ ```ruby
55
+ address = Incognia::Address.new(line: "West 34th Street, New York City, NY 10001")
56
+ installation_id = "WlMksW+jh5GPhqWBorsV8yDihoSHHpmt+DpjJ7eYxpHhuO/5tuHTuA..."
57
+
58
+ assessment = api.register_signup(
59
+ installation_id: installation_id,
60
+ address: address
61
+ )
62
+
63
+ # => #<OpenStruct id="...", request_id="...", device_id="...", risk_assessment="..", evidence=...>
64
+
65
+ ```
66
+
67
+ ### Getting a Signup
68
+
69
+ This method allows you to query the latest assessment for a given signup event, returning signup assessment, containing the risk assessment and supporting evidence:
70
+
71
+ ```ruby
72
+ assessment = api.get_signup_assessment(signup_id: "95a9fc56-f65e-436b-a87f-a1338043678f")
73
+
74
+ # => #<OpenStruct id="...", request_id="...", device_id="...", risk_assessment="..", evidence=...>
75
+
76
+ ```
77
+
78
+ ## Exception handling
79
+
80
+ Every method call can throw `APIError` and `APIAuthenticationError`.
81
+
82
+ `APIError` is thrown when the API returned an unexpected http status code or if something goes wrong with the request (network failure, for example). You can retrieve it by calling the `status` method in the exception, along with the `errors` method, which returns the api response payload, which might include additional details. As any subclass of `StandardError` it also responds to `message`.
83
+
84
+ `APIAuthenticationError` indicates that the credentials used to authenticate were considered invalid by the API.
85
+
86
+ ## How to Contribute
87
+
88
+ If you have found a bug or if you have a feature request, please report them at this repository issues section.
89
+
90
+ ### Development
91
+
92
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
93
+
94
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
95
+
96
+ ## License
97
+
98
+ The gem is available as open source under the terms of the [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: %i[spec]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "incognia"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,101 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://incognia.inloco.com.br/api/v2/token
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v1.4.2
12
+ Authorization:
13
+ - Basic R1BXSzFMQ1paSW8xRkxPQ0NuTExNcU44UWkxSHYzazQ6RUxHOV8yazU5T0hkMUdiVXhIaGRTdGtqZUI3TXlQZ21vRjhlR2YxM0xBMU1scmZRZ1Q1bkhFMmFIaVNobVc0WA==
14
+ Content-Type:
15
+ - application/x-www-form-urlencoded
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ date:
22
+ - Fri, 28 May 2021 18:35:32 GMT
23
+ content-type:
24
+ - application/json
25
+ transfer-encoding:
26
+ - chunked
27
+ connection:
28
+ - keep-alive
29
+ cf-cache-status:
30
+ - DYNAMIC
31
+ cf-request-id:
32
+ - 0a55dba85a0000db787b9d4000000001
33
+ expect-ct:
34
+ - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
35
+ report-to:
36
+ - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v2?s=TNlC7ygzRcV1NVUH05toX7rM1LCh0iEmsEwDAp%2Bmruqc6hMLyH%2Bb4cUreSYsSI96oTX%2FVfOnOzWPNZ5eYZwGww6giYqd97ZXMHfLpU7A%2BuiFoCyVeeqTCIRgsmZ1O787%2F2rN"}],"group":"cf-nel","max_age":604800}'
37
+ nel:
38
+ - '{"report_to":"cf-nel","max_age":604800}'
39
+ strict-transport-security:
40
+ - max-age=15552000; includeSubDomains; preload
41
+ x-content-type-options:
42
+ - nosniff
43
+ server:
44
+ - cloudflare
45
+ cf-ray:
46
+ - 65699553cdf2db78-GIG
47
+ alt-svc:
48
+ - h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
49
+ body:
50
+ encoding: ASCII-8BIT
51
+ string: '{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJFVkNPVGMwTkVaRk9EVTFNekUzTlVRMFEwSTNNekZDTVVFeE5ESkdSREJHUWpkQlFVSTVNUSJ9.eyJodHRwczovL2FjY291bnRzL29yZ2FuaXphdGlvbl9pZCI6IjQ5MSIsImlzcyI6Imh0dHBzOi8vaW5sb2NvLXByb2R1Y3Rpb24uYXV0aDAuY29tLyIsInN1YiI6IkdQV0sxTENaWklvMUZMT0NDbkxMTXFOOFFpMUh2M2s0QGNsaWVudHMiLCJhdWQiOiJodHRwczovL2luY29nbmlhLmlubG9jby5jb20uYnIiLCJpYXQiOjE2MjIyMjY5MzIsImV4cCI6MTYyMjIyODEzMiwiYXpwIjoiR1BXSzFMQ1paSW8xRkxPQ0NuTExNcU44UWkxSHYzazQiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.Csc3cJ4eqzqR4s-aLh5Qvdl41LrTyD2DnBe3iNv4gtwzAVqRD6rdTxZAfKzWwOdYZ91bw0o1aCVN7MA3fGj6dUqkgtylvCFdWVTU5xWlW6ugaZ6VMRuPmJkD0DkZuctjXkFl_Um9mw-_M-84CqSvrVqFHDK_AJrdymztcsc_aoFKVMDLFgn-gHBNT9TchLatePHFeRKa6S3IaevcR900DiAmeU4_BKvVYc_TlhS4iIJGwIXUNX4V2x-76CxSs6aFFJD3t76x1GehGdrjmxzis-ciWZrhflSWSFq_2M4kWFiCIiCgiFe0pln0JUG-u9Hm5yu5S3dPJ46Br3kg8MOZJQ","expires_in":"1200","token_type":"Bearer"}'
52
+ recorded_at: Fri, 28 May 2021 18:35:30 GMT
53
+ - request:
54
+ method: post
55
+ uri: https://incognia.inloco.com.br/api/onboarding/signups
56
+ body:
57
+ encoding: UTF-8
58
+ string: '{"installation_id":"xyz"}'
59
+ headers:
60
+ User-Agent:
61
+ - Faraday v1.4.2
62
+ Authorization:
63
+ - Bearer access_token
64
+ Content-Type:
65
+ - application/json
66
+ response:
67
+ status:
68
+ code: 401
69
+ message: Unauthorized
70
+ headers:
71
+ date:
72
+ - Fri, 28 May 2021 18:35:33 GMT
73
+ transfer-encoding:
74
+ - chunked
75
+ connection:
76
+ - keep-alive
77
+ cf-cache-status:
78
+ - DYNAMIC
79
+ cf-request-id:
80
+ - 0a55dbadde000009d0c5074000000001
81
+ expect-ct:
82
+ - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
83
+ report-to:
84
+ - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v2?s=wRYcemb6TiPJlpWuANxj0o5Qq05jbH3gynAJX%2FNI8ErLVVffL65N7zUFJfOhFs1U9bUZqEUCkKOgJaD%2B%2FKYe%2FjeL4oPo%2FGyc3Ax1vvz4TCIOTEVMpRd%2FcCO1J11ulga8bve0"}],"group":"cf-nel","max_age":604800}'
85
+ nel:
86
+ - '{"report_to":"cf-nel","max_age":604800}'
87
+ strict-transport-security:
88
+ - max-age=15552000; includeSubDomains; preload
89
+ x-content-type-options:
90
+ - nosniff
91
+ server:
92
+ - cloudflare
93
+ cf-ray:
94
+ - 6569955c9fcd09d0-GIG
95
+ alt-svc:
96
+ - h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
97
+ body:
98
+ encoding: UTF-8
99
+ string: ''
100
+ recorded_at: Fri, 28 May 2021 18:35:31 GMT
101
+ recorded_with: VCR 6.0.0
data/incognia.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/incognia/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "incognia_api"
7
+ spec.version = Incognia::VERSION
8
+ spec.authors = ["Guilherme Cavalcanti"]
9
+ spec.email = ["guiocavalcanti@gmail.com"]
10
+
11
+ spec.summary = "Official Ruby lib for communicating with Incognia API"
12
+ spec.description = "Official Ruby lib for communicating with Incognia API"
13
+ spec.homepage = "https://github.com/inloco/incognia-api-ruby"
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/inloco/incognia-api-ruby"
18
+ spec.metadata["changelog_uri"] = "https://github.com/inloco/incognia-api-ruby/blob/master/"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ # Uncomment to register a new dependency of your gem
30
+ # spec.add_dependency "example-gem", "~> 1.0"
31
+ spec.add_dependency('faraday')
32
+ spec.add_dependency('faraday_middleware')
33
+
34
+ # For more information and examples about making a new gem, checkout our
35
+ # guide at: https://bundler.io/guides/creating_gem.html
36
+ end
@@ -0,0 +1,108 @@
1
+ require "ostruct"
2
+
3
+ module Incognia
4
+ class Address
5
+ attr_reader :line, :coordinates, :structured
6
+
7
+ class Line
8
+ def initialize(address)
9
+ @address = address
10
+ end
11
+
12
+ def to_hash
13
+ { address_line: @address }
14
+ end
15
+ end
16
+
17
+ class Coordinates
18
+ def initialize(lat:, lng:)
19
+ @lat, @lng = lat, lng
20
+ end
21
+
22
+ def to_hash
23
+ { address_coordinates: { lat: @lat, lng: @lng } }
24
+ end
25
+ end
26
+
27
+ class Structured
28
+ attr_reader :locale, :country_name, :country_code, :state, :city, :borough,
29
+ :neighborhood, :state, :city, :borough, :neighborhood, :postal_code,
30
+ :street, :number, :complements
31
+
32
+ def initialize(locale: nil, country_name: nil, country_code: nil, \
33
+ state: nil, city: nil, borough: nil, neighborhood: nil, \
34
+ postal_code: nil, street: nil, number: nil, complements: nil)
35
+
36
+ @locale = locale
37
+ @country_name = country_name
38
+ @country_code = country_code
39
+ @state = state
40
+ @city = city
41
+ @borough = borough
42
+ @neighborhood = neighborhood
43
+ @postal_code = postal_code
44
+ @street = street
45
+ @number = number
46
+ @complements = complements
47
+ end
48
+
49
+ def to_hash
50
+ {
51
+ structured_address: {
52
+ locale: locale,
53
+ country_name: country_name,
54
+ country_code: country_code,
55
+ state: state,
56
+ city: city,
57
+ borough: borough,
58
+ neighborhood: neighborhood,
59
+ street: street,
60
+ number: number,
61
+ complements: complements,
62
+ postal_code: postal_code
63
+ }.select { |_,v| !v.nil? }
64
+ }
65
+ end
66
+ end
67
+
68
+ FORMATS = [:line, :coordinates, :structured].freeze
69
+
70
+ def initialize(line: nil, coordinates: {}, structured: {})
71
+ coordinates = Util.symbolize_names(coordinates)
72
+ structured = Util.symbolize_names(structured)
73
+
74
+ if line.nil? && coordinates.empty? && structured.empty?
75
+ raise ArgumentError.new(
76
+ "missing keyword: should be one of #{FORMATS.join(', ')}"
77
+ )
78
+ end
79
+
80
+ @line = build_line(line)
81
+ @coordinates = build_coordinates(coordinates)
82
+ @structured = build_structured(structured)
83
+ end
84
+
85
+ def to_hash
86
+ hash = {}
87
+ hash.merge!(@line.to_hash)
88
+ hash.merge!(@coordinates.to_hash)
89
+ hash.merge!(@structured.to_hash)
90
+ hash
91
+ end
92
+
93
+ protected
94
+
95
+ def build_coordinates(hash)
96
+ hash.empty? ? hash : Coordinates.new(**hash)
97
+ end
98
+
99
+ def build_line(raw_line = nil)
100
+ raw_line ? Line.new(raw_line) : {}
101
+ end
102
+
103
+ def build_structured(hash)
104
+ hash.empty? ? hash : Structured.new(**hash)
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,39 @@
1
+ require "faraday"
2
+ require "json"
3
+ require "logger"
4
+ require 'faraday_middleware'
5
+
6
+ module Incognia
7
+ class Api
8
+ # business layer: uses the Client to build domain objects
9
+ # raises missing parameters errors
10
+ attr_accessor :connection
11
+
12
+ def initialize(client_id:, client_secret:)
13
+ @connection = Client.new(client_id: client_id,
14
+ client_secret: client_secret,
15
+ host: "https://api.incognia.com/api")
16
+ end
17
+
18
+ def register_signup(installation_id:, address: )
19
+ response = connection.request(
20
+ :post,
21
+ 'v2/onboarding/signups',
22
+ installation_id: installation_id,
23
+ **address.to_hash
24
+ )
25
+
26
+ SignupAssessment.from_hash(response.body) if response.success?
27
+ end
28
+
29
+ def get_signup_assessment(signup_id:)
30
+ response = connection.request(
31
+ :get,
32
+ "v2/onboarding/signups/#{signup_id}"
33
+ )
34
+
35
+ SignupAssessment.from_hash(response.body) if response.success?
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,74 @@
1
+ require "time"
2
+
3
+ module Incognia
4
+ class Client
5
+ # TODO:
6
+ # (ok) http/adapter specific code
7
+ # (ok) raises network/authentication errors
8
+ # (ok) handles token refreshing ok
9
+ # future: handles retrying
10
+ attr_reader :connection
11
+
12
+ def initialize(client_id:, client_secret:, host:)
13
+ @client_id = client_id
14
+ @client_secret = client_secret
15
+ @host = host
16
+
17
+ @connection = Faraday.new(host) do |faraday|
18
+ faraday.adapter Faraday.default_adapter
19
+ faraday.request :json
20
+ faraday.response :json, content_type: /\bjson$/
21
+ # faraday.response :logger, nil, { headers: true, bodies: true }
22
+ faraday.response :raise_error
23
+ end
24
+ end
25
+
26
+ def request(method, endpoint = nil, data = nil, headers = {})
27
+ connection.send(method, endpoint, data, headers) do |r|
28
+ r.headers[Faraday::Request::Authorization::KEY] ||= Faraday::Request
29
+ .lookup_middleware(:authorization)
30
+ .header(:Bearer, credentials.access_token)
31
+ end
32
+ rescue Faraday::ClientError, Faraday::ServerError => e
33
+ raise APIError.new(e.to_s, e.response)
34
+ rescue Faraday::Error => e
35
+ raise APIError.new(e.to_s)
36
+ end
37
+
38
+ def credentials
39
+ @credentials = request_credentials if @credentials.nil? || @credentials.stale?
40
+
41
+ @credentials
42
+ end
43
+
44
+ protected
45
+
46
+ def request_credentials
47
+ basic_auth = Faraday::Request
48
+ .lookup_middleware(:basic_auth)
49
+ .header(@client_id, @client_secret)
50
+
51
+ response = connection.send(:post, 'v2/token') do |r|
52
+ r.headers[Faraday::Request::Authorization::KEY] = basic_auth
53
+ end
54
+
55
+ response.success? ? build_credentials(response) : nil
56
+ rescue Faraday::UnauthorizedError => e
57
+ raise APIAuthenticationError
58
+ rescue Faraday::Error => e
59
+ raise APIError.new(e.to_s)
60
+ end
61
+
62
+ def build_credentials(raw_response)
63
+ body = raw_response.body
64
+ response_date = raw_response.headers['Date']
65
+
66
+ properties = body.merge(
67
+ generated_at: response_date ? Time.parse(response_date) : Time.now
68
+ )
69
+
70
+ Credentials.from_hash(properties)
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,13 @@
1
+ require 'delegate'
2
+
3
+ module Incognia
4
+ class APIResource < SimpleDelegator
5
+ def self.from_hash(hash)
6
+ hash = hash.each_with_object({}) do |(k, v), h|
7
+ h[k] = v.is_a?(Hash) ? from_hash(v) : v
8
+ end
9
+
10
+ new(OpenStruct.new(hash))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'ostruct'
2
+
3
+ module Incognia
4
+ class Credentials < APIResource
5
+ STALE_BEFORE = 10
6
+
7
+ def stale?
8
+ Time.now >= (generated_at + expires_in.to_i - STALE_BEFORE)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "api_resource"
2
+
3
+ module Incognia
4
+ class SignupAssessment < APIResource; end
5
+ end
@@ -0,0 +1,19 @@
1
+ module Incognia
2
+ module Util
3
+ def self.symbolize_names(object)
4
+ case object
5
+ when Hash
6
+ new_hash = {}
7
+ object.each do |key, value|
8
+ key = (begin key.to_sym; rescue StandardError; key end) || key
9
+ new_hash[key] = symbolize_names(value)
10
+ end
11
+ new_hash
12
+ when Array
13
+ object.map { |value| symbolize_names(value) }
14
+ else
15
+ object
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Incognia
4
+ VERSION = "0.1.0"
5
+ end
data/lib/incognia.rb ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "incognia/version"
4
+ require_relative "incognia/client"
5
+ require_relative "incognia/util"
6
+ require_relative "incognia/address"
7
+ require_relative "incognia/api"
8
+
9
+ require_relative "incognia/resources/api_resource"
10
+ require_relative "incognia/resources/signup_assessment"
11
+ require_relative "incognia/resources/credentials"
12
+
13
+ module Incognia
14
+ class APIError < StandardError
15
+ attr_reader :message, :errors, :status
16
+
17
+ def initialize(message, response_info = {})
18
+ @status = response_info[:status]
19
+ @errors = response_info[:body]
20
+ @message = format_message(message)
21
+ end
22
+
23
+ def to_s
24
+ message
25
+ end
26
+
27
+ def format_message(initial_message)
28
+ message = "[HTTP #{status}]: #{initial_message}"
29
+ message += "\n#{errors}" if errors
30
+ end
31
+ end
32
+
33
+ class APIAuthenticationError < StandardError
34
+ def to_s
35
+ "Informed credentials failed"
36
+ end
37
+ end
38
+ # Your code goes here...
39
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: incognia_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Guilherme Cavalcanti
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-04-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday_middleware
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Official Ruby lib for communicating with Incognia API
42
+ email:
43
+ - guiocavalcanti@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".github/CODEOWNERS"
49
+ - ".github/workflows/main.yml"
50
+ - ".gitignore"
51
+ - ".rspec"
52
+ - CHANGELOG.md
53
+ - Gemfile
54
+ - Gemfile.lock
55
+ - README.md
56
+ - Rakefile
57
+ - bin/console
58
+ - bin/setup
59
+ - fixtures/vcr_cassettes/token.yml
60
+ - incognia.gemspec
61
+ - lib/incognia.rb
62
+ - lib/incognia/address.rb
63
+ - lib/incognia/api.rb
64
+ - lib/incognia/client.rb
65
+ - lib/incognia/resources/api_resource.rb
66
+ - lib/incognia/resources/credentials.rb
67
+ - lib/incognia/resources/signup_assessment.rb
68
+ - lib/incognia/util.rb
69
+ - lib/incognia/version.rb
70
+ homepage: https://github.com/inloco/incognia-api-ruby
71
+ licenses: []
72
+ metadata:
73
+ homepage_uri: https://github.com/inloco/incognia-api-ruby
74
+ source_code_uri: https://github.com/inloco/incognia-api-ruby
75
+ changelog_uri: https://github.com/inloco/incognia-api-ruby/blob/master/
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.4.0
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.2.3
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Official Ruby lib for communicating with Incognia API
95
+ test_files: []