magic-admin 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/ISSUE_TEMPLATE/question.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +23 -0
- data/.gitignore +7 -0
- data/.rspec +6 -0
- data/.rubocop.yml +45 -0
- data/CHANGELOG.md +17 -0
- data/CONTRIBUTING.md +142 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +73 -0
- data/bin/magic-console +14 -0
- data/lib/magic-admin.rb +135 -0
- data/lib/magic-admin/config.rb +71 -0
- data/lib/magic-admin/errors.rb +98 -0
- data/lib/magic-admin/http/client.rb +136 -0
- data/lib/magic-admin/http/request.rb +89 -0
- data/lib/magic-admin/http/response.rb +95 -0
- data/lib/magic-admin/resource/token.rb +146 -0
- data/lib/magic-admin/resource/user.rb +130 -0
- data/lib/magic-admin/util.rb +61 -0
- data/lib/magic-admin/version.rb +5 -0
- data/magic-admin.gemspec +36 -0
- data/test/http/client_test.rb +79 -0
- data/test/http/request_test.rb +52 -0
- data/test/http/response_test.rb +192 -0
- data/test/magic_test.rb +124 -0
- data/test/resource/token_test.rb +187 -0
- data/test/resource/user_test.rb +98 -0
- data/test/spec_helper.rb +48 -0
- data/test/util_test.rb +42 -0
- metadata +140 -15
data/bin/magic-console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "irb"
|
5
|
+
require "irb/completion"
|
6
|
+
require "byebug"
|
7
|
+
require "#{::File.dirname(__FILE__)}/../lib/magic-admin"
|
8
|
+
|
9
|
+
# Config IRB to enable --simple-prompt and auto indent
|
10
|
+
IRB.conf[:PROMPT_MODE] = :SIMPLE
|
11
|
+
IRB.conf[:AUTO_INDENT] = true
|
12
|
+
|
13
|
+
puts "Loaded gem 'magic-admin'"
|
14
|
+
IRB.start
|
data/lib/magic-admin.rb
CHANGED
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Magic Ruby bindings
|
4
|
+
require "etc"
|
5
|
+
require "json"
|
6
|
+
require "net/http"
|
7
|
+
require "uri"
|
8
|
+
require "base64"
|
9
|
+
require "eth"
|
10
|
+
|
11
|
+
# Version
|
12
|
+
require "magic-admin/version"
|
13
|
+
|
14
|
+
# Magic API Classes
|
15
|
+
require "magic-admin/util"
|
16
|
+
require "magic-admin/config"
|
17
|
+
require "magic-admin/errors"
|
18
|
+
|
19
|
+
# HTTP Classes
|
20
|
+
require "magic-admin/http/client"
|
21
|
+
require "magic-admin/http/request"
|
22
|
+
require "magic-admin/http/response"
|
23
|
+
|
24
|
+
# Magic Resource Classes
|
25
|
+
require "magic-admin/resource/token"
|
26
|
+
require "magic-admin/resource/user"
|
27
|
+
|
28
|
+
# Magic Class to access resources
|
29
|
+
class Magic
|
30
|
+
RETRIES = 3
|
31
|
+
TIMEOUT = 5
|
32
|
+
BACKOFF = 0.02
|
33
|
+
|
34
|
+
# attribute reader for magic api secret key
|
35
|
+
attr_reader :secret_key
|
36
|
+
|
37
|
+
# attribute reader for magic http client
|
38
|
+
attr_reader :http_client
|
39
|
+
|
40
|
+
# The constructor allows you to specify your own API secret key
|
41
|
+
# and HTTP request strategy when your application interacting
|
42
|
+
# with the Magic API.
|
43
|
+
#
|
44
|
+
# It will automatically configure required arguments
|
45
|
+
# using the following environment variables
|
46
|
+
# MAGIC_API_SECRET_KEY
|
47
|
+
# MAGIC_API_RETRIES
|
48
|
+
# MAGIC_API_TIMEOUT
|
49
|
+
# MAGIC_API_BACKOFF
|
50
|
+
#
|
51
|
+
# Arguments:
|
52
|
+
# api_secret_key: Your API Secret Key retrieved from the Magic Dashboard.
|
53
|
+
# retries: Total number of retries to allow.
|
54
|
+
# timeout: A period of time the request is going to wait for a response.
|
55
|
+
# backoff: A backoff factor to apply between retry attempts.
|
56
|
+
#
|
57
|
+
# Returns:
|
58
|
+
# A Magic object that provides access to all the supported resources.
|
59
|
+
#
|
60
|
+
# Examples:
|
61
|
+
#
|
62
|
+
# Magic.new
|
63
|
+
# Magic.new api_secret_key: "SECRET_KEY>"
|
64
|
+
# Magic.new api_secret_key: "SECRET_KEY>",
|
65
|
+
# retries: 2,
|
66
|
+
# timeout: 2,
|
67
|
+
# backoff: 0.2
|
68
|
+
#
|
69
|
+
#
|
70
|
+
|
71
|
+
def initialize(api_secret_key: nil,
|
72
|
+
retries: nil,
|
73
|
+
timeout: nil,
|
74
|
+
backoff: nil)
|
75
|
+
secret_key!(api_secret_key)
|
76
|
+
http_client!(retries, timeout, backoff)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Description:
|
80
|
+
# Method provides you User object
|
81
|
+
# for interacting with the Magic API.
|
82
|
+
#
|
83
|
+
# Returns:
|
84
|
+
# A User object that provides access to
|
85
|
+
# all the supported resources.
|
86
|
+
|
87
|
+
def user
|
88
|
+
MagicAdmin::Resource::User.new(self)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Description:
|
92
|
+
# Method provides you Token object
|
93
|
+
# for various utility methods of Token.
|
94
|
+
#
|
95
|
+
# Returns:
|
96
|
+
# A Token object that provides access to
|
97
|
+
# all the supported resources.
|
98
|
+
|
99
|
+
def token
|
100
|
+
MagicAdmin::Resource::Token.new
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def secret_key?
|
106
|
+
!(secret_key.nil? || secret_key.empty?)
|
107
|
+
end
|
108
|
+
|
109
|
+
def secret_key!(api_secret_key)
|
110
|
+
@secret_key = api_secret_key || ENV["MAGIC_API_SECRET_KEY"]
|
111
|
+
message = "Magic api secret key was not found."
|
112
|
+
|
113
|
+
raise MagicAdmin::MagicError, message unless secret_key?
|
114
|
+
end
|
115
|
+
|
116
|
+
def configure_retries(retries)
|
117
|
+
retries || ENV["MAGIC_API_RETRIES"] || RETRIES
|
118
|
+
end
|
119
|
+
|
120
|
+
def configure_timeout(timeout)
|
121
|
+
timeout || ENV["MAGIC_API_TIMEOUT"] || TIMEOUT
|
122
|
+
end
|
123
|
+
|
124
|
+
def configure_backoff(backoff)
|
125
|
+
backoff || ENV["MAGIC_API_BACKOFF"] || BACKOFF
|
126
|
+
end
|
127
|
+
|
128
|
+
def http_client!(retries, timeout, backoff)
|
129
|
+
@http_client = MagicAdmin::Http::Client
|
130
|
+
.new(MagicAdmin::Config.api_base,
|
131
|
+
configure_retries(retries),
|
132
|
+
configure_timeout(timeout),
|
133
|
+
configure_backoff(backoff))
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicAdmin
|
4
|
+
|
5
|
+
module Config
|
6
|
+
|
7
|
+
# Description:
|
8
|
+
# Method provides you platform information
|
9
|
+
#
|
10
|
+
# Returns:
|
11
|
+
# user platform information
|
12
|
+
def self.platform
|
13
|
+
RUBY_PLATFORM
|
14
|
+
end
|
15
|
+
|
16
|
+
# Description:
|
17
|
+
# Method provides you sdk programming language
|
18
|
+
#
|
19
|
+
# Returns:
|
20
|
+
# sdk programming language
|
21
|
+
def self.language
|
22
|
+
"ruby"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Description:
|
26
|
+
# Method provides you sdk programming language version
|
27
|
+
#
|
28
|
+
# Returns:
|
29
|
+
# sdk programming language version
|
30
|
+
def self.language_version
|
31
|
+
RUBY_VERSION
|
32
|
+
end
|
33
|
+
|
34
|
+
# Description:
|
35
|
+
# Method provides you installation machine user_name
|
36
|
+
#
|
37
|
+
# Returns:
|
38
|
+
# installation machine user_name
|
39
|
+
def self.user_name
|
40
|
+
Etc.getpwnam(Etc.getlogin).gecos.split(/,/).first
|
41
|
+
end
|
42
|
+
|
43
|
+
# Description:
|
44
|
+
# Method provides you sdk publisher name
|
45
|
+
#
|
46
|
+
# Returns:
|
47
|
+
# sdk publisher name
|
48
|
+
def self.publisher
|
49
|
+
"MagicLabs"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Description:
|
53
|
+
# Method provides you api base url
|
54
|
+
#
|
55
|
+
# Returns:
|
56
|
+
# api base url
|
57
|
+
def self.api_base
|
58
|
+
"https://api.magic.link"
|
59
|
+
end
|
60
|
+
|
61
|
+
# Description:
|
62
|
+
# Method provides you nbf grace period
|
63
|
+
#
|
64
|
+
# Returns:
|
65
|
+
# nbf grace period
|
66
|
+
def self.nbf_grace_period
|
67
|
+
300
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicAdmin
|
4
|
+
|
5
|
+
# MagicAdmin::MagicError class
|
6
|
+
class MagicError < StandardError
|
7
|
+
|
8
|
+
# attribute reader for error message
|
9
|
+
attr_reader :message
|
10
|
+
|
11
|
+
# Description:
|
12
|
+
# The constructor allows you to specify error message
|
13
|
+
#
|
14
|
+
# Arguments:
|
15
|
+
# message: error message.
|
16
|
+
def initialize(message)
|
17
|
+
@message = message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# MagicAdmin::MagicError class
|
22
|
+
class DIDTokenError < MagicError; end
|
23
|
+
|
24
|
+
# RequestError Class
|
25
|
+
class RequestError < MagicError
|
26
|
+
# attribute reader for http response status
|
27
|
+
attr_reader :http_status
|
28
|
+
|
29
|
+
# attribute reader for http response code
|
30
|
+
attr_reader :http_code
|
31
|
+
|
32
|
+
# attribute reader for http response
|
33
|
+
attr_reader :http_response
|
34
|
+
|
35
|
+
# attribute reader for http response message
|
36
|
+
attr_reader :http_message
|
37
|
+
|
38
|
+
# attribute reader for http response error code
|
39
|
+
attr_reader :http_error_code
|
40
|
+
|
41
|
+
# attribute reader for http request params
|
42
|
+
attr_reader :http_request_params
|
43
|
+
|
44
|
+
# attribute reader for http request data
|
45
|
+
attr_reader :http_request_data
|
46
|
+
|
47
|
+
# attribute reader for http request method
|
48
|
+
attr_reader :http_method
|
49
|
+
|
50
|
+
# Description:
|
51
|
+
# The constructor allows you to specify error message
|
52
|
+
# and HTTP request and response info
|
53
|
+
#
|
54
|
+
# Arguments:
|
55
|
+
# message: request error message.
|
56
|
+
# opt: hash of request and response info of following keys:
|
57
|
+
# http_status
|
58
|
+
# http_code
|
59
|
+
# http_response
|
60
|
+
# http_message
|
61
|
+
# http_error_code
|
62
|
+
# http_request_params
|
63
|
+
# http_request_data
|
64
|
+
# http_method
|
65
|
+
# Returns:
|
66
|
+
# A Error object that provides additional error info for magic api call.
|
67
|
+
def initialize(message, opt = {})
|
68
|
+
super(message)
|
69
|
+
@http_status = opt[:http_status]
|
70
|
+
@http_code = opt[:http_code]
|
71
|
+
@http_response = opt[:http_response]
|
72
|
+
@http_message = opt[:http_message]
|
73
|
+
@http_error_code = opt[:http_error_code]
|
74
|
+
@http_request_params = opt[:http_request_params]
|
75
|
+
@http_request_data = opt[:http_request_data]
|
76
|
+
@http_method = opt[:http_method]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# MagicAdmin::MagicError class
|
81
|
+
class APIConnectionError < RequestError; end
|
82
|
+
|
83
|
+
# MagicAdmin::RateLimitingError class
|
84
|
+
class RateLimitingError < RequestError; end
|
85
|
+
|
86
|
+
# MagicAdmin::BadRequestError class
|
87
|
+
class BadRequestError < RequestError; end
|
88
|
+
|
89
|
+
# MagicAdmin::AuthenticationError class
|
90
|
+
class AuthenticationError < RequestError; end
|
91
|
+
|
92
|
+
# MagicAdmin::ForbiddenError class
|
93
|
+
class ForbiddenError < RequestError; end
|
94
|
+
|
95
|
+
# MagicAdmin::APIError class
|
96
|
+
class APIError < RequestError; end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicAdmin
|
4
|
+
|
5
|
+
module Http
|
6
|
+
|
7
|
+
# Http Client and its methods are accessible
|
8
|
+
# on the Magic instance by the http_client attribute.
|
9
|
+
# It provides methods to interact with the http client.
|
10
|
+
class Client
|
11
|
+
|
12
|
+
# attribute reader for magic api max retries
|
13
|
+
attr_reader :retries
|
14
|
+
|
15
|
+
# attribute reader for magic api backoff factor
|
16
|
+
attr_reader :backoff
|
17
|
+
|
18
|
+
# attribute reader for magic api timeout
|
19
|
+
attr_reader :timeout
|
20
|
+
|
21
|
+
# attribute reader for magic api base api url
|
22
|
+
attr_reader :base_url
|
23
|
+
|
24
|
+
# attribute reader for magic http request class
|
25
|
+
attr_reader :http_request
|
26
|
+
|
27
|
+
# attribute reader for magic http response class
|
28
|
+
attr_reader :http_response
|
29
|
+
|
30
|
+
# The constructor allows you to configure HTTP request strategy
|
31
|
+
# when your application interacting with the Magic API
|
32
|
+
#
|
33
|
+
# Arguments:
|
34
|
+
# api_base: api base url.
|
35
|
+
# req_retries: Total number of retries to allow.
|
36
|
+
# req_timeout: A period of time the request is going
|
37
|
+
# to wait for a response.
|
38
|
+
# req_backoff: A backoff factor to apply between retry attempts.
|
39
|
+
#
|
40
|
+
# Returns:
|
41
|
+
# A Http Client object that provides access to
|
42
|
+
# all the supported resources.
|
43
|
+
#
|
44
|
+
# Examples:
|
45
|
+
# Client.new(<api_base>, <req_retries>, <req_timeout>, <req_backoff>)
|
46
|
+
def initialize(api_base, req_retries, req_timeout, req_backoff)
|
47
|
+
@retries = req_retries.to_i
|
48
|
+
@backoff = req_backoff.to_f
|
49
|
+
@timeout = req_timeout.to_f
|
50
|
+
@base_url = api_base
|
51
|
+
@http_request = Request
|
52
|
+
@http_response = Response
|
53
|
+
end
|
54
|
+
|
55
|
+
# Description:
|
56
|
+
# call create http request and provide response
|
57
|
+
#
|
58
|
+
# Arguments:
|
59
|
+
# method: http method
|
60
|
+
# path: api path
|
61
|
+
# options: a hash contains params and headers for request
|
62
|
+
#
|
63
|
+
# Returns:
|
64
|
+
# A response object
|
65
|
+
def call(method, path, options)
|
66
|
+
url = URI("#{base_url}#{path}")
|
67
|
+
req = http_request.request(method, url, options)
|
68
|
+
resp = backoff_retries(retries, backoff) do
|
69
|
+
base_client(url, req, timeout)
|
70
|
+
end
|
71
|
+
http_response.from_net_http(resp, req)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Description:
|
77
|
+
# backoff_retries implementations of retries strategy
|
78
|
+
# with backoff factor
|
79
|
+
#
|
80
|
+
# Arguments:
|
81
|
+
# max_retries: max retries count
|
82
|
+
# backoff_factor: backoff factor for configure delay in retries
|
83
|
+
# block: block of code that uses retries backoff strategy
|
84
|
+
#
|
85
|
+
# Returns:
|
86
|
+
# it returns, block return object
|
87
|
+
def backoff_retries(max_retries, backoff_factor, &block)
|
88
|
+
attempts = 0
|
89
|
+
begin
|
90
|
+
attempts += 1
|
91
|
+
block.call
|
92
|
+
rescue StandardError => e
|
93
|
+
raise e if attempts >= max_retries
|
94
|
+
|
95
|
+
sleep_seconds = backoff_factor * (2**(attempts - 1))
|
96
|
+
sleep sleep_seconds
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Description:
|
102
|
+
# use_ssl? provide true if url uses https protocol otherwise false
|
103
|
+
#
|
104
|
+
# Arguments:
|
105
|
+
# url: max retries count
|
106
|
+
#
|
107
|
+
# Returns:
|
108
|
+
# boolean value
|
109
|
+
def use_ssl?(url)
|
110
|
+
url.scheme == "https"
|
111
|
+
end
|
112
|
+
|
113
|
+
# Description:
|
114
|
+
# base_client is base http request/response mechanism
|
115
|
+
#
|
116
|
+
# Arguments:
|
117
|
+
# url: request url
|
118
|
+
# request: request object
|
119
|
+
# read_timeout: read_timeout for request
|
120
|
+
#
|
121
|
+
# Returns:
|
122
|
+
# response
|
123
|
+
def base_client(url, request, read_timeout)
|
124
|
+
begin
|
125
|
+
Net::HTTP.start(url.host, url.port, use_ssl: use_ssl?(url)) do |http|
|
126
|
+
http.read_timeout = read_timeout
|
127
|
+
http.request(request)
|
128
|
+
end
|
129
|
+
rescue SocketError => e
|
130
|
+
raise APIConnectionError.new(e.message)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|