tokens.go raw
1 package desec
2
3 import (
4 "context"
5 "fmt"
6 "net/http"
7 "time"
8 )
9
10 // Token a token representation.
11 //
12 // https://desec.readthedocs.io/en/latest/auth/tokens.html#token-field-reference
13 type Token struct {
14 ID string `json:"id,omitempty"`
15 Created *time.Time `json:"created,omitempty"`
16 LastUsed *time.Time `json:"last_used,omitempty"`
17 Owner string `json:"owner,omitempty"`
18 UserOverride string `json:"user_override,omitempty"`
19 Name string `json:"name,omitempty"`
20 PermCreateDomain bool `json:"perm_create_domain"`
21 PermDeleteDomain bool `json:"perm_delete_domain"`
22 PermManageTokens bool `json:"perm_manage_tokens"`
23 IsValid bool `json:"is_valid,omitempty"`
24 AllowedSubnets []string `json:"allowed_subnets,omitempty"`
25 AutoPolicy bool `json:"auto_policy"`
26 Value string `json:"token,omitempty"`
27 // Not currently implemented
28 // MaxAge *time.Duration `json:"name,omitempty"`
29 // MaxUnusedPeriod *time.Duration `json:"name,omitempty"`
30 }
31
32 // TokensService handles communication with the tokens related methods of the deSEC API.
33 //
34 // https://desec.readthedocs.io/en/latest/auth/tokens.html
35 type TokensService struct {
36 client *Client
37 }
38
39 // GetAll retrieving all current tokens.
40 // https://desec.readthedocs.io/en/latest/auth/tokens.html#retrieving-all-current-tokens
41 func (s *TokensService) GetAll(ctx context.Context) ([]Token, error) {
42 endpoint, err := s.client.createEndpoint("auth", "tokens")
43 if err != nil {
44 return nil, fmt.Errorf("failed to create endpoint: %w", err)
45 }
46
47 req, err := s.client.newRequest(ctx, http.MethodGet, endpoint, nil)
48 if err != nil {
49 return nil, err
50 }
51
52 resp, err := s.client.httpClient.Do(req)
53 if err != nil {
54 return nil, fmt.Errorf("failed to call API: %w", err)
55 }
56
57 defer func() { _ = resp.Body.Close() }()
58
59 if resp.StatusCode != http.StatusOK {
60 return nil, handleError(resp)
61 }
62
63 var tokens []Token
64
65 err = handleResponse(resp, &tokens)
66 if err != nil {
67 return nil, err
68 }
69
70 return tokens, nil
71 }
72
73 // Get retrieves a specific token.
74 // https://desec.readthedocs.io/en/latest/auth/tokens.html#retrieving-a-specific-token
75 // NOTE: This method used to retrieve all policies for a token, that is now done by GetAll.
76 func (s *TokensService) Get(ctx context.Context, id string) (*Token, error) {
77 endpoint, err := s.client.createEndpoint("auth", "tokens", id)
78 if err != nil {
79 return nil, fmt.Errorf("failed to create endpoint: %w", err)
80 }
81
82 req, err := s.client.newRequest(ctx, http.MethodGet, endpoint, nil)
83 if err != nil {
84 return nil, err
85 }
86
87 resp, err := s.client.httpClient.Do(req)
88 if err != nil {
89 return nil, fmt.Errorf("failed to call API: %w", err)
90 }
91
92 defer func() { _ = resp.Body.Close() }()
93
94 if resp.StatusCode == http.StatusNotFound {
95 return nil, nil
96 }
97
98 if resp.StatusCode != http.StatusOK {
99 return nil, handleError(resp)
100 }
101
102 token := &Token{}
103
104 err = handleResponse(resp, token)
105 if err != nil {
106 return nil, err
107 }
108
109 return token, nil
110 }
111
112 // Create creates additional tokens.
113 // https://desec.readthedocs.io/en/latest/auth/tokens.html#create-additional-tokens
114 func (s *TokensService) Create(ctx context.Context, name string) (*Token, error) {
115 endpoint, err := s.client.createEndpoint("auth", "tokens")
116 if err != nil {
117 return nil, fmt.Errorf("failed to create endpoint: %w", err)
118 }
119
120 req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, Token{Name: name})
121 if err != nil {
122 return nil, err
123 }
124
125 resp, err := s.client.httpClient.Do(req)
126 if err != nil {
127 return nil, fmt.Errorf("failed to call API: %w", err)
128 }
129
130 defer func() { _ = resp.Body.Close() }()
131
132 if resp.StatusCode != http.StatusCreated {
133 return nil, handleError(resp)
134 }
135
136 var token Token
137
138 err = handleResponse(resp, &token)
139 if err != nil {
140 return nil, err
141 }
142
143 return &token, nil
144 }
145
146 // Update a token.
147 // https://desec.readthedocs.io/en/latest/auth/tokens.html#modifying-a-token
148 func (s *TokensService) Update(ctx context.Context, id string, token *Token) (*Token, error) {
149 endpoint, err := s.client.createEndpoint("auth", "tokens", id)
150 if err != nil {
151 return nil, fmt.Errorf("failed to create endpoint: %w", err)
152 }
153
154 // Copy values, including only fields that can be modified
155 req, err := s.client.newRequest(ctx, http.MethodPatch, endpoint, Token{
156 Owner: token.Owner,
157 UserOverride: token.UserOverride,
158 Name: token.Name,
159 PermCreateDomain: token.PermCreateDomain,
160 PermDeleteDomain: token.PermDeleteDomain,
161 PermManageTokens: token.PermManageTokens,
162 AllowedSubnets: token.AllowedSubnets,
163 AutoPolicy: token.AutoPolicy,
164 })
165 if err != nil {
166 return nil, err
167 }
168
169 resp, err := s.client.httpClient.Do(req)
170 if err != nil {
171 return nil, fmt.Errorf("failed to call API: %w", err)
172 }
173
174 defer func() { _ = resp.Body.Close() }()
175
176 if resp.StatusCode != http.StatusOK {
177 return nil, handleError(resp)
178 }
179
180 result := &Token{}
181
182 err = handleResponse(resp, result)
183 if err != nil {
184 return nil, err
185 }
186
187 return result, nil
188 }
189
190 // Delete deletes tokens.
191 // https://desec.readthedocs.io/en/latest/auth/tokens.html#delete-tokens
192 func (s *TokensService) Delete(ctx context.Context, tokenID string) error {
193 endpoint, err := s.client.createEndpoint("auth", "tokens", tokenID)
194 if err != nil {
195 return fmt.Errorf("failed to create endpoint: %w", err)
196 }
197
198 req, err := s.client.newRequest(ctx, http.MethodDelete, endpoint, nil)
199 if err != nil {
200 return err
201 }
202
203 resp, err := s.client.httpClient.Do(req)
204 if err != nil {
205 return fmt.Errorf("failed to call API: %w", err)
206 }
207
208 defer func() { _ = resp.Body.Close() }()
209
210 if resp.StatusCode != http.StatusNoContent {
211 return handleError(resp)
212 }
213
214 return nil
215 }
216