From bfcb6858388726016eb8bdf23f75874a537f8158 Mon Sep 17 00:00:00 2001 From: Joakim Tangnes <10198932+Zarux@users.noreply.github.com> Date: Wed, 6 Nov 2024 13:37:28 +0100 Subject: [PATCH 1/2] Add `DeviceCredentialsManager` to manage device credentials (#369) --- management/device_credentials.go | 61 ++++++++ management/device_credentials_test.go | 82 ++++++++++ management/management.gen.go | 66 ++++++++ management/management.gen_test.go | 86 +++++++++++ management/management.go | 4 + .../TestDeviceCredentials_Create.yaml | 74 +++++++++ .../TestDeviceCredentials_Delete.yaml | 145 ++++++++++++++++++ .../TestDeviceCredentials_List.yaml | 110 +++++++++++++ 8 files changed, 628 insertions(+) create mode 100644 management/device_credentials.go create mode 100644 management/device_credentials_test.go create mode 100644 test/data/recordings/TestDeviceCredentials_Create.yaml create mode 100644 test/data/recordings/TestDeviceCredentials_Delete.yaml create mode 100644 test/data/recordings/TestDeviceCredentials_List.yaml diff --git a/management/device_credentials.go b/management/device_credentials.go new file mode 100644 index 00000000..a5448ba9 --- /dev/null +++ b/management/device_credentials.go @@ -0,0 +1,61 @@ +package management + +import "context" + +// DeviceCredential is a device credential. +type DeviceCredential struct { + // ID of this device credential + ID *string `json:"id,omitempty"` + + // The id of the client. + ClientID *string `json:"client_id,omitempty"` + + // The id of the user. + UserID *string `json:"user_id,omitempty"` + + // User agent for this device + DeviceName *string `json:"device_name,omitempty"` + + // Unique identifier for the device. NOTE: This field is generally not populated for refresh_tokens and rotating_refresh_tokens + DeviceID *string `json:"device_id,omitempty"` + + // Type of credential. Can be public_key, refresh_token, or rotating_refresh_token + Type *string `json:"type,omitempty"` + + // Base64 encoded string containing the credential + Value *string `json:"value,omitempty"` +} + +// DeviceCredentialList is a list of DeviceCredentials. +type DeviceCredentialList struct { + List + DeviceCredentials []*DeviceCredential `json:"device_credentials"` +} + +// DeviceCredentialsManager manages Auth0 device-credentials resources. +type DeviceCredentialsManager manager + +// Create a device credential public key to manage refresh token rotation for a given user_id +// Type of credential must be "public_key". +// +// See: https://auth0.com/docs/api/management/v2/device-credentials/post-device-credentials +func (m *DeviceCredentialsManager) Create(ctx context.Context, d *DeviceCredential, opts ...RequestOption) error { + return m.management.Request(ctx, "POST", m.management.URI("device-credentials"), d, opts...) +} + +// List device credential information (public_key, refresh_token, or rotating_refresh_token) associated with a specific user. +// +// For information on how to paginate using this function see https://pkg.go.dev/github.com/auth0/go-auth0/management#hdr-Page_Based_Pagination +// +// See: https://auth0.com/docs/api/management/v2/device-credentials/get-device-credentials +func (m *DeviceCredentialsManager) List(ctx context.Context, opts ...RequestOption) (d *DeviceCredentialList, err error) { + err = m.management.Request(ctx, "GET", m.management.URI("device-credentials"), &d, applyListDefaults(opts)) + return +} + +// Delete a device credential (such as a refresh token or public key) with the given ID. +// +// See: https://auth0.com/docs/api/management/v2/device-credentials/delete-device-credentials-by-id +func (m *DeviceCredentialsManager) Delete(ctx context.Context, id string, opts ...RequestOption) error { + return m.management.Request(ctx, "DELETE", m.management.URI("device-credentials", id), nil, opts...) +} diff --git a/management/device_credentials_test.go b/management/device_credentials_test.go new file mode 100644 index 00000000..6b896b65 --- /dev/null +++ b/management/device_credentials_test.go @@ -0,0 +1,82 @@ +package management + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/auth0/go-auth0" +) + +func TestDeviceCredentials_Create(t *testing.T) { + configureHTTPTestRecordings(t) + + expectedDeviceCredential := &DeviceCredential{ + DeviceName: auth0.String("TestDevice"), + Type: auth0.String("public_key"), + Value: auth0.String("ABCD"), + DeviceID: auth0.String("test_device"), + ClientID: auth0.String("test_client"), + } + + err := api.DeviceCredentials.Create(context.Background(), expectedDeviceCredential) + assert.NoError(t, err) + assert.NotEmpty(t, expectedDeviceCredential.GetID()) + + t.Cleanup(func() { + cleanupDeviceCredential(t, expectedDeviceCredential.GetID()) + }) +} + +func TestDeviceCredentials_List(t *testing.T) { + configureHTTPTestRecordings(t) + + expectedDeviceCredential := givenADeviceCredential(t) + + deviceCredentialList, err := api.DeviceCredentials.List(context.Background(), IncludeFields("id")) + + assert.NoError(t, err) + assert.Contains(t, deviceCredentialList.DeviceCredentials, &DeviceCredential{ID: expectedDeviceCredential.ID}) +} + +func TestDeviceCredentials_Delete(t *testing.T) { + configureHTTPTestRecordings(t) + + expectedDeviceCredential := givenADeviceCredential(t) + + err := api.DeviceCredentials.Delete(context.Background(), expectedDeviceCredential.GetID()) + assert.NoError(t, err) + + actualDeviceCredentials, err := api.DeviceCredentials.List(context.Background()) + assert.NoError(t, err) + assert.Empty(t, actualDeviceCredentials.DeviceCredentials) +} + +func givenADeviceCredential(t *testing.T) *DeviceCredential { + t.Helper() + + deviceCredential := &DeviceCredential{ + DeviceName: auth0.String("TestDevice"), + Type: auth0.String("refresh_token"), + Value: auth0.String("ABCD"), + DeviceID: auth0.String("test_device"), + ClientID: auth0.String("test_client"), + } + err := api.DeviceCredentials.Create(context.Background(), deviceCredential) + require.NoError(t, err) + + t.Cleanup(func() { + cleanupDeviceCredential(t, deviceCredential.GetID()) + }) + + return deviceCredential +} + +func cleanupDeviceCredential(t *testing.T, id string) { + t.Helper() + + err := api.DeviceCredentials.Delete(context.Background(), id) + require.NoError(t, err) +} diff --git a/management/management.gen.go b/management/management.gen.go index 99685f73..3115b6b8 100644 --- a/management/management.gen.go +++ b/management/management.gen.go @@ -6347,6 +6347,72 @@ func (d *DailyStat) String() string { return Stringify(d) } +// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. +func (d *DeviceCredential) GetClientID() string { + if d == nil || d.ClientID == nil { + return "" + } + return *d.ClientID +} + +// GetDeviceID returns the DeviceID field if it's non-nil, zero value otherwise. +func (d *DeviceCredential) GetDeviceID() string { + if d == nil || d.DeviceID == nil { + return "" + } + return *d.DeviceID +} + +// GetDeviceName returns the DeviceName field if it's non-nil, zero value otherwise. +func (d *DeviceCredential) GetDeviceName() string { + if d == nil || d.DeviceName == nil { + return "" + } + return *d.DeviceName +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (d *DeviceCredential) GetID() string { + if d == nil || d.ID == nil { + return "" + } + return *d.ID +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (d *DeviceCredential) GetType() string { + if d == nil || d.Type == nil { + return "" + } + return *d.Type +} + +// GetUserID returns the UserID field if it's non-nil, zero value otherwise. +func (d *DeviceCredential) GetUserID() string { + if d == nil || d.UserID == nil { + return "" + } + return *d.UserID +} + +// GetValue returns the Value field if it's non-nil, zero value otherwise. +func (d *DeviceCredential) GetValue() string { + if d == nil || d.Value == nil { + return "" + } + return *d.Value +} + +// String returns a string representation of DeviceCredential. +func (d *DeviceCredential) String() string { + return Stringify(d) +} + +// String returns a string representation of DeviceCredentialList. +func (d *DeviceCredentialList) String() string { + return Stringify(d) +} + // String returns a string representation of DropboxClientAddon. func (d *DropboxClientAddon) String() string { return Stringify(d) diff --git a/management/management.gen_test.go b/management/management.gen_test.go index 54e4832d..d8e26b76 100644 --- a/management/management.gen_test.go +++ b/management/management.gen_test.go @@ -7848,6 +7848,92 @@ func TestDailyStat_String(t *testing.T) { } } +func TestDeviceCredential_GetClientID(tt *testing.T) { + var zeroValue string + d := &DeviceCredential{ClientID: &zeroValue} + d.GetClientID() + d = &DeviceCredential{} + d.GetClientID() + d = nil + d.GetClientID() +} + +func TestDeviceCredential_GetDeviceID(tt *testing.T) { + var zeroValue string + d := &DeviceCredential{DeviceID: &zeroValue} + d.GetDeviceID() + d = &DeviceCredential{} + d.GetDeviceID() + d = nil + d.GetDeviceID() +} + +func TestDeviceCredential_GetDeviceName(tt *testing.T) { + var zeroValue string + d := &DeviceCredential{DeviceName: &zeroValue} + d.GetDeviceName() + d = &DeviceCredential{} + d.GetDeviceName() + d = nil + d.GetDeviceName() +} + +func TestDeviceCredential_GetID(tt *testing.T) { + var zeroValue string + d := &DeviceCredential{ID: &zeroValue} + d.GetID() + d = &DeviceCredential{} + d.GetID() + d = nil + d.GetID() +} + +func TestDeviceCredential_GetType(tt *testing.T) { + var zeroValue string + d := &DeviceCredential{Type: &zeroValue} + d.GetType() + d = &DeviceCredential{} + d.GetType() + d = nil + d.GetType() +} + +func TestDeviceCredential_GetUserID(tt *testing.T) { + var zeroValue string + d := &DeviceCredential{UserID: &zeroValue} + d.GetUserID() + d = &DeviceCredential{} + d.GetUserID() + d = nil + d.GetUserID() +} + +func TestDeviceCredential_GetValue(tt *testing.T) { + var zeroValue string + d := &DeviceCredential{Value: &zeroValue} + d.GetValue() + d = &DeviceCredential{} + d.GetValue() + d = nil + d.GetValue() +} + +func TestDeviceCredential_String(t *testing.T) { + var rawJSON json.RawMessage + v := &DeviceCredential{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + +func TestDeviceCredentialList_String(t *testing.T) { + var rawJSON json.RawMessage + v := &DeviceCredentialList{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + func TestDropboxClientAddon_String(t *testing.T) { var rawJSON json.RawMessage v := &DropboxClientAddon{} diff --git a/management/management.go b/management/management.go index 2caf05d9..1ccda18d 100644 --- a/management/management.go +++ b/management/management.go @@ -31,6 +31,9 @@ type Management struct { // CustomDomain manages Auth0 Custom Domains. CustomDomain *CustomDomainManager + // DeviceCredentials manages Auth0 device credentials. + DeviceCredentials *DeviceCredentialsManager + // Grant manages Auth0 Grants. Grant *GrantManager @@ -180,6 +183,7 @@ func New(domain string, options ...Option) (*Management, error) { m.ClientGrant = (*ClientGrantManager)(&m.common) m.Connection = (*ConnectionManager)(&m.common) m.CustomDomain = (*CustomDomainManager)(&m.common) + m.DeviceCredentials = (*DeviceCredentialsManager)(&m.common) m.EmailProvider = (*EmailProviderManager)(&m.common) m.EmailTemplate = (*EmailTemplateManager)(&m.common) m.Grant = (*GrantManager)(&m.common) diff --git a/test/data/recordings/TestDeviceCredentials_Create.yaml b/test/data/recordings/TestDeviceCredentials_Create.yaml new file mode 100644 index 00000000..3eb0e336 --- /dev/null +++ b/test/data/recordings/TestDeviceCredentials_Create.yaml @@ -0,0 +1,74 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 178 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"client_id":"test_client","device_name":"TestDevice","device_id":"test_device","type":"public_key","value":"ABCD"} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 26 + uncompressed: false + body: '{"id":"test_credential"}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 100ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials/test_credential + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 100ms diff --git a/test/data/recordings/TestDeviceCredentials_Delete.yaml b/test/data/recordings/TestDeviceCredentials_Delete.yaml new file mode 100644 index 00000000..cdc5f430 --- /dev/null +++ b/test/data/recordings/TestDeviceCredentials_Delete.yaml @@ -0,0 +1,145 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 178 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"client_id":"test_client","device_name":"TestDevice","device_id":"test_device","type":"public_key","value":"ABCD"} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 26 + uncompressed: false + body: '{"id":"test_credential"}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 100ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials/test_credential + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 100ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 5 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + null + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials?include_totals=true&per_page=50 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 56 + uncompressed: true + body: '{"total":0,"start":0,"limit":50,"device_credentials":[]}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 Ok + code: 200 + duration: 100ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials/test_credential + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 100ms diff --git a/test/data/recordings/TestDeviceCredentials_List.yaml b/test/data/recordings/TestDeviceCredentials_List.yaml new file mode 100644 index 00000000..5956966c --- /dev/null +++ b/test/data/recordings/TestDeviceCredentials_List.yaml @@ -0,0 +1,110 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 178 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"client_id":"test_client","device_name":"TestDevice","device_id":"test_device","type":"public_key","value":"ABCD"} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 26 + uncompressed: false + body: '{"id":"test_credential"}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 100ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 5 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + null + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials?fields=id&include_fields=true&include_totals=true&per_page=50 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"total":1,"start":0,"limit":50,"device_credentials":[{"id":"test_credential"}]}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 100ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/device-credentials/test_credential + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 100ms From 1d32c219c2a9f9f088a28c485ff71729958667e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 19:17:03 +0530 Subject: [PATCH 2/2] Bump github.com/lestrrat-go/jwx/v2 from 2.1.1 to 2.1.2 (#456) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 25c1da07..ac76fe5f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/PuerkitoBio/rehttp v1.4.0 github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 - github.com/lestrrat-go/jwx/v2 v2.1.1 + github.com/lestrrat-go/jwx/v2 v2.1.2 github.com/stretchr/testify v1.9.0 go.devnw.com/structs v1.0.0 golang.org/x/oauth2 v0.23.0 @@ -25,8 +25,8 @@ require ( github.com/lestrrat-go/option v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/segmentio/asm v1.2.0 // indirect - golang.org/x/crypto v0.25.0 // indirect + golang.org/x/crypto v0.28.0 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.22.0 // indirect + golang.org/x/sys v0.26.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 81a850df..c9fdb46b 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCG github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx/v2 v2.1.1 h1:Y2ltVl8J6izLYFs54BVcpXLv5msSW4o8eXwnzZLI32E= -github.com/lestrrat-go/jwx/v2 v2.1.1/go.mod h1:4LvZg7oxu6Q5VJwn7Mk/UwooNRnTHUpXBj2C4j3HNx0= +github.com/lestrrat-go/jwx/v2 v2.1.2 h1:6poete4MPsO8+LAEVhpdrNI4Xp2xdiafgl2RD89moBc= +github.com/lestrrat-go/jwx/v2 v2.1.2/go.mod h1:pO+Gz9whn7MPdbsqSJzG8TlEpMZCwQDXnFJ+zsUVh8Y= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -42,8 +42,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.devnw.com/structs v1.0.0 h1:FFkBoBOkapCdxFEIkpOZRmMOMr9b9hxjKTD3bJYl9lk= go.devnw.com/structs v1.0.0/go.mod h1:wHBkdQpNeazdQHszJ2sxwVEpd8zGTEsKkeywDLGbrmg= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= @@ -51,8 +51,8 @@ golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=