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