github.com/google/osv-scalibr@v0.4.1/veles/secrets/slacktoken/validator.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package slacktoken 16 17 import ( 18 "encoding/json" 19 "io" 20 "net/http" 21 "time" 22 23 "github.com/google/osv-scalibr/veles" 24 "github.com/google/osv-scalibr/veles/secrets/common/simplevalidate" 25 ) 26 27 // slackResponse represents the common response structure from Slack API 28 type slackResponse struct { 29 Ok bool `json:"ok"` 30 Error string `json:"error"` 31 } 32 33 const ( 34 // slackAPIBaseURL is the base URL for Slack API. 35 slackAPIBaseURL = "https://slack.com" 36 // SlackAPIEndpoint is the API endpoint for token validation. 37 SlackAPIEndpoint = "/api/auth.test" 38 // validationTimeout is timeout for API validation requests. 39 validationTimeout = 10 * time.Second 40 ) 41 42 func statusFromResponseBody(body io.Reader) (veles.ValidationStatus, error) { 43 bodyBytes, err := io.ReadAll(body) 44 if err != nil { 45 return veles.ValidationFailed, err 46 } 47 48 var response slackResponse 49 if err := json.Unmarshal(bodyBytes, &response); err != nil { 50 return veles.ValidationFailed, err 51 } 52 53 if response.Ok { 54 return veles.ValidationValid, nil 55 } 56 if response.Error == "invalid_auth" { 57 return veles.ValidationInvalid, nil 58 } 59 return veles.ValidationFailed, nil 60 } 61 62 // NewAppLevelTokenValidator creates a new Validator for SlackAppLevelToken. 63 func NewAppLevelTokenValidator() *simplevalidate.Validator[SlackAppLevelToken] { 64 return &simplevalidate.Validator[SlackAppLevelToken]{ 65 Endpoint: slackAPIBaseURL + SlackAPIEndpoint, 66 HTTPMethod: http.MethodPost, 67 HTTPHeaders: func(k SlackAppLevelToken) map[string]string { 68 return map[string]string{ 69 "Authorization": "Bearer " + k.Token, 70 "Content-Type": "application/x-www-form-urlencoded", 71 } 72 }, 73 StatusFromResponseBody: statusFromResponseBody, 74 HTTPC: &http.Client{ 75 Timeout: validationTimeout, 76 }, 77 } 78 } 79 80 // NewAppConfigAccessTokenValidator creates a new Validator for SlackAppConfigAccessToken. 81 func NewAppConfigAccessTokenValidator() *simplevalidate.Validator[SlackAppConfigAccessToken] { 82 return &simplevalidate.Validator[SlackAppConfigAccessToken]{ 83 Endpoint: slackAPIBaseURL + SlackAPIEndpoint, 84 HTTPMethod: http.MethodPost, 85 HTTPHeaders: func(k SlackAppConfigAccessToken) map[string]string { 86 return map[string]string{ 87 "Authorization": "Bearer " + k.Token, 88 "Content-Type": "application/x-www-form-urlencoded", 89 } 90 }, 91 StatusFromResponseBody: statusFromResponseBody, 92 HTTPC: &http.Client{ 93 Timeout: validationTimeout, 94 }, 95 } 96 } 97 98 // NewAppConfigRefreshTokenValidator creates a new Validator for SlackAppConfigRefreshToken. 99 func NewAppConfigRefreshTokenValidator() *simplevalidate.Validator[SlackAppConfigRefreshToken] { 100 return &simplevalidate.Validator[SlackAppConfigRefreshToken]{ 101 Endpoint: slackAPIBaseURL + SlackAPIEndpoint, 102 HTTPMethod: http.MethodPost, 103 HTTPHeaders: func(k SlackAppConfigRefreshToken) map[string]string { 104 return map[string]string{ 105 "Authorization": "Bearer " + k.Token, 106 "Content-Type": "application/x-www-form-urlencoded", 107 } 108 }, 109 StatusFromResponseBody: statusFromResponseBody, 110 HTTPC: &http.Client{ 111 Timeout: validationTimeout, 112 }, 113 } 114 }