account.go raw
1 package desec
2
3 import (
4 "context"
5 "fmt"
6 "net/http"
7 "time"
8 )
9
10 // Account an account representation.
11 type Account struct {
12 Email string `json:"email"`
13 Password string `json:"password"`
14 LimitDomains int `json:"limit_domains,omitempty"`
15 Created *time.Time `json:"created,omitempty"`
16 }
17
18 // Captcha a captcha representation.
19 type Captcha struct {
20 ID string `json:"id,omitempty"`
21 Challenge string `json:"challenge,omitempty"`
22 Solution string `json:"solution,omitempty"`
23 }
24
25 // Registration a registration representation.
26 type Registration struct {
27 Email string `json:"email,omitempty"`
28 Password string `json:"password,omitempty"`
29 NewEmail string `json:"new_email,omitempty"`
30 Captcha *Captcha `json:"captcha,omitempty"`
31 }
32
33 // AccountService handles communication with the account related methods of the deSEC API.
34 //
35 // https://desec.readthedocs.io/en/latest/auth/account.html
36 type AccountService struct {
37 client *Client
38 }
39
40 // Login Log in.
41 // https://desec.readthedocs.io/en/latest/auth/account.html#log-in
42 func (s *AccountService) Login(ctx context.Context, email, password string) (*Token, error) {
43 endpoint, err := s.client.createEndpoint("auth", "login")
44 if err != nil {
45 return nil, fmt.Errorf("failed to create endpoint: %w", err)
46 }
47
48 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, Account{Email: email, Password: password})
49 if err != nil {
50 return nil, err
51 }
52
53 resp, err := s.client.httpClient.Do(req)
54 if err != nil {
55 return nil, fmt.Errorf("failed to call API: %w", err)
56 }
57
58 defer func() { _ = resp.Body.Close() }()
59
60 if resp.StatusCode != http.StatusOK {
61 return nil, handleError(resp)
62 }
63
64 var token Token
65
66 err = handleResponse(resp, &token)
67 if err != nil {
68 return nil, err
69 }
70
71 s.client.token = token.Value
72
73 return &token, nil
74 }
75
76 // Logout log out (= delete current token).
77 // https://desec.readthedocs.io/en/latest/auth/account.html#log-out
78 func (s *AccountService) Logout(ctx context.Context) error {
79 endpoint, err := s.client.createEndpoint("auth", "logout")
80 if err != nil {
81 return fmt.Errorf("failed to create endpoint: %w", err)
82 }
83
84 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, nil)
85 if err != nil {
86 return err
87 }
88
89 resp, err := s.client.httpClient.Do(req)
90 if err != nil {
91 return fmt.Errorf("failed to call API: %w", err)
92 }
93
94 defer func() { _ = resp.Body.Close() }()
95
96 if resp.StatusCode != http.StatusNoContent {
97 return handleError(resp)
98 }
99
100 s.client.token = ""
101
102 return nil
103 }
104
105 // ObtainCaptcha Obtain a captcha.
106 // https://desec.readthedocs.io/en/latest/auth/account.html#obtain-a-captcha
107 func (s *AccountService) ObtainCaptcha(ctx context.Context) (*Captcha, error) {
108 endpoint, err := s.client.createEndpoint("captcha")
109 if err != nil {
110 return nil, fmt.Errorf("failed to create endpoint: %w", err)
111 }
112
113 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, nil)
114 if err != nil {
115 return nil, err
116 }
117
118 resp, err := s.client.httpClient.Do(req)
119 if err != nil {
120 return nil, fmt.Errorf("failed to call API: %w", err)
121 }
122
123 defer func() { _ = resp.Body.Close() }()
124
125 if resp.StatusCode != http.StatusOK {
126 return nil, handleError(resp)
127 }
128
129 var captcha Captcha
130
131 err = handleResponse(resp, &captcha)
132 if err != nil {
133 return nil, err
134 }
135
136 return &captcha, nil
137 }
138
139 // Register register account.
140 // https://desec.readthedocs.io/en/latest/auth/account.html#register-account
141 func (s *AccountService) Register(ctx context.Context, registration Registration) error {
142 endpoint, err := s.client.createEndpoint("auth")
143 if err != nil {
144 return fmt.Errorf("failed to create endpoint: %w", err)
145 }
146
147 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, registration)
148 if err != nil {
149 return err
150 }
151
152 resp, err := s.client.httpClient.Do(req)
153 if err != nil {
154 return fmt.Errorf("failed to call API: %w", err)
155 }
156
157 defer func() { _ = resp.Body.Close() }()
158
159 if resp.StatusCode != http.StatusAccepted {
160 return handleError(resp)
161 }
162
163 return nil
164 }
165
166 // RetrieveInformation retrieve account information.
167 // https://desec.readthedocs.io/en/latest/auth/account.html#retrieve-account-information
168 func (s *AccountService) RetrieveInformation(ctx context.Context) (*Account, error) {
169 endpoint, err := s.client.createEndpoint("auth", "account")
170 if err != nil {
171 return nil, fmt.Errorf("failed to create endpoint: %w", err)
172 }
173
174 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, nil)
175 if err != nil {
176 return nil, err
177 }
178
179 resp, err := s.client.httpClient.Do(req)
180 if err != nil {
181 return nil, fmt.Errorf("failed to call API: %w", err)
182 }
183
184 defer func() { _ = resp.Body.Close() }()
185
186 if resp.StatusCode != http.StatusOK {
187 return nil, handleError(resp)
188 }
189
190 var account Account
191
192 err = handleResponse(resp, &account)
193 if err != nil {
194 return nil, err
195 }
196
197 return &account, nil
198 }
199
200 // PasswordReset password reset and password change.
201 // https://desec.readthedocs.io/en/latest/auth/account.html#password-reset
202 // https://desec.readthedocs.io/en/latest/auth/account.html#password-change
203 func (s *AccountService) PasswordReset(ctx context.Context, email string, captcha Captcha) error {
204 endpoint, err := s.client.createEndpoint("auth", "account", "reset-password")
205 if err != nil {
206 return fmt.Errorf("failed to create endpoint: %w", err)
207 }
208
209 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, Registration{Email: email, Captcha: &captcha})
210 if err != nil {
211 return err
212 }
213
214 resp, err := s.client.httpClient.Do(req)
215 if err != nil {
216 return fmt.Errorf("failed to call API: %w", err)
217 }
218
219 defer func() { _ = resp.Body.Close() }()
220
221 if resp.StatusCode != http.StatusAccepted {
222 return handleError(resp)
223 }
224
225 return nil
226 }
227
228 // ChangeEmail changes email address.
229 // https://desec.readthedocs.io/en/latest/auth/account.html#change-email-address
230 func (s *AccountService) ChangeEmail(ctx context.Context, email, password, newEmail string) error {
231 endpoint, err := s.client.createEndpoint("auth", "account", "change-email")
232 if err != nil {
233 return fmt.Errorf("failed to create endpoint: %w", err)
234 }
235
236 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, Registration{Email: email, Password: password, NewEmail: newEmail})
237 if err != nil {
238 return err
239 }
240
241 resp, err := s.client.httpClient.Do(req)
242 if err != nil {
243 return fmt.Errorf("failed to call API: %w", err)
244 }
245
246 defer func() { _ = resp.Body.Close() }()
247
248 if resp.StatusCode != http.StatusAccepted {
249 return handleError(resp)
250 }
251
252 return nil
253 }
254
255 // Delete deletes account.
256 // https://desec.readthedocs.io/en/latest/auth/account.html#delete-account
257 func (s *AccountService) Delete(ctx context.Context, email, password string) error {
258 endpoint, err := s.client.createEndpoint("auth", "account", "delete")
259 if err != nil {
260 return fmt.Errorf("failed to create endpoint: %w", err)
261 }
262
263 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, Account{Email: email, Password: password})
264 if err != nil {
265 return err
266 }
267
268 resp, err := s.client.httpClient.Do(req)
269 if err != nil {
270 return fmt.Errorf("failed to call API: %w", err)
271 }
272
273 defer func() { _ = resp.Body.Close() }()
274
275 if resp.StatusCode != http.StatusAccepted {
276 return handleError(resp)
277 }
278
279 return nil
280 }
281