@@ -7,6 +7,18 @@ import (
7
7
"net/http"
8
8
)
9
9
10
+ var endpoints = map [string ]string {
11
+ // api key endpoints
12
+ "models" : "https://api.anthropic.com/v1/models" ,
13
+ "messageBatches" : "https://api.anthropic.com/v1/messages/batches" ,
14
+
15
+ // admin key endpoints
16
+ "orgUsers" : "https://api.anthropic.com/v1/organizations/users" ,
17
+ "workspaces" : "https://api.anthropic.com/v1/organizations/workspaces" ,
18
+ "workspaceMembers" : "https://api.anthropic.com/v1/organizations/workspaces/%s/members" , // require workspace id
19
+ "apiKeys" : "https://api.anthropic.com/v1/organizations/api_keys" ,
20
+ }
21
+
10
22
type ModelsResponse struct {
11
23
Data []struct {
12
24
ID string `json:"id"`
@@ -25,6 +37,47 @@ type MessageResponse struct {
25
37
} `json:"data"`
26
38
}
27
39
40
+ type OrgUsersResponse struct {
41
+ Data []struct {
42
+ ID string `json:"id"`
43
+ Type string `json:"type"`
44
+ Email string `json:"email"`
45
+ Name string `json:"name"`
46
+ Role string `json:"role"`
47
+ } `json:"data"`
48
+ }
49
+
50
+ type WorkspacesResponse struct {
51
+ Data []struct {
52
+ ID string `json:"id"`
53
+ Type string `json:"type"`
54
+ Name string `json:"name"`
55
+ } `json:"data"`
56
+ }
57
+
58
+ type WorkspaceMembersResponse struct {
59
+ Data []struct {
60
+ WorkspaceID string `json:"workspace_id"`
61
+ UserID string `json:"user_id"`
62
+ Type string `json:"type"`
63
+ WorkspaceRole string `json:"workspace_role"`
64
+ } `json:"data"`
65
+ }
66
+
67
+ type APIKeysResponse struct {
68
+ Data []struct {
69
+ ID string `json:"id"`
70
+ Type string `json:"type"`
71
+ Name string `json:"name"`
72
+ WorkspaceID string `json:"workspace_id"`
73
+ CreatedBy struct {
74
+ ID string `json:"id"`
75
+ } `json:"created_by"`
76
+ PartialKeyHint string `json:"partial_key_hint"`
77
+ Status string `json:"status"`
78
+ } `json:"data"`
79
+ }
80
+
28
81
// makeAnthropicRequest send the API request to passed url with passed key as API Key and return response body and status code
29
82
func makeAnthropicRequest (client * http.Client , url , key string ) ([]byte , int , error ) {
30
83
// create request
@@ -56,8 +109,38 @@ func makeAnthropicRequest(client *http.Client, url, key string) ([]byte, int, er
56
109
return responseBodyByte , resp .StatusCode , nil
57
110
}
58
111
59
- func listModels (client * http.Client , key string , secretInfo * SecretInfo ) error {
60
- response , statusCode , err := makeAnthropicRequest (client , "https://api.anthropic.com/v1/models" , key )
112
+ // captureAPIKeyResources capture resources associated with api key
113
+ func captureAPIKeyResources (client * http.Client , apiKey string , secretInfo * SecretInfo ) error {
114
+ if err := captureModels (client , apiKey , secretInfo ); err != nil {
115
+ return err
116
+ }
117
+
118
+ if err := captureMessageBatches (client , apiKey , secretInfo ); err != nil {
119
+ return err
120
+ }
121
+
122
+ return nil
123
+ }
124
+
125
+ // captureAdminKeyResources capture resources associated with admin key
126
+ func captureAdminKeyResources (client * http.Client , adminKey string , secretInfo * SecretInfo ) error {
127
+ if err := captureOrgUsers (client , adminKey , secretInfo ); err != nil {
128
+ return err
129
+ }
130
+
131
+ if err := captureWorkspaces (client , adminKey , secretInfo ); err != nil {
132
+ return err
133
+ }
134
+
135
+ if err := captureAPIKeys (client , adminKey , secretInfo ); err != nil {
136
+ return err
137
+ }
138
+
139
+ return nil
140
+ }
141
+
142
+ func captureModels (client * http.Client , apiKey string , secretInfo * SecretInfo ) error {
143
+ response , statusCode , err := makeAnthropicRequest (client , endpoints ["models" ], apiKey )
61
144
if err != nil {
62
145
return err
63
146
}
@@ -86,8 +169,8 @@ func listModels(client *http.Client, key string, secretInfo *SecretInfo) error {
86
169
}
87
170
}
88
171
89
- func listMessageBatches (client * http.Client , key string , secretInfo * SecretInfo ) error {
90
- response , statusCode , err := makeAnthropicRequest (client , "https://api.anthropic.com/v1/messages/batches" , key )
172
+ func captureMessageBatches (client * http.Client , apiKey string , secretInfo * SecretInfo ) error {
173
+ response , statusCode , err := makeAnthropicRequest (client , endpoints [ "messageBatches" ], apiKey )
91
174
if err != nil {
92
175
return err
93
176
}
@@ -119,3 +202,140 @@ func listMessageBatches(client *http.Client, key string, secretInfo *SecretInfo)
119
202
return fmt .Errorf ("unexpected status code: %d while fetching models" , statusCode )
120
203
}
121
204
}
205
+
206
+ func captureOrgUsers (client * http.Client , adminKey string , secretInfo * SecretInfo ) error {
207
+ response , statusCode , err := makeAnthropicRequest (client , endpoints ["orgUsers" ], adminKey )
208
+ if err != nil {
209
+ return err
210
+ }
211
+
212
+ switch statusCode {
213
+ case http .StatusOK :
214
+ var users OrgUsersResponse
215
+
216
+ if err := json .Unmarshal (response , & users ); err != nil {
217
+ return err
218
+ }
219
+
220
+ for _ , user := range users .Data {
221
+ secretInfo .AnthropicResources = append (secretInfo .AnthropicResources , AnthropicResource {
222
+ ID : user .ID ,
223
+ Name : user .Name ,
224
+ Type : user .Type ,
225
+ Metadata : map [string ]string {
226
+ "Role" : user .Role ,
227
+ "Email" : user .Email ,
228
+ },
229
+ })
230
+ }
231
+
232
+ return nil
233
+ case http .StatusNotFound , http .StatusUnauthorized :
234
+ return fmt .Errorf ("invalid/revoked api-key" )
235
+ default :
236
+ return fmt .Errorf ("unexpected status code: %d while fetching models" , statusCode )
237
+ }
238
+ }
239
+
240
+ func captureWorkspaces (client * http.Client , adminKey string , secretInfo * SecretInfo ) error {
241
+ response , statusCode , err := makeAnthropicRequest (client , endpoints ["workspaces" ], adminKey )
242
+ if err != nil {
243
+ return err
244
+ }
245
+
246
+ switch statusCode {
247
+ case http .StatusOK :
248
+ var workspaces WorkspacesResponse
249
+
250
+ if err := json .Unmarshal (response , & workspaces ); err != nil {
251
+ return err
252
+ }
253
+
254
+ for _ , workspace := range workspaces .Data {
255
+ resource := AnthropicResource {
256
+ ID : workspace .ID ,
257
+ Name : workspace .Name ,
258
+ Type : workspace .Type ,
259
+ }
260
+
261
+ secretInfo .AnthropicResources = append (secretInfo .AnthropicResources , resource )
262
+ // capture each workspace members
263
+ if err := captureWorkspaceMembers (client , adminKey , resource , secretInfo ); err != nil {
264
+ return err
265
+ }
266
+ }
267
+
268
+ return nil
269
+ case http .StatusNotFound , http .StatusUnauthorized :
270
+ return fmt .Errorf ("invalid/revoked api-key" )
271
+ default :
272
+ return fmt .Errorf ("unexpected status code: %d while fetching models" , statusCode )
273
+ }
274
+ }
275
+
276
+ func captureWorkspaceMembers (client * http.Client , key string , parentWorkspace AnthropicResource , secretInfo * SecretInfo ) error {
277
+ response , statusCode , err := makeAnthropicRequest (client , fmt .Sprintf (endpoints ["workspaceMembers" ], parentWorkspace .ID ), key )
278
+ if err != nil {
279
+ return err
280
+ }
281
+
282
+ switch statusCode {
283
+ case http .StatusOK :
284
+ var members WorkspaceMembersResponse
285
+
286
+ if err := json .Unmarshal (response , & members ); err != nil {
287
+ return err
288
+ }
289
+
290
+ for _ , member := range members .Data {
291
+ secretInfo .AnthropicResources = append (secretInfo .AnthropicResources , AnthropicResource {
292
+ ID : fmt .Sprintf ("anthropic/workspace/%s/member/%s" , member .WorkspaceID , member .UserID ),
293
+ Name : member .UserID ,
294
+ Type : member .Type ,
295
+ Parent : & parentWorkspace ,
296
+ })
297
+ }
298
+
299
+ return nil
300
+ case http .StatusNotFound , http .StatusUnauthorized :
301
+ return fmt .Errorf ("invalid/revoked api-key" )
302
+ default :
303
+ return fmt .Errorf ("unexpected status code: %d while fetching models" , statusCode )
304
+ }
305
+ }
306
+
307
+ func captureAPIKeys (client * http.Client , adminKey string , secretInfo * SecretInfo ) error {
308
+ response , statusCode , err := makeAnthropicRequest (client , endpoints ["apiKeys" ], adminKey )
309
+ if err != nil {
310
+ return err
311
+ }
312
+
313
+ switch statusCode {
314
+ case http .StatusOK :
315
+ var apiKeys APIKeysResponse
316
+
317
+ if err := json .Unmarshal (response , & apiKeys ); err != nil {
318
+ return err
319
+ }
320
+
321
+ for _ , apiKey := range apiKeys .Data {
322
+ secretInfo .AnthropicResources = append (secretInfo .AnthropicResources , AnthropicResource {
323
+ ID : apiKey .ID ,
324
+ Name : apiKey .Name ,
325
+ Type : apiKey .Type ,
326
+ Metadata : map [string ]string {
327
+ "WorkspaceID" : apiKey .WorkspaceID ,
328
+ "CreatedBy" : apiKey .CreatedBy .ID ,
329
+ "PartialKeyHint" : apiKey .PartialKeyHint ,
330
+ "Status" : apiKey .Status ,
331
+ },
332
+ })
333
+ }
334
+
335
+ return nil
336
+ case http .StatusNotFound , http .StatusUnauthorized :
337
+ return fmt .Errorf ("invalid/revoked api-key" )
338
+ default :
339
+ return fmt .Errorf ("unexpected status code: %d while fetching models" , statusCode )
340
+ }
341
+ }
0 commit comments