Compare commits
40 Commits
Author | SHA1 | Date |
---|---|---|
Maksim Nabokikh | 2081f7d057 | |
mayurwaghmode | b9d88c723f | |
dependabot[bot] | e74acdff6c | |
Márk Sági-Kazár | b479d26137 | |
dependabot[bot] | adb5454913 | |
dependabot[bot] | 4bcdcf8e1e | |
dependabot[bot] | 3df7c489ce | |
dependabot[bot] | ce11154529 | |
Bob Callaway | e1a407830d | |
Bob Callaway | 83e2df821e | |
dependabot[bot] | 454122ca22 | |
Björn Busse | 4a0218e87c | |
Joe Knight | 27c25d00be | |
dependabot[bot] | 367487d7c5 | |
dependabot[bot] | 3b7e56035a | |
dependabot[bot] | f53fab6b06 | |
dhaus67 | 100246328b | |
Maksim Nabokikh | d564cc7200 | |
Chance Zibolski | a3e2946cfc | |
Maksim Nabokikh | f49e7bc218 | |
Maksim Nabokikh | 9ebcd651ff | |
dependabot[bot] | 1aaa7fa0b7 | |
Maksim Nabokikh | c561318baa | |
Maksim Nabokikh | 5066414735 | |
Maksim Nabokikh | 731d0d7d9d | |
Márk Sági-Kazár | 1cc26fab2f | |
dependabot[bot] | f34529b13f | |
dependabot[bot] | ffec99287b | |
dependabot[bot] | ea46fc39ca | |
dependabot[bot] | e253fa8efb | |
Márk Sági-Kazár | c538f3d6a2 | |
dependabot[bot] | 33483aa179 | |
Maksim Nabokikh | b6c4112c88 | |
dependabot[bot] | 60228d8fd8 | |
Maksim Nabokikh | b07c8b1d8d | |
Michael Kelly | 9079c31637 | |
Michael Kelly | a51d12056f | |
Michael Kelly | 6c99a9b99d | |
Michael Kelly | 502a2d0d4a | |
m.nabokikh | 3d5a3befb4 |
|
@ -70,7 +70,7 @@ jobs:
|
|||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
|
||||
# cache-from: type=gha
|
||||
# cache-to: type=gha,mode=max
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
|
@ -83,7 +83,7 @@ jobs:
|
|||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@0.3.0
|
||||
uses: aquasecurity/trivy-action@0.6.1
|
||||
with:
|
||||
image-ref: "ghcr.io/dexidp/dex:${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}"
|
||||
format: "sarif"
|
||||
|
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Check minimum labels
|
||||
uses: mheap/github-action-required-labels@v1
|
||||
uses: mheap/github-action-required-labels@v2
|
||||
with:
|
||||
mode: minimum
|
||||
count: 1
|
||||
|
|
|
@ -73,7 +73,7 @@ jobs:
|
|||
run: docker-compose -f docker-compose.test.yaml up -d
|
||||
|
||||
- name: Create kind cluster
|
||||
uses: helm/kind-action@v1.2.0
|
||||
uses: helm/kind-action@v1.3.0
|
||||
with:
|
||||
version: v0.11.1
|
||||
node_image: kindest/node:v1.19.11@sha256:07db187ae84b4b7de440a73886f008cf903fcf5764ba8106a9fd5243d6f32729
|
||||
|
|
|
@ -75,7 +75,7 @@ jobs:
|
|||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
|
||||
# cache-from: type=gha
|
||||
# cache-to: type=gha,mode=max
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
|
@ -96,7 +96,7 @@ jobs:
|
|||
org.opencontainers.image.documentation=https://dexidp.io/docs/
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@0.3.0
|
||||
uses: aquasecurity/trivy-action@0.6.1
|
||||
with:
|
||||
image-ref: "ghcr.io/dexidp/dex:${{ steps.tags.outputs.version }}"
|
||||
format: "template"
|
||||
|
|
10
Dockerfile
10
Dockerfile
|
@ -1,6 +1,6 @@
|
|||
ARG BASE_IMAGE=alpine
|
||||
|
||||
FROM golang:1.18.3-alpine3.15 AS builder
|
||||
FROM golang:1.18.4-alpine3.15 AS builder
|
||||
|
||||
WORKDIR /usr/local/src/dex
|
||||
|
||||
|
@ -22,26 +22,26 @@ COPY . .
|
|||
|
||||
RUN make release-binary
|
||||
|
||||
FROM alpine:3.16.0 AS stager
|
||||
FROM alpine:3.16.2 AS stager
|
||||
|
||||
RUN mkdir -p /var/dex
|
||||
RUN mkdir -p /etc/dex
|
||||
COPY config.docker.yaml /etc/dex/
|
||||
|
||||
FROM alpine:3.16.0 AS gomplate
|
||||
FROM alpine:3.16.2 AS gomplate
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
|
||||
ENV GOMPLATE_VERSION=v3.10.0
|
||||
ENV GOMPLATE_VERSION=v3.11.2
|
||||
|
||||
RUN wget -O /usr/local/bin/gomplate \
|
||||
"https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_${TARGETOS:-linux}-${TARGETARCH:-amd64}${TARGETVARIANT}" \
|
||||
&& chmod +x /usr/local/bin/gomplate
|
||||
|
||||
# For Dependabot to detect base image versions
|
||||
FROM alpine:3.16.0 AS alpine
|
||||
FROM alpine:3.16.2 AS alpine
|
||||
FROM gcr.io/distroless/static:latest AS distroless
|
||||
|
||||
FROM $BASE_IMAGE
|
||||
|
|
|
@ -85,6 +85,11 @@ web:
|
|||
# deviceRequests: "5m"
|
||||
# signingKeys: "6h"
|
||||
# idTokens: "24h"
|
||||
# refreshTokens:
|
||||
# disableRotation: false
|
||||
# reuseInterval: "3s"
|
||||
# validIfNotUsedFor: "2160h" # 90 days
|
||||
# absoluteLifetime: "3960h" # 165 days
|
||||
|
||||
# OAuth2 configuration
|
||||
# oauth2:
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
|
@ -61,8 +62,9 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error)
|
|||
}
|
||||
|
||||
type connectorData struct {
|
||||
// GitLab's OAuth2 tokens never expire. We don't need a refresh token.
|
||||
AccessToken string `json:"accessToken"`
|
||||
// Support GitLab's Access Tokens and Refresh tokens.
|
||||
AccessToken string `json:"accessToken"`
|
||||
RefreshToken string `json:"refreshToken"`
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -135,6 +137,11 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
|
|||
return identity, fmt.Errorf("gitlab: failed to get token: %v", err)
|
||||
}
|
||||
|
||||
return c.identity(ctx, s, token)
|
||||
}
|
||||
|
||||
func (c *gitlabConnector) identity(ctx context.Context, s connector.Scopes, token *oauth2.Token) (identity connector.Identity, err error) {
|
||||
oauth2Config := c.oauth2Config(s)
|
||||
client := oauth2Config.Client(ctx, token)
|
||||
|
||||
user, err := c.user(ctx, client)
|
||||
|
@ -146,6 +153,7 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
|
|||
if username == "" {
|
||||
username = user.Email
|
||||
}
|
||||
|
||||
identity = connector.Identity{
|
||||
UserID: strconv.Itoa(user.ID),
|
||||
Username: username,
|
||||
|
@ -166,10 +174,10 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
|
|||
}
|
||||
|
||||
if s.OfflineAccess {
|
||||
data := connectorData{AccessToken: token.AccessToken}
|
||||
data := connectorData{RefreshToken: token.RefreshToken, AccessToken: token.AccessToken}
|
||||
connData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return identity, fmt.Errorf("marshal connector data: %v", err)
|
||||
return identity, fmt.Errorf("gitlab: marshal connector data: %v", err)
|
||||
}
|
||||
identity.ConnectorData = connData
|
||||
}
|
||||
|
@ -178,37 +186,39 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
|
|||
}
|
||||
|
||||
func (c *gitlabConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
|
||||
if len(ident.ConnectorData) == 0 {
|
||||
return ident, errors.New("no upstream access token found")
|
||||
}
|
||||
|
||||
var data connectorData
|
||||
if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
|
||||
return ident, fmt.Errorf("gitlab: unmarshal access token: %v", err)
|
||||
return ident, fmt.Errorf("gitlab: unmarshal connector data: %v", err)
|
||||
}
|
||||
oauth2Config := c.oauth2Config(s)
|
||||
|
||||
if c.httpClient != nil {
|
||||
ctx = context.WithValue(ctx, oauth2.HTTPClient, c.httpClient)
|
||||
}
|
||||
|
||||
client := c.oauth2Config(s).Client(ctx, &oauth2.Token{AccessToken: data.AccessToken})
|
||||
user, err := c.user(ctx, client)
|
||||
if err != nil {
|
||||
return ident, fmt.Errorf("gitlab: get user: %v", err)
|
||||
}
|
||||
|
||||
username := user.Name
|
||||
if username == "" {
|
||||
username = user.Email
|
||||
}
|
||||
ident.Username = username
|
||||
ident.PreferredUsername = user.Username
|
||||
ident.Email = user.Email
|
||||
|
||||
if c.groupsRequired(s.Groups) {
|
||||
groups, err := c.getGroups(ctx, client, s.Groups, user.Username)
|
||||
if err != nil {
|
||||
return ident, fmt.Errorf("gitlab: get groups: %v", err)
|
||||
switch {
|
||||
case data.RefreshToken != "":
|
||||
{
|
||||
t := &oauth2.Token{
|
||||
RefreshToken: data.RefreshToken,
|
||||
Expiry: time.Now().Add(-time.Hour),
|
||||
}
|
||||
token, err := oauth2Config.TokenSource(ctx, t).Token()
|
||||
if err != nil {
|
||||
return ident, fmt.Errorf("gitlab: failed to get refresh token: %v", err)
|
||||
}
|
||||
return c.identity(ctx, s, token)
|
||||
}
|
||||
ident.Groups = groups
|
||||
case data.AccessToken != "":
|
||||
{
|
||||
token := &oauth2.Token{
|
||||
AccessToken: data.AccessToken,
|
||||
}
|
||||
return c.identity(ctx, s, token)
|
||||
}
|
||||
default:
|
||||
return ident, errors.New("no refresh or access token found")
|
||||
}
|
||||
return ident, nil
|
||||
}
|
||||
|
||||
func (c *gitlabConnector) groupsRequired(groupScope bool) bool {
|
||||
|
|
|
@ -180,6 +180,75 @@ func TestLoginWithTeamNonWhitelisted(t *testing.T) {
|
|||
expectEquals(t, err.Error(), "gitlab: get groups: gitlab: user \"joebloggs\" is not in any of the required groups")
|
||||
}
|
||||
|
||||
func TestRefresh(t *testing.T) {
|
||||
s := newTestServer(map[string]interface{}{
|
||||
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678},
|
||||
"/oauth/token": map[string]interface{}{
|
||||
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
"refresh_token": "oRzxVjCnohYRHEYEhZshkmakKmoyVoTjfUGC",
|
||||
"expires_in": "30",
|
||||
},
|
||||
"/oauth/userinfo": userInfo{
|
||||
Groups: []string{"team-1"},
|
||||
},
|
||||
})
|
||||
defer s.Close()
|
||||
|
||||
hostURL, err := url.Parse(s.URL)
|
||||
expectNil(t, err)
|
||||
|
||||
req, err := http.NewRequest("GET", hostURL.String(), nil)
|
||||
expectNil(t, err)
|
||||
|
||||
c := gitlabConnector{baseURL: s.URL, httpClient: newClient()}
|
||||
|
||||
expectedConnectorData, err := json.Marshal(connectorData{
|
||||
RefreshToken: "oRzxVjCnohYRHEYEhZshkmakKmoyVoTjfUGC",
|
||||
AccessToken: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
})
|
||||
expectNil(t, err)
|
||||
|
||||
identity, err := c.HandleCallback(connector.Scopes{OfflineAccess: true}, req)
|
||||
expectNil(t, err)
|
||||
expectEquals(t, identity.Username, "some@email.com")
|
||||
expectEquals(t, identity.UserID, "12345678")
|
||||
expectEquals(t, identity.ConnectorData, expectedConnectorData)
|
||||
|
||||
identity, err = c.Refresh(context.Background(), connector.Scopes{OfflineAccess: true}, identity)
|
||||
expectNil(t, err)
|
||||
expectEquals(t, identity.Username, "some@email.com")
|
||||
expectEquals(t, identity.UserID, "12345678")
|
||||
expectEquals(t, identity.ConnectorData, expectedConnectorData)
|
||||
}
|
||||
|
||||
func TestRefreshWithEmptyConnectorData(t *testing.T) {
|
||||
s := newTestServer(map[string]interface{}{
|
||||
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678},
|
||||
"/oauth/token": map[string]interface{}{
|
||||
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
"refresh_token": "oRzxVjCnohYRHEYEhZshkmakKmoyVoTjfUGC",
|
||||
"expires_in": "30",
|
||||
},
|
||||
"/oauth/userinfo": userInfo{
|
||||
Groups: []string{"team-1"},
|
||||
},
|
||||
})
|
||||
defer s.Close()
|
||||
|
||||
emptyConnectorData, err := json.Marshal(connectorData{
|
||||
RefreshToken: "",
|
||||
AccessToken: "",
|
||||
})
|
||||
expectNil(t, err)
|
||||
|
||||
c := gitlabConnector{baseURL: s.URL, httpClient: newClient()}
|
||||
emptyIdentity := connector.Identity{ConnectorData: emptyConnectorData}
|
||||
|
||||
identity, err := c.Refresh(context.Background(), connector.Scopes{OfflineAccess: true}, emptyIdentity)
|
||||
expectNotNil(t, err, "Refresh error")
|
||||
expectEquals(t, emptyIdentity, identity)
|
||||
}
|
||||
|
||||
func newTestServer(responses map[string]interface{}) *httptest.Server {
|
||||
return httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
response := responses[r.RequestURI]
|
||||
|
|
|
@ -57,6 +57,9 @@ type Config struct {
|
|||
// PromptType is used for the prompt query parameter.
|
||||
// For valid values, see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code.
|
||||
PromptType string `json:"promptType"`
|
||||
DomainHint string `json:"domainHint"`
|
||||
|
||||
Scopes []string `json:"scopes"` // defaults to scopeUser (user.read)
|
||||
}
|
||||
|
||||
// Open returns a strategy for logging in through Microsoft.
|
||||
|
@ -75,6 +78,8 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error)
|
|||
logger: logger,
|
||||
emailToLowercase: c.EmailToLowercase,
|
||||
promptType: c.PromptType,
|
||||
domainHint: c.DomainHint,
|
||||
scopes: c.Scopes,
|
||||
}
|
||||
// By default allow logins from both personal and business/school
|
||||
// accounts.
|
||||
|
@ -119,6 +124,8 @@ type microsoftConnector struct {
|
|||
logger log.Logger
|
||||
emailToLowercase bool
|
||||
promptType string
|
||||
domainHint string
|
||||
scopes []string
|
||||
}
|
||||
|
||||
func (c *microsoftConnector) isOrgTenant() bool {
|
||||
|
@ -130,7 +137,12 @@ func (c *microsoftConnector) groupsRequired(groupScope bool) bool {
|
|||
}
|
||||
|
||||
func (c *microsoftConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
|
||||
microsoftScopes := []string{scopeUser}
|
||||
var microsoftScopes []string
|
||||
if len(c.scopes) > 0 {
|
||||
microsoftScopes = c.scopes
|
||||
} else {
|
||||
microsoftScopes = append(microsoftScopes, scopeUser)
|
||||
}
|
||||
if c.groupsRequired(scopes.Groups) {
|
||||
microsoftScopes = append(microsoftScopes, scopeGroups)
|
||||
}
|
||||
|
@ -160,6 +172,9 @@ func (c *microsoftConnector) LoginURL(scopes connector.Scopes, callbackURL, stat
|
|||
if c.promptType != "" {
|
||||
options = append(options, oauth2.SetAuthURLParam("prompt", c.promptType))
|
||||
}
|
||||
if c.domainHint != "" {
|
||||
options = append(options, oauth2.SetAuthURLParam("domain_hint", c.domainHint))
|
||||
}
|
||||
|
||||
return c.oauth2Config(scopes).AuthCodeURL(state, options...), nil
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
@ -16,13 +17,68 @@ type testResponse struct {
|
|||
data interface{}
|
||||
}
|
||||
|
||||
const tenant = "9b1c3439-a67e-4e92-bb0d-0571d44ca965"
|
||||
const (
|
||||
tenant = "9b1c3439-a67e-4e92-bb0d-0571d44ca965"
|
||||
clientID = "a115ebf3-6020-4384-8eb1-c0c42e667b6f"
|
||||
)
|
||||
|
||||
var dummyToken = testResponse{data: map[string]interface{}{
|
||||
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
"expires_in": "30",
|
||||
}}
|
||||
|
||||
func TestLoginURL(t *testing.T) {
|
||||
testURL := "https://test.com"
|
||||
testState := "some-state"
|
||||
|
||||
conn := microsoftConnector{
|
||||
apiURL: testURL,
|
||||
graphURL: testURL,
|
||||
redirectURI: testURL,
|
||||
clientID: clientID,
|
||||
tenant: tenant,
|
||||
}
|
||||
|
||||
loginURL, _ := conn.LoginURL(connector.Scopes{}, conn.redirectURI, testState)
|
||||
|
||||
parsedLoginURL, _ := url.Parse(loginURL)
|
||||
queryParams := parsedLoginURL.Query()
|
||||
|
||||
expectEquals(t, parsedLoginURL.Path, "/"+tenant+"/oauth2/v2.0/authorize")
|
||||
expectEquals(t, queryParams.Get("client_id"), clientID)
|
||||
expectEquals(t, queryParams.Get("redirect_uri"), testURL)
|
||||
expectEquals(t, queryParams.Get("response_type"), "code")
|
||||
expectEquals(t, queryParams.Get("scope"), "user.read")
|
||||
expectEquals(t, queryParams.Get("state"), testState)
|
||||
expectEquals(t, queryParams.Get("prompt"), "")
|
||||
expectEquals(t, queryParams.Get("domain_hint"), "")
|
||||
}
|
||||
|
||||
func TestLoginURLWithOptions(t *testing.T) {
|
||||
testURL := "https://test.com"
|
||||
promptType := "consent"
|
||||
domainHint := "domain.hint"
|
||||
|
||||
conn := microsoftConnector{
|
||||
apiURL: testURL,
|
||||
graphURL: testURL,
|
||||
redirectURI: testURL,
|
||||
clientID: clientID,
|
||||
tenant: tenant,
|
||||
|
||||
promptType: promptType,
|
||||
domainHint: domainHint,
|
||||
}
|
||||
|
||||
loginURL, _ := conn.LoginURL(connector.Scopes{}, conn.redirectURI, "some-state")
|
||||
|
||||
parsedLoginURL, _ := url.Parse(loginURL)
|
||||
queryParams := parsedLoginURL.Query()
|
||||
|
||||
expectEquals(t, queryParams.Get("prompt"), promptType)
|
||||
expectEquals(t, queryParams.Get("domain_hint"), domainHint)
|
||||
}
|
||||
|
||||
func TestUserIdentityFromGraphAPI(t *testing.T) {
|
||||
s := newTestServer(map[string]testResponse{
|
||||
"/v1.0/me?$select=id,displayName,userPrincipalName": {
|
||||
|
|
|
@ -58,7 +58,7 @@ func createPassword(cli api.DexClient) error {
|
|||
|
||||
// Create password.
|
||||
if resp, err := cli.CreatePassword(context.TODO(), createReq); err != nil || resp.AlreadyExists {
|
||||
if resp.AlreadyExists {
|
||||
if resp != nil && resp.AlreadyExists {
|
||||
return fmt.Errorf("Password %s already exists", createReq.Password.Email)
|
||||
}
|
||||
return fmt.Errorf("failed to create password: %v", err)
|
||||
|
@ -115,7 +115,7 @@ func createPassword(cli api.DexClient) error {
|
|||
|
||||
// Delete password with email = test@example.com.
|
||||
if resp, err := cli.DeletePassword(context.TODO(), deleteReq); err != nil || resp.NotFound {
|
||||
if resp.NotFound {
|
||||
if resp != nil && resp.NotFound {
|
||||
return fmt.Errorf("Password %s not found", deleteReq.Email)
|
||||
}
|
||||
return fmt.Errorf("failed to delete password: %v", err)
|
||||
|
|
35
go.mod
35
go.mod
|
@ -12,7 +12,7 @@ require (
|
|||
github.com/dexidp/dex/api/v2 v2.1.0
|
||||
github.com/felixge/httpsnoop v1.0.3
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
|
@ -23,26 +23,26 @@ require (
|
|||
github.com/mattn/go-sqlite3 v1.14.11
|
||||
github.com/oklog/run v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/russellhaering/goxmldsig v1.2.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/stretchr/testify v1.7.2
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4
|
||||
go.etcd.io/etcd/client/v3 v3.5.4
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d
|
||||
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401
|
||||
google.golang.org/api v0.82.0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
|
||||
google.golang.org/api v0.89.0
|
||||
google.golang.org/grpc v1.47.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3 // indirect
|
||||
cloud.google.com/go/compute v1.6.1 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
|
@ -52,13 +52,14 @@ require (
|
|||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.10.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.1 // indirect
|
||||
|
@ -71,8 +72,8 @@ require (
|
|||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
|
@ -83,10 +84,10 @@ require (
|
|||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.17.0 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
98
go.sum
98
go.sum
|
@ -29,6 +29,7 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW
|
|||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
|
@ -39,10 +40,12 @@ cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTB
|
|||
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||
cloud.google.com/go/compute v1.6.1 h1:2sMmt8prCn7DPaG4Pmh0N3Inmc8cT8ae5k1M6VJ9Wqc=
|
||||
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
|
||||
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
|
@ -52,13 +55,14 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
|||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
entgo.io/ent v0.10.1 h1:dM5h4Zk6yHGIgw4dCqVzGw3nWgpGYJiV4/kyHEF6PFo=
|
||||
entgo.io/ent v0.10.1/go.mod h1:YPgxeLnoQ/YdpVORRtqjBF+wCy9NX9IR7veTv3Bffus=
|
||||
github.com/AppsFlyer/go-sundheit v0.5.0 h1:/VxpyigCfJrq1r97mn9HPiAB2qrhcTFHwNIIDr15CZM=
|
||||
github.com/AppsFlyer/go-sundheit v0.5.0/go.mod h1:2ZM0BnfqT/mljBQO224VbL5XH06TgWuQ6Cn+cTtCpTY=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
|
@ -113,7 +117,7 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf
|
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -136,19 +140,21 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
|
|||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-ldap/ldap/v3 v3.4.2 h1:zFZKcXKLqZpFMrMQGHeHWKXbDTdNCmhGY9AK41zPh+8=
|
||||
github.com/go-ldap/ldap/v3 v3.4.2/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
|
||||
github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
|
@ -236,6 +242,9 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
|
@ -244,6 +253,7 @@ github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/Oth
|
|||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
|
@ -325,8 +335,9 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
|
|||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
|
||||
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
@ -335,14 +346,16 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
|
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
|
@ -358,29 +371,32 @@ github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR
|
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
|
||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
|
@ -421,10 +437,9 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -502,14 +517,15 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
|||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -529,8 +545,9 @@ golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ
|
|||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 h1:zwrSfklXn0gxyLRX/aR+q6cgHbV/ItVyzbPlbA+dkAw=
|
||||
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -542,7 +559,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -557,7 +574,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -610,8 +626,12 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -685,8 +705,9 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
|
@ -724,8 +745,10 @@ google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc
|
|||
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||
google.golang.org/api v0.82.0 h1:h6EGeZuzhoKSS7BUznzkW+2wHZ+4Ubd6rsVvvh3dRkw=
|
||||
google.golang.org/api v0.82.0/go.mod h1:Ld58BeTlL9DIYr2M2ajvoSqmGLei0BMn+kVBmkam1os=
|
||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||
google.golang.org/api v0.89.0 h1:OUywo5UEEZ8H1eMy55mFpkL9Sy59mQ5TzYGWa+td8zo=
|
||||
google.golang.org/api v0.89.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -773,6 +796,7 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D
|
|||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
|
@ -807,9 +831,12 @@ google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX
|
|||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
|
||||
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8 h1:qRu95HZ148xXw+XeZ3dvqe85PxH4X8+jIo0iRPKcEnM=
|
||||
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
|
||||
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f h1:hJ/Y5SqPXbarffmAsApliUlcvMU+wScNGfyop4bZm8o=
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -856,8 +883,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
|||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"github.com/dexidp/dex/pkg/log"
|
||||
"github.com/dexidp/dex/storage"
|
||||
)
|
||||
|
@ -71,6 +73,17 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
|
|||
clientID := r.Form.Get("client_id")
|
||||
clientSecret := r.Form.Get("client_secret")
|
||||
scopes := strings.Fields(r.Form.Get("scope"))
|
||||
codeChallenge := r.Form.Get("code_challenge")
|
||||
codeChallengeMethod := r.Form.Get("code_challenge_method")
|
||||
|
||||
if codeChallengeMethod == "" {
|
||||
codeChallengeMethod = codeChallengeMethodPlain
|
||||
}
|
||||
if codeChallengeMethod != codeChallengeMethodS256 && codeChallengeMethod != codeChallengeMethodPlain {
|
||||
description := fmt.Sprintf("Unsupported PKCE challenge method (%q).", codeChallengeMethod)
|
||||
s.tokenErrHelper(w, errInvalidRequest, description, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Infof("Received device request for client %v with scopes %v", clientID, scopes)
|
||||
|
||||
|
@ -106,6 +119,10 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
|
|||
Expiry: expireTime,
|
||||
LastRequestTime: s.now(),
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
}
|
||||
|
||||
if err := s.storage.CreateDeviceToken(deviceToken); err != nil {
|
||||
|
@ -234,6 +251,30 @@ func (s *Server) handleDeviceToken(w http.ResponseWriter, r *http.Request) {
|
|||
s.tokenErrHelper(w, deviceTokenPending, "", http.StatusUnauthorized)
|
||||
}
|
||||
case deviceTokenComplete:
|
||||
codeChallengeFromStorage := deviceToken.PKCE.CodeChallenge
|
||||
providedCodeVerifier := r.Form.Get("code_verifier")
|
||||
|
||||
switch {
|
||||
case providedCodeVerifier != "" && codeChallengeFromStorage != "":
|
||||
calculatedCodeChallenge, err := s.calculateCodeChallenge(providedCodeVerifier, deviceToken.PKCE.CodeChallengeMethod)
|
||||
if err != nil {
|
||||
s.logger.Error(err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if codeChallengeFromStorage != calculatedCodeChallenge {
|
||||
s.tokenErrHelper(w, errInvalidGrant, "Invalid code_verifier.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
case providedCodeVerifier != "":
|
||||
// Received no code_challenge on /auth, but a code_verifier on /token
|
||||
s.tokenErrHelper(w, errInvalidRequest, "No PKCE flow started. Cannot check code_verifier.", http.StatusBadRequest)
|
||||
return
|
||||
case codeChallengeFromStorage != "":
|
||||
// Received PKCE request on /auth, but no code_verifier on /token
|
||||
s.tokenErrHelper(w, errInvalidGrant, "Expecting parameter code_verifier in PKCE flow.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.Write([]byte(deviceToken.Token))
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +292,9 @@ func (s *Server) handleDeviceCallback(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// Authorization redirect callback from OAuth2 auth flow.
|
||||
if errMsg := r.FormValue("error"); errMsg != "" {
|
||||
http.Error(w, errMsg+": "+r.FormValue("error_description"), http.StatusBadRequest)
|
||||
// escape the message to prevent cross-site scripting
|
||||
msg := html.EscapeString(errMsg + ": " + r.FormValue("error_description"))
|
||||
http.Error(w, msg, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ func TestHandleDeviceCode(t *testing.T) {
|
|||
tests := []struct {
|
||||
testName string
|
||||
clientID string
|
||||
codeChallengeMethod string
|
||||
requestType string
|
||||
scopes []string
|
||||
expectedResponseCode int
|
||||
|
@ -71,6 +72,24 @@ func TestHandleDeviceCode(t *testing.T) {
|
|||
expectedResponseCode: http.StatusBadRequest,
|
||||
expectedContentType: "application/json",
|
||||
},
|
||||
{
|
||||
testName: "New Code with valid PKCE",
|
||||
clientID: "test",
|
||||
requestType: "POST",
|
||||
scopes: []string{"openid", "profile", "email"},
|
||||
codeChallengeMethod: "S256",
|
||||
expectedResponseCode: http.StatusOK,
|
||||
expectedContentType: "application/json",
|
||||
},
|
||||
{
|
||||
testName: "Invalid code challenge method",
|
||||
clientID: "test",
|
||||
requestType: "POST",
|
||||
codeChallengeMethod: "invalid",
|
||||
scopes: []string{"openid", "profile", "email"},
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
expectedContentType: "application/json",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
|
@ -92,6 +111,7 @@ func TestHandleDeviceCode(t *testing.T) {
|
|||
|
||||
data := url.Values{}
|
||||
data.Set("client_id", tc.clientID)
|
||||
data.Set("code_challenge_method", tc.codeChallengeMethod)
|
||||
for _, scope := range tc.scopes {
|
||||
data.Add("scope", scope)
|
||||
}
|
||||
|
@ -167,12 +187,13 @@ func TestDeviceCallback(t *testing.T) {
|
|||
}
|
||||
|
||||
tests := []struct {
|
||||
testName string
|
||||
expectedResponseCode int
|
||||
values formValues
|
||||
testAuthCode storage.AuthCode
|
||||
testDeviceRequest storage.DeviceRequest
|
||||
testDeviceToken storage.DeviceToken
|
||||
testName string
|
||||
expectedResponseCode int
|
||||
expectedServerResponse string
|
||||
values formValues
|
||||
testAuthCode storage.AuthCode
|
||||
testDeviceRequest storage.DeviceRequest
|
||||
testDeviceToken storage.DeviceToken
|
||||
}{
|
||||
{
|
||||
testName: "Missing State",
|
||||
|
@ -199,7 +220,8 @@ func TestDeviceCallback(t *testing.T) {
|
|||
code: "somecode",
|
||||
error: "Error Condition",
|
||||
},
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
expectedServerResponse: "Error Condition: \n",
|
||||
},
|
||||
{
|
||||
testName: "Expired Auth Code",
|
||||
|
@ -321,6 +343,16 @@ func TestDeviceCallback(t *testing.T) {
|
|||
testDeviceToken: baseDeviceToken,
|
||||
expectedResponseCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
testName: "Prevent cross-site scripting",
|
||||
values: formValues{
|
||||
state: "XXXX-XXXX",
|
||||
code: "somecode",
|
||||
error: "<script>console.log(window);</script>",
|
||||
},
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
expectedServerResponse: "<script>console.log(window);</script>: \n",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
|
@ -373,6 +405,13 @@ func TestDeviceCallback(t *testing.T) {
|
|||
if rr.Code != tc.expectedResponseCode {
|
||||
t.Errorf("%s: Unexpected Response Type. Expected %v got %v", tc.testName, tc.expectedResponseCode, rr.Code)
|
||||
}
|
||||
|
||||
if len(tc.expectedServerResponse) > 0 {
|
||||
result, _ := io.ReadAll(rr.Body)
|
||||
if string(result) != tc.expectedServerResponse {
|
||||
t.Errorf("%s: Unexpected Response. Expected %q got %q", tc.testName, tc.expectedServerResponse, result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +421,13 @@ func TestDeviceTokenResponse(t *testing.T) {
|
|||
|
||||
now := func() time.Time { return t0 }
|
||||
|
||||
// Base PKCE values
|
||||
// base64-urlencoded, sha256 digest of code_verifier
|
||||
codeChallenge := "L7ZqsT_zNwvrH8E7J0CqPHx1wgBaFiaE-fAZcKUUAbc"
|
||||
codeChallengeMethod := "S256"
|
||||
// "random" string between 43 & 128 ASCII characters
|
||||
codeVerifier := "66114650f56cc45dee7ee03c49f048ddf9aa53cbf5b09985832fa4f790ff2604"
|
||||
|
||||
baseDeviceRequest := storage.DeviceRequest{
|
||||
UserCode: "ABCD-WXYZ",
|
||||
DeviceCode: "foo",
|
||||
|
@ -396,6 +442,7 @@ func TestDeviceTokenResponse(t *testing.T) {
|
|||
testDeviceToken storage.DeviceToken
|
||||
testGrantType string
|
||||
testDeviceCode string
|
||||
testCodeVerifier string
|
||||
expectedServerResponse string
|
||||
expectedResponseCode int
|
||||
}{
|
||||
|
@ -505,6 +552,101 @@ func TestDeviceTokenResponse(t *testing.T) {
|
|||
expectedServerResponse: "{\"access_token\": \"foobar\"}",
|
||||
expectedResponseCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
testName: "Successful Exchange with PKCE",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: codeVerifier,
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: "{\"access_token\": \"foobar\"}",
|
||||
expectedResponseCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
testName: "Test Exchange started with PKCE but without verifier provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidGrant,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
testName: "Test Exchange not started with PKCE but verifier provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: codeVerifier,
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidRequest,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
testName: "Test with PKCE but incorrect verifier provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: "invalid",
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidGrant,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
testName: "Test with PKCE but incorrect challenge provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: "invalid",
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: codeVerifier,
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidGrant,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
|
@ -539,6 +681,9 @@ func TestDeviceTokenResponse(t *testing.T) {
|
|||
}
|
||||
data.Set("grant_type", grantType)
|
||||
data.Set("device_code", tc.testDeviceCode)
|
||||
if tc.testCodeVerifier != "" {
|
||||
data.Set("code_verifier", tc.testCodeVerifier)
|
||||
}
|
||||
req, _ := http.NewRequest("POST", u.String(), bytes.NewBufferString(data.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
||||
|
||||
|
|
|
@ -890,6 +890,10 @@ func testGC(t *testing.T, s storage.Storage) {
|
|||
Expiry: expiry,
|
||||
LastRequestTime: time.Now(),
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: "challenge",
|
||||
CodeChallengeMethod: "S256",
|
||||
},
|
||||
}
|
||||
|
||||
if err := s.CreateDeviceToken(dt); err != nil {
|
||||
|
@ -989,6 +993,11 @@ func testDeviceRequestCRUD(t *testing.T, s storage.Storage) {
|
|||
}
|
||||
|
||||
func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
|
||||
codeChallenge := storage.PKCE{
|
||||
CodeChallenge: "code_challenge_test",
|
||||
CodeChallengeMethod: "plain",
|
||||
}
|
||||
|
||||
// Create a Token
|
||||
d1 := storage.DeviceToken{
|
||||
DeviceCode: storage.NewID(),
|
||||
|
@ -997,6 +1006,7 @@ func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
|
|||
Expiry: neverExpire,
|
||||
LastRequestTime: time.Now(),
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: codeChallenge,
|
||||
}
|
||||
|
||||
if err := s.CreateDeviceToken(d1); err != nil {
|
||||
|
@ -1029,4 +1039,7 @@ func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
|
|||
if got.Token != "token data" {
|
||||
t.Fatalf("update failed, wanted token %v got %v", "token data", got.Token)
|
||||
}
|
||||
if !reflect.DeepEqual(got.PKCE, codeChallenge) {
|
||||
t.Fatalf("storage does not support PKCE, wanted challenge=%#v got %#v", codeChallenge, got.PKCE)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ func (d *Database) CreateDeviceToken(token storage.DeviceToken) error {
|
|||
SetExpiry(token.Expiry.UTC()).
|
||||
SetLastRequest(token.LastRequestTime.UTC()).
|
||||
SetStatus(token.Status).
|
||||
SetCodeChallenge(token.PKCE.CodeChallenge).
|
||||
SetCodeChallengeMethod(token.PKCE.CodeChallengeMethod).
|
||||
Save(context.TODO())
|
||||
if err != nil {
|
||||
return convertDBError("create device token: %w", err)
|
||||
|
@ -63,6 +65,8 @@ func (d *Database) UpdateDeviceToken(deviceCode string, updater func(old storage
|
|||
SetExpiry(newToken.Expiry.UTC()).
|
||||
SetLastRequest(newToken.LastRequestTime.UTC()).
|
||||
SetStatus(newToken.Status).
|
||||
SetCodeChallenge(newToken.PKCE.CodeChallenge).
|
||||
SetCodeChallengeMethod(newToken.PKCE.CodeChallengeMethod).
|
||||
Save(context.TODO())
|
||||
if err != nil {
|
||||
return rollback(tx, "update device token uploading: %w", err)
|
||||
|
|
|
@ -164,5 +164,9 @@ func toStorageDeviceToken(t *db.DeviceToken) storage.DeviceToken {
|
|||
Expiry: t.Expiry,
|
||||
LastRequestTime: t.LastRequest,
|
||||
PollIntervalSeconds: t.PollInterval,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: t.CodeChallenge,
|
||||
CodeChallengeMethod: t.CodeChallengeMethod,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ type DeviceToken struct {
|
|||
LastRequest time.Time `json:"last_request,omitempty"`
|
||||
// PollInterval holds the value of the "poll_interval" field.
|
||||
PollInterval int `json:"poll_interval,omitempty"`
|
||||
// CodeChallenge holds the value of the "code_challenge" field.
|
||||
CodeChallenge string `json:"code_challenge,omitempty"`
|
||||
// CodeChallengeMethod holds the value of the "code_challenge_method" field.
|
||||
CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
|
@ -39,7 +43,7 @@ func (*DeviceToken) scanValues(columns []string) ([]interface{}, error) {
|
|||
values[i] = new([]byte)
|
||||
case devicetoken.FieldID, devicetoken.FieldPollInterval:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case devicetoken.FieldDeviceCode, devicetoken.FieldStatus:
|
||||
case devicetoken.FieldDeviceCode, devicetoken.FieldStatus, devicetoken.FieldCodeChallenge, devicetoken.FieldCodeChallengeMethod:
|
||||
values[i] = new(sql.NullString)
|
||||
case devicetoken.FieldExpiry, devicetoken.FieldLastRequest:
|
||||
values[i] = new(sql.NullTime)
|
||||
|
@ -100,6 +104,18 @@ func (dt *DeviceToken) assignValues(columns []string, values []interface{}) erro
|
|||
} else if value.Valid {
|
||||
dt.PollInterval = int(value.Int64)
|
||||
}
|
||||
case devicetoken.FieldCodeChallenge:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field code_challenge", values[i])
|
||||
} else if value.Valid {
|
||||
dt.CodeChallenge = value.String
|
||||
}
|
||||
case devicetoken.FieldCodeChallengeMethod:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field code_challenge_method", values[i])
|
||||
} else if value.Valid {
|
||||
dt.CodeChallengeMethod = value.String
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -142,6 +158,10 @@ func (dt *DeviceToken) String() string {
|
|||
builder.WriteString(dt.LastRequest.Format(time.ANSIC))
|
||||
builder.WriteString(", poll_interval=")
|
||||
builder.WriteString(fmt.Sprintf("%v", dt.PollInterval))
|
||||
builder.WriteString(", code_challenge=")
|
||||
builder.WriteString(dt.CodeChallenge)
|
||||
builder.WriteString(", code_challenge_method=")
|
||||
builder.WriteString(dt.CodeChallengeMethod)
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ const (
|
|||
FieldLastRequest = "last_request"
|
||||
// FieldPollInterval holds the string denoting the poll_interval field in the database.
|
||||
FieldPollInterval = "poll_interval"
|
||||
// FieldCodeChallenge holds the string denoting the code_challenge field in the database.
|
||||
FieldCodeChallenge = "code_challenge"
|
||||
// FieldCodeChallengeMethod holds the string denoting the code_challenge_method field in the database.
|
||||
FieldCodeChallengeMethod = "code_challenge_method"
|
||||
// Table holds the table name of the devicetoken in the database.
|
||||
Table = "device_tokens"
|
||||
)
|
||||
|
@ -32,6 +36,8 @@ var Columns = []string{
|
|||
FieldExpiry,
|
||||
FieldLastRequest,
|
||||
FieldPollInterval,
|
||||
FieldCodeChallenge,
|
||||
FieldCodeChallengeMethod,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
|
@ -49,4 +55,8 @@ var (
|
|||
DeviceCodeValidator func(string) error
|
||||
// StatusValidator is a validator for the "status" field. It is called by the builders before save.
|
||||
StatusValidator func(string) error
|
||||
// DefaultCodeChallenge holds the default value on creation for the "code_challenge" field.
|
||||
DefaultCodeChallenge string
|
||||
// DefaultCodeChallengeMethod holds the default value on creation for the "code_challenge_method" field.
|
||||
DefaultCodeChallengeMethod string
|
||||
)
|
||||
|
|
|
@ -134,6 +134,20 @@ func PollInterval(v int) predicate.DeviceToken {
|
|||
})
|
||||
}
|
||||
|
||||
// CodeChallenge applies equality check predicate on the "code_challenge" field. It's identical to CodeChallengeEQ.
|
||||
func CodeChallenge(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethod applies equality check predicate on the "code_challenge_method" field. It's identical to CodeChallengeMethodEQ.
|
||||
func CodeChallengeMethod(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// DeviceCodeEQ applies the EQ predicate on the "device_code" field.
|
||||
func DeviceCodeEQ(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
|
@ -674,6 +688,228 @@ func PollIntervalLTE(v int) predicate.DeviceToken {
|
|||
})
|
||||
}
|
||||
|
||||
// CodeChallengeEQ applies the EQ predicate on the "code_challenge" field.
|
||||
func CodeChallengeEQ(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeNEQ applies the NEQ predicate on the "code_challenge" field.
|
||||
func CodeChallengeNEQ(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeIn applies the In predicate on the "code_challenge" field.
|
||||
func CodeChallengeIn(vs ...string) predicate.DeviceToken {
|
||||
v := make([]interface{}, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
// if not arguments were provided, append the FALSE constants,
|
||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
||||
if len(v) == 0 {
|
||||
s.Where(sql.False())
|
||||
return
|
||||
}
|
||||
s.Where(sql.In(s.C(FieldCodeChallenge), v...))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeNotIn applies the NotIn predicate on the "code_challenge" field.
|
||||
func CodeChallengeNotIn(vs ...string) predicate.DeviceToken {
|
||||
v := make([]interface{}, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
// if not arguments were provided, append the FALSE constants,
|
||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
||||
if len(v) == 0 {
|
||||
s.Where(sql.False())
|
||||
return
|
||||
}
|
||||
s.Where(sql.NotIn(s.C(FieldCodeChallenge), v...))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeGT applies the GT predicate on the "code_challenge" field.
|
||||
func CodeChallengeGT(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeGTE applies the GTE predicate on the "code_challenge" field.
|
||||
func CodeChallengeGTE(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeLT applies the LT predicate on the "code_challenge" field.
|
||||
func CodeChallengeLT(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeLTE applies the LTE predicate on the "code_challenge" field.
|
||||
func CodeChallengeLTE(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeContains applies the Contains predicate on the "code_challenge" field.
|
||||
func CodeChallengeContains(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.Contains(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeHasPrefix applies the HasPrefix predicate on the "code_challenge" field.
|
||||
func CodeChallengeHasPrefix(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.HasPrefix(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeHasSuffix applies the HasSuffix predicate on the "code_challenge" field.
|
||||
func CodeChallengeHasSuffix(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.HasSuffix(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeEqualFold applies the EqualFold predicate on the "code_challenge" field.
|
||||
func CodeChallengeEqualFold(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.EqualFold(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeContainsFold applies the ContainsFold predicate on the "code_challenge" field.
|
||||
func CodeChallengeContainsFold(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.ContainsFold(s.C(FieldCodeChallenge), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodEQ applies the EQ predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodEQ(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodNEQ applies the NEQ predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodNEQ(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodIn applies the In predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodIn(vs ...string) predicate.DeviceToken {
|
||||
v := make([]interface{}, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
// if not arguments were provided, append the FALSE constants,
|
||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
||||
if len(v) == 0 {
|
||||
s.Where(sql.False())
|
||||
return
|
||||
}
|
||||
s.Where(sql.In(s.C(FieldCodeChallengeMethod), v...))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodNotIn applies the NotIn predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodNotIn(vs ...string) predicate.DeviceToken {
|
||||
v := make([]interface{}, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
// if not arguments were provided, append the FALSE constants,
|
||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
||||
if len(v) == 0 {
|
||||
s.Where(sql.False())
|
||||
return
|
||||
}
|
||||
s.Where(sql.NotIn(s.C(FieldCodeChallengeMethod), v...))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodGT applies the GT predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodGT(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodGTE applies the GTE predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodGTE(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodLT applies the LT predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodLT(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodLTE applies the LTE predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodLTE(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodContains applies the Contains predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodContains(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.Contains(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodHasPrefix applies the HasPrefix predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodHasPrefix(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.HasPrefix(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodHasSuffix applies the HasSuffix predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodHasSuffix(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.HasSuffix(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodEqualFold applies the EqualFold predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodEqualFold(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.EqualFold(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// CodeChallengeMethodContainsFold applies the ContainsFold predicate on the "code_challenge_method" field.
|
||||
func CodeChallengeMethodContainsFold(v string) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
s.Where(sql.ContainsFold(s.C(FieldCodeChallengeMethod), v))
|
||||
})
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.DeviceToken) predicate.DeviceToken {
|
||||
return predicate.DeviceToken(func(s *sql.Selector) {
|
||||
|
|
|
@ -56,6 +56,34 @@ func (dtc *DeviceTokenCreate) SetPollInterval(i int) *DeviceTokenCreate {
|
|||
return dtc
|
||||
}
|
||||
|
||||
// SetCodeChallenge sets the "code_challenge" field.
|
||||
func (dtc *DeviceTokenCreate) SetCodeChallenge(s string) *DeviceTokenCreate {
|
||||
dtc.mutation.SetCodeChallenge(s)
|
||||
return dtc
|
||||
}
|
||||
|
||||
// SetNillableCodeChallenge sets the "code_challenge" field if the given value is not nil.
|
||||
func (dtc *DeviceTokenCreate) SetNillableCodeChallenge(s *string) *DeviceTokenCreate {
|
||||
if s != nil {
|
||||
dtc.SetCodeChallenge(*s)
|
||||
}
|
||||
return dtc
|
||||
}
|
||||
|
||||
// SetCodeChallengeMethod sets the "code_challenge_method" field.
|
||||
func (dtc *DeviceTokenCreate) SetCodeChallengeMethod(s string) *DeviceTokenCreate {
|
||||
dtc.mutation.SetCodeChallengeMethod(s)
|
||||
return dtc
|
||||
}
|
||||
|
||||
// SetNillableCodeChallengeMethod sets the "code_challenge_method" field if the given value is not nil.
|
||||
func (dtc *DeviceTokenCreate) SetNillableCodeChallengeMethod(s *string) *DeviceTokenCreate {
|
||||
if s != nil {
|
||||
dtc.SetCodeChallengeMethod(*s)
|
||||
}
|
||||
return dtc
|
||||
}
|
||||
|
||||
// Mutation returns the DeviceTokenMutation object of the builder.
|
||||
func (dtc *DeviceTokenCreate) Mutation() *DeviceTokenMutation {
|
||||
return dtc.mutation
|
||||
|
@ -67,6 +95,7 @@ func (dtc *DeviceTokenCreate) Save(ctx context.Context) (*DeviceToken, error) {
|
|||
err error
|
||||
node *DeviceToken
|
||||
)
|
||||
dtc.defaults()
|
||||
if len(dtc.hooks) == 0 {
|
||||
if err = dtc.check(); err != nil {
|
||||
return nil, err
|
||||
|
@ -124,6 +153,18 @@ func (dtc *DeviceTokenCreate) ExecX(ctx context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// defaults sets the default values of the builder before save.
|
||||
func (dtc *DeviceTokenCreate) defaults() {
|
||||
if _, ok := dtc.mutation.CodeChallenge(); !ok {
|
||||
v := devicetoken.DefaultCodeChallenge
|
||||
dtc.mutation.SetCodeChallenge(v)
|
||||
}
|
||||
if _, ok := dtc.mutation.CodeChallengeMethod(); !ok {
|
||||
v := devicetoken.DefaultCodeChallengeMethod
|
||||
dtc.mutation.SetCodeChallengeMethod(v)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (dtc *DeviceTokenCreate) check() error {
|
||||
if _, ok := dtc.mutation.DeviceCode(); !ok {
|
||||
|
@ -151,6 +192,12 @@ func (dtc *DeviceTokenCreate) check() error {
|
|||
if _, ok := dtc.mutation.PollInterval(); !ok {
|
||||
return &ValidationError{Name: "poll_interval", err: errors.New(`db: missing required field "DeviceToken.poll_interval"`)}
|
||||
}
|
||||
if _, ok := dtc.mutation.CodeChallenge(); !ok {
|
||||
return &ValidationError{Name: "code_challenge", err: errors.New(`db: missing required field "DeviceToken.code_challenge"`)}
|
||||
}
|
||||
if _, ok := dtc.mutation.CodeChallengeMethod(); !ok {
|
||||
return &ValidationError{Name: "code_challenge_method", err: errors.New(`db: missing required field "DeviceToken.code_challenge_method"`)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -226,6 +273,22 @@ func (dtc *DeviceTokenCreate) createSpec() (*DeviceToken, *sqlgraph.CreateSpec)
|
|||
})
|
||||
_node.PollInterval = value
|
||||
}
|
||||
if value, ok := dtc.mutation.CodeChallenge(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: devicetoken.FieldCodeChallenge,
|
||||
})
|
||||
_node.CodeChallenge = value
|
||||
}
|
||||
if value, ok := dtc.mutation.CodeChallengeMethod(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: devicetoken.FieldCodeChallengeMethod,
|
||||
})
|
||||
_node.CodeChallengeMethod = value
|
||||
}
|
||||
return _node, _spec
|
||||
}
|
||||
|
||||
|
@ -243,6 +306,7 @@ func (dtcb *DeviceTokenCreateBulk) Save(ctx context.Context) ([]*DeviceToken, er
|
|||
for i := range dtcb.builders {
|
||||
func(i int, root context.Context) {
|
||||
builder := dtcb.builders[i]
|
||||
builder.defaults()
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*DeviceTokenMutation)
|
||||
if !ok {
|
||||
|
|
|
@ -77,6 +77,34 @@ func (dtu *DeviceTokenUpdate) AddPollInterval(i int) *DeviceTokenUpdate {
|
|||
return dtu
|
||||
}
|
||||
|
||||
// SetCodeChallenge sets the "code_challenge" field.
|
||||
func (dtu *DeviceTokenUpdate) SetCodeChallenge(s string) *DeviceTokenUpdate {
|
||||
dtu.mutation.SetCodeChallenge(s)
|
||||
return dtu
|
||||
}
|
||||
|
||||
// SetNillableCodeChallenge sets the "code_challenge" field if the given value is not nil.
|
||||
func (dtu *DeviceTokenUpdate) SetNillableCodeChallenge(s *string) *DeviceTokenUpdate {
|
||||
if s != nil {
|
||||
dtu.SetCodeChallenge(*s)
|
||||
}
|
||||
return dtu
|
||||
}
|
||||
|
||||
// SetCodeChallengeMethod sets the "code_challenge_method" field.
|
||||
func (dtu *DeviceTokenUpdate) SetCodeChallengeMethod(s string) *DeviceTokenUpdate {
|
||||
dtu.mutation.SetCodeChallengeMethod(s)
|
||||
return dtu
|
||||
}
|
||||
|
||||
// SetNillableCodeChallengeMethod sets the "code_challenge_method" field if the given value is not nil.
|
||||
func (dtu *DeviceTokenUpdate) SetNillableCodeChallengeMethod(s *string) *DeviceTokenUpdate {
|
||||
if s != nil {
|
||||
dtu.SetCodeChallengeMethod(*s)
|
||||
}
|
||||
return dtu
|
||||
}
|
||||
|
||||
// Mutation returns the DeviceTokenMutation object of the builder.
|
||||
func (dtu *DeviceTokenUpdate) Mutation() *DeviceTokenMutation {
|
||||
return dtu.mutation
|
||||
|
@ -230,6 +258,20 @@ func (dtu *DeviceTokenUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||
Column: devicetoken.FieldPollInterval,
|
||||
})
|
||||
}
|
||||
if value, ok := dtu.mutation.CodeChallenge(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: devicetoken.FieldCodeChallenge,
|
||||
})
|
||||
}
|
||||
if value, ok := dtu.mutation.CodeChallengeMethod(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: devicetoken.FieldCodeChallengeMethod,
|
||||
})
|
||||
}
|
||||
if n, err = sqlgraph.UpdateNodes(ctx, dtu.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{devicetoken.Label}
|
||||
|
@ -298,6 +340,34 @@ func (dtuo *DeviceTokenUpdateOne) AddPollInterval(i int) *DeviceTokenUpdateOne {
|
|||
return dtuo
|
||||
}
|
||||
|
||||
// SetCodeChallenge sets the "code_challenge" field.
|
||||
func (dtuo *DeviceTokenUpdateOne) SetCodeChallenge(s string) *DeviceTokenUpdateOne {
|
||||
dtuo.mutation.SetCodeChallenge(s)
|
||||
return dtuo
|
||||
}
|
||||
|
||||
// SetNillableCodeChallenge sets the "code_challenge" field if the given value is not nil.
|
||||
func (dtuo *DeviceTokenUpdateOne) SetNillableCodeChallenge(s *string) *DeviceTokenUpdateOne {
|
||||
if s != nil {
|
||||
dtuo.SetCodeChallenge(*s)
|
||||
}
|
||||
return dtuo
|
||||
}
|
||||
|
||||
// SetCodeChallengeMethod sets the "code_challenge_method" field.
|
||||
func (dtuo *DeviceTokenUpdateOne) SetCodeChallengeMethod(s string) *DeviceTokenUpdateOne {
|
||||
dtuo.mutation.SetCodeChallengeMethod(s)
|
||||
return dtuo
|
||||
}
|
||||
|
||||
// SetNillableCodeChallengeMethod sets the "code_challenge_method" field if the given value is not nil.
|
||||
func (dtuo *DeviceTokenUpdateOne) SetNillableCodeChallengeMethod(s *string) *DeviceTokenUpdateOne {
|
||||
if s != nil {
|
||||
dtuo.SetCodeChallengeMethod(*s)
|
||||
}
|
||||
return dtuo
|
||||
}
|
||||
|
||||
// Mutation returns the DeviceTokenMutation object of the builder.
|
||||
func (dtuo *DeviceTokenUpdateOne) Mutation() *DeviceTokenMutation {
|
||||
return dtuo.mutation
|
||||
|
@ -475,6 +545,20 @@ func (dtuo *DeviceTokenUpdateOne) sqlSave(ctx context.Context) (_node *DeviceTok
|
|||
Column: devicetoken.FieldPollInterval,
|
||||
})
|
||||
}
|
||||
if value, ok := dtuo.mutation.CodeChallenge(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: devicetoken.FieldCodeChallenge,
|
||||
})
|
||||
}
|
||||
if value, ok := dtuo.mutation.CodeChallengeMethod(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: devicetoken.FieldCodeChallengeMethod,
|
||||
})
|
||||
}
|
||||
_node = &DeviceToken{config: dtuo.config}
|
||||
_spec.Assign = _node.assignValues
|
||||
_spec.ScanValues = _node.scanValues
|
||||
|
|
|
@ -101,6 +101,8 @@ var (
|
|||
{Name: "expiry", Type: field.TypeTime, SchemaType: map[string]string{"mysql": "datetime(3)", "postgres": "timestamptz", "sqlite3": "timestamp"}},
|
||||
{Name: "last_request", Type: field.TypeTime, SchemaType: map[string]string{"mysql": "datetime(3)", "postgres": "timestamptz", "sqlite3": "timestamp"}},
|
||||
{Name: "poll_interval", Type: field.TypeInt},
|
||||
{Name: "code_challenge", Type: field.TypeString, Size: 2147483647, Default: "", SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
|
||||
{Name: "code_challenge_method", Type: field.TypeString, Size: 2147483647, Default: "", SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
|
||||
}
|
||||
// DeviceTokensTable holds the schema information for the "device_tokens" table.
|
||||
DeviceTokensTable = &schema.Table{
|
||||
|
|
|
@ -3633,20 +3633,22 @@ func (m *DeviceRequestMutation) ResetEdge(name string) error {
|
|||
// DeviceTokenMutation represents an operation that mutates the DeviceToken nodes in the graph.
|
||||
type DeviceTokenMutation struct {
|
||||
config
|
||||
op Op
|
||||
typ string
|
||||
id *int
|
||||
device_code *string
|
||||
status *string
|
||||
token *[]byte
|
||||
expiry *time.Time
|
||||
last_request *time.Time
|
||||
poll_interval *int
|
||||
addpoll_interval *int
|
||||
clearedFields map[string]struct{}
|
||||
done bool
|
||||
oldValue func(context.Context) (*DeviceToken, error)
|
||||
predicates []predicate.DeviceToken
|
||||
op Op
|
||||
typ string
|
||||
id *int
|
||||
device_code *string
|
||||
status *string
|
||||
token *[]byte
|
||||
expiry *time.Time
|
||||
last_request *time.Time
|
||||
poll_interval *int
|
||||
addpoll_interval *int
|
||||
code_challenge *string
|
||||
code_challenge_method *string
|
||||
clearedFields map[string]struct{}
|
||||
done bool
|
||||
oldValue func(context.Context) (*DeviceToken, error)
|
||||
predicates []predicate.DeviceToken
|
||||
}
|
||||
|
||||
var _ ent.Mutation = (*DeviceTokenMutation)(nil)
|
||||
|
@ -3996,6 +3998,78 @@ func (m *DeviceTokenMutation) ResetPollInterval() {
|
|||
m.addpoll_interval = nil
|
||||
}
|
||||
|
||||
// SetCodeChallenge sets the "code_challenge" field.
|
||||
func (m *DeviceTokenMutation) SetCodeChallenge(s string) {
|
||||
m.code_challenge = &s
|
||||
}
|
||||
|
||||
// CodeChallenge returns the value of the "code_challenge" field in the mutation.
|
||||
func (m *DeviceTokenMutation) CodeChallenge() (r string, exists bool) {
|
||||
v := m.code_challenge
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldCodeChallenge returns the old "code_challenge" field's value of the DeviceToken entity.
|
||||
// If the DeviceToken object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *DeviceTokenMutation) OldCodeChallenge(ctx context.Context) (v string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldCodeChallenge is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldCodeChallenge requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldCodeChallenge: %w", err)
|
||||
}
|
||||
return oldValue.CodeChallenge, nil
|
||||
}
|
||||
|
||||
// ResetCodeChallenge resets all changes to the "code_challenge" field.
|
||||
func (m *DeviceTokenMutation) ResetCodeChallenge() {
|
||||
m.code_challenge = nil
|
||||
}
|
||||
|
||||
// SetCodeChallengeMethod sets the "code_challenge_method" field.
|
||||
func (m *DeviceTokenMutation) SetCodeChallengeMethod(s string) {
|
||||
m.code_challenge_method = &s
|
||||
}
|
||||
|
||||
// CodeChallengeMethod returns the value of the "code_challenge_method" field in the mutation.
|
||||
func (m *DeviceTokenMutation) CodeChallengeMethod() (r string, exists bool) {
|
||||
v := m.code_challenge_method
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldCodeChallengeMethod returns the old "code_challenge_method" field's value of the DeviceToken entity.
|
||||
// If the DeviceToken object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *DeviceTokenMutation) OldCodeChallengeMethod(ctx context.Context) (v string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldCodeChallengeMethod is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldCodeChallengeMethod requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldCodeChallengeMethod: %w", err)
|
||||
}
|
||||
return oldValue.CodeChallengeMethod, nil
|
||||
}
|
||||
|
||||
// ResetCodeChallengeMethod resets all changes to the "code_challenge_method" field.
|
||||
func (m *DeviceTokenMutation) ResetCodeChallengeMethod() {
|
||||
m.code_challenge_method = nil
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the DeviceTokenMutation builder.
|
||||
func (m *DeviceTokenMutation) Where(ps ...predicate.DeviceToken) {
|
||||
m.predicates = append(m.predicates, ps...)
|
||||
|
@ -4015,7 +4089,7 @@ func (m *DeviceTokenMutation) Type() string {
|
|||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *DeviceTokenMutation) Fields() []string {
|
||||
fields := make([]string, 0, 6)
|
||||
fields := make([]string, 0, 8)
|
||||
if m.device_code != nil {
|
||||
fields = append(fields, devicetoken.FieldDeviceCode)
|
||||
}
|
||||
|
@ -4034,6 +4108,12 @@ func (m *DeviceTokenMutation) Fields() []string {
|
|||
if m.poll_interval != nil {
|
||||
fields = append(fields, devicetoken.FieldPollInterval)
|
||||
}
|
||||
if m.code_challenge != nil {
|
||||
fields = append(fields, devicetoken.FieldCodeChallenge)
|
||||
}
|
||||
if m.code_challenge_method != nil {
|
||||
fields = append(fields, devicetoken.FieldCodeChallengeMethod)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
|
@ -4054,6 +4134,10 @@ func (m *DeviceTokenMutation) Field(name string) (ent.Value, bool) {
|
|||
return m.LastRequest()
|
||||
case devicetoken.FieldPollInterval:
|
||||
return m.PollInterval()
|
||||
case devicetoken.FieldCodeChallenge:
|
||||
return m.CodeChallenge()
|
||||
case devicetoken.FieldCodeChallengeMethod:
|
||||
return m.CodeChallengeMethod()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
@ -4075,6 +4159,10 @@ func (m *DeviceTokenMutation) OldField(ctx context.Context, name string) (ent.Va
|
|||
return m.OldLastRequest(ctx)
|
||||
case devicetoken.FieldPollInterval:
|
||||
return m.OldPollInterval(ctx)
|
||||
case devicetoken.FieldCodeChallenge:
|
||||
return m.OldCodeChallenge(ctx)
|
||||
case devicetoken.FieldCodeChallengeMethod:
|
||||
return m.OldCodeChallengeMethod(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown DeviceToken field %s", name)
|
||||
}
|
||||
|
@ -4126,6 +4214,20 @@ func (m *DeviceTokenMutation) SetField(name string, value ent.Value) error {
|
|||
}
|
||||
m.SetPollInterval(v)
|
||||
return nil
|
||||
case devicetoken.FieldCodeChallenge:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetCodeChallenge(v)
|
||||
return nil
|
||||
case devicetoken.FieldCodeChallengeMethod:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetCodeChallengeMethod(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown DeviceToken field %s", name)
|
||||
}
|
||||
|
@ -4217,6 +4319,12 @@ func (m *DeviceTokenMutation) ResetField(name string) error {
|
|||
case devicetoken.FieldPollInterval:
|
||||
m.ResetPollInterval()
|
||||
return nil
|
||||
case devicetoken.FieldCodeChallenge:
|
||||
m.ResetCodeChallenge()
|
||||
return nil
|
||||
case devicetoken.FieldCodeChallengeMethod:
|
||||
m.ResetCodeChallengeMethod()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown DeviceToken field %s", name)
|
||||
}
|
||||
|
|
|
@ -142,6 +142,14 @@ func init() {
|
|||
devicetokenDescStatus := devicetokenFields[1].Descriptor()
|
||||
// devicetoken.StatusValidator is a validator for the "status" field. It is called by the builders before save.
|
||||
devicetoken.StatusValidator = devicetokenDescStatus.Validators[0].(func(string) error)
|
||||
// devicetokenDescCodeChallenge is the schema descriptor for code_challenge field.
|
||||
devicetokenDescCodeChallenge := devicetokenFields[6].Descriptor()
|
||||
// devicetoken.DefaultCodeChallenge holds the default value on creation for the code_challenge field.
|
||||
devicetoken.DefaultCodeChallenge = devicetokenDescCodeChallenge.Default.(string)
|
||||
// devicetokenDescCodeChallengeMethod is the schema descriptor for code_challenge_method field.
|
||||
devicetokenDescCodeChallengeMethod := devicetokenFields[7].Descriptor()
|
||||
// devicetoken.DefaultCodeChallengeMethod holds the default value on creation for the code_challenge_method field.
|
||||
devicetoken.DefaultCodeChallengeMethod = devicetokenDescCodeChallengeMethod.Default.(string)
|
||||
keysFields := schema.Keys{}.Fields()
|
||||
_ = keysFields
|
||||
// keysDescID is the schema descriptor for id field.
|
||||
|
|
|
@ -8,12 +8,14 @@ import (
|
|||
/* Original SQL table:
|
||||
create table device_token
|
||||
(
|
||||
device_code text not null primary key,
|
||||
status text not null,
|
||||
token blob,
|
||||
expiry timestamp not null,
|
||||
last_request timestamp not null,
|
||||
poll_interval integer not null
|
||||
device_code text not null primary key,
|
||||
status text not null,
|
||||
token blob,
|
||||
expiry timestamp not null,
|
||||
last_request timestamp not null,
|
||||
poll_interval integer not null,
|
||||
code_challenge text default '' not null,
|
||||
code_challenge_method text default '' not null
|
||||
);
|
||||
*/
|
||||
|
||||
|
@ -38,6 +40,12 @@ func (DeviceToken) Fields() []ent.Field {
|
|||
field.Time("last_request").
|
||||
SchemaType(timeSchema),
|
||||
field.Int("poll_interval"),
|
||||
field.Text("code_challenge").
|
||||
SchemaType(textSchema).
|
||||
Default(""),
|
||||
field.Text("code_challenge_method").
|
||||
SchemaType(textSchema).
|
||||
Default(""),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -605,8 +605,11 @@ func (c *conn) CreateDeviceToken(t storage.DeviceToken) error {
|
|||
func (c *conn) GetDeviceToken(deviceCode string) (t storage.DeviceToken, err error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultStorageTimeout)
|
||||
defer cancel()
|
||||
err = c.getKey(ctx, keyID(deviceTokenPrefix, deviceCode), &t)
|
||||
return t, err
|
||||
var dt DeviceToken
|
||||
if err = c.getKey(ctx, keyID(deviceTokenPrefix, deviceCode), &dt); err == nil {
|
||||
t = toStorageDeviceToken(dt)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *conn) listDeviceTokens(ctx context.Context) (deviceTokens []DeviceToken, err error) {
|
||||
|
|
|
@ -281,6 +281,8 @@ type DeviceToken struct {
|
|||
Expiry time.Time `json:"expiry"`
|
||||
LastRequestTime time.Time `json:"last_request"`
|
||||
PollIntervalSeconds int `json:"poll_interval"`
|
||||
CodeChallenge string `json:"code_challenge,omitempty"`
|
||||
CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
|
||||
}
|
||||
|
||||
func fromStorageDeviceToken(t storage.DeviceToken) DeviceToken {
|
||||
|
@ -291,6 +293,8 @@ func fromStorageDeviceToken(t storage.DeviceToken) DeviceToken {
|
|||
Expiry: t.Expiry,
|
||||
LastRequestTime: t.LastRequestTime,
|
||||
PollIntervalSeconds: t.PollIntervalSeconds,
|
||||
CodeChallenge: t.PKCE.CodeChallenge,
|
||||
CodeChallengeMethod: t.PKCE.CodeChallengeMethod,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,5 +306,9 @@ func toStorageDeviceToken(t DeviceToken) storage.DeviceToken {
|
|||
Expiry: t.Expiry,
|
||||
LastRequestTime: t.LastRequestTime,
|
||||
PollIntervalSeconds: t.PollIntervalSeconds,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: t.CodeChallenge,
|
||||
CodeChallengeMethod: t.CodeChallengeMethod,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
@ -82,7 +83,9 @@ func offlineTokenName(userID string, connID string, h func() hash.Hash) string {
|
|||
return strings.TrimRight(encoding.EncodeToString(hash.Sum(nil)), "=")
|
||||
}
|
||||
|
||||
func (cli *client) urlFor(apiVersion, namespace, resource, name string) string {
|
||||
func (cli *client) urlForWithParams(
|
||||
apiVersion, namespace, resource, name string, params url.Values,
|
||||
) string {
|
||||
basePath := "apis/"
|
||||
if apiVersion == "v1" {
|
||||
basePath = "api/"
|
||||
|
@ -94,10 +97,22 @@ func (cli *client) urlFor(apiVersion, namespace, resource, name string) string {
|
|||
} else {
|
||||
p = path.Join(basePath, apiVersion, resource, name)
|
||||
}
|
||||
if strings.HasSuffix(cli.baseURL, "/") {
|
||||
return cli.baseURL + p
|
||||
|
||||
encodedParams := params.Encode()
|
||||
paramsSuffix := ""
|
||||
if len(encodedParams) > 0 {
|
||||
paramsSuffix = "?" + encodedParams
|
||||
}
|
||||
return cli.baseURL + "/" + p
|
||||
|
||||
if strings.HasSuffix(cli.baseURL, "/") {
|
||||
return cli.baseURL + p + paramsSuffix
|
||||
}
|
||||
|
||||
return cli.baseURL + "/" + p + paramsSuffix
|
||||
}
|
||||
|
||||
func (cli *client) urlFor(apiVersion, namespace, resource, name string) string {
|
||||
return cli.urlForWithParams(apiVersion, namespace, resource, name, url.Values{})
|
||||
}
|
||||
|
||||
// Define an error interface so we can get at the underlying status code if it's
|
||||
|
@ -163,8 +178,7 @@ func (cli *client) get(resource, name string, v interface{}) error {
|
|||
return cli.getResource(cli.apiVersion, cli.namespace, resource, name, v)
|
||||
}
|
||||
|
||||
func (cli *client) getResource(apiVersion, namespace, resource, name string, v interface{}) error {
|
||||
url := cli.urlFor(apiVersion, namespace, resource, name)
|
||||
func (cli *client) getURL(url string, v interface{}) error {
|
||||
resp, err := cli.client.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -176,6 +190,17 @@ func (cli *client) getResource(apiVersion, namespace, resource, name string, v i
|
|||
return json.NewDecoder(resp.Body).Decode(v)
|
||||
}
|
||||
|
||||
func (cli *client) getResource(apiVersion, namespace, resource, name string, v interface{}) error {
|
||||
return cli.getURL(cli.urlFor(apiVersion, namespace, resource, name), v)
|
||||
}
|
||||
|
||||
func (cli *client) listN(resource string, v interface{}, n int) error {
|
||||
params := url.Values{}
|
||||
params.Add("limit", fmt.Sprintf("%d", n))
|
||||
u := cli.urlForWithParams(cli.apiVersion, cli.namespace, resource, "", params)
|
||||
return cli.getURL(u, v)
|
||||
}
|
||||
|
||||
func (cli *client) list(resource string, v interface{}) error {
|
||||
return cli.get(resource, "", v)
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ const (
|
|||
resourceDeviceToken = "devicetokens"
|
||||
)
|
||||
|
||||
const (
|
||||
gcResultLimit = 500
|
||||
)
|
||||
|
||||
// Config values for the Kubernetes storage type.
|
||||
type Config struct {
|
||||
InCluster bool `json:"inCluster"`
|
||||
|
@ -599,7 +603,7 @@ func (cli *client) UpdateConnector(id string, updater func(a storage.Connector)
|
|||
|
||||
func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err error) {
|
||||
var authRequests AuthRequestList
|
||||
if err := cli.list(resourceAuthRequest, &authRequests); err != nil {
|
||||
if err := cli.listN(resourceAuthRequest, &authRequests, gcResultLimit); err != nil {
|
||||
return result, fmt.Errorf("failed to list auth requests: %v", err)
|
||||
}
|
||||
|
||||
|
@ -618,7 +622,7 @@ func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err e
|
|||
}
|
||||
|
||||
var authCodes AuthCodeList
|
||||
if err := cli.list(resourceAuthCode, &authCodes); err != nil {
|
||||
if err := cli.listN(resourceAuthCode, &authCodes, gcResultLimit); err != nil {
|
||||
return result, fmt.Errorf("failed to list auth codes: %v", err)
|
||||
}
|
||||
|
||||
|
@ -633,7 +637,7 @@ func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err e
|
|||
}
|
||||
|
||||
var deviceRequests DeviceRequestList
|
||||
if err := cli.list(resourceDeviceRequest, &deviceRequests); err != nil {
|
||||
if err := cli.listN(resourceDeviceRequest, &deviceRequests, gcResultLimit); err != nil {
|
||||
return result, fmt.Errorf("failed to list device requests: %v", err)
|
||||
}
|
||||
|
||||
|
@ -648,7 +652,7 @@ func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err e
|
|||
}
|
||||
|
||||
var deviceTokens DeviceTokenList
|
||||
if err := cli.list(resourceDeviceToken, &deviceTokens); err != nil {
|
||||
if err := cli.listN(resourceDeviceToken, &deviceTokens, gcResultLimit); err != nil {
|
||||
return result, fmt.Errorf("failed to list device tokens: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -802,6 +802,8 @@ type DeviceToken struct {
|
|||
Expiry time.Time `json:"expiry"`
|
||||
LastRequestTime time.Time `json:"last_request"`
|
||||
PollIntervalSeconds int `json:"poll_interval"`
|
||||
CodeChallenge string `json:"code_challenge,omitempty"`
|
||||
CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
|
||||
}
|
||||
|
||||
// DeviceTokenList is a list of DeviceTokens.
|
||||
|
@ -826,6 +828,8 @@ func (cli *client) fromStorageDeviceToken(t storage.DeviceToken) DeviceToken {
|
|||
Expiry: t.Expiry,
|
||||
LastRequestTime: t.LastRequestTime,
|
||||
PollIntervalSeconds: t.PollIntervalSeconds,
|
||||
CodeChallenge: t.PKCE.CodeChallenge,
|
||||
CodeChallengeMethod: t.PKCE.CodeChallengeMethod,
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
@ -838,5 +842,9 @@ func toStorageDeviceToken(t DeviceToken) storage.DeviceToken {
|
|||
Expiry: t.Expiry,
|
||||
LastRequestTime: t.LastRequestTime,
|
||||
PollIntervalSeconds: t.PollIntervalSeconds,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: t.CodeChallenge,
|
||||
CodeChallengeMethod: t.CodeChallengeMethod,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -927,12 +927,12 @@ func (c *conn) CreateDeviceRequest(d storage.DeviceRequest) error {
|
|||
func (c *conn) CreateDeviceToken(t storage.DeviceToken) error {
|
||||
_, err := c.Exec(`
|
||||
insert into device_token (
|
||||
device_code, status, token, expiry, last_request, poll_interval
|
||||
device_code, status, token, expiry, last_request, poll_interval, code_challenge, code_challenge_method
|
||||
)
|
||||
values (
|
||||
$1, $2, $3, $4, $5, $6
|
||||
$1, $2, $3, $4, $5, $6, $7, $8
|
||||
);`,
|
||||
t.DeviceCode, t.Status, t.Token, t.Expiry, t.LastRequestTime, t.PollIntervalSeconds,
|
||||
t.DeviceCode, t.Status, t.Token, t.Expiry, t.LastRequestTime, t.PollIntervalSeconds, t.PKCE.CodeChallenge, t.PKCE.CodeChallengeMethod,
|
||||
)
|
||||
if err != nil {
|
||||
if c.alreadyExistsCheck(err) {
|
||||
|
@ -972,10 +972,10 @@ func (c *conn) GetDeviceToken(deviceCode string) (storage.DeviceToken, error) {
|
|||
func getDeviceToken(q querier, deviceCode string) (a storage.DeviceToken, err error) {
|
||||
err = q.QueryRow(`
|
||||
select
|
||||
status, token, expiry, last_request, poll_interval
|
||||
status, token, expiry, last_request, poll_interval, code_challenge, code_challenge_method
|
||||
from device_token where device_code = $1;
|
||||
`, deviceCode).Scan(
|
||||
&a.Status, &a.Token, &a.Expiry, &a.LastRequestTime, &a.PollIntervalSeconds,
|
||||
&a.Status, &a.Token, &a.Expiry, &a.LastRequestTime, &a.PollIntervalSeconds, &a.PKCE.CodeChallenge, &a.PKCE.CodeChallengeMethod,
|
||||
)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -1002,11 +1002,13 @@ func (c *conn) UpdateDeviceToken(deviceCode string, updater func(old storage.Dev
|
|||
status = $1,
|
||||
token = $2,
|
||||
last_request = $3,
|
||||
poll_interval = $4
|
||||
poll_interval = $4,
|
||||
code_challenge = $5,
|
||||
code_challenge_method = $6
|
||||
where
|
||||
device_code = $5
|
||||
device_code = $7
|
||||
`,
|
||||
r.Status, r.Token, r.LastRequestTime, r.PollIntervalSeconds, r.DeviceCode,
|
||||
r.Status, r.Token, r.LastRequestTime, r.PollIntervalSeconds, r.PKCE.CodeChallenge, r.PKCE.CodeChallengeMethod, r.DeviceCode,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update device token: %v", err)
|
||||
|
|
|
@ -281,4 +281,14 @@ var migrations = []migration{
|
|||
add column obsolete_token text default '';`,
|
||||
},
|
||||
},
|
||||
{
|
||||
stmts: []string{
|
||||
`
|
||||
alter table device_token
|
||||
add column code_challenge text not null default '';`,
|
||||
`
|
||||
alter table device_token
|
||||
add column code_challenge_method text not null default '';`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -427,4 +427,5 @@ type DeviceToken struct {
|
|||
Expiry time.Time
|
||||
LastRequestTime time.Time
|
||||
PollIntervalSeconds int
|
||||
PKCE PKCE
|
||||
}
|
||||
|
|
Reference in New Issue