1 # frozen_string_literal: true
2
3 require 'json'
4 require_relative 'auth/version'
5 # Fat native gems ship one extension per Ruby minor (lib/auth/3.4/auth.bundle);
6 # source and single-ABI builds put it directly under lib/auth/.
7 begin
8 RUBY_VERSION =~ /(\d+\.\d+)/
9 require_relative "auth/#{Regexp.last_match(1)}/auth"
10 rescue LoadError
11 require_relative 'auth/auth'
12 end
13
14 module Auth
15 end
16
17 module SmbCloud
18 module Auth
19 class Error < StandardError
20 attr_reader :error_code, :payload
21
22 def initialize(message = nil, error_code: nil, payload: nil)
23 super(message)
24 @error_code = error_code
25 @payload = payload
26 end
27 end
28
29 module Environment
30 DEV = 'dev'
31 PRODUCTION = 'production'
32 end
33
34 class Client
35 attr_reader :environment, :app_id, :app_secret
36
37 def initialize(environment:, app_id:, app_secret:)
38 @environment = environment
39 @app_id = app_id
40 @app_secret = app_secret
41 end
42
43 def signup(email:, password:)
44 Auth.send(:parse_json, Auth.__signup_with_client(environment, app_id, app_secret, email, password))
45 rescue RuntimeError => e
46 raise Auth.send(:normalize_error, e)
47 end
48
49 def login(email:, password:)
50 Auth.send(:parse_json, Auth.__login_with_client(environment, app_id, app_secret, email, password))
51 rescue RuntimeError => e
52 raise Auth.send(:normalize_error, e)
53 end
54
55 # Requests password-reset instructions for the given email. The endpoint
56 # never reveals whether the account exists (no enumeration), and calling
57 # it again re-issues the token, so this also serves the "resend reset
58 # instructions" flow. Returns { code:, message: }.
59 def reset_password(email:)
60 Auth.send(:parse_json, Auth.__reset_password_with_client(environment, app_id, app_secret, email))
61 rescue RuntimeError => e
62 raise Auth.send(:normalize_error, e)
63 end
64
65 def me(access_token:)
66 Auth.send(:parse_json, Auth.__me_with_client(environment, app_id, app_secret, access_token))
67 rescue RuntimeError => e
68 raise Auth.send(:normalize_error, e)
69 end
70
71 def logout(access_token:)
72 Auth.__logout_with_client(environment, app_id, app_secret, access_token)
73 rescue RuntimeError => e
74 raise Auth.send(:normalize_error, e)
75 end
76
77 def remove(access_token:)
78 Auth.__remove_with_client(environment, app_id, app_secret, access_token)
79 rescue RuntimeError => e
80 raise Auth.send(:normalize_error, e)
81 end
82 end
83
84 class << self
85 def client(environment:, app_id:, app_secret:)
86 Client.new(environment:, app_id:, app_secret:)
87 end
88
89 def signup_with_client(environment:, app_id:, app_secret:, email:, password:)
90 client(environment:, app_id:, app_secret:).signup(email:, password:)
91 end
92
93 def login_with_client(environment:, app_id:, app_secret:, email:, password:)
94 client(environment:, app_id:, app_secret:).login(email:, password:)
95 end
96
97 def reset_password_with_client(environment:, app_id:, app_secret:, email:)
98 client(environment:, app_id:, app_secret:).reset_password(email:)
99 end
100
101 def me_with_client(environment:, app_id:, app_secret:, access_token:)
102 client(environment:, app_id:, app_secret:).me(access_token:)
103 end
104
105 def logout_with_client(environment:, app_id:, app_secret:, access_token:)
106 client(environment:, app_id:, app_secret:).logout(access_token:)
107 end
108
109 def remove_with_client(environment:, app_id:, app_secret:, access_token:)
110 client(environment:, app_id:, app_secret:).remove(access_token:)
111 end
112
113 private
114
115 def parse_json(payload)
116 return payload unless payload.is_a?(String)
117
118 JSON.parse(payload, symbolize_names: true)
119 end
120
121 def normalize_error(error)
122 payload = parse_json(error.message)
123 error_hash = payload[:error] || payload
124 message = error_hash[:message] || error.message
125 error_code = error_hash[:error_code]
126 Error.new(message, error_code: error_code, payload: payload)
127 rescue JSON::ParserError, NoMethodError, TypeError
128 Error.new(error.message)
129 end
130 end
131 end
132 end