-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwebhooks.go
160 lines (135 loc) · 6.2 KB
/
webhooks.go
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright (c) David Bond, Tailscale Inc, & Contributors
// SPDX-License-Identifier: MIT
package tailscale
import (
"context"
"net/http"
"time"
)
// WebhooksResource provides access to https://tailscale.com/api#tag/webhooks.
type WebhooksResource struct {
*Client
}
const (
WebhookEmptyProviderType WebhookProviderType = ""
WebhookSlackProviderType WebhookProviderType = "slack"
WebhookMattermostProviderType WebhookProviderType = "mattermost"
WebhookGoogleChatProviderType WebhookProviderType = "googlechat"
WebhookDiscordProviderType WebhookProviderType = "discord"
)
const (
// WebhookCategoryTailnetManagement implies the entire group of events below.
// Note that subscribing to WebhookCategoryTailnetManagement will include any
// future events added below.
WebhookCategoryTailnetManagement WebhookSubscriptionType = "categoryTailnetManagement"
WebhookNodeCreated WebhookSubscriptionType = "nodeCreated"
WebhookNodeNeedsApproval WebhookSubscriptionType = "nodeNeedsApproval"
WebhookNodeApproved WebhookSubscriptionType = "nodeApproved"
WebhookNodeKeyExpiringInOneDay WebhookSubscriptionType = "nodeKeyExpiringInOneDay"
WebhookNodeKeyExpired WebhookSubscriptionType = "nodeKeyExpired"
WebhookNodeDeleted WebhookSubscriptionType = "nodeDeleted"
WebhookPolicyUpdate WebhookSubscriptionType = "policyUpdate"
WebhookUserCreated WebhookSubscriptionType = "userCreated"
WebhookUserNeedsApproval WebhookSubscriptionType = "userNeedsApproval"
WebhookUserSuspended WebhookSubscriptionType = "userSuspended"
WebhookUserRestored WebhookSubscriptionType = "userRestored"
WebhookUserDeleted WebhookSubscriptionType = "userDeleted"
WebhookUserApproved WebhookSubscriptionType = "userApproved"
WebhookUserRoleUpdated WebhookSubscriptionType = "userRoleUpdated"
)
const (
// WebhookCategoryDeviceMisconfigurations implies the entire group of events below.
// Note that subscribing to WebhookCategoryDeviceMisconfigurations will include any
// future events added below.
WebhookCategoryDeviceMisconfigurations WebhookSubscriptionType = "categoryDeviceMisconfigurations"
WebhookSubnetIPForwardingNotEnabled WebhookSubscriptionType = "subnetIPForwardingNotEnabled"
WebhookExitNodeIPForwardingNotEnabled WebhookSubscriptionType = "exitNodeIPForwardingNotEnabled"
)
// WebhookProviderType defines the provider type for a Webhook destination.
type WebhookProviderType string
// WebhookSubscriptionType defines events in tailscale to subscribe a Webhook to.
type WebhookSubscriptionType string
// Webhook type defines a webhook endpoint within a tailnet.
type Webhook struct {
EndpointID string `json:"endpointId"`
EndpointURL string `json:"endpointUrl"`
ProviderType WebhookProviderType `json:"providerType"`
CreatorLoginName string `json:"creatorLoginName"`
Created time.Time `json:"created"`
LastModified time.Time `json:"lastModified"`
Subscriptions []WebhookSubscriptionType `json:"subscriptions"`
// Secret is only populated on Webhook creation and after secret rotation.
Secret *string `json:"secret,omitempty"`
}
// CreateWebhookRequest type describes the configuration for creating a Webhook.
type CreateWebhookRequest struct {
EndpointURL string `json:"endpointUrl"`
ProviderType WebhookProviderType `json:"providerType"`
Subscriptions []WebhookSubscriptionType `json:"subscriptions"`
}
// Create creates a new [Webhook] with the specifications provided in the [CreateWebhookRequest].
// Returns the created [Webhook] if successful.
func (wr *WebhooksResource) Create(ctx context.Context, request CreateWebhookRequest) (*Webhook, error) {
req, err := wr.buildRequest(ctx, http.MethodPost, wr.buildTailnetURL("webhooks"), requestBody(request))
if err != nil {
return nil, err
}
return body[Webhook](wr, req)
}
// List lists every [Webhook] in the tailnet.
func (wr *WebhooksResource) List(ctx context.Context) ([]Webhook, error) {
req, err := wr.buildRequest(ctx, http.MethodGet, wr.buildTailnetURL("webhooks"))
if err != nil {
return nil, err
}
resp := make(map[string][]Webhook)
if err = wr.do(req, &resp); err != nil {
return nil, err
}
return resp["webhooks"], nil
}
// Get retrieves a specific [Webhook].
func (wr *WebhooksResource) Get(ctx context.Context, endpointID string) (*Webhook, error) {
req, err := wr.buildRequest(ctx, http.MethodGet, wr.buildURL("webhooks", endpointID))
if err != nil {
return nil, err
}
return body[Webhook](wr, req)
}
// Update updates an existing webhook's subscriptions. Returns the updated [Webhook] on success.
func (wr *WebhooksResource) Update(ctx context.Context, endpointID string, subscriptions []WebhookSubscriptionType) (*Webhook, error) {
req, err := wr.buildRequest(ctx, http.MethodPatch, wr.buildURL("webhooks", endpointID), requestBody(map[string][]WebhookSubscriptionType{
"subscriptions": subscriptions,
}))
if err != nil {
return nil, err
}
return body[Webhook](wr, req)
}
// Delete deletes a specific webhook.
func (wr *WebhooksResource) Delete(ctx context.Context, endpointID string) error {
req, err := wr.buildRequest(ctx, http.MethodDelete, wr.buildURL("webhooks", endpointID))
if err != nil {
return err
}
return wr.do(req, nil)
}
// Test queues a test event to be sent to a specific webhook.
// Sending the test event is an asynchronous operation which will
// typically happen a few seconds after using this method.
func (wr *WebhooksResource) Test(ctx context.Context, endpointID string) error {
req, err := wr.buildRequest(ctx, http.MethodPost, wr.buildURL("webhooks", endpointID, "test"))
if err != nil {
return err
}
return wr.do(req, nil)
}
// RotateSecret rotates the secret associated with a webhook.
// A new secret will be generated and set on the returned [Webhook].
func (wr *WebhooksResource) RotateSecret(ctx context.Context, endpointID string) (*Webhook, error) {
req, err := wr.buildRequest(ctx, http.MethodPost, wr.buildURL("webhooks", endpointID, "rotate"))
if err != nil {
return nil, err
}
return body[Webhook](wr, req)
}