Repository navigation
Expand file tree
/
Copy pathclients.go
More file actions
141 lines (127 loc) · 4.58 KB
/
Copy pathclients.go
File metadata and controls
141 lines (127 loc) · 4.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package firezone
import (
"context"
"time"
)
// ClientDevice is a Firezone Client - an enrolled end-user device.
//
// The API calls this a "Client", but [Client] is already this SDK's own
// API client type, so the device concept carries the Device suffix here.
//
// Client devices are not created through this API: a device registers
// itself when it first connects. They can be read, renamed, verified,
// and deleted, but never provisioned - so there is no
// CreateClientRequest.
type ClientDevice struct {
ID string `json:"id"`
FirezoneID string `json:"firezone_id"`
ActorID string `json:"actor_id"`
Name string `json:"name"`
IPv4 string `json:"ipv4"`
IPv6 string `json:"ipv6"`
Online bool `json:"online"`
PublicKey string `json:"public_key,omitempty"`
Hostname string `json:"hostname,omitempty"`
DeviceSerial string `json:"device_serial,omitempty"`
DeviceUUID string `json:"device_uuid,omitempty"`
// VerifiedAt is nil until an admin verifies the device. Policies can
// require verification via the client_verified condition property.
VerifiedAt *time.Time `json:"verified_at,omitempty"`
// LastSeenAt is nil for a Client that has enrolled but never
// connected.
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
LastSeenVersion string `json:"last_seen_version,omitempty"`
LastSeenRemoteIP string `json:"last_seen_remote_ip,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// UpdateClientRequest is the request body for [ClientsService.Update].
// Name is the only mutable field, and the API requires it, so it is
// always sent - omitting it on an empty value would produce a body the
// API rejects for a reason that doesn't name the field.
type UpdateClientRequest struct {
Name string `json:"name"`
}
// ClientsService manages Clients.
type ClientsService struct {
client *Client
}
// Get fetches a single Client by ID.
func (s *ClientsService) Get(ctx context.Context, id string) (*ClientDevice, error) {
if err := checkID("Client ID", id); err != nil {
return nil, err
}
var c ClientDevice
if err := s.client.do(ctx, "GET", buildPath("clients", id), nil, nil, &c); err != nil {
return nil, err
}
return &c, nil
}
// ClientListOptions extends ListOptions with Clients-specific filters.
type ClientListOptions struct {
ListOptions
// Name filters to Clients with this exact name. Names are not
// unique, so this can still match more than one.
Name string
// FirezoneID filters to Clients with this exact Firezone ID. Unique
// per actor rather than per account, so this too can match more than
// one - though in practice rarely does.
FirezoneID string
}
// List returns a page of Clients. Pass nil for opts to use the API's
// default page size and no filters.
func (s *ClientsService) List(ctx context.Context, opts *ClientListOptions) (*Page[ClientDevice], error) {
if opts == nil {
opts = &ClientListOptions{}
}
q := filterQuery(opts.ListOptions,
[2]string{"name", opts.Name},
[2]string{"firezone_id", opts.FirezoneID},
)
return doList[ClientDevice](ctx, s.client, "GET", "clients", q)
}
// Update renames a Client.
func (s *ClientsService) Update(ctx context.Context, id string, req *UpdateClientRequest) (*ClientDevice, error) {
if err := checkID("Client ID", id); err != nil {
return nil, err
}
body, err := wrapBody("client", req)
if err != nil {
return nil, err
}
var c ClientDevice
if err := s.client.do(ctx, "PATCH", buildPath("clients", id), nil, body, &c); err != nil {
return nil, err
}
return &c, nil
}
// Delete deletes a Client, unenrolling the device.
func (s *ClientsService) Delete(ctx context.Context, id string) error {
if err := checkID("Client ID", id); err != nil {
return err
}
return s.client.do(ctx, "DELETE", buildPath("clients", id), nil, nil, nil)
}
// Verify marks a Client as admin-verified, satisfying the
// client_verified Policy condition.
func (s *ClientsService) Verify(ctx context.Context, id string) (*ClientDevice, error) {
if err := checkID("Client ID", id); err != nil {
return nil, err
}
var c ClientDevice
if err := s.client.do(ctx, "PUT", buildPath("clients", id, "verify"), nil, nil, &c); err != nil {
return nil, err
}
return &c, nil
}
// Unverify clears a Client's verification.
func (s *ClientsService) Unverify(ctx context.Context, id string) (*ClientDevice, error) {
if err := checkID("Client ID", id); err != nil {
return nil, err
}
var c ClientDevice
if err := s.client.do(ctx, "PUT", buildPath("clients", id, "unverify"), nil, nil, &c); err != nil {
return nil, err
}
return &c, nil
}