uid2 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca62bf4baf03040acd589422b287455bf830b29b7169754a18dd8191dc031e4f
4
- data.tar.gz: 34f3b2736cc70383184cb69ea742e73469e06a274cabfcb53275081698cdc982
3
+ metadata.gz: 63c73ef45bda732e21922cc4f6a8fab9ed68471f1361cac468bef5199934ceb9
4
+ data.tar.gz: 4fcdfbc699215daddd062b2032fdd5b0640817eca754ea6a584111a893f0df4a
5
5
  SHA512:
6
- metadata.gz: b635f3d73fae3870b3a698f6c2beeffdece28daba803f590324b6f9c6a59d01d441e56b79d13410709bd4555a300149c4c9b40e1041e35c6b5e0653c5b004741
7
- data.tar.gz: 4482a0398dafb9c9af3e438ba837dbb67c0b508f2dead329cd33066b3e9c881aa4d77473fe5a2f1df8d6fc087eb86bcb32add1e8c2a46f82cde5169e7295913d
6
+ metadata.gz: 57d5aa6003cd365972157c588493fbb5b90508e1e681ed3ad5fa563dd814fbabad419129665c07c96b1ae10a516dfd95348de825ede173a8a03bb4f19366dd3c
7
+ data.tar.gz: 838a537bce16ff6d5cb0c24a4373737a7b46dda1309b1d987d8cfcb4032a64454ddb7e8c50c8d7b81751b6a3f58c8f4e0423701c681430b32942e2a6f970f3c5
@@ -10,7 +10,7 @@ jobs:
10
10
  - name: Set up Ruby
11
11
  uses: ruby/setup-ruby@v1
12
12
  with:
13
- ruby-version: 2.7.2
13
+ ruby-version: 3.1.2
14
14
  bundler-cache: true
15
15
  - name: Run the default task
16
16
  run: bundle exec rake
data/Gemfile CHANGED
@@ -2,11 +2,8 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- # Specify your gem's dependencies in uid2.gemspec
6
5
  gemspec
7
6
 
8
- gem "rake", "~> 13.0"
9
-
10
- gem "rspec", "~> 3.0"
11
-
12
- gem "rubocop", "~> 1.7"
7
+ gem "rake"
8
+ gem "rspec"
9
+ gem "standard"
data/Gemfile.lock ADDED
@@ -0,0 +1,96 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ uid2 (0.2.0)
5
+ faraday (>= 1)
6
+ faraday_middleware (>= 1)
7
+ hashie (>= 4)
8
+ net-http-persistent (>= 4)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ ast (2.4.2)
14
+ connection_pool (2.2.5)
15
+ diff-lcs (1.5.0)
16
+ faraday (1.10.0)
17
+ faraday-em_http (~> 1.0)
18
+ faraday-em_synchrony (~> 1.0)
19
+ faraday-excon (~> 1.1)
20
+ faraday-httpclient (~> 1.0)
21
+ faraday-multipart (~> 1.0)
22
+ faraday-net_http (~> 1.0)
23
+ faraday-net_http_persistent (~> 1.0)
24
+ faraday-patron (~> 1.0)
25
+ faraday-rack (~> 1.0)
26
+ faraday-retry (~> 1.0)
27
+ ruby2_keywords (>= 0.0.4)
28
+ faraday-em_http (1.0.0)
29
+ faraday-em_synchrony (1.0.0)
30
+ faraday-excon (1.1.0)
31
+ faraday-httpclient (1.0.1)
32
+ faraday-multipart (1.0.4)
33
+ multipart-post (~> 2)
34
+ faraday-net_http (1.0.1)
35
+ faraday-net_http_persistent (1.2.0)
36
+ faraday-patron (1.0.0)
37
+ faraday-rack (1.0.0)
38
+ faraday-retry (1.0.3)
39
+ faraday_middleware (1.2.0)
40
+ faraday (~> 1.0)
41
+ hashie (5.0.0)
42
+ multipart-post (2.2.3)
43
+ net-http-persistent (4.0.1)
44
+ connection_pool (~> 2.2)
45
+ parallel (1.22.1)
46
+ parser (3.1.2.0)
47
+ ast (~> 2.4.1)
48
+ rainbow (3.1.1)
49
+ rake (13.0.6)
50
+ regexp_parser (2.5.0)
51
+ rexml (3.2.5)
52
+ rspec (3.11.0)
53
+ rspec-core (~> 3.11.0)
54
+ rspec-expectations (~> 3.11.0)
55
+ rspec-mocks (~> 3.11.0)
56
+ rspec-core (3.11.0)
57
+ rspec-support (~> 3.11.0)
58
+ rspec-expectations (3.11.0)
59
+ diff-lcs (>= 1.2.0, < 2.0)
60
+ rspec-support (~> 3.11.0)
61
+ rspec-mocks (3.11.1)
62
+ diff-lcs (>= 1.2.0, < 2.0)
63
+ rspec-support (~> 3.11.0)
64
+ rspec-support (3.11.0)
65
+ rubocop (1.29.1)
66
+ parallel (~> 1.10)
67
+ parser (>= 3.1.0.0)
68
+ rainbow (>= 2.2.2, < 4.0)
69
+ regexp_parser (>= 1.8, < 3.0)
70
+ rexml (>= 3.2.5, < 4.0)
71
+ rubocop-ast (>= 1.17.0, < 2.0)
72
+ ruby-progressbar (~> 1.7)
73
+ unicode-display_width (>= 1.4.0, < 3.0)
74
+ rubocop-ast (1.19.1)
75
+ parser (>= 3.1.1.0)
76
+ rubocop-performance (1.13.3)
77
+ rubocop (>= 1.7.0, < 2.0)
78
+ rubocop-ast (>= 0.4.0)
79
+ ruby-progressbar (1.11.0)
80
+ ruby2_keywords (0.0.5)
81
+ standard (1.12.1)
82
+ rubocop (= 1.29.1)
83
+ rubocop-performance (= 1.13.3)
84
+ unicode-display_width (2.2.0)
85
+
86
+ PLATFORMS
87
+ ruby
88
+
89
+ DEPENDENCIES
90
+ rake
91
+ rspec
92
+ standard
93
+ uid2!
94
+
95
+ BUNDLED WITH
96
+ 2.3.16
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # Uid2
1
+ # UID2 - A Ruby API client for Unified ID 2.0
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/uid2`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ This gem provides an API client for [Unified ID 2.0](https://github.com/UnifiedID2/uid2docs).
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ Current supports UID2 API v2.
6
6
 
7
7
  ## Installation
8
8
 
@@ -12,17 +12,34 @@ Add this line to your application's Gemfile:
12
12
  gem 'uid2'
13
13
  ```
14
14
 
15
- And then execute:
15
+ ## Usage
16
16
 
17
- $ bundle install
17
+ This gem implements every Unified ID 2.0 APIs.
18
18
 
19
- Or install it yourself as:
19
+ To create a client:
20
20
 
21
- $ gem install uid2
21
+ ```ruby
22
+ client = Uid2::Client.new do |client|
23
+ c.bearer_token = "YOUR_TOKEN_HERE"
24
+ c.secret_key = "YOUR_SECRET_KEY_HERE"
25
+ end
26
+ ```
22
27
 
23
- ## Usage
28
+ Then call methods:
29
+
30
+ ```ruby
31
+ # To generate UID2 token
32
+ client.generate_token(email: 'foo@bar.com')
33
+ client.generate_token(phone: '+886912345678')
34
+
35
+ # To map UID2 identity
36
+ client.generate_identifier(email: 'foo@bar.com')
37
+ client.generate_identifier(phone: '+886912345678')
38
+
39
+ # To get salt buckets
40
+ client.get_salt_buckets
41
+ ```
24
42
 
25
- TODO: Write usage instructions here
26
43
 
27
44
  ## Development
28
45
 
@@ -32,7 +49,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
49
 
33
50
  ## Contributing
34
51
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/uid2. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/uid2/blob/main/CODE_OF_CONDUCT.md).
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/polydice/uid2. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/uid2/blob/main/CODE_OF_CONDUCT.md).
36
53
 
37
54
  ## License
38
55
 
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "base64"
5
+ require "hashie/mash"
6
+
7
+ module Faraday
8
+ module Uid2
9
+ class Middleware < Faraday::Middleware
10
+ def initialize(app, secret_key, is_refresh, options = {})
11
+ super(app, options)
12
+
13
+ @key = Base64.decode64(secret_key)
14
+ @is_refresh = is_refresh
15
+ end
16
+
17
+ def call(request_env)
18
+ unless @is_refresh
19
+ @nonce = Random.new.bytes(8)
20
+
21
+ cipher = create_cipher.encrypt
22
+ iv = cipher.random_iv
23
+
24
+ body = request_env.body
25
+ payload = timestamp_bytes + @nonce + body
26
+ encrypted = cipher.update(payload) + cipher.final
27
+ request_env.body = Base64.strict_encode64(["\x1", iv, encrypted, cipher.auth_tag].join)
28
+ end
29
+
30
+ @app.call(request_env).on_complete do |response_env|
31
+ process_response(response_env)
32
+ end
33
+ end
34
+
35
+ def process_response(env)
36
+ resp = Base64.decode64(env.body).unpack("C*")
37
+ iv = resp[0..11].pack("C*")
38
+ cipher_text = resp[12...-16].pack("C*")
39
+ auth_tag = resp[-16...-1].pack("C*")
40
+
41
+ cipher = create_cipher.decrypt
42
+ cipher.iv = iv
43
+ cipher.auth_tag = auth_tag
44
+
45
+ payload = cipher.update(cipher_text) + cipher.final
46
+
47
+ data = if @is_refresh
48
+ payload
49
+ else
50
+ timestamp = Time.at(payload[0..7].unpack1("Q>") / 1000.0)
51
+ raise Faraday::ParsingError.new("Response timestamp is too old", env[:response]) if Time.now - timestamp > 5 * 60
52
+
53
+ nonce = payload[8..15]
54
+ raise Faraday::ParsingError.new("Nonce mismatch", env[:response]) if nonce != @nonce
55
+
56
+ payload[16..]
57
+ end
58
+
59
+ env.response_headers["Content-Type"] = "application/json"
60
+ env.body = Hashie::Mash.new(JSON.parse(data))
61
+ end
62
+
63
+ def timestamp_bytes
64
+ [(Time.now.to_f * 1000).to_i].pack("Q>")
65
+ end
66
+
67
+ def create_cipher
68
+ cipher = OpenSSL::Cipher.new("aes-256-gcm").encrypt
69
+ cipher.padding = 0
70
+ cipher.key = @key
71
+ cipher.auth_data = ""
72
+ cipher
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,8 @@
1
+ require_relative "uid2/middleware"
2
+ require "faraday"
3
+
4
+ module Faraday
5
+ module Uid2
6
+ Faraday::Request.register_middleware uid2_encryption: Middleware
7
+ end
8
+ end
data/lib/uid2/client.rb CHANGED
@@ -3,77 +3,45 @@
3
3
  require "net/http/persistent"
4
4
  require "faraday"
5
5
  require "faraday_middleware"
6
+ require "faraday/uid2"
6
7
  require "time"
7
8
 
8
9
  module Uid2
9
10
  class Client
10
- attr_accessor :bearer_token, :base_url
11
+ attr_accessor :bearer_token, :base_url, :secret_key
11
12
 
12
13
  def initialize(_options = {})
13
14
  yield(self) if block_given?
14
15
 
15
- self.base_url ||= "https://integ.uidapi.com/v1/"
16
+ self.base_url ||= "https://prod.uidapi.com/v2/"
16
17
  end
17
18
 
18
- def generate_token(email: nil, email_hash: nil)
19
- raise ArgumentError, "Either email or email_hash needs to be provided" if email.nil? && email_hash.nil?
20
-
21
- # As stated in doc, if email and email_hash are both supplied in the same request,
22
- # only the email will return a mapping response.
23
- params = if email.empty?
24
- { email_hash: email_hash }
25
- else
26
- { email: email }
27
- end
28
- http.get("token/generate", params).body
19
+ def generate_token(email: nil, email_hash: nil, phone: nil, phone_hash: nil)
20
+ params = {email: email, email_hash: email_hash, phone: phone, phone_hash: phone_hash}.reject { |_, v| v.nil? }
21
+ raise ArgumentError, "One of the argument needs to be provided" if params.empty?
22
+ http.post("token/generate", params).body
29
23
  end
30
24
 
31
- def validate_token(token:, email: nil, email_hash: nil)
32
- raise ArgumentError, "Either email or email_hash needs to be provided" if email.nil? && email_hash.nil?
33
-
34
- params = if email.empty?
35
- { email_hash: email_hash }
36
- else
37
- { email: email }
38
- end
25
+ def validate_token(token:, email: nil, email_hash: nil, phone: nil, phone_hash: nil)
26
+ params = {email: email, email_hash: email_hash, phone: phone, phone_hash: phone_hash}.reject { |_, v| v.nil? }
27
+ raise ArgumentError, "One of the argument needs to be provided" if params.empty?
39
28
 
40
- http.get("token/validate", params.merge(token: token)).body
29
+ http.post("token/validate", params.merge(token: token)).body
41
30
  end
42
31
 
43
- def refresh_token(refresh_token:)
44
- http.get("token/refresh", { refresh_token: refresh_token }).body
32
+ def refresh_token(refresh_token:, refresh_response_key:)
33
+ http(is_refresh: true, refresh_response_key: refresh_response_key).post("token/refresh", refresh_token).body
45
34
  end
46
35
 
47
36
  def get_salt_buckets(since: Time.now)
48
37
  # By default, Ruby's iso8601 generates timezone parts (`T`)
49
38
  # which needs to be removed for UID2 APIs
50
- http.get("identity/buckets", since_timestamp: since.utc.iso8601[0..-2]).body
39
+ http.post("identity/buckets", since_timestamp: since.utc.iso8601[0..-2]).body
51
40
  end
52
41
 
53
- def generate_identifier(email: nil, email_hash: nil)
54
- raise ArgumentError, "Either email or email_hash needs to be provided" if email.nil? && email_hash.nil?
55
-
56
- # As stated in doc, if email and email_hash are both supplied in the same request,
57
- # only the email will return a mapping response.
58
- params = if email.empty?
59
- { email_hash: email_hash }
60
- else
61
- { email: email }
62
- end
63
-
64
- http.get("identity/map", params).body
65
- end
66
-
67
- def batch_generate_identifier(email: nil, email_hash: nil)
68
- raise ArgumentError, "Either email or email_hash needs to be provided" if email.nil? && email_hash.nil?
69
-
70
- # As stated in doc, if email and email_hash are both supplied in the same request,
71
- # only the email will return a mapping response.
72
- params = if email.empty?
73
- { email_hash: Array(email_hash) }
74
- else
75
- { email: Array(email) }
76
- end
42
+ def generate_identifier(email: nil, email_hash: nil, phone: nil, phone_hash: nil)
43
+ params = {email: Array(email), email_hash: Array(email_hash), phone: Array(phone), phone_hash: Array(phone_hash)}.reject { |_, v| v.empty? }
44
+ raise ArgumentError, "One of the argument needs to be provided" if params.empty?
77
45
 
78
46
  http.post("identity/map", params).body
79
47
  end
@@ -86,17 +54,13 @@ module Uid2
86
54
  }
87
55
  end
88
56
 
89
- def http
90
- @http ||= Faraday.new(
57
+ def http(is_refresh: false, refresh_response_key: nil)
58
+ Faraday.new(
91
59
  url: base_url,
92
60
  headers: credentials
93
61
  ) do |f|
94
- f.request :json
95
-
96
- f.response :raise_error
97
- f.response :mashify
98
- f.response :json
99
-
62
+ f.request :json unless refresh_response_key
63
+ f.request :uid2_encryption, refresh_response_key || secret_key, is_refresh
100
64
  f.adapter :net_http_persistent
101
65
  end
102
66
  end
data/lib/uid2/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Uid2
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/uid2.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "uid2/version"
4
+
5
+ require_relative "faraday/uid2"
4
6
  require_relative "uid2/client"
data/uid2.gemspec CHANGED
@@ -3,15 +3,15 @@
3
3
  require_relative "lib/uid2/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "uid2"
7
- spec.version = Uid2::VERSION
8
- spec.authors = ["Richard Lee"]
9
- spec.email = ["14349+dlackty@users.noreply.github.com"]
6
+ spec.name = "uid2"
7
+ spec.version = Uid2::VERSION
8
+ spec.authors = ["Richard Lee"]
9
+ spec.email = ["14349+dlackty@users.noreply.github.com"]
10
10
 
11
- spec.summary = "Ruby API client for Unified ID 2.0"
12
- spec.description = spec.summary
13
- spec.homepage = "https://github.com/polydice/uid2"
14
- spec.license = "MIT"
11
+ spec.summary = "Ruby API client for Unified ID 2.0"
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/polydice/uid2"
14
+ spec.license = "MIT"
15
15
  spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uid2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Lee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-07 00:00:00.000000000 Z
11
+ date: 2022-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -80,11 +80,14 @@ files:
80
80
  - CHANGELOG.md
81
81
  - CODE_OF_CONDUCT.md
82
82
  - Gemfile
83
+ - Gemfile.lock
83
84
  - LICENSE.txt
84
85
  - README.md
85
86
  - Rakefile
86
87
  - bin/console
87
88
  - bin/setup
89
+ - lib/faraday/uid2.rb
90
+ - lib/faraday/uid2/middleware.rb
88
91
  - lib/uid2.rb
89
92
  - lib/uid2/client.rb
90
93
  - lib/uid2/version.rb
@@ -111,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
114
  - !ruby/object:Gem::Version
112
115
  version: '0'
113
116
  requirements: []
114
- rubygems_version: 3.1.4
117
+ rubygems_version: 3.1.6
115
118
  signing_key:
116
119
  specification_version: 4
117
120
  summary: Ruby API client for Unified ID 2.0