vendor
This commit is contained in:
parent
c8cdd1f2cf
commit
8e386659e2
BIN
src/server/Order.png
Normal file
BIN
src/server/Order.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
@ -2,9 +2,12 @@ package game
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
mergeDataCfg "server/conf/mergeData"
|
||||||
"server/game/mod/order"
|
"server/game/mod/order"
|
||||||
"server/game/mod/sevenLogin"
|
"server/game/mod/sevenLogin"
|
||||||
"server/msg"
|
"server/msg"
|
||||||
|
"server/pkg/github.com/name5566/leaf/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UnitEndlessReward(p *Player) error {
|
func UnitEndlessReward(p *Player) error {
|
||||||
@ -105,3 +108,75 @@ func UnitCard(p *Player) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func UnitOrder1(p *Player, Lv, EnergyMul int) ([]string, [][]float64) {
|
||||||
|
// ChessMod := p.PlayMod.getChessMod()
|
||||||
|
// Emit := ChessMod.GetEmitList()
|
||||||
|
// OrderMod := p.PlayMod.getOrderMod()
|
||||||
|
// OrderMod.LastDiff = 1
|
||||||
|
// OrderMod.OrderList = make(map[int]order.Order)
|
||||||
|
// // ChessMod := p.PlayMod.getChessMod()
|
||||||
|
// // EmitList := ChessMod.GetEmitList()
|
||||||
|
// // fmt.Println(EmitList)
|
||||||
|
// OrderMod.Debug = make(map[int]int)
|
||||||
|
// for i := 0; i < 5000; i++ {
|
||||||
|
// err := OrderMod.CreateNormalOrder(Lv, Emit, EnergyMul)
|
||||||
|
// log.Debug("OrderMod.CreateNormalOrder %d", i)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// I := make(map[int]int)
|
||||||
|
// for k, v := range OrderMod.Debug {
|
||||||
|
// // fmt.Printf("chessId %d, num %d\n", k, v)
|
||||||
|
// ChessLv := mergeDataCfg.GetLvById(k)
|
||||||
|
// I[ChessLv] += v
|
||||||
|
// }
|
||||||
|
// keys := make([]int, 0, len(I))
|
||||||
|
// Sum := 0
|
||||||
|
// for k, v := range I {
|
||||||
|
// Sum += v
|
||||||
|
// keys = append(keys, k)
|
||||||
|
// }
|
||||||
|
// sort.Ints(keys)
|
||||||
|
// xValue := make([]string, 0)
|
||||||
|
// yValue := make([][]float64, 0)
|
||||||
|
// line := make([]float64, 0)
|
||||||
|
// for _, k := range keys {
|
||||||
|
// xValue = append(xValue, fmt.Sprintf("Lv %d", k))
|
||||||
|
// line = append(line, float64(I[k])/float64(Sum)*100)
|
||||||
|
// fmt.Printf("Lv %d, num %.2f %%\n", k, float64(I[k])/float64(Sum)*100)
|
||||||
|
// }
|
||||||
|
// yValue = append(yValue, line)
|
||||||
|
// return xValue, yValue
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnitOrder2(p *Player, Lv, EnergyMul int) float64 {
|
||||||
|
ChessMod := p.PlayMod.getChessMod()
|
||||||
|
Emit := ChessMod.GetEmitList()
|
||||||
|
OrderMod := p.PlayMod.getOrderMod()
|
||||||
|
OrderMod.LastDiff = 1
|
||||||
|
OrderMod.OrderList = make(map[int]order.Order)
|
||||||
|
// ChessMod := p.PlayMod.getChessMod()
|
||||||
|
// EmitList := ChessMod.GetEmitList()
|
||||||
|
// fmt.Println(EmitList)
|
||||||
|
// OrderMod.Debug = make(map[int]int)
|
||||||
|
for i := 0; i < 5000; i++ {
|
||||||
|
err := OrderMod.CreateNormalOrder(Lv, Emit, EnergyMul)
|
||||||
|
log.Debug("OrderMod.CreateNormalOrder %d", i)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Energy := 0.0
|
||||||
|
for _, v := range OrderMod.OrderList {
|
||||||
|
for _, v1 := range v.MergeId {
|
||||||
|
Color := mergeDataCfg.GetColorById(v1)
|
||||||
|
Lv := mergeDataCfg.GetLvById(v1)
|
||||||
|
EmitId := order.GetEmitByColor(Emit, Color)
|
||||||
|
AdjustLv := mergeDataCfg.GetAdjust(EmitId, Color)
|
||||||
|
Energy += math.Pow(2, float64(Lv-1+AdjustLv))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Energy / float64(5000)
|
||||||
|
}
|
||||||
|
|||||||
@ -11,37 +11,20 @@ require (
|
|||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/segmentio/kafka-go v0.4.47
|
github.com/segmentio/kafka-go v0.4.47
|
||||||
github.com/vicanso/go-charts/v2 v2.6.10
|
github.com/vicanso/go-charts/v2 v2.6.10
|
||||||
google.golang.org/api v0.217.0
|
|
||||||
google.golang.org/protobuf v1.36.2
|
google.golang.org/protobuf v1.36.2
|
||||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/auth v0.14.0 // indirect
|
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
|
|
||||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/google/s2a-go v0.1.9 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
|
||||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
|
||||||
github.com/klauspost/compress v1.15.9 // indirect
|
github.com/klauspost/compress v1.15.9 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||||
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.0 // indirect
|
github.com/wcharczuk/go-chart/v2 v2.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
|
|
||||||
go.opentelemetry.io/otel v1.31.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/metric v1.31.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/trace v1.31.0 // indirect
|
|
||||||
golang.org/x/crypto v0.32.0 // indirect
|
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
|
||||||
golang.org/x/net v0.34.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/oauth2 v0.25.0 // indirect
|
|
||||||
golang.org/x/text v0.21.0 // indirect
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
|
|
||||||
google.golang.org/grpc v1.69.4 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
cloud.google.com/go/auth v0.14.0 h1:A5C4dKV/Spdvxcl0ggWwWEzzP7AZMJSEIgrkngwhGYM=
|
|
||||||
cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A=
|
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
|
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
|
|
||||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
|
||||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
|
||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
github.com/ThinkingDataAnalytics/go-sdk/v2 v2.0.3 h1:+2h2cOKzZgP8DmtuvkmUhOs5WfyseFTc0KLNR3EU2eA=
|
github.com/ThinkingDataAnalytics/go-sdk/v2 v2.0.3 h1:+2h2cOKzZgP8DmtuvkmUhOs5WfyseFTc0KLNR3EU2eA=
|
||||||
@ -21,32 +15,17 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
|||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
|
||||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
|
||||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
|
||||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
|
||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
|
||||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
@ -91,23 +70,9 @@ github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3k
|
|||||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
|
|
||||||
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
|
|
||||||
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
|
|
||||||
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
|
|
||||||
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
|
|
||||||
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
|
|
||||||
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
|
||||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
@ -120,13 +85,9 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
|
|
||||||
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -156,14 +117,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.217.0 h1:GYrUtD289o4zl1AhiTZL0jvQGa2RDLyC+kX1N/lfGOU=
|
|
||||||
google.golang.org/api v0.217.0/go.mod h1:qMc2E8cBAbQlRypBTBWHklNJlaZZJBwDv81B1Iu8oSI=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
|
|
||||||
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
|
|
||||||
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
|
||||||
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
|
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
|
||||||
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
382
src/server/vendor/cloud.google.com/go/auth/CHANGES.md
generated
vendored
382
src/server/vendor/cloud.google.com/go/auth/CHANGES.md
generated
vendored
@ -1,382 +0,0 @@
|
|||||||
# Changelog
|
|
||||||
|
|
||||||
## [0.14.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.13.0...auth/v0.14.0) (2025-01-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add universe domain support to idtoken ([#11059](https://github.com/googleapis/google-cloud-go/issues/11059)) ([72add7e](https://github.com/googleapis/google-cloud-go/commit/72add7e9f8f455af695e8ef79212a4bd3122fb3a))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
|
|
||||||
* **auth:** Fix copy of delegates in impersonate.NewIDTokenCredentials ([#11386](https://github.com/googleapis/google-cloud-go/issues/11386)) ([ff7ef8e](https://github.com/googleapis/google-cloud-go/commit/ff7ef8e7ade7171bce3e4f30ff10a2e9f6c27ca0)), refs [#11379](https://github.com/googleapis/google-cloud-go/issues/11379)
|
|
||||||
* **auth:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
|
|
||||||
|
|
||||||
## [0.13.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.1...auth/v0.13.0) (2024-12-13)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add logging support ([#11079](https://github.com/googleapis/google-cloud-go/issues/11079)) ([c80e31d](https://github.com/googleapis/google-cloud-go/commit/c80e31df5ecb33a810be3dfb9d9e27ac531aa91d))
|
|
||||||
* **auth:** Pass logger from auth layer to metadata package ([#11288](https://github.com/googleapis/google-cloud-go/issues/11288)) ([b552efd](https://github.com/googleapis/google-cloud-go/commit/b552efd6ab34e5dfded18438e0fbfd925805614f))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Check compute cred type before non-default flag for DP ([#11255](https://github.com/googleapis/google-cloud-go/issues/11255)) ([4347ca1](https://github.com/googleapis/google-cloud-go/commit/4347ca141892be8ae813399b4b437662a103bc90))
|
|
||||||
|
|
||||||
## [0.12.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.0...auth/v0.12.1) (2024-12-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Correct typo in link ([#11160](https://github.com/googleapis/google-cloud-go/issues/11160)) ([af6fb46](https://github.com/googleapis/google-cloud-go/commit/af6fb46d7cd694ddbe8c9d63bc4cdcd62b9fb2c1))
|
|
||||||
|
|
||||||
## [0.12.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.11.0...auth/v0.12.0) (2024-12-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add support for providing custom certificate URL ([#11006](https://github.com/googleapis/google-cloud-go/issues/11006)) ([ebf3657](https://github.com/googleapis/google-cloud-go/commit/ebf36579724afb375d3974cf1da38f703e3b7dbc)), refs [#11005](https://github.com/googleapis/google-cloud-go/issues/11005)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Ensure endpoints are present in Validator ([#11209](https://github.com/googleapis/google-cloud-go/issues/11209)) ([106cd53](https://github.com/googleapis/google-cloud-go/commit/106cd53309facaef1b8ea78376179f523f6912b9)), refs [#11006](https://github.com/googleapis/google-cloud-go/issues/11006) [#11190](https://github.com/googleapis/google-cloud-go/issues/11190) [#11189](https://github.com/googleapis/google-cloud-go/issues/11189) [#11188](https://github.com/googleapis/google-cloud-go/issues/11188)
|
|
||||||
|
|
||||||
## [0.11.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.2...auth/v0.11.0) (2024-11-21)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add universe domain support to mTLS ([#11159](https://github.com/googleapis/google-cloud-go/issues/11159)) ([117748b](https://github.com/googleapis/google-cloud-go/commit/117748ba1cfd4ae62a6a4feb7e30951cb2bc9344))
|
|
||||||
|
|
||||||
## [0.10.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.1...auth/v0.10.2) (2024-11-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Restore use of grpc.Dial ([#11118](https://github.com/googleapis/google-cloud-go/issues/11118)) ([2456b94](https://github.com/googleapis/google-cloud-go/commit/2456b943b7b8aaabd4d8bfb7572c0f477ae0db45)), refs [#7556](https://github.com/googleapis/google-cloud-go/issues/7556)
|
|
||||||
|
|
||||||
## [0.10.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.0...auth/v0.10.1) (2024-11-06)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Restore Application Default Credentials support to idtoken ([#11083](https://github.com/googleapis/google-cloud-go/issues/11083)) ([8771f2e](https://github.com/googleapis/google-cloud-go/commit/8771f2ea9807ab822083808e0678392edff3b4f2))
|
|
||||||
* **auth:** Skip impersonate universe domain check if empty ([#11086](https://github.com/googleapis/google-cloud-go/issues/11086)) ([87159c1](https://github.com/googleapis/google-cloud-go/commit/87159c1059d4a18d1367ce62746a838a94964ab6))
|
|
||||||
|
|
||||||
## [0.10.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.9...auth/v0.10.0) (2024-10-30)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add universe domain support to credentials/impersonate ([#10953](https://github.com/googleapis/google-cloud-go/issues/10953)) ([e06cb64](https://github.com/googleapis/google-cloud-go/commit/e06cb6499f7eda3aef08ab18ff197016f667684b))
|
|
||||||
|
|
||||||
## [0.9.9](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.8...auth/v0.9.9) (2024-10-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Fallback cert lookups for missing files ([#11013](https://github.com/googleapis/google-cloud-go/issues/11013)) ([bd76695](https://github.com/googleapis/google-cloud-go/commit/bd766957ec238b7c40ddbabb369e612dc9b07313)), refs [#10844](https://github.com/googleapis/google-cloud-go/issues/10844)
|
|
||||||
* **auth:** Replace MDS endpoint universe_domain with universe-domain ([#11000](https://github.com/googleapis/google-cloud-go/issues/11000)) ([6a1586f](https://github.com/googleapis/google-cloud-go/commit/6a1586f2ce9974684affaea84e7b629313b4d114))
|
|
||||||
|
|
||||||
## [0.9.8](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.7...auth/v0.9.8) (2024-10-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Restore OpenTelemetry handling in transports ([#10968](https://github.com/googleapis/google-cloud-go/issues/10968)) ([08c6d04](https://github.com/googleapis/google-cloud-go/commit/08c6d04901c1a20e219b2d86df41dbaa6d7d7b55)), refs [#10962](https://github.com/googleapis/google-cloud-go/issues/10962)
|
|
||||||
* **auth:** Try talk to plaintext S2A if credentials can not be found for mTLS-S2A ([#10941](https://github.com/googleapis/google-cloud-go/issues/10941)) ([0f0bf2d](https://github.com/googleapis/google-cloud-go/commit/0f0bf2d18c97dd8b65bcf0099f0802b5631c6287))
|
|
||||||
|
|
||||||
## [0.9.7](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.6...auth/v0.9.7) (2024-10-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Restore support for non-default service accounts for DirectPath ([#10937](https://github.com/googleapis/google-cloud-go/issues/10937)) ([a38650e](https://github.com/googleapis/google-cloud-go/commit/a38650edbf420223077498cafa537aec74b37aad)), refs [#10907](https://github.com/googleapis/google-cloud-go/issues/10907)
|
|
||||||
|
|
||||||
## [0.9.6](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.5...auth/v0.9.6) (2024-09-30)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Make aws credentials provider retrieve fresh credentials ([#10920](https://github.com/googleapis/google-cloud-go/issues/10920)) ([250fbf8](https://github.com/googleapis/google-cloud-go/commit/250fbf87d858d865e399a241b7e537c4ff0c3dd8))
|
|
||||||
|
|
||||||
## [0.9.5](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.4...auth/v0.9.5) (2024-09-25)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Restore support for GOOGLE_CLOUD_UNIVERSE_DOMAIN env ([#10915](https://github.com/googleapis/google-cloud-go/issues/10915)) ([94caaaa](https://github.com/googleapis/google-cloud-go/commit/94caaaa061362d0e00ef6214afcc8a0a3e7ebfb2))
|
|
||||||
* **auth:** Skip directpath credentials overwrite when it's not on GCE ([#10833](https://github.com/googleapis/google-cloud-go/issues/10833)) ([7e5e8d1](https://github.com/googleapis/google-cloud-go/commit/7e5e8d10b761b0a6e43e19a028528db361bc07b1))
|
|
||||||
* **auth:** Use new context for non-blocking token refresh ([#10919](https://github.com/googleapis/google-cloud-go/issues/10919)) ([cf7102d](https://github.com/googleapis/google-cloud-go/commit/cf7102d33a21be1e5a9d47a49456b3a57c43b350))
|
|
||||||
|
|
||||||
## [0.9.4](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.3...auth/v0.9.4) (2024-09-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Enable self-signed JWT for non-GDU universe domain ([#10831](https://github.com/googleapis/google-cloud-go/issues/10831)) ([f9869f7](https://github.com/googleapis/google-cloud-go/commit/f9869f7903cfd34d1b97c25d0dc5669d2c5138e6))
|
|
||||||
|
|
||||||
## [0.9.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.2...auth/v0.9.3) (2024-09-03)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Choose quota project envvar over file when both present ([#10807](https://github.com/googleapis/google-cloud-go/issues/10807)) ([2d8dd77](https://github.com/googleapis/google-cloud-go/commit/2d8dd7700eff92d4b95027be55e26e1e7aa79181)), refs [#10804](https://github.com/googleapis/google-cloud-go/issues/10804)
|
|
||||||
|
|
||||||
## [0.9.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.1...auth/v0.9.2) (2024-08-30)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Handle non-Transport DefaultTransport ([#10733](https://github.com/googleapis/google-cloud-go/issues/10733)) ([98d91dc](https://github.com/googleapis/google-cloud-go/commit/98d91dc8316b247498fab41ab35e57a0446fe556)), refs [#10742](https://github.com/googleapis/google-cloud-go/issues/10742)
|
|
||||||
* **auth:** Make sure quota option takes precedence over env/file ([#10797](https://github.com/googleapis/google-cloud-go/issues/10797)) ([f1b050d](https://github.com/googleapis/google-cloud-go/commit/f1b050d56d804b245cab048c2980d32b0eaceb4e)), refs [#10795](https://github.com/googleapis/google-cloud-go/issues/10795)
|
|
||||||
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
* **auth:** Fix Go doc comment link ([#10751](https://github.com/googleapis/google-cloud-go/issues/10751)) ([015acfa](https://github.com/googleapis/google-cloud-go/commit/015acfab4d172650928bb1119bc2cd6307b9a437))
|
|
||||||
|
|
||||||
## [0.9.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.0...auth/v0.9.1) (2024-08-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Setting expireEarly to default when the value is 0 ([#10732](https://github.com/googleapis/google-cloud-go/issues/10732)) ([5e67869](https://github.com/googleapis/google-cloud-go/commit/5e67869a31e9e8ecb4eeebd2cfa11a761c3b1948))
|
|
||||||
|
|
||||||
## [0.9.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.8.1...auth/v0.9.0) (2024-08-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Auth library can talk to S2A over mTLS ([#10634](https://github.com/googleapis/google-cloud-go/issues/10634)) ([5250a13](https://github.com/googleapis/google-cloud-go/commit/5250a13ec95b8d4eefbe0158f82857ff2189cb45))
|
|
||||||
|
|
||||||
## [0.8.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.8.0...auth/v0.8.1) (2024-08-13)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Make default client creation more lenient ([#10669](https://github.com/googleapis/google-cloud-go/issues/10669)) ([1afb9ee](https://github.com/googleapis/google-cloud-go/commit/1afb9ee1ee9de9810722800018133304a0ca34d1)), refs [#10638](https://github.com/googleapis/google-cloud-go/issues/10638)
|
|
||||||
|
|
||||||
## [0.8.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.3...auth/v0.8.0) (2024-08-07)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Adds support for X509 workload identity federation ([#10373](https://github.com/googleapis/google-cloud-go/issues/10373)) ([5d07505](https://github.com/googleapis/google-cloud-go/commit/5d075056cbe27bb1da4072a26070c41f8999eb9b))
|
|
||||||
|
|
||||||
## [0.7.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.2...auth/v0.7.3) (2024-08-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
|
||||||
* **auth:** Disable automatic universe domain check for MDS ([#10620](https://github.com/googleapis/google-cloud-go/issues/10620)) ([7cea5ed](https://github.com/googleapis/google-cloud-go/commit/7cea5edd5a0c1e6bca558696f5607879141910e8))
|
|
||||||
* **auth:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
|
||||||
|
|
||||||
## [0.7.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.1...auth/v0.7.2) (2024-07-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Use default client for universe metadata lookup ([#10551](https://github.com/googleapis/google-cloud-go/issues/10551)) ([d9046fd](https://github.com/googleapis/google-cloud-go/commit/d9046fdd1435d1ce48f374806c1def4cb5ac6cd3)), refs [#10544](https://github.com/googleapis/google-cloud-go/issues/10544)
|
|
||||||
|
|
||||||
## [0.7.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.0...auth/v0.7.1) (2024-07-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Bump google.golang.org/grpc@v1.64.1 ([8ecc4e9](https://github.com/googleapis/google-cloud-go/commit/8ecc4e9622e5bbe9b90384d5848ab816027226c5))
|
|
||||||
|
|
||||||
## [0.7.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.6.1...auth/v0.7.0) (2024-07-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add workload X509 cert provider as a default cert provider ([#10479](https://github.com/googleapis/google-cloud-go/issues/10479)) ([c51ee6c](https://github.com/googleapis/google-cloud-go/commit/c51ee6cf65ce05b4d501083e49d468c75ac1ea63))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Bump google.golang.org/api@v0.187.0 ([8fa9e39](https://github.com/googleapis/google-cloud-go/commit/8fa9e398e512fd8533fd49060371e61b5725a85b))
|
|
||||||
* **auth:** Bump google.golang.org/api@v0.187.0 ([8fa9e39](https://github.com/googleapis/google-cloud-go/commit/8fa9e398e512fd8533fd49060371e61b5725a85b))
|
|
||||||
* **auth:** Check len of slices, not non-nil ([#10483](https://github.com/googleapis/google-cloud-go/issues/10483)) ([0a966a1](https://github.com/googleapis/google-cloud-go/commit/0a966a183e5f0e811977216d736d875b7233e942))
|
|
||||||
|
|
||||||
## [0.6.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.6.0...auth/v0.6.1) (2024-07-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Support gRPC API keys ([#10460](https://github.com/googleapis/google-cloud-go/issues/10460)) ([daa6646](https://github.com/googleapis/google-cloud-go/commit/daa6646d2af5d7fb5b30489f4934c7db89868c7c))
|
|
||||||
* **auth:** Update http and grpc transports to support token exchange over mTLS ([#10397](https://github.com/googleapis/google-cloud-go/issues/10397)) ([c6dfdcf](https://github.com/googleapis/google-cloud-go/commit/c6dfdcf893c3f971eba15026c12db0a960ae81f2))
|
|
||||||
|
|
||||||
## [0.6.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.5.2...auth/v0.6.0) (2024-06-25)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add non-blocking token refresh for compute MDS ([#10263](https://github.com/googleapis/google-cloud-go/issues/10263)) ([9ac350d](https://github.com/googleapis/google-cloud-go/commit/9ac350da11a49b8e2174d3fc5b1a5070fec78b4e))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Return error if envvar detected file returns an error ([#10431](https://github.com/googleapis/google-cloud-go/issues/10431)) ([e52b9a7](https://github.com/googleapis/google-cloud-go/commit/e52b9a7c45468827f5d220ab00965191faeb9d05))
|
|
||||||
|
|
||||||
## [0.5.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.5.1...auth/v0.5.2) (2024-06-24)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Fetch initial token when CachedTokenProviderOptions.DisableAutoRefresh is true ([#10415](https://github.com/googleapis/google-cloud-go/issues/10415)) ([3266763](https://github.com/googleapis/google-cloud-go/commit/32667635ca2efad05cd8c087c004ca07d7406913)), refs [#10414](https://github.com/googleapis/google-cloud-go/issues/10414)
|
|
||||||
|
|
||||||
## [0.5.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.5.0...auth/v0.5.1) (2024-05-31)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Pass through client to 2LO and 3LO flows ([#10290](https://github.com/googleapis/google-cloud-go/issues/10290)) ([685784e](https://github.com/googleapis/google-cloud-go/commit/685784ea84358c15e9214bdecb307d37aa3b6d2f))
|
|
||||||
|
|
||||||
## [0.5.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.4.2...auth/v0.5.0) (2024-05-28)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Adds X509 workload certificate provider ([#10233](https://github.com/googleapis/google-cloud-go/issues/10233)) ([17a9db7](https://github.com/googleapis/google-cloud-go/commit/17a9db73af35e3d1a7a25ac4fd1377a103de6150))
|
|
||||||
|
|
||||||
## [0.4.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.4.1...auth/v0.4.2) (2024-05-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Enable client certificates by default only for GDU ([#10151](https://github.com/googleapis/google-cloud-go/issues/10151)) ([7c52978](https://github.com/googleapis/google-cloud-go/commit/7c529786275a39b7e00525f7d5e7be0d963e9e15))
|
|
||||||
* **auth:** Handle non-Transport DefaultTransport ([#10162](https://github.com/googleapis/google-cloud-go/issues/10162)) ([fa3bfdb](https://github.com/googleapis/google-cloud-go/commit/fa3bfdb23aaa45b34394a8b61e753b3587506782)), refs [#10159](https://github.com/googleapis/google-cloud-go/issues/10159)
|
|
||||||
* **auth:** Have refresh time match docs ([#10147](https://github.com/googleapis/google-cloud-go/issues/10147)) ([bcb5568](https://github.com/googleapis/google-cloud-go/commit/bcb5568c07a54dd3d2e869d15f502b0741a609e8))
|
|
||||||
* **auth:** Update compute token fetching error with named prefix ([#10180](https://github.com/googleapis/google-cloud-go/issues/10180)) ([4573504](https://github.com/googleapis/google-cloud-go/commit/4573504828d2928bebedc875d87650ba227829ea))
|
|
||||||
|
|
||||||
## [0.4.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.4.0...auth/v0.4.1) (2024-05-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Don't try to detect default creds it opt configured ([#10143](https://github.com/googleapis/google-cloud-go/issues/10143)) ([804632e](https://github.com/googleapis/google-cloud-go/commit/804632e7c5b0b85ff522f7951114485e256eb5bc))
|
|
||||||
|
|
||||||
## [0.4.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.3.0...auth/v0.4.0) (2024-05-07)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Enable client certificates by default ([#10102](https://github.com/googleapis/google-cloud-go/issues/10102)) ([9013e52](https://github.com/googleapis/google-cloud-go/commit/9013e5200a6ec0f178ed91acb255481ffb073a2c))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Get s2a logic up to date ([#10093](https://github.com/googleapis/google-cloud-go/issues/10093)) ([4fe9ae4](https://github.com/googleapis/google-cloud-go/commit/4fe9ae4b7101af2a5221d6d6b2e77b479305bb06))
|
|
||||||
|
|
||||||
## [0.3.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.2.2...auth/v0.3.0) (2024-04-23)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth/httptransport:** Add ability to customize transport ([#10023](https://github.com/googleapis/google-cloud-go/issues/10023)) ([72c7f6b](https://github.com/googleapis/google-cloud-go/commit/72c7f6bbec3136cc7a62788fc7186bc33ef6c3b3)), refs [#9812](https://github.com/googleapis/google-cloud-go/issues/9812) [#9814](https://github.com/googleapis/google-cloud-go/issues/9814)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/credentials:** Error on bad file name if explicitly set ([#10018](https://github.com/googleapis/google-cloud-go/issues/10018)) ([55beaa9](https://github.com/googleapis/google-cloud-go/commit/55beaa993aaf052d8be39766afc6777c3c2a0bdd)), refs [#9809](https://github.com/googleapis/google-cloud-go/issues/9809)
|
|
||||||
|
|
||||||
## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.2.1...auth/v0.2.2) (2024-04-19)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Add internal opt to skip validation on transports ([#9999](https://github.com/googleapis/google-cloud-go/issues/9999)) ([9e20ef8](https://github.com/googleapis/google-cloud-go/commit/9e20ef89f6287d6bd03b8697d5898dc43b4a77cf)), refs [#9823](https://github.com/googleapis/google-cloud-go/issues/9823)
|
|
||||||
* **auth:** Set secure flag for gRPC conn pools ([#10002](https://github.com/googleapis/google-cloud-go/issues/10002)) ([14e3956](https://github.com/googleapis/google-cloud-go/commit/14e3956dfd736399731b5ee8d9b178ae085cf7ba)), refs [#9833](https://github.com/googleapis/google-cloud-go/issues/9833)
|
|
||||||
|
|
||||||
## [0.2.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.2.0...auth/v0.2.1) (2024-04-18)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth:** Default gRPC token type to Bearer if not set ([#9800](https://github.com/googleapis/google-cloud-go/issues/9800)) ([5284066](https://github.com/googleapis/google-cloud-go/commit/5284066670b6fe65d79089cfe0199c9660f87fc7))
|
|
||||||
|
|
||||||
## [0.2.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.1.1...auth/v0.2.0) (2024-04-15)
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
In the below mentioned commits there were a few large breaking changes since the
|
|
||||||
last release of the module.
|
|
||||||
|
|
||||||
1. The `Credentials` type has been moved to the root of the module as it is
|
|
||||||
becoming the core abstraction for the whole module.
|
|
||||||
2. Because of the above mentioned change many functions that previously
|
|
||||||
returned a `TokenProvider` now return `Credentials`. Similarly, these
|
|
||||||
functions have been renamed to be more specific.
|
|
||||||
3. Most places that used to take an optional `TokenProvider` now accept
|
|
||||||
`Credentials`. You can make a `Credentials` from a `TokenProvider` using the
|
|
||||||
constructor found in the `auth` package.
|
|
||||||
4. The `detect` package has been renamed to `credentials`. With this change some
|
|
||||||
function signatures were also updated for better readability.
|
|
||||||
5. Derivative auth flows like `impersonate` and `downscope` have been moved to
|
|
||||||
be under the new `credentials` package.
|
|
||||||
|
|
||||||
Although these changes are disruptive we think that they are for the best of the
|
|
||||||
long-term health of the module. We do not expect any more large breaking changes
|
|
||||||
like these in future revisions, even before 1.0.0. This version will be the
|
|
||||||
first version of the auth library that our client libraries start to use and
|
|
||||||
depend on.
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth/credentials/externalaccount:** Add default TokenURL ([#9700](https://github.com/googleapis/google-cloud-go/issues/9700)) ([81830e6](https://github.com/googleapis/google-cloud-go/commit/81830e6848ceefd055aa4d08f933d1154455a0f6))
|
|
||||||
* **auth:** Add downscope.Options.UniverseDomain ([#9634](https://github.com/googleapis/google-cloud-go/issues/9634)) ([52cf7d7](https://github.com/googleapis/google-cloud-go/commit/52cf7d780853594291c4e34302d618299d1f5a1d))
|
|
||||||
* **auth:** Add universe domain to grpctransport and httptransport ([#9663](https://github.com/googleapis/google-cloud-go/issues/9663)) ([67d353b](https://github.com/googleapis/google-cloud-go/commit/67d353beefe3b607c08c891876fbd95ab89e5fe3)), refs [#9670](https://github.com/googleapis/google-cloud-go/issues/9670)
|
|
||||||
* **auth:** Add UniverseDomain to DetectOptions ([#9536](https://github.com/googleapis/google-cloud-go/issues/9536)) ([3618d3f](https://github.com/googleapis/google-cloud-go/commit/3618d3f7061615c0e189f376c75abc201203b501))
|
|
||||||
* **auth:** Make package externalaccount public ([#9633](https://github.com/googleapis/google-cloud-go/issues/9633)) ([a0978d8](https://github.com/googleapis/google-cloud-go/commit/a0978d8e96968399940ebd7d092539772bf9caac))
|
|
||||||
* **auth:** Move credentials to base auth package ([#9590](https://github.com/googleapis/google-cloud-go/issues/9590)) ([1a04baf](https://github.com/googleapis/google-cloud-go/commit/1a04bafa83c27342b9308d785645e1e5423ea10d))
|
|
||||||
* **auth:** Refactor public sigs to use Credentials ([#9603](https://github.com/googleapis/google-cloud-go/issues/9603)) ([69cb240](https://github.com/googleapis/google-cloud-go/commit/69cb240c530b1f7173a9af2555c19e9a1beb56c5))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update protobuf dep to v1.33.0 ([30b038d](https://github.com/googleapis/google-cloud-go/commit/30b038d8cac0b8cd5dd4761c87f3f298760dd33a))
|
|
||||||
* **auth:** Fix uint32 conversion ([9221c7f](https://github.com/googleapis/google-cloud-go/commit/9221c7fa12cef9d5fb7ddc92f41f1d6204971c7b))
|
|
||||||
* **auth:** Port sts expires fix ([#9618](https://github.com/googleapis/google-cloud-go/issues/9618)) ([7bec97b](https://github.com/googleapis/google-cloud-go/commit/7bec97b2f51ed3ac4f9b88bf100d301da3f5d1bd))
|
|
||||||
* **auth:** Read universe_domain from all credentials files ([#9632](https://github.com/googleapis/google-cloud-go/issues/9632)) ([16efbb5](https://github.com/googleapis/google-cloud-go/commit/16efbb52e39ea4a319e5ee1e95c0e0305b6d9824))
|
|
||||||
* **auth:** Remove content-type header from idms get requests ([#9508](https://github.com/googleapis/google-cloud-go/issues/9508)) ([8589f41](https://github.com/googleapis/google-cloud-go/commit/8589f41599d265d7c3d46a3d86c9fab2329cbdd9))
|
|
||||||
* **auth:** Update protobuf dep to v1.33.0 ([30b038d](https://github.com/googleapis/google-cloud-go/commit/30b038d8cac0b8cd5dd4761c87f3f298760dd33a))
|
|
||||||
|
|
||||||
## [0.1.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.1.0...auth/v0.1.1) (2024-03-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/impersonate:** Properly send default detect params ([#9529](https://github.com/googleapis/google-cloud-go/issues/9529)) ([5b6b8be](https://github.com/googleapis/google-cloud-go/commit/5b6b8bef577f82707e51f5cc5d258d5bdf90218f)), refs [#9136](https://github.com/googleapis/google-cloud-go/issues/9136)
|
|
||||||
* **auth:** Update grpc-go to v1.56.3 ([343cea8](https://github.com/googleapis/google-cloud-go/commit/343cea8c43b1e31ae21ad50ad31d3b0b60143f8c))
|
|
||||||
* **auth:** Update grpc-go to v1.59.0 ([81a97b0](https://github.com/googleapis/google-cloud-go/commit/81a97b06cb28b25432e4ece595c55a9857e960b7))
|
|
||||||
|
|
||||||
## 0.1.0 (2023-10-18)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth:** Add base auth package ([#8465](https://github.com/googleapis/google-cloud-go/issues/8465)) ([6a45f26](https://github.com/googleapis/google-cloud-go/commit/6a45f26b809b64edae21f312c18d4205f96b180e))
|
|
||||||
* **auth:** Add cert support to httptransport ([#8569](https://github.com/googleapis/google-cloud-go/issues/8569)) ([37e3435](https://github.com/googleapis/google-cloud-go/commit/37e3435f8e98595eafab481bdfcb31a4c56fa993))
|
|
||||||
* **auth:** Add Credentials.UniverseDomain() ([#8654](https://github.com/googleapis/google-cloud-go/issues/8654)) ([af0aa1e](https://github.com/googleapis/google-cloud-go/commit/af0aa1ed8015bc8fe0dd87a7549ae029107cbdb8))
|
|
||||||
* **auth:** Add detect package ([#8491](https://github.com/googleapis/google-cloud-go/issues/8491)) ([d977419](https://github.com/googleapis/google-cloud-go/commit/d977419a3269f6acc193df77a2136a6eb4b4add7))
|
|
||||||
* **auth:** Add downscope package ([#8532](https://github.com/googleapis/google-cloud-go/issues/8532)) ([dda9bff](https://github.com/googleapis/google-cloud-go/commit/dda9bff8ec70e6d104901b4105d13dcaa4e2404c))
|
|
||||||
* **auth:** Add grpctransport package ([#8625](https://github.com/googleapis/google-cloud-go/issues/8625)) ([69a8347](https://github.com/googleapis/google-cloud-go/commit/69a83470bdcc7ed10c6c36d1abc3b7cfdb8a0ee5))
|
|
||||||
* **auth:** Add httptransport package ([#8567](https://github.com/googleapis/google-cloud-go/issues/8567)) ([6898597](https://github.com/googleapis/google-cloud-go/commit/6898597d2ea95d630fcd00fd15c58c75ea843bff))
|
|
||||||
* **auth:** Add idtoken package ([#8580](https://github.com/googleapis/google-cloud-go/issues/8580)) ([a79e693](https://github.com/googleapis/google-cloud-go/commit/a79e693e97e4e3e1c6742099af3dbc58866d88fe))
|
|
||||||
* **auth:** Add impersonate package ([#8578](https://github.com/googleapis/google-cloud-go/issues/8578)) ([e29ba0c](https://github.com/googleapis/google-cloud-go/commit/e29ba0cb7bd3888ab9e808087027dc5a32474c04))
|
|
||||||
* **auth:** Add support for external accounts in detect ([#8508](https://github.com/googleapis/google-cloud-go/issues/8508)) ([62210d5](https://github.com/googleapis/google-cloud-go/commit/62210d5d3e56e8e9f35db8e6ac0defec19582507))
|
|
||||||
* **auth:** Port external account changes ([#8697](https://github.com/googleapis/google-cloud-go/issues/8697)) ([5823db5](https://github.com/googleapis/google-cloud-go/commit/5823db5d633069999b58b9131a7f9cd77e82c899))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update golang.org/x/net to v0.17.0 ([174da47](https://github.com/googleapis/google-cloud-go/commit/174da47254fefb12921bbfc65b7829a453af6f5d))
|
|
||||||
* **auth:** Update golang.org/x/net to v0.17.0 ([174da47](https://github.com/googleapis/google-cloud-go/commit/174da47254fefb12921bbfc65b7829a453af6f5d))
|
|
||||||
202
src/server/vendor/cloud.google.com/go/auth/LICENSE
generated
vendored
202
src/server/vendor/cloud.google.com/go/auth/LICENSE
generated
vendored
@ -1,202 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
40
src/server/vendor/cloud.google.com/go/auth/README.md
generated
vendored
40
src/server/vendor/cloud.google.com/go/auth/README.md
generated
vendored
@ -1,40 +0,0 @@
|
|||||||
# Google Auth Library for Go
|
|
||||||
|
|
||||||
[](https://pkg.go.dev/cloud.google.com/go/auth)
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
``` bash
|
|
||||||
go get cloud.google.com/go/auth@latest
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
The most common way this library is used is transitively, by default, from any
|
|
||||||
of our Go client libraries.
|
|
||||||
|
|
||||||
### Notable use-cases
|
|
||||||
|
|
||||||
- To create a credential directly please see examples in the
|
|
||||||
[credentials](https://pkg.go.dev/cloud.google.com/go/auth/credentials)
|
|
||||||
package.
|
|
||||||
- To create a authenticated HTTP client please see examples in the
|
|
||||||
[httptransport](https://pkg.go.dev/cloud.google.com/go/auth/httptransport)
|
|
||||||
package.
|
|
||||||
- To create a authenticated gRPC connection please see examples in the
|
|
||||||
[grpctransport](https://pkg.go.dev/cloud.google.com/go/auth/grpctransport)
|
|
||||||
package.
|
|
||||||
- To create an ID token please see examples in the
|
|
||||||
[idtoken](https://pkg.go.dev/cloud.google.com/go/auth/credentials/idtoken)
|
|
||||||
package.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions are welcome. Please, see the
|
|
||||||
[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
|
|
||||||
document for details.
|
|
||||||
|
|
||||||
Please note that this project is released with a Contributor Code of Conduct.
|
|
||||||
By participating in this project you agree to abide by its terms.
|
|
||||||
See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
|
|
||||||
for more information.
|
|
||||||
618
src/server/vendor/cloud.google.com/go/auth/auth.go
generated
vendored
618
src/server/vendor/cloud.google.com/go/auth/auth.go
generated
vendored
@ -1,618 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package auth provides utilities for managing Google Cloud credentials,
|
|
||||||
// including functionality for creating, caching, and refreshing OAuth2 tokens.
|
|
||||||
// It offers customizable options for different OAuth2 flows, such as 2-legged
|
|
||||||
// (2LO) and 3-legged (3LO) OAuth, along with support for PKCE and automatic
|
|
||||||
// token management.
|
|
||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/jwt"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Parameter keys for AuthCodeURL method to support PKCE.
|
|
||||||
codeChallengeKey = "code_challenge"
|
|
||||||
codeChallengeMethodKey = "code_challenge_method"
|
|
||||||
|
|
||||||
// Parameter key for Exchange method to support PKCE.
|
|
||||||
codeVerifierKey = "code_verifier"
|
|
||||||
|
|
||||||
// 3 minutes and 45 seconds before expiration. The shortest MDS cache is 4 minutes,
|
|
||||||
// so we give it 15 seconds to refresh it's cache before attempting to refresh a token.
|
|
||||||
defaultExpiryDelta = 225 * time.Second
|
|
||||||
|
|
||||||
universeDomainDefault = "googleapis.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
// tokenState represents different states for a [Token].
|
|
||||||
type tokenState int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// fresh indicates that the [Token] is valid. It is not expired or close to
|
|
||||||
// expired, or the token has no expiry.
|
|
||||||
fresh tokenState = iota
|
|
||||||
// stale indicates that the [Token] is close to expired, and should be
|
|
||||||
// refreshed. The token can be used normally.
|
|
||||||
stale
|
|
||||||
// invalid indicates that the [Token] is expired or invalid. The token
|
|
||||||
// cannot be used for a normal operation.
|
|
||||||
invalid
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
defaultGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
|
||||||
defaultHeader = &jwt.Header{Algorithm: jwt.HeaderAlgRSA256, Type: jwt.HeaderType}
|
|
||||||
|
|
||||||
// for testing
|
|
||||||
timeNow = time.Now
|
|
||||||
)
|
|
||||||
|
|
||||||
// TokenProvider specifies an interface for anything that can return a token.
|
|
||||||
type TokenProvider interface {
|
|
||||||
// Token returns a Token or an error.
|
|
||||||
// The Token returned must be safe to use
|
|
||||||
// concurrently.
|
|
||||||
// The returned Token must not be modified.
|
|
||||||
// The context provided must be sent along to any requests that are made in
|
|
||||||
// the implementing code.
|
|
||||||
Token(context.Context) (*Token, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token holds the credential token used to authorized requests. All fields are
|
|
||||||
// considered read-only.
|
|
||||||
type Token struct {
|
|
||||||
// Value is the token used to authorize requests. It is usually an access
|
|
||||||
// token but may be other types of tokens such as ID tokens in some flows.
|
|
||||||
Value string
|
|
||||||
// Type is the type of token Value is. If uninitialized, it should be
|
|
||||||
// assumed to be a "Bearer" token.
|
|
||||||
Type string
|
|
||||||
// Expiry is the time the token is set to expire.
|
|
||||||
Expiry time.Time
|
|
||||||
// Metadata may include, but is not limited to, the body of the token
|
|
||||||
// response returned by the server.
|
|
||||||
Metadata map[string]interface{} // TODO(codyoss): maybe make a method to flatten metadata to avoid []string for url.Values
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValid reports that a [Token] is non-nil, has a [Token.Value], and has not
|
|
||||||
// expired. A token is considered expired if [Token.Expiry] has passed or will
|
|
||||||
// pass in the next 225 seconds.
|
|
||||||
func (t *Token) IsValid() bool {
|
|
||||||
return t.isValidWithEarlyExpiry(defaultExpiryDelta)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MetadataString is a convenience method for accessing string values in the
|
|
||||||
// token's metadata. Returns an empty string if the metadata is nil or the value
|
|
||||||
// for the given key cannot be cast to a string.
|
|
||||||
func (t *Token) MetadataString(k string) string {
|
|
||||||
if t.Metadata == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
s, ok := t.Metadata[k].(string)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Token) isValidWithEarlyExpiry(earlyExpiry time.Duration) bool {
|
|
||||||
if t.isEmpty() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if t.Expiry.IsZero() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return !t.Expiry.Round(0).Add(-earlyExpiry).Before(timeNow())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Token) isEmpty() bool {
|
|
||||||
return t == nil || t.Value == ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Credentials holds Google credentials, including
|
|
||||||
// [Application Default Credentials].
|
|
||||||
//
|
|
||||||
// [Application Default Credentials]: https://developers.google.com/accounts/docs/application-default-credentials
|
|
||||||
type Credentials struct {
|
|
||||||
json []byte
|
|
||||||
projectID CredentialsPropertyProvider
|
|
||||||
quotaProjectID CredentialsPropertyProvider
|
|
||||||
// universeDomain is the default service domain for a given Cloud universe.
|
|
||||||
universeDomain CredentialsPropertyProvider
|
|
||||||
|
|
||||||
TokenProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON returns the bytes associated with the the file used to source
|
|
||||||
// credentials if one was used.
|
|
||||||
func (c *Credentials) JSON() []byte {
|
|
||||||
return c.json
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectID returns the associated project ID from the underlying file or
|
|
||||||
// environment.
|
|
||||||
func (c *Credentials) ProjectID(ctx context.Context) (string, error) {
|
|
||||||
if c.projectID == nil {
|
|
||||||
return internal.GetProjectID(c.json, ""), nil
|
|
||||||
}
|
|
||||||
v, err := c.projectID.GetProperty(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return internal.GetProjectID(c.json, v), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuotaProjectID returns the associated quota project ID from the underlying
|
|
||||||
// file or environment.
|
|
||||||
func (c *Credentials) QuotaProjectID(ctx context.Context) (string, error) {
|
|
||||||
if c.quotaProjectID == nil {
|
|
||||||
return internal.GetQuotaProject(c.json, ""), nil
|
|
||||||
}
|
|
||||||
v, err := c.quotaProjectID.GetProperty(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return internal.GetQuotaProject(c.json, v), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UniverseDomain returns the default service domain for a given Cloud universe.
|
|
||||||
// The default value is "googleapis.com".
|
|
||||||
func (c *Credentials) UniverseDomain(ctx context.Context) (string, error) {
|
|
||||||
if c.universeDomain == nil {
|
|
||||||
return universeDomainDefault, nil
|
|
||||||
}
|
|
||||||
v, err := c.universeDomain.GetProperty(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if v == "" {
|
|
||||||
return universeDomainDefault, nil
|
|
||||||
}
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CredentialsPropertyProvider provides an implementation to fetch a property
|
|
||||||
// value for [Credentials].
|
|
||||||
type CredentialsPropertyProvider interface {
|
|
||||||
GetProperty(context.Context) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CredentialsPropertyFunc is a type adapter to allow the use of ordinary
|
|
||||||
// functions as a [CredentialsPropertyProvider].
|
|
||||||
type CredentialsPropertyFunc func(context.Context) (string, error)
|
|
||||||
|
|
||||||
// GetProperty loads the properly value provided the given context.
|
|
||||||
func (p CredentialsPropertyFunc) GetProperty(ctx context.Context) (string, error) {
|
|
||||||
return p(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CredentialsOptions are used to configure [Credentials].
|
|
||||||
type CredentialsOptions struct {
|
|
||||||
// TokenProvider is a means of sourcing a token for the credentials. Required.
|
|
||||||
TokenProvider TokenProvider
|
|
||||||
// JSON is the raw contents of the credentials file if sourced from a file.
|
|
||||||
JSON []byte
|
|
||||||
// ProjectIDProvider resolves the project ID associated with the
|
|
||||||
// credentials.
|
|
||||||
ProjectIDProvider CredentialsPropertyProvider
|
|
||||||
// QuotaProjectIDProvider resolves the quota project ID associated with the
|
|
||||||
// credentials.
|
|
||||||
QuotaProjectIDProvider CredentialsPropertyProvider
|
|
||||||
// UniverseDomainProvider resolves the universe domain with the credentials.
|
|
||||||
UniverseDomainProvider CredentialsPropertyProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCredentials returns new [Credentials] from the provided options.
|
|
||||||
func NewCredentials(opts *CredentialsOptions) *Credentials {
|
|
||||||
creds := &Credentials{
|
|
||||||
TokenProvider: opts.TokenProvider,
|
|
||||||
json: opts.JSON,
|
|
||||||
projectID: opts.ProjectIDProvider,
|
|
||||||
quotaProjectID: opts.QuotaProjectIDProvider,
|
|
||||||
universeDomain: opts.UniverseDomainProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
return creds
|
|
||||||
}
|
|
||||||
|
|
||||||
// CachedTokenProviderOptions provides options for configuring a cached
|
|
||||||
// [TokenProvider].
|
|
||||||
type CachedTokenProviderOptions struct {
|
|
||||||
// DisableAutoRefresh makes the TokenProvider always return the same token,
|
|
||||||
// even if it is expired. The default is false. Optional.
|
|
||||||
DisableAutoRefresh bool
|
|
||||||
// ExpireEarly configures the amount of time before a token expires, that it
|
|
||||||
// should be refreshed. If unset, the default value is 3 minutes and 45
|
|
||||||
// seconds. Optional.
|
|
||||||
ExpireEarly time.Duration
|
|
||||||
// DisableAsyncRefresh configures a synchronous workflow that refreshes
|
|
||||||
// tokens in a blocking manner. The default is false. Optional.
|
|
||||||
DisableAsyncRefresh bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctpo *CachedTokenProviderOptions) autoRefresh() bool {
|
|
||||||
if ctpo == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return !ctpo.DisableAutoRefresh
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctpo *CachedTokenProviderOptions) expireEarly() time.Duration {
|
|
||||||
if ctpo == nil || ctpo.ExpireEarly == 0 {
|
|
||||||
return defaultExpiryDelta
|
|
||||||
}
|
|
||||||
return ctpo.ExpireEarly
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctpo *CachedTokenProviderOptions) blockingRefresh() bool {
|
|
||||||
if ctpo == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return ctpo.DisableAsyncRefresh
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCachedTokenProvider wraps a [TokenProvider] to cache the tokens returned
|
|
||||||
// by the underlying provider. By default it will refresh tokens asynchronously
|
|
||||||
// a few minutes before they expire.
|
|
||||||
func NewCachedTokenProvider(tp TokenProvider, opts *CachedTokenProviderOptions) TokenProvider {
|
|
||||||
if ctp, ok := tp.(*cachedTokenProvider); ok {
|
|
||||||
return ctp
|
|
||||||
}
|
|
||||||
return &cachedTokenProvider{
|
|
||||||
tp: tp,
|
|
||||||
autoRefresh: opts.autoRefresh(),
|
|
||||||
expireEarly: opts.expireEarly(),
|
|
||||||
blockingRefresh: opts.blockingRefresh(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type cachedTokenProvider struct {
|
|
||||||
tp TokenProvider
|
|
||||||
autoRefresh bool
|
|
||||||
expireEarly time.Duration
|
|
||||||
blockingRefresh bool
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
cachedToken *Token
|
|
||||||
// isRefreshRunning ensures that the non-blocking refresh will only be
|
|
||||||
// attempted once, even if multiple callers enter the Token method.
|
|
||||||
isRefreshRunning bool
|
|
||||||
// isRefreshErr ensures that the non-blocking refresh will only be attempted
|
|
||||||
// once per refresh window if an error is encountered.
|
|
||||||
isRefreshErr bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cachedTokenProvider) Token(ctx context.Context) (*Token, error) {
|
|
||||||
if c.blockingRefresh {
|
|
||||||
return c.tokenBlocking(ctx)
|
|
||||||
}
|
|
||||||
return c.tokenNonBlocking(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cachedTokenProvider) tokenNonBlocking(ctx context.Context) (*Token, error) {
|
|
||||||
switch c.tokenState() {
|
|
||||||
case fresh:
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
return c.cachedToken, nil
|
|
||||||
case stale:
|
|
||||||
// Call tokenAsync with a new Context because the user-provided context
|
|
||||||
// may have a short timeout incompatible with async token refresh.
|
|
||||||
c.tokenAsync(context.Background())
|
|
||||||
// Return the stale token immediately to not block customer requests to Cloud services.
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
return c.cachedToken, nil
|
|
||||||
default: // invalid
|
|
||||||
return c.tokenBlocking(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tokenState reports the token's validity.
|
|
||||||
func (c *cachedTokenProvider) tokenState() tokenState {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
t := c.cachedToken
|
|
||||||
now := timeNow()
|
|
||||||
if t == nil || t.Value == "" {
|
|
||||||
return invalid
|
|
||||||
} else if t.Expiry.IsZero() {
|
|
||||||
return fresh
|
|
||||||
} else if now.After(t.Expiry.Round(0)) {
|
|
||||||
return invalid
|
|
||||||
} else if now.After(t.Expiry.Round(0).Add(-c.expireEarly)) {
|
|
||||||
return stale
|
|
||||||
}
|
|
||||||
return fresh
|
|
||||||
}
|
|
||||||
|
|
||||||
// tokenAsync uses a bool to ensure that only one non-blocking token refresh
|
|
||||||
// happens at a time, even if multiple callers have entered this function
|
|
||||||
// concurrently. This avoids creating an arbitrary number of concurrent
|
|
||||||
// goroutines. Retries should be attempted and managed within the Token method.
|
|
||||||
// If the refresh attempt fails, no further attempts are made until the refresh
|
|
||||||
// window expires and the token enters the invalid state, at which point the
|
|
||||||
// blocking call to Token should likely return the same error on the main goroutine.
|
|
||||||
func (c *cachedTokenProvider) tokenAsync(ctx context.Context) {
|
|
||||||
fn := func() {
|
|
||||||
c.mu.Lock()
|
|
||||||
c.isRefreshRunning = true
|
|
||||||
c.mu.Unlock()
|
|
||||||
t, err := c.tp.Token(ctx)
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.isRefreshRunning = false
|
|
||||||
if err != nil {
|
|
||||||
// Discard errors from the non-blocking refresh, but prevent further
|
|
||||||
// attempts.
|
|
||||||
c.isRefreshErr = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.cachedToken = t
|
|
||||||
}
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
if !c.isRefreshRunning && !c.isRefreshErr {
|
|
||||||
go fn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cachedTokenProvider) tokenBlocking(ctx context.Context) (*Token, error) {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.isRefreshErr = false
|
|
||||||
if c.cachedToken.IsValid() || (!c.autoRefresh && !c.cachedToken.isEmpty()) {
|
|
||||||
return c.cachedToken, nil
|
|
||||||
}
|
|
||||||
t, err := c.tp.Token(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.cachedToken = t
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error is a error associated with retrieving a [Token]. It can hold useful
|
|
||||||
// additional details for debugging.
|
|
||||||
type Error struct {
|
|
||||||
// Response is the HTTP response associated with error. The body will always
|
|
||||||
// be already closed and consumed.
|
|
||||||
Response *http.Response
|
|
||||||
// Body is the HTTP response body.
|
|
||||||
Body []byte
|
|
||||||
// Err is the underlying wrapped error.
|
|
||||||
Err error
|
|
||||||
|
|
||||||
// code returned in the token response
|
|
||||||
code string
|
|
||||||
// description returned in the token response
|
|
||||||
description string
|
|
||||||
// uri returned in the token response
|
|
||||||
uri string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
|
||||||
if e.code != "" {
|
|
||||||
s := fmt.Sprintf("auth: %q", e.code)
|
|
||||||
if e.description != "" {
|
|
||||||
s += fmt.Sprintf(" %q", e.description)
|
|
||||||
}
|
|
||||||
if e.uri != "" {
|
|
||||||
s += fmt.Sprintf(" %q", e.uri)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("auth: cannot fetch token: %v\nResponse: %s", e.Response.StatusCode, e.Body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary returns true if the error is considered temporary and may be able
|
|
||||||
// to be retried.
|
|
||||||
func (e *Error) Temporary() bool {
|
|
||||||
if e.Response == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
sc := e.Response.StatusCode
|
|
||||||
return sc == http.StatusInternalServerError || sc == http.StatusServiceUnavailable || sc == http.StatusRequestTimeout || sc == http.StatusTooManyRequests
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Unwrap() error {
|
|
||||||
return e.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Style describes how the token endpoint wants to receive the ClientID and
|
|
||||||
// ClientSecret.
|
|
||||||
type Style int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// StyleUnknown means the value has not been initiated. Sending this in
|
|
||||||
// a request will cause the token exchange to fail.
|
|
||||||
StyleUnknown Style = iota
|
|
||||||
// StyleInParams sends client info in the body of a POST request.
|
|
||||||
StyleInParams
|
|
||||||
// StyleInHeader sends client info using Basic Authorization header.
|
|
||||||
StyleInHeader
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options2LO is the configuration settings for doing a 2-legged JWT OAuth2 flow.
|
|
||||||
type Options2LO struct {
|
|
||||||
// Email is the OAuth2 client ID. This value is set as the "iss" in the
|
|
||||||
// JWT.
|
|
||||||
Email string
|
|
||||||
// PrivateKey contains the contents of an RSA private key or the
|
|
||||||
// contents of a PEM file that contains a private key. It is used to sign
|
|
||||||
// the JWT created.
|
|
||||||
PrivateKey []byte
|
|
||||||
// TokenURL is th URL the JWT is sent to. Required.
|
|
||||||
TokenURL string
|
|
||||||
// PrivateKeyID is the ID of the key used to sign the JWT. It is used as the
|
|
||||||
// "kid" in the JWT header. Optional.
|
|
||||||
PrivateKeyID string
|
|
||||||
// Subject is the used for to impersonate a user. It is used as the "sub" in
|
|
||||||
// the JWT.m Optional.
|
|
||||||
Subject string
|
|
||||||
// Scopes specifies requested permissions for the token. Optional.
|
|
||||||
Scopes []string
|
|
||||||
// Expires specifies the lifetime of the token. Optional.
|
|
||||||
Expires time.Duration
|
|
||||||
// Audience specifies the "aud" in the JWT. Optional.
|
|
||||||
Audience string
|
|
||||||
// PrivateClaims allows specifying any custom claims for the JWT. Optional.
|
|
||||||
PrivateClaims map[string]interface{}
|
|
||||||
|
|
||||||
// Client is the client to be used to make the underlying token requests.
|
|
||||||
// Optional.
|
|
||||||
Client *http.Client
|
|
||||||
// UseIDToken requests that the token returned be an ID token if one is
|
|
||||||
// returned from the server. Optional.
|
|
||||||
UseIDToken bool
|
|
||||||
// Logger is used for debug logging. If provided, logging will be enabled
|
|
||||||
// at the loggers configured level. By default logging is disabled unless
|
|
||||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
|
||||||
// logger will be used. Optional.
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options2LO) client() *http.Client {
|
|
||||||
if o.Client != nil {
|
|
||||||
return o.Client
|
|
||||||
}
|
|
||||||
return internal.DefaultClient()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options2LO) validate() error {
|
|
||||||
if o == nil {
|
|
||||||
return errors.New("auth: options must be provided")
|
|
||||||
}
|
|
||||||
if o.Email == "" {
|
|
||||||
return errors.New("auth: email must be provided")
|
|
||||||
}
|
|
||||||
if len(o.PrivateKey) == 0 {
|
|
||||||
return errors.New("auth: private key must be provided")
|
|
||||||
}
|
|
||||||
if o.TokenURL == "" {
|
|
||||||
return errors.New("auth: token URL must be provided")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New2LOTokenProvider returns a [TokenProvider] from the provided options.
|
|
||||||
func New2LOTokenProvider(opts *Options2LO) (TokenProvider, error) {
|
|
||||||
if err := opts.validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tokenProvider2LO{opts: opts, Client: opts.client(), logger: internallog.New(opts.Logger)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type tokenProvider2LO struct {
|
|
||||||
opts *Options2LO
|
|
||||||
Client *http.Client
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp tokenProvider2LO) Token(ctx context.Context) (*Token, error) {
|
|
||||||
pk, err := internal.ParseKey(tp.opts.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
claimSet := &jwt.Claims{
|
|
||||||
Iss: tp.opts.Email,
|
|
||||||
Scope: strings.Join(tp.opts.Scopes, " "),
|
|
||||||
Aud: tp.opts.TokenURL,
|
|
||||||
AdditionalClaims: tp.opts.PrivateClaims,
|
|
||||||
Sub: tp.opts.Subject,
|
|
||||||
}
|
|
||||||
if t := tp.opts.Expires; t > 0 {
|
|
||||||
claimSet.Exp = time.Now().Add(t).Unix()
|
|
||||||
}
|
|
||||||
if aud := tp.opts.Audience; aud != "" {
|
|
||||||
claimSet.Aud = aud
|
|
||||||
}
|
|
||||||
h := *defaultHeader
|
|
||||||
h.KeyID = tp.opts.PrivateKeyID
|
|
||||||
payload, err := jwt.EncodeJWS(&h, claimSet, pk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
v := url.Values{}
|
|
||||||
v.Set("grant_type", defaultGrantType)
|
|
||||||
v.Set("assertion", payload)
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", tp.opts.TokenURL, strings.NewReader(v.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
tp.logger.DebugContext(ctx, "2LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
|
||||||
resp, body, err := internal.DoRequest(tp.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("auth: cannot fetch token: %w", err)
|
|
||||||
}
|
|
||||||
tp.logger.DebugContext(ctx, "2LO token response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
|
||||||
return nil, &Error{
|
|
||||||
Response: resp,
|
|
||||||
Body: body,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// tokenRes is the JSON response body.
|
|
||||||
var tokenRes struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
IDToken string `json:"id_token"`
|
|
||||||
ExpiresIn int64 `json:"expires_in"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(body, &tokenRes); err != nil {
|
|
||||||
return nil, fmt.Errorf("auth: cannot fetch token: %w", err)
|
|
||||||
}
|
|
||||||
token := &Token{
|
|
||||||
Value: tokenRes.AccessToken,
|
|
||||||
Type: tokenRes.TokenType,
|
|
||||||
}
|
|
||||||
token.Metadata = make(map[string]interface{})
|
|
||||||
json.Unmarshal(body, &token.Metadata) // no error checks for optional fields
|
|
||||||
|
|
||||||
if secs := tokenRes.ExpiresIn; secs > 0 {
|
|
||||||
token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
|
|
||||||
}
|
|
||||||
if v := tokenRes.IDToken; v != "" {
|
|
||||||
// decode returned id token to get expiry
|
|
||||||
claimSet, err := jwt.DecodeJWS(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("auth: error decoding JWT token: %w", err)
|
|
||||||
}
|
|
||||||
token.Expiry = time.Unix(claimSet.Exp, 0)
|
|
||||||
}
|
|
||||||
if tp.opts.UseIDToken {
|
|
||||||
if tokenRes.IDToken == "" {
|
|
||||||
return nil, fmt.Errorf("auth: response doesn't have JWT token")
|
|
||||||
}
|
|
||||||
token.Value = tokenRes.IDToken
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
90
src/server/vendor/cloud.google.com/go/auth/credentials/compute.go
generated
vendored
90
src/server/vendor/cloud.google.com/go/auth/credentials/compute.go
generated
vendored
@ -1,90 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package credentials
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/compute/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
computeTokenMetadata = map[string]interface{}{
|
|
||||||
"auth.google.tokenSource": "compute-metadata",
|
|
||||||
"auth.google.serviceAccount": "default",
|
|
||||||
}
|
|
||||||
computeTokenURI = "instance/service-accounts/default/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
// computeTokenProvider creates a [cloud.google.com/go/auth.TokenProvider] that
|
|
||||||
// uses the metadata service to retrieve tokens.
|
|
||||||
func computeTokenProvider(opts *DetectOptions, client *metadata.Client) auth.TokenProvider {
|
|
||||||
return auth.NewCachedTokenProvider(&computeProvider{
|
|
||||||
scopes: opts.Scopes,
|
|
||||||
client: client,
|
|
||||||
}, &auth.CachedTokenProviderOptions{
|
|
||||||
ExpireEarly: opts.EarlyTokenRefresh,
|
|
||||||
DisableAsyncRefresh: opts.DisableAsyncRefresh,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// computeProvider fetches tokens from the google cloud metadata service.
|
|
||||||
type computeProvider struct {
|
|
||||||
scopes []string
|
|
||||||
client *metadata.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
type metadataTokenResp struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
ExpiresInSec int `json:"expires_in"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *computeProvider) Token(ctx context.Context) (*auth.Token, error) {
|
|
||||||
tokenURI, err := url.Parse(computeTokenURI)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(cs.scopes) > 0 {
|
|
||||||
v := url.Values{}
|
|
||||||
v.Set("scopes", strings.Join(cs.scopes, ","))
|
|
||||||
tokenURI.RawQuery = v.Encode()
|
|
||||||
}
|
|
||||||
tokenJSON, err := cs.client.GetWithContext(ctx, tokenURI.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
|
||||||
}
|
|
||||||
var res metadataTokenResp
|
|
||||||
if err := json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res); err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: invalid token JSON from metadata: %w", err)
|
|
||||||
}
|
|
||||||
if res.ExpiresInSec == 0 || res.AccessToken == "" {
|
|
||||||
return nil, errors.New("credentials: incomplete token received from metadata")
|
|
||||||
}
|
|
||||||
return &auth.Token{
|
|
||||||
Value: res.AccessToken,
|
|
||||||
Type: res.TokenType,
|
|
||||||
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
|
|
||||||
Metadata: computeTokenMetadata,
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
279
src/server/vendor/cloud.google.com/go/auth/credentials/detect.go
generated
vendored
279
src/server/vendor/cloud.google.com/go/auth/credentials/detect.go
generated
vendored
@ -1,279 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package credentials
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/credsfile"
|
|
||||||
"cloud.google.com/go/compute/metadata"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// jwtTokenURL is Google's OAuth 2.0 token URL to use with the JWT(2LO) flow.
|
|
||||||
jwtTokenURL = "https://oauth2.googleapis.com/token"
|
|
||||||
|
|
||||||
// Google's OAuth 2.0 default endpoints.
|
|
||||||
googleAuthURL = "https://accounts.google.com/o/oauth2/auth"
|
|
||||||
googleTokenURL = "https://oauth2.googleapis.com/token"
|
|
||||||
|
|
||||||
// GoogleMTLSTokenURL is Google's default OAuth2.0 mTLS endpoint.
|
|
||||||
GoogleMTLSTokenURL = "https://oauth2.mtls.googleapis.com/token"
|
|
||||||
|
|
||||||
// Help on default credentials
|
|
||||||
adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// for testing
|
|
||||||
allowOnGCECheck = true
|
|
||||||
)
|
|
||||||
|
|
||||||
// OnGCE reports whether this process is running in Google Cloud.
|
|
||||||
func OnGCE() bool {
|
|
||||||
// TODO(codyoss): once all libs use this auth lib move metadata check here
|
|
||||||
return allowOnGCECheck && metadata.OnGCE()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetectDefault searches for "Application Default Credentials" and returns
|
|
||||||
// a credential based on the [DetectOptions] provided.
|
|
||||||
//
|
|
||||||
// It looks for credentials in the following places, preferring the first
|
|
||||||
// location found:
|
|
||||||
//
|
|
||||||
// - A JSON file whose path is specified by the GOOGLE_APPLICATION_CREDENTIALS
|
|
||||||
// environment variable. For workload identity federation, refer to
|
|
||||||
// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation
|
|
||||||
// on how to generate the JSON configuration file for on-prem/non-Google
|
|
||||||
// cloud platforms.
|
|
||||||
// - A JSON file in a location known to the gcloud command-line tool. On
|
|
||||||
// Windows, this is %APPDATA%/gcloud/application_default_credentials.json. On
|
|
||||||
// other systems, $HOME/.config/gcloud/application_default_credentials.json.
|
|
||||||
// - On Google Compute Engine, Google App Engine standard second generation
|
|
||||||
// runtimes, and Google App Engine flexible environment, it fetches
|
|
||||||
// credentials from the metadata server.
|
|
||||||
func DetectDefault(opts *DetectOptions) (*auth.Credentials, error) {
|
|
||||||
if err := opts.validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(opts.CredentialsJSON) > 0 {
|
|
||||||
return readCredentialsFileJSON(opts.CredentialsJSON, opts)
|
|
||||||
}
|
|
||||||
if opts.CredentialsFile != "" {
|
|
||||||
return readCredentialsFile(opts.CredentialsFile, opts)
|
|
||||||
}
|
|
||||||
if filename := os.Getenv(credsfile.GoogleAppCredsEnvVar); filename != "" {
|
|
||||||
creds, err := readCredentialsFile(filename, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return creds, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fileName := credsfile.GetWellKnownFileName()
|
|
||||||
if b, err := os.ReadFile(fileName); err == nil {
|
|
||||||
return readCredentialsFileJSON(b, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
if OnGCE() {
|
|
||||||
metadataClient := metadata.NewWithOptions(&metadata.Options{
|
|
||||||
Logger: opts.logger(),
|
|
||||||
})
|
|
||||||
return auth.NewCredentials(&auth.CredentialsOptions{
|
|
||||||
TokenProvider: computeTokenProvider(opts, metadataClient),
|
|
||||||
ProjectIDProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
|
|
||||||
return metadataClient.ProjectIDWithContext(ctx)
|
|
||||||
}),
|
|
||||||
UniverseDomainProvider: &internal.ComputeUniverseDomainProvider{
|
|
||||||
MetadataClient: metadataClient,
|
|
||||||
},
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("credentials: could not find default credentials. See %v for more information", adcSetupURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetectOptions provides configuration for [DetectDefault].
|
|
||||||
type DetectOptions struct {
|
|
||||||
// Scopes that credentials tokens should have. Example:
|
|
||||||
// https://www.googleapis.com/auth/cloud-platform. Required if Audience is
|
|
||||||
// not provided.
|
|
||||||
Scopes []string
|
|
||||||
// Audience that credentials tokens should have. Only applicable for 2LO
|
|
||||||
// flows with service accounts. If specified, scopes should not be provided.
|
|
||||||
Audience string
|
|
||||||
// Subject is the user email used for [domain wide delegation](https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority).
|
|
||||||
// Optional.
|
|
||||||
Subject string
|
|
||||||
// EarlyTokenRefresh configures how early before a token expires that it
|
|
||||||
// should be refreshed. Once the token’s time until expiration has entered
|
|
||||||
// this refresh window the token is considered valid but stale. If unset,
|
|
||||||
// the default value is 3 minutes and 45 seconds. Optional.
|
|
||||||
EarlyTokenRefresh time.Duration
|
|
||||||
// DisableAsyncRefresh configures a synchronous workflow that refreshes
|
|
||||||
// stale tokens while blocking. The default is false. Optional.
|
|
||||||
DisableAsyncRefresh bool
|
|
||||||
// AuthHandlerOptions configures an authorization handler and other options
|
|
||||||
// for 3LO flows. It is required, and only used, for client credential
|
|
||||||
// flows.
|
|
||||||
AuthHandlerOptions *auth.AuthorizationHandlerOptions
|
|
||||||
// TokenURL allows to set the token endpoint for user credential flows. If
|
|
||||||
// unset the default value is: https://oauth2.googleapis.com/token.
|
|
||||||
// Optional.
|
|
||||||
TokenURL string
|
|
||||||
// STSAudience is the audience sent to when retrieving an STS token.
|
|
||||||
// Currently this only used for GDCH auth flow, for which it is required.
|
|
||||||
STSAudience string
|
|
||||||
// CredentialsFile overrides detection logic and sources a credential file
|
|
||||||
// from the provided filepath. If provided, CredentialsJSON must not be.
|
|
||||||
// Optional.
|
|
||||||
CredentialsFile string
|
|
||||||
// CredentialsJSON overrides detection logic and uses the JSON bytes as the
|
|
||||||
// source for the credential. If provided, CredentialsFile must not be.
|
|
||||||
// Optional.
|
|
||||||
CredentialsJSON []byte
|
|
||||||
// UseSelfSignedJWT directs service account based credentials to create a
|
|
||||||
// self-signed JWT with the private key found in the file, skipping any
|
|
||||||
// network requests that would normally be made. Optional.
|
|
||||||
UseSelfSignedJWT bool
|
|
||||||
// Client configures the underlying client used to make network requests
|
|
||||||
// when fetching tokens. Optional.
|
|
||||||
Client *http.Client
|
|
||||||
// UniverseDomain is the default service domain for a given Cloud universe.
|
|
||||||
// The default value is "googleapis.com". This option is ignored for
|
|
||||||
// authentication flows that do not support universe domain. Optional.
|
|
||||||
UniverseDomain string
|
|
||||||
// Logger is used for debug logging. If provided, logging will be enabled
|
|
||||||
// at the loggers configured level. By default logging is disabled unless
|
|
||||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
|
||||||
// logger will be used. Optional.
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *DetectOptions) validate() error {
|
|
||||||
if o == nil {
|
|
||||||
return errors.New("credentials: options must be provided")
|
|
||||||
}
|
|
||||||
if len(o.Scopes) > 0 && o.Audience != "" {
|
|
||||||
return errors.New("credentials: both scopes and audience were provided")
|
|
||||||
}
|
|
||||||
if len(o.CredentialsJSON) > 0 && o.CredentialsFile != "" {
|
|
||||||
return errors.New("credentials: both credentials file and JSON were provided")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *DetectOptions) tokenURL() string {
|
|
||||||
if o.TokenURL != "" {
|
|
||||||
return o.TokenURL
|
|
||||||
}
|
|
||||||
return googleTokenURL
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *DetectOptions) scopes() []string {
|
|
||||||
scopes := make([]string, len(o.Scopes))
|
|
||||||
copy(scopes, o.Scopes)
|
|
||||||
return scopes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *DetectOptions) client() *http.Client {
|
|
||||||
if o.Client != nil {
|
|
||||||
return o.Client
|
|
||||||
}
|
|
||||||
return internal.DefaultClient()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *DetectOptions) logger() *slog.Logger {
|
|
||||||
return internallog.New(o.Logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readCredentialsFile(filename string, opts *DetectOptions) (*auth.Credentials, error) {
|
|
||||||
b, err := os.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return readCredentialsFileJSON(b, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readCredentialsFileJSON(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
|
|
||||||
// attempt to parse jsonData as a Google Developers Console client_credentials.json.
|
|
||||||
config := clientCredConfigFromJSON(b, opts)
|
|
||||||
if config != nil {
|
|
||||||
if config.AuthHandlerOpts == nil {
|
|
||||||
return nil, errors.New("credentials: auth handler must be specified for this credential filetype")
|
|
||||||
}
|
|
||||||
tp, err := auth.New3LOTokenProvider(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return auth.NewCredentials(&auth.CredentialsOptions{
|
|
||||||
TokenProvider: tp,
|
|
||||||
JSON: b,
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
return fileCredentials(b, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func clientCredConfigFromJSON(b []byte, opts *DetectOptions) *auth.Options3LO {
|
|
||||||
var creds credsfile.ClientCredentialsFile
|
|
||||||
var c *credsfile.Config3LO
|
|
||||||
if err := json.Unmarshal(b, &creds); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case creds.Web != nil:
|
|
||||||
c = creds.Web
|
|
||||||
case creds.Installed != nil:
|
|
||||||
c = creds.Installed
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if len(c.RedirectURIs) < 1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var handleOpts *auth.AuthorizationHandlerOptions
|
|
||||||
if opts.AuthHandlerOptions != nil {
|
|
||||||
handleOpts = &auth.AuthorizationHandlerOptions{
|
|
||||||
Handler: opts.AuthHandlerOptions.Handler,
|
|
||||||
State: opts.AuthHandlerOptions.State,
|
|
||||||
PKCEOpts: opts.AuthHandlerOptions.PKCEOpts,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &auth.Options3LO{
|
|
||||||
ClientID: c.ClientID,
|
|
||||||
ClientSecret: c.ClientSecret,
|
|
||||||
RedirectURL: c.RedirectURIs[0],
|
|
||||||
Scopes: opts.scopes(),
|
|
||||||
AuthURL: c.AuthURI,
|
|
||||||
TokenURL: c.TokenURI,
|
|
||||||
Client: opts.client(),
|
|
||||||
Logger: opts.logger(),
|
|
||||||
EarlyTokenExpiry: opts.EarlyTokenRefresh,
|
|
||||||
AuthHandlerOpts: handleOpts,
|
|
||||||
// TODO(codyoss): refactor this out. We need to add in auto-detection
|
|
||||||
// for this use case.
|
|
||||||
AuthStyle: auth.StyleInParams,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
45
src/server/vendor/cloud.google.com/go/auth/credentials/doc.go
generated
vendored
45
src/server/vendor/cloud.google.com/go/auth/credentials/doc.go
generated
vendored
@ -1,45 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package credentials provides support for making OAuth2 authorized and
|
|
||||||
// authenticated HTTP requests to Google APIs. It supports the Web server flow,
|
|
||||||
// client-side credentials, service accounts, Google Compute Engine service
|
|
||||||
// accounts, Google App Engine service accounts and workload identity federation
|
|
||||||
// from non-Google cloud platforms.
|
|
||||||
//
|
|
||||||
// A brief overview of the package follows. For more information, please read
|
|
||||||
// https://developers.google.com/accounts/docs/OAuth2
|
|
||||||
// and
|
|
||||||
// https://developers.google.com/accounts/docs/application-default-credentials.
|
|
||||||
// For more information on using workload identity federation, refer to
|
|
||||||
// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation.
|
|
||||||
//
|
|
||||||
// # Credentials
|
|
||||||
//
|
|
||||||
// The [cloud.google.com/go/auth.Credentials] type represents Google
|
|
||||||
// credentials, including Application Default Credentials.
|
|
||||||
//
|
|
||||||
// Use [DetectDefault] to obtain Application Default Credentials.
|
|
||||||
//
|
|
||||||
// Application Default Credentials support workload identity federation to
|
|
||||||
// access Google Cloud resources from non-Google Cloud platforms including Amazon
|
|
||||||
// Web Services (AWS), Microsoft Azure or any identity provider that supports
|
|
||||||
// OpenID Connect (OIDC). Workload identity federation is recommended for
|
|
||||||
// non-Google Cloud environments as it avoids the need to download, manage, and
|
|
||||||
// store service account private keys locally.
|
|
||||||
//
|
|
||||||
// # Workforce Identity Federation
|
|
||||||
//
|
|
||||||
// For more information on this feature see [cloud.google.com/go/auth/credentials/externalaccount].
|
|
||||||
package credentials
|
|
||||||
231
src/server/vendor/cloud.google.com/go/auth/credentials/filetypes.go
generated
vendored
231
src/server/vendor/cloud.google.com/go/auth/credentials/filetypes.go
generated
vendored
@ -1,231 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package credentials
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/credentials/internal/externalaccount"
|
|
||||||
"cloud.google.com/go/auth/credentials/internal/externalaccountuser"
|
|
||||||
"cloud.google.com/go/auth/credentials/internal/gdch"
|
|
||||||
"cloud.google.com/go/auth/credentials/internal/impersonate"
|
|
||||||
internalauth "cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/credsfile"
|
|
||||||
)
|
|
||||||
|
|
||||||
func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
|
|
||||||
fileType, err := credsfile.ParseFileType(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var projectID, universeDomain string
|
|
||||||
var tp auth.TokenProvider
|
|
||||||
switch fileType {
|
|
||||||
case credsfile.ServiceAccountKey:
|
|
||||||
f, err := credsfile.ParseServiceAccount(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tp, err = handleServiceAccount(f, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
projectID = f.ProjectID
|
|
||||||
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
|
||||||
case credsfile.UserCredentialsKey:
|
|
||||||
f, err := credsfile.ParseUserCredentials(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tp, err = handleUserCredential(f, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
universeDomain = f.UniverseDomain
|
|
||||||
case credsfile.ExternalAccountKey:
|
|
||||||
f, err := credsfile.ParseExternalAccount(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tp, err = handleExternalAccount(f, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
|
||||||
case credsfile.ExternalAccountAuthorizedUserKey:
|
|
||||||
f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tp, err = handleExternalAccountAuthorizedUser(f, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
universeDomain = f.UniverseDomain
|
|
||||||
case credsfile.ImpersonatedServiceAccountKey:
|
|
||||||
f, err := credsfile.ParseImpersonatedServiceAccount(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tp, err = handleImpersonatedServiceAccount(f, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
|
||||||
case credsfile.GDCHServiceAccountKey:
|
|
||||||
f, err := credsfile.ParseGDCHServiceAccount(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tp, err = handleGDCHServiceAccount(f, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
projectID = f.Project
|
|
||||||
universeDomain = f.UniverseDomain
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("credentials: unsupported filetype %q", fileType)
|
|
||||||
}
|
|
||||||
return auth.NewCredentials(&auth.CredentialsOptions{
|
|
||||||
TokenProvider: auth.NewCachedTokenProvider(tp, &auth.CachedTokenProviderOptions{
|
|
||||||
ExpireEarly: opts.EarlyTokenRefresh,
|
|
||||||
}),
|
|
||||||
JSON: b,
|
|
||||||
ProjectIDProvider: internalauth.StaticCredentialsProperty(projectID),
|
|
||||||
// TODO(codyoss): only set quota project here if there was a user override
|
|
||||||
UniverseDomainProvider: internalauth.StaticCredentialsProperty(universeDomain),
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveUniverseDomain returns optsUniverseDomain if non-empty, in order to
|
|
||||||
// support configuring universe-specific credentials in code. Auth flows
|
|
||||||
// unsupported for universe domain should not use this func, but should instead
|
|
||||||
// simply set the file universe domain on the credentials.
|
|
||||||
func resolveUniverseDomain(optsUniverseDomain, fileUniverseDomain string) string {
|
|
||||||
if optsUniverseDomain != "" {
|
|
||||||
return optsUniverseDomain
|
|
||||||
}
|
|
||||||
return fileUniverseDomain
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
|
||||||
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
|
||||||
if opts.UseSelfSignedJWT {
|
|
||||||
return configureSelfSignedJWT(f, opts)
|
|
||||||
} else if ud != "" && ud != internalauth.DefaultUniverseDomain {
|
|
||||||
// For non-GDU universe domains, token exchange is impossible and services
|
|
||||||
// must support self-signed JWTs.
|
|
||||||
opts.UseSelfSignedJWT = true
|
|
||||||
return configureSelfSignedJWT(f, opts)
|
|
||||||
}
|
|
||||||
opts2LO := &auth.Options2LO{
|
|
||||||
Email: f.ClientEmail,
|
|
||||||
PrivateKey: []byte(f.PrivateKey),
|
|
||||||
PrivateKeyID: f.PrivateKeyID,
|
|
||||||
Scopes: opts.scopes(),
|
|
||||||
TokenURL: f.TokenURL,
|
|
||||||
Subject: opts.Subject,
|
|
||||||
Client: opts.client(),
|
|
||||||
Logger: opts.logger(),
|
|
||||||
}
|
|
||||||
if opts2LO.TokenURL == "" {
|
|
||||||
opts2LO.TokenURL = jwtTokenURL
|
|
||||||
}
|
|
||||||
return auth.New2LOTokenProvider(opts2LO)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleUserCredential(f *credsfile.UserCredentialsFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
|
||||||
opts3LO := &auth.Options3LO{
|
|
||||||
ClientID: f.ClientID,
|
|
||||||
ClientSecret: f.ClientSecret,
|
|
||||||
Scopes: opts.scopes(),
|
|
||||||
AuthURL: googleAuthURL,
|
|
||||||
TokenURL: opts.tokenURL(),
|
|
||||||
AuthStyle: auth.StyleInParams,
|
|
||||||
EarlyTokenExpiry: opts.EarlyTokenRefresh,
|
|
||||||
RefreshToken: f.RefreshToken,
|
|
||||||
Client: opts.client(),
|
|
||||||
Logger: opts.logger(),
|
|
||||||
}
|
|
||||||
return auth.New3LOTokenProvider(opts3LO)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleExternalAccount(f *credsfile.ExternalAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
|
||||||
externalOpts := &externalaccount.Options{
|
|
||||||
Audience: f.Audience,
|
|
||||||
SubjectTokenType: f.SubjectTokenType,
|
|
||||||
TokenURL: f.TokenURL,
|
|
||||||
TokenInfoURL: f.TokenInfoURL,
|
|
||||||
ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
|
|
||||||
ClientSecret: f.ClientSecret,
|
|
||||||
ClientID: f.ClientID,
|
|
||||||
CredentialSource: f.CredentialSource,
|
|
||||||
QuotaProjectID: f.QuotaProjectID,
|
|
||||||
Scopes: opts.scopes(),
|
|
||||||
WorkforcePoolUserProject: f.WorkforcePoolUserProject,
|
|
||||||
Client: opts.client(),
|
|
||||||
Logger: opts.logger(),
|
|
||||||
IsDefaultClient: opts.Client == nil,
|
|
||||||
}
|
|
||||||
if f.ServiceAccountImpersonation != nil {
|
|
||||||
externalOpts.ServiceAccountImpersonationLifetimeSeconds = f.ServiceAccountImpersonation.TokenLifetimeSeconds
|
|
||||||
}
|
|
||||||
return externalaccount.NewTokenProvider(externalOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleExternalAccountAuthorizedUser(f *credsfile.ExternalAccountAuthorizedUserFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
|
||||||
externalOpts := &externalaccountuser.Options{
|
|
||||||
Audience: f.Audience,
|
|
||||||
RefreshToken: f.RefreshToken,
|
|
||||||
TokenURL: f.TokenURL,
|
|
||||||
TokenInfoURL: f.TokenInfoURL,
|
|
||||||
ClientID: f.ClientID,
|
|
||||||
ClientSecret: f.ClientSecret,
|
|
||||||
Scopes: opts.scopes(),
|
|
||||||
Client: opts.client(),
|
|
||||||
Logger: opts.logger(),
|
|
||||||
}
|
|
||||||
return externalaccountuser.NewTokenProvider(externalOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
|
||||||
if f.ServiceAccountImpersonationURL == "" || f.CredSource == nil {
|
|
||||||
return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials")
|
|
||||||
}
|
|
||||||
|
|
||||||
tp, err := fileCredentials(f.CredSource, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return impersonate.NewTokenProvider(&impersonate.Options{
|
|
||||||
URL: f.ServiceAccountImpersonationURL,
|
|
||||||
Scopes: opts.scopes(),
|
|
||||||
Tp: tp,
|
|
||||||
Delegates: f.Delegates,
|
|
||||||
Client: opts.client(),
|
|
||||||
Logger: opts.logger(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleGDCHServiceAccount(f *credsfile.GDCHServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
|
||||||
return gdch.NewTokenProvider(f, &gdch.Options{
|
|
||||||
STSAudience: opts.STSAudience,
|
|
||||||
Client: opts.client(),
|
|
||||||
Logger: opts.logger(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,531 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// getenv aliases os.Getenv for testing
|
|
||||||
getenv = os.Getenv
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// AWS Signature Version 4 signing algorithm identifier.
|
|
||||||
awsAlgorithm = "AWS4-HMAC-SHA256"
|
|
||||||
|
|
||||||
// The termination string for the AWS credential scope value as defined in
|
|
||||||
// https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
|
|
||||||
awsRequestType = "aws4_request"
|
|
||||||
|
|
||||||
// The AWS authorization header name for the security session token if available.
|
|
||||||
awsSecurityTokenHeader = "x-amz-security-token"
|
|
||||||
|
|
||||||
// The name of the header containing the session token for metadata endpoint calls
|
|
||||||
awsIMDSv2SessionTokenHeader = "X-aws-ec2-metadata-token"
|
|
||||||
|
|
||||||
awsIMDSv2SessionTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds"
|
|
||||||
|
|
||||||
awsIMDSv2SessionTTL = "300"
|
|
||||||
|
|
||||||
// The AWS authorization header name for the auto-generated date.
|
|
||||||
awsDateHeader = "x-amz-date"
|
|
||||||
|
|
||||||
defaultRegionalCredentialVerificationURL = "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
|
|
||||||
|
|
||||||
// Supported AWS configuration environment variables.
|
|
||||||
awsAccessKeyIDEnvVar = "AWS_ACCESS_KEY_ID"
|
|
||||||
awsDefaultRegionEnvVar = "AWS_DEFAULT_REGION"
|
|
||||||
awsRegionEnvVar = "AWS_REGION"
|
|
||||||
awsSecretAccessKeyEnvVar = "AWS_SECRET_ACCESS_KEY"
|
|
||||||
awsSessionTokenEnvVar = "AWS_SESSION_TOKEN"
|
|
||||||
|
|
||||||
awsTimeFormatLong = "20060102T150405Z"
|
|
||||||
awsTimeFormatShort = "20060102"
|
|
||||||
awsProviderType = "aws"
|
|
||||||
)
|
|
||||||
|
|
||||||
type awsSubjectProvider struct {
|
|
||||||
EnvironmentID string
|
|
||||||
RegionURL string
|
|
||||||
RegionalCredVerificationURL string
|
|
||||||
CredVerificationURL string
|
|
||||||
IMDSv2SessionTokenURL string
|
|
||||||
TargetResource string
|
|
||||||
requestSigner *awsRequestSigner
|
|
||||||
region string
|
|
||||||
securityCredentialsProvider AwsSecurityCredentialsProvider
|
|
||||||
reqOpts *RequestOptions
|
|
||||||
|
|
||||||
Client *http.Client
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
|
||||||
// Set Defaults
|
|
||||||
if sp.RegionalCredVerificationURL == "" {
|
|
||||||
sp.RegionalCredVerificationURL = defaultRegionalCredentialVerificationURL
|
|
||||||
}
|
|
||||||
headers := make(map[string]string)
|
|
||||||
if sp.shouldUseMetadataServer() {
|
|
||||||
awsSessionToken, err := sp.getAWSSessionToken(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if awsSessionToken != "" {
|
|
||||||
headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
awsSecurityCredentials, err := sp.getSecurityCredentials(ctx, headers)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if sp.region, err = sp.getRegion(ctx, headers); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
sp.requestSigner = &awsRequestSigner{
|
|
||||||
RegionName: sp.region,
|
|
||||||
AwsSecurityCredentials: awsSecurityCredentials,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the signed request to AWS STS GetCallerIdentity API.
|
|
||||||
// Use the required regional endpoint. Otherwise, the request will fail.
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", strings.Replace(sp.RegionalCredVerificationURL, "{region}", sp.region, 1), nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// The full, canonical resource name of the workload identity pool
|
|
||||||
// provider, with or without the HTTPS prefix.
|
|
||||||
// Including this header as part of the signature is recommended to
|
|
||||||
// ensure data integrity.
|
|
||||||
if sp.TargetResource != "" {
|
|
||||||
req.Header.Set("x-goog-cloud-target-resource", sp.TargetResource)
|
|
||||||
}
|
|
||||||
sp.requestSigner.signRequest(req)
|
|
||||||
|
|
||||||
/*
|
|
||||||
The GCP STS endpoint expects the headers to be formatted as:
|
|
||||||
# [
|
|
||||||
# {key: 'x-amz-date', value: '...'},
|
|
||||||
# {key: 'Authorization', value: '...'},
|
|
||||||
# ...
|
|
||||||
# ]
|
|
||||||
# And then serialized as:
|
|
||||||
# quote(json.dumps({
|
|
||||||
# url: '...',
|
|
||||||
# method: 'POST',
|
|
||||||
# headers: [{key: 'x-amz-date', value: '...'}, ...]
|
|
||||||
# }))
|
|
||||||
*/
|
|
||||||
|
|
||||||
awsSignedReq := awsRequest{
|
|
||||||
URL: req.URL.String(),
|
|
||||||
Method: "POST",
|
|
||||||
}
|
|
||||||
for headerKey, headerList := range req.Header {
|
|
||||||
for _, headerValue := range headerList {
|
|
||||||
awsSignedReq.Headers = append(awsSignedReq.Headers, awsRequestHeader{
|
|
||||||
Key: headerKey,
|
|
||||||
Value: headerValue,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(awsSignedReq.Headers, func(i, j int) bool {
|
|
||||||
headerCompare := strings.Compare(awsSignedReq.Headers[i].Key, awsSignedReq.Headers[j].Key)
|
|
||||||
if headerCompare == 0 {
|
|
||||||
return strings.Compare(awsSignedReq.Headers[i].Value, awsSignedReq.Headers[j].Value) < 0
|
|
||||||
}
|
|
||||||
return headerCompare < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
result, err := json.Marshal(awsSignedReq)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return url.QueryEscape(string(result)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) providerType() string {
|
|
||||||
if sp.securityCredentialsProvider != nil {
|
|
||||||
return programmaticProviderType
|
|
||||||
}
|
|
||||||
return awsProviderType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) getAWSSessionToken(ctx context.Context) (string, error) {
|
|
||||||
if sp.IMDSv2SessionTokenURL == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "PUT", sp.IMDSv2SessionTokenURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
req.Header.Set(awsIMDSv2SessionTTLHeader, awsIMDSv2SessionTTL)
|
|
||||||
|
|
||||||
sp.logger.DebugContext(ctx, "aws session token request", "request", internallog.HTTPRequest(req, nil))
|
|
||||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
sp.logger.DebugContext(ctx, "aws session token response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return "", fmt.Errorf("credentials: unable to retrieve AWS session token: %s", body)
|
|
||||||
}
|
|
||||||
return string(body), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) getRegion(ctx context.Context, headers map[string]string) (string, error) {
|
|
||||||
if sp.securityCredentialsProvider != nil {
|
|
||||||
return sp.securityCredentialsProvider.AwsRegion(ctx, sp.reqOpts)
|
|
||||||
}
|
|
||||||
if canRetrieveRegionFromEnvironment() {
|
|
||||||
if envAwsRegion := getenv(awsRegionEnvVar); envAwsRegion != "" {
|
|
||||||
return envAwsRegion, nil
|
|
||||||
}
|
|
||||||
return getenv(awsDefaultRegionEnvVar), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if sp.RegionURL == "" {
|
|
||||||
return "", errors.New("credentials: unable to determine AWS region")
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", sp.RegionURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, value := range headers {
|
|
||||||
req.Header.Add(name, value)
|
|
||||||
}
|
|
||||||
sp.logger.DebugContext(ctx, "aws region request", "request", internallog.HTTPRequest(req, nil))
|
|
||||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
sp.logger.DebugContext(ctx, "aws region response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return "", fmt.Errorf("credentials: unable to retrieve AWS region - %s", body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This endpoint will return the region in format: us-east-2b.
|
|
||||||
// Only the us-east-2 part should be used.
|
|
||||||
bodyLen := len(body)
|
|
||||||
if bodyLen == 0 {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
return string(body[:bodyLen-1]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) getSecurityCredentials(ctx context.Context, headers map[string]string) (result *AwsSecurityCredentials, err error) {
|
|
||||||
if sp.securityCredentialsProvider != nil {
|
|
||||||
return sp.securityCredentialsProvider.AwsSecurityCredentials(ctx, sp.reqOpts)
|
|
||||||
}
|
|
||||||
if canRetrieveSecurityCredentialFromEnvironment() {
|
|
||||||
return &AwsSecurityCredentials{
|
|
||||||
AccessKeyID: getenv(awsAccessKeyIDEnvVar),
|
|
||||||
SecretAccessKey: getenv(awsSecretAccessKeyEnvVar),
|
|
||||||
SessionToken: getenv(awsSessionTokenEnvVar),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
roleName, err := sp.getMetadataRoleName(ctx, headers)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
credentials, err := sp.getMetadataSecurityCredentials(ctx, roleName, headers)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if credentials.AccessKeyID == "" {
|
|
||||||
return result, errors.New("credentials: missing AccessKeyId credential")
|
|
||||||
}
|
|
||||||
if credentials.SecretAccessKey == "" {
|
|
||||||
return result, errors.New("credentials: missing SecretAccessKey credential")
|
|
||||||
}
|
|
||||||
|
|
||||||
return credentials, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) getMetadataSecurityCredentials(ctx context.Context, roleName string, headers map[string]string) (*AwsSecurityCredentials, error) {
|
|
||||||
var result *AwsSecurityCredentials
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s", sp.CredVerificationURL, roleName), nil)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
for name, value := range headers {
|
|
||||||
req.Header.Add(name, value)
|
|
||||||
}
|
|
||||||
sp.logger.DebugContext(ctx, "aws security credential request", "request", internallog.HTTPRequest(req, nil))
|
|
||||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
sp.logger.DebugContext(ctx, "aws security credential response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return result, fmt.Errorf("credentials: unable to retrieve AWS security credentials - %s", body)
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(body, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) getMetadataRoleName(ctx context.Context, headers map[string]string) (string, error) {
|
|
||||||
if sp.CredVerificationURL == "" {
|
|
||||||
return "", errors.New("credentials: unable to determine the AWS metadata server security credentials endpoint")
|
|
||||||
}
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", sp.CredVerificationURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
for name, value := range headers {
|
|
||||||
req.Header.Add(name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
sp.logger.DebugContext(ctx, "aws metadata role request", "request", internallog.HTTPRequest(req, nil))
|
|
||||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
sp.logger.DebugContext(ctx, "aws metadata role response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return "", fmt.Errorf("credentials: unable to retrieve AWS role name - %s", body)
|
|
||||||
}
|
|
||||||
return string(body), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// awsRequestSigner is a utility class to sign http requests using a AWS V4 signature.
|
|
||||||
type awsRequestSigner struct {
|
|
||||||
RegionName string
|
|
||||||
AwsSecurityCredentials *AwsSecurityCredentials
|
|
||||||
}
|
|
||||||
|
|
||||||
// signRequest adds the appropriate headers to an http.Request
|
|
||||||
// or returns an error if something prevented this.
|
|
||||||
func (rs *awsRequestSigner) signRequest(req *http.Request) error {
|
|
||||||
// req is assumed non-nil
|
|
||||||
signedRequest := cloneRequest(req)
|
|
||||||
timestamp := Now()
|
|
||||||
signedRequest.Header.Set("host", requestHost(req))
|
|
||||||
if rs.AwsSecurityCredentials.SessionToken != "" {
|
|
||||||
signedRequest.Header.Set(awsSecurityTokenHeader, rs.AwsSecurityCredentials.SessionToken)
|
|
||||||
}
|
|
||||||
if signedRequest.Header.Get("date") == "" {
|
|
||||||
signedRequest.Header.Set(awsDateHeader, timestamp.Format(awsTimeFormatLong))
|
|
||||||
}
|
|
||||||
authorizationCode, err := rs.generateAuthentication(signedRequest, timestamp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
signedRequest.Header.Set("Authorization", authorizationCode)
|
|
||||||
req.Header = signedRequest.Header
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *awsRequestSigner) generateAuthentication(req *http.Request, timestamp time.Time) (string, error) {
|
|
||||||
canonicalHeaderColumns, canonicalHeaderData := canonicalHeaders(req)
|
|
||||||
dateStamp := timestamp.Format(awsTimeFormatShort)
|
|
||||||
serviceName := ""
|
|
||||||
|
|
||||||
if splitHost := strings.Split(requestHost(req), "."); len(splitHost) > 0 {
|
|
||||||
serviceName = splitHost[0]
|
|
||||||
}
|
|
||||||
credentialScope := strings.Join([]string{dateStamp, rs.RegionName, serviceName, awsRequestType}, "/")
|
|
||||||
requestString, err := canonicalRequest(req, canonicalHeaderColumns, canonicalHeaderData)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
requestHash, err := getSha256([]byte(requestString))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
stringToSign := strings.Join([]string{awsAlgorithm, timestamp.Format(awsTimeFormatLong), credentialScope, requestHash}, "\n")
|
|
||||||
signingKey := []byte("AWS4" + rs.AwsSecurityCredentials.SecretAccessKey)
|
|
||||||
for _, signingInput := range []string{
|
|
||||||
dateStamp, rs.RegionName, serviceName, awsRequestType, stringToSign,
|
|
||||||
} {
|
|
||||||
signingKey, err = getHmacSha256(signingKey, []byte(signingInput))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", awsAlgorithm, rs.AwsSecurityCredentials.AccessKeyID, credentialScope, canonicalHeaderColumns, hex.EncodeToString(signingKey)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSha256(input []byte) (string, error) {
|
|
||||||
hash := sha256.New()
|
|
||||||
if _, err := hash.Write(input); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHmacSha256(key, input []byte) ([]byte, error) {
|
|
||||||
hash := hmac.New(sha256.New, key)
|
|
||||||
if _, err := hash.Write(input); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return hash.Sum(nil), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cloneRequest(r *http.Request) *http.Request {
|
|
||||||
r2 := new(http.Request)
|
|
||||||
*r2 = *r
|
|
||||||
if r.Header != nil {
|
|
||||||
r2.Header = make(http.Header, len(r.Header))
|
|
||||||
|
|
||||||
// Find total number of values.
|
|
||||||
headerCount := 0
|
|
||||||
for _, headerValues := range r.Header {
|
|
||||||
headerCount += len(headerValues)
|
|
||||||
}
|
|
||||||
copiedHeaders := make([]string, headerCount) // shared backing array for headers' values
|
|
||||||
|
|
||||||
for headerKey, headerValues := range r.Header {
|
|
||||||
headerCount = copy(copiedHeaders, headerValues)
|
|
||||||
r2.Header[headerKey] = copiedHeaders[:headerCount:headerCount]
|
|
||||||
copiedHeaders = copiedHeaders[headerCount:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r2
|
|
||||||
}
|
|
||||||
|
|
||||||
func canonicalPath(req *http.Request) string {
|
|
||||||
result := req.URL.EscapedPath()
|
|
||||||
if result == "" {
|
|
||||||
return "/"
|
|
||||||
}
|
|
||||||
return path.Clean(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func canonicalQuery(req *http.Request) string {
|
|
||||||
queryValues := req.URL.Query()
|
|
||||||
for queryKey := range queryValues {
|
|
||||||
sort.Strings(queryValues[queryKey])
|
|
||||||
}
|
|
||||||
return queryValues.Encode()
|
|
||||||
}
|
|
||||||
|
|
||||||
func canonicalHeaders(req *http.Request) (string, string) {
|
|
||||||
// Header keys need to be sorted alphabetically.
|
|
||||||
var headers []string
|
|
||||||
lowerCaseHeaders := make(http.Header)
|
|
||||||
for k, v := range req.Header {
|
|
||||||
k := strings.ToLower(k)
|
|
||||||
if _, ok := lowerCaseHeaders[k]; ok {
|
|
||||||
// include additional values
|
|
||||||
lowerCaseHeaders[k] = append(lowerCaseHeaders[k], v...)
|
|
||||||
} else {
|
|
||||||
headers = append(headers, k)
|
|
||||||
lowerCaseHeaders[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(headers)
|
|
||||||
|
|
||||||
var fullHeaders bytes.Buffer
|
|
||||||
for _, header := range headers {
|
|
||||||
headerValue := strings.Join(lowerCaseHeaders[header], ",")
|
|
||||||
fullHeaders.WriteString(header)
|
|
||||||
fullHeaders.WriteRune(':')
|
|
||||||
fullHeaders.WriteString(headerValue)
|
|
||||||
fullHeaders.WriteRune('\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(headers, ";"), fullHeaders.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func requestDataHash(req *http.Request) (string, error) {
|
|
||||||
var requestData []byte
|
|
||||||
if req.Body != nil {
|
|
||||||
requestBody, err := req.GetBody()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer requestBody.Close()
|
|
||||||
|
|
||||||
requestData, err = internal.ReadAll(requestBody)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getSha256(requestData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func requestHost(req *http.Request) string {
|
|
||||||
if req.Host != "" {
|
|
||||||
return req.Host
|
|
||||||
}
|
|
||||||
return req.URL.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
func canonicalRequest(req *http.Request, canonicalHeaderColumns, canonicalHeaderData string) (string, error) {
|
|
||||||
dataHash, err := requestDataHash(req)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", req.Method, canonicalPath(req), canonicalQuery(req), canonicalHeaderData, canonicalHeaderColumns, dataHash), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type awsRequestHeader struct {
|
|
||||||
Key string `json:"key"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type awsRequest struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
Method string `json:"method"`
|
|
||||||
Headers []awsRequestHeader `json:"headers"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// The AWS region can be provided through AWS_REGION or AWS_DEFAULT_REGION. Only one is
|
|
||||||
// required.
|
|
||||||
func canRetrieveRegionFromEnvironment() bool {
|
|
||||||
return getenv(awsRegionEnvVar) != "" || getenv(awsDefaultRegionEnvVar) != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are available.
|
|
||||||
func canRetrieveSecurityCredentialFromEnvironment() bool {
|
|
||||||
return getenv(awsAccessKeyIDEnvVar) != "" && getenv(awsSecretAccessKeyEnvVar) != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *awsSubjectProvider) shouldUseMetadataServer() bool {
|
|
||||||
return sp.securityCredentialsProvider == nil && (!canRetrieveRegionFromEnvironment() || !canRetrieveSecurityCredentialFromEnvironment())
|
|
||||||
}
|
|
||||||
@ -1,284 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
executableSupportedMaxVersion = 1
|
|
||||||
executableDefaultTimeout = 30 * time.Second
|
|
||||||
executableSource = "response"
|
|
||||||
executableProviderType = "executable"
|
|
||||||
outputFileSource = "output file"
|
|
||||||
|
|
||||||
allowExecutablesEnvVar = "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES"
|
|
||||||
|
|
||||||
jwtTokenType = "urn:ietf:params:oauth:token-type:jwt"
|
|
||||||
idTokenType = "urn:ietf:params:oauth:token-type:id_token"
|
|
||||||
saml2TokenType = "urn:ietf:params:oauth:token-type:saml2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
serviceAccountImpersonationRE = regexp.MustCompile(`https://iamcredentials..+/v1/projects/-/serviceAccounts/(.*@.*):generateAccessToken`)
|
|
||||||
)
|
|
||||||
|
|
||||||
type nonCacheableError struct {
|
|
||||||
message string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (nce nonCacheableError) Error() string {
|
|
||||||
return nce.message
|
|
||||||
}
|
|
||||||
|
|
||||||
// environment is a contract for testing
|
|
||||||
type environment interface {
|
|
||||||
existingEnv() []string
|
|
||||||
getenv(string) string
|
|
||||||
run(ctx context.Context, command string, env []string) ([]byte, error)
|
|
||||||
now() time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type runtimeEnvironment struct{}
|
|
||||||
|
|
||||||
func (r runtimeEnvironment) existingEnv() []string {
|
|
||||||
return os.Environ()
|
|
||||||
}
|
|
||||||
func (r runtimeEnvironment) getenv(key string) string {
|
|
||||||
return os.Getenv(key)
|
|
||||||
}
|
|
||||||
func (r runtimeEnvironment) now() time.Time {
|
|
||||||
return time.Now().UTC()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r runtimeEnvironment) run(ctx context.Context, command string, env []string) ([]byte, error) {
|
|
||||||
splitCommand := strings.Fields(command)
|
|
||||||
cmd := exec.CommandContext(ctx, splitCommand[0], splitCommand[1:]...)
|
|
||||||
cmd.Env = env
|
|
||||||
|
|
||||||
var stdout, stderr bytes.Buffer
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
if ctx.Err() == context.DeadlineExceeded {
|
|
||||||
return nil, context.DeadlineExceeded
|
|
||||||
}
|
|
||||||
if exitError, ok := err.(*exec.ExitError); ok {
|
|
||||||
return nil, exitCodeError(exitError)
|
|
||||||
}
|
|
||||||
return nil, executableError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesStdout := bytes.TrimSpace(stdout.Bytes())
|
|
||||||
if len(bytesStdout) > 0 {
|
|
||||||
return bytesStdout, nil
|
|
||||||
}
|
|
||||||
return bytes.TrimSpace(stderr.Bytes()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type executableSubjectProvider struct {
|
|
||||||
Command string
|
|
||||||
Timeout time.Duration
|
|
||||||
OutputFile string
|
|
||||||
client *http.Client
|
|
||||||
opts *Options
|
|
||||||
env environment
|
|
||||||
}
|
|
||||||
|
|
||||||
type executableResponse struct {
|
|
||||||
Version int `json:"version,omitempty"`
|
|
||||||
Success *bool `json:"success,omitempty"`
|
|
||||||
TokenType string `json:"token_type,omitempty"`
|
|
||||||
ExpirationTime int64 `json:"expiration_time,omitempty"`
|
|
||||||
IDToken string `json:"id_token,omitempty"`
|
|
||||||
SamlResponse string `json:"saml_response,omitempty"`
|
|
||||||
Code string `json:"code,omitempty"`
|
|
||||||
Message string `json:"message,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *executableSubjectProvider) parseSubjectTokenFromSource(response []byte, source string, now int64) (string, error) {
|
|
||||||
var result executableResponse
|
|
||||||
if err := json.Unmarshal(response, &result); err != nil {
|
|
||||||
return "", jsonParsingError(source, string(response))
|
|
||||||
}
|
|
||||||
// Validate
|
|
||||||
if result.Version == 0 {
|
|
||||||
return "", missingFieldError(source, "version")
|
|
||||||
}
|
|
||||||
if result.Success == nil {
|
|
||||||
return "", missingFieldError(source, "success")
|
|
||||||
}
|
|
||||||
if !*result.Success {
|
|
||||||
if result.Code == "" || result.Message == "" {
|
|
||||||
return "", malformedFailureError()
|
|
||||||
}
|
|
||||||
return "", userDefinedError(result.Code, result.Message)
|
|
||||||
}
|
|
||||||
if result.Version > executableSupportedMaxVersion || result.Version < 0 {
|
|
||||||
return "", unsupportedVersionError(source, result.Version)
|
|
||||||
}
|
|
||||||
if result.ExpirationTime == 0 && sp.OutputFile != "" {
|
|
||||||
return "", missingFieldError(source, "expiration_time")
|
|
||||||
}
|
|
||||||
if result.TokenType == "" {
|
|
||||||
return "", missingFieldError(source, "token_type")
|
|
||||||
}
|
|
||||||
if result.ExpirationTime != 0 && result.ExpirationTime < now {
|
|
||||||
return "", tokenExpiredError()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch result.TokenType {
|
|
||||||
case jwtTokenType, idTokenType:
|
|
||||||
if result.IDToken == "" {
|
|
||||||
return "", missingFieldError(source, "id_token")
|
|
||||||
}
|
|
||||||
return result.IDToken, nil
|
|
||||||
case saml2TokenType:
|
|
||||||
if result.SamlResponse == "" {
|
|
||||||
return "", missingFieldError(source, "saml_response")
|
|
||||||
}
|
|
||||||
return result.SamlResponse, nil
|
|
||||||
default:
|
|
||||||
return "", tokenTypeError(source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *executableSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
|
||||||
if token, err := sp.getTokenFromOutputFile(); token != "" || err != nil {
|
|
||||||
return token, err
|
|
||||||
}
|
|
||||||
return sp.getTokenFromExecutableCommand(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *executableSubjectProvider) providerType() string {
|
|
||||||
return executableProviderType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *executableSubjectProvider) getTokenFromOutputFile() (token string, err error) {
|
|
||||||
if sp.OutputFile == "" {
|
|
||||||
// This ExecutableCredentialSource doesn't use an OutputFile.
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(sp.OutputFile)
|
|
||||||
if err != nil {
|
|
||||||
// No OutputFile found. Hasn't been created yet, so skip it.
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
data, err := internal.ReadAll(file)
|
|
||||||
if err != nil || len(data) == 0 {
|
|
||||||
// Cachefile exists, but no data found. Get new credential.
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err = sp.parseSubjectTokenFromSource(data, outputFileSource, sp.env.now().Unix())
|
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(nonCacheableError); ok {
|
|
||||||
// If the cached token is expired we need a new token,
|
|
||||||
// and if the cache contains a failure, we need to try again.
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// There was an error in the cached token, and the developer should be aware of it.
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// Token parsing succeeded. Use found token.
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *executableSubjectProvider) executableEnvironment() []string {
|
|
||||||
result := sp.env.existingEnv()
|
|
||||||
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE=%v", sp.opts.Audience))
|
|
||||||
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE=%v", sp.opts.SubjectTokenType))
|
|
||||||
result = append(result, "GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE=0")
|
|
||||||
if sp.opts.ServiceAccountImpersonationURL != "" {
|
|
||||||
matches := serviceAccountImpersonationRE.FindStringSubmatch(sp.opts.ServiceAccountImpersonationURL)
|
|
||||||
if matches != nil {
|
|
||||||
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL=%v", matches[1]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sp.OutputFile != "" {
|
|
||||||
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE=%v", sp.OutputFile))
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *executableSubjectProvider) getTokenFromExecutableCommand(ctx context.Context) (string, error) {
|
|
||||||
// For security reasons, we need our consumers to set this environment variable to allow executables to be run.
|
|
||||||
if sp.env.getenv(allowExecutablesEnvVar) != "1" {
|
|
||||||
return "", errors.New("credentials: executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithDeadline(ctx, sp.env.now().Add(sp.Timeout))
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
output, err := sp.env.run(ctx, sp.Command, sp.executableEnvironment())
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return sp.parseSubjectTokenFromSource(output, executableSource, sp.env.now().Unix())
|
|
||||||
}
|
|
||||||
|
|
||||||
func missingFieldError(source, field string) error {
|
|
||||||
return fmt.Errorf("credentials: %q missing %q field", source, field)
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsonParsingError(source, data string) error {
|
|
||||||
return fmt.Errorf("credentials: unable to parse %q: %v", source, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func malformedFailureError() error {
|
|
||||||
return nonCacheableError{"credentials: response must include `error` and `message` fields when unsuccessful"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func userDefinedError(code, message string) error {
|
|
||||||
return nonCacheableError{fmt.Sprintf("credentials: response contains unsuccessful response: (%v) %v", code, message)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func unsupportedVersionError(source string, version int) error {
|
|
||||||
return fmt.Errorf("credentials: %v contains unsupported version: %v", source, version)
|
|
||||||
}
|
|
||||||
|
|
||||||
func tokenExpiredError() error {
|
|
||||||
return nonCacheableError{"credentials: the token returned by the executable is expired"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func tokenTypeError(source string) error {
|
|
||||||
return fmt.Errorf("credentials: %v contains unsupported token type", source)
|
|
||||||
}
|
|
||||||
|
|
||||||
func exitCodeError(err *exec.ExitError) error {
|
|
||||||
return fmt.Errorf("credentials: executable command failed with exit code %v: %w", err.ExitCode(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func executableError(err error) error {
|
|
||||||
return fmt.Errorf("credentials: executable command failed: %w", err)
|
|
||||||
}
|
|
||||||
@ -1,428 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/credentials/internal/impersonate"
|
|
||||||
"cloud.google.com/go/auth/credentials/internal/stsexchange"
|
|
||||||
"cloud.google.com/go/auth/internal/credsfile"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
timeoutMinimum = 5 * time.Second
|
|
||||||
timeoutMaximum = 120 * time.Second
|
|
||||||
|
|
||||||
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
|
|
||||||
defaultTokenURL = "https://sts.UNIVERSE_DOMAIN/v1/token"
|
|
||||||
defaultUniverseDomain = "googleapis.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Now aliases time.Now for testing
|
|
||||||
Now = func() time.Time {
|
|
||||||
return time.Now().UTC()
|
|
||||||
}
|
|
||||||
validWorkforceAudiencePattern *regexp.Regexp = regexp.MustCompile(`//iam\.googleapis\.com/locations/[^/]+/workforcePools/`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options stores the configuration for fetching tokens with external credentials.
|
|
||||||
type Options struct {
|
|
||||||
// Audience is the Secure Token Service (STS) audience which contains the resource name for the workload
|
|
||||||
// identity pool or the workforce pool and the provider identifier in that pool.
|
|
||||||
Audience string
|
|
||||||
// SubjectTokenType is the STS token type based on the Oauth2.0 token exchange spec
|
|
||||||
// e.g. `urn:ietf:params:oauth:token-type:jwt`.
|
|
||||||
SubjectTokenType string
|
|
||||||
// TokenURL is the STS token exchange endpoint.
|
|
||||||
TokenURL string
|
|
||||||
// TokenInfoURL is the token_info endpoint used to retrieve the account related information (
|
|
||||||
// user attributes like account identifier, eg. email, username, uid, etc). This is
|
|
||||||
// needed for gCloud session account identification.
|
|
||||||
TokenInfoURL string
|
|
||||||
// ServiceAccountImpersonationURL is the URL for the service account impersonation request. This is only
|
|
||||||
// required for workload identity pools when APIs to be accessed have not integrated with UberMint.
|
|
||||||
ServiceAccountImpersonationURL string
|
|
||||||
// ServiceAccountImpersonationLifetimeSeconds is the number of seconds the service account impersonation
|
|
||||||
// token will be valid for.
|
|
||||||
ServiceAccountImpersonationLifetimeSeconds int
|
|
||||||
// ClientSecret is currently only required if token_info endpoint also
|
|
||||||
// needs to be called with the generated GCP access token. When provided, STS will be
|
|
||||||
// called with additional basic authentication using client_id as username and client_secret as password.
|
|
||||||
ClientSecret string
|
|
||||||
// ClientID is only required in conjunction with ClientSecret, as described above.
|
|
||||||
ClientID string
|
|
||||||
// CredentialSource contains the necessary information to retrieve the token itself, as well
|
|
||||||
// as some environmental information.
|
|
||||||
CredentialSource *credsfile.CredentialSource
|
|
||||||
// QuotaProjectID is injected by gCloud. If the value is non-empty, the Auth libraries
|
|
||||||
// will set the x-goog-user-project which overrides the project associated with the credentials.
|
|
||||||
QuotaProjectID string
|
|
||||||
// Scopes contains the desired scopes for the returned access token.
|
|
||||||
Scopes []string
|
|
||||||
// WorkforcePoolUserProject should be set when it is a workforce pool and
|
|
||||||
// not a workload identity pool. The underlying principal must still have
|
|
||||||
// serviceusage.services.use IAM permission to use the project for
|
|
||||||
// billing/quota. Optional.
|
|
||||||
WorkforcePoolUserProject string
|
|
||||||
// UniverseDomain is the default service domain for a given Cloud universe.
|
|
||||||
// This value will be used in the default STS token URL. The default value
|
|
||||||
// is "googleapis.com". It will not be used if TokenURL is set. Optional.
|
|
||||||
UniverseDomain string
|
|
||||||
// SubjectTokenProvider is an optional token provider for OIDC/SAML
|
|
||||||
// credentials. One of SubjectTokenProvider, AWSSecurityCredentialProvider
|
|
||||||
// or CredentialSource must be provided. Optional.
|
|
||||||
SubjectTokenProvider SubjectTokenProvider
|
|
||||||
// AwsSecurityCredentialsProvider is an AWS Security Credential provider
|
|
||||||
// for AWS credentials. One of SubjectTokenProvider,
|
|
||||||
// AWSSecurityCredentialProvider or CredentialSource must be provided. Optional.
|
|
||||||
AwsSecurityCredentialsProvider AwsSecurityCredentialsProvider
|
|
||||||
// Client for token request.
|
|
||||||
Client *http.Client
|
|
||||||
// IsDefaultClient marks whether the client passed in is a default client that can be overriden.
|
|
||||||
// This is important for X509 credentials which should create a new client if the default was used
|
|
||||||
// but should respect a client explicitly passed in by the user.
|
|
||||||
IsDefaultClient bool
|
|
||||||
// Logger is used for debug logging. If provided, logging will be enabled
|
|
||||||
// at the loggers configured level. By default logging is disabled unless
|
|
||||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
|
||||||
// logger will be used. Optional.
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubjectTokenProvider can be used to supply a subject token to exchange for a
|
|
||||||
// GCP access token.
|
|
||||||
type SubjectTokenProvider interface {
|
|
||||||
// SubjectToken should return a valid subject token or an error.
|
|
||||||
// The external account token provider does not cache the returned subject
|
|
||||||
// token, so caching logic should be implemented in the provider to prevent
|
|
||||||
// multiple requests for the same subject token.
|
|
||||||
SubjectToken(ctx context.Context, opts *RequestOptions) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestOptions contains information about the requested subject token or AWS
|
|
||||||
// security credentials from the Google external account credential.
|
|
||||||
type RequestOptions struct {
|
|
||||||
// Audience is the requested audience for the external account credential.
|
|
||||||
Audience string
|
|
||||||
// Subject token type is the requested subject token type for the external
|
|
||||||
// account credential. Expected values include:
|
|
||||||
// “urn:ietf:params:oauth:token-type:jwt”
|
|
||||||
// “urn:ietf:params:oauth:token-type:id-token”
|
|
||||||
// “urn:ietf:params:oauth:token-type:saml2”
|
|
||||||
// “urn:ietf:params:aws:token-type:aws4_request”
|
|
||||||
SubjectTokenType string
|
|
||||||
}
|
|
||||||
|
|
||||||
// AwsSecurityCredentialsProvider can be used to supply AwsSecurityCredentials
|
|
||||||
// and an AWS Region to exchange for a GCP access token.
|
|
||||||
type AwsSecurityCredentialsProvider interface {
|
|
||||||
// AwsRegion should return the AWS region or an error.
|
|
||||||
AwsRegion(ctx context.Context, opts *RequestOptions) (string, error)
|
|
||||||
// GetAwsSecurityCredentials should return a valid set of
|
|
||||||
// AwsSecurityCredentials or an error. The external account token provider
|
|
||||||
// does not cache the returned security credentials, so caching logic should
|
|
||||||
// be implemented in the provider to prevent multiple requests for the
|
|
||||||
// same security credentials.
|
|
||||||
AwsSecurityCredentials(ctx context.Context, opts *RequestOptions) (*AwsSecurityCredentials, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AwsSecurityCredentials models AWS security credentials.
|
|
||||||
type AwsSecurityCredentials struct {
|
|
||||||
// AccessKeyId is the AWS Access Key ID - Required.
|
|
||||||
AccessKeyID string `json:"AccessKeyID"`
|
|
||||||
// SecretAccessKey is the AWS Secret Access Key - Required.
|
|
||||||
SecretAccessKey string `json:"SecretAccessKey"`
|
|
||||||
// SessionToken is the AWS Session token. This should be provided for
|
|
||||||
// temporary AWS security credentials - Optional.
|
|
||||||
SessionToken string `json:"Token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options) validate() error {
|
|
||||||
if o.Audience == "" {
|
|
||||||
return fmt.Errorf("externalaccount: Audience must be set")
|
|
||||||
}
|
|
||||||
if o.SubjectTokenType == "" {
|
|
||||||
return fmt.Errorf("externalaccount: Subject token type must be set")
|
|
||||||
}
|
|
||||||
if o.WorkforcePoolUserProject != "" {
|
|
||||||
if valid := validWorkforceAudiencePattern.MatchString(o.Audience); !valid {
|
|
||||||
return fmt.Errorf("externalaccount: workforce_pool_user_project should not be set for non-workforce pool credentials")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count := 0
|
|
||||||
if o.CredentialSource != nil {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
if o.SubjectTokenProvider != nil {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
if o.AwsSecurityCredentialsProvider != nil {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
if count == 0 {
|
|
||||||
return fmt.Errorf("externalaccount: one of CredentialSource, SubjectTokenProvider, or AwsSecurityCredentialsProvider must be set")
|
|
||||||
}
|
|
||||||
if count > 1 {
|
|
||||||
return fmt.Errorf("externalaccount: only one of CredentialSource, SubjectTokenProvider, or AwsSecurityCredentialsProvider must be set")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// client returns the http client that should be used for the token exchange. If a non-default client
|
|
||||||
// is provided, then the client configured in the options will always be returned. If a default client
|
|
||||||
// is provided and the options are configured for X509 credentials, a new client will be created.
|
|
||||||
func (o *Options) client() (*http.Client, error) {
|
|
||||||
// If a client was provided and no override certificate config location was provided, use the provided client.
|
|
||||||
if o.CredentialSource == nil || o.CredentialSource.Certificate == nil || (!o.IsDefaultClient && o.CredentialSource.Certificate.CertificateConfigLocation == "") {
|
|
||||||
return o.Client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a new client should be created, validate and use the certificate source to create a new mTLS client.
|
|
||||||
cert := o.CredentialSource.Certificate
|
|
||||||
if !cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation == "" {
|
|
||||||
return nil, errors.New("credentials: \"certificate\" object must either specify a certificate_config_location or use_default_certificate_config should be true")
|
|
||||||
}
|
|
||||||
if cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation != "" {
|
|
||||||
return nil, errors.New("credentials: \"certificate\" object cannot specify both a certificate_config_location and use_default_certificate_config=true")
|
|
||||||
}
|
|
||||||
return createX509Client(cert.CertificateConfigLocation)
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveTokenURL sets the default STS token endpoint with the configured
|
|
||||||
// universe domain.
|
|
||||||
func (o *Options) resolveTokenURL() {
|
|
||||||
if o.TokenURL != "" {
|
|
||||||
return
|
|
||||||
} else if o.UniverseDomain != "" {
|
|
||||||
o.TokenURL = strings.Replace(defaultTokenURL, universeDomainPlaceholder, o.UniverseDomain, 1)
|
|
||||||
} else {
|
|
||||||
o.TokenURL = strings.Replace(defaultTokenURL, universeDomainPlaceholder, defaultUniverseDomain, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider]
|
|
||||||
// configured with the provided options.
|
|
||||||
func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
|
||||||
if err := opts.validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
opts.resolveTokenURL()
|
|
||||||
logger := internallog.New(opts.Logger)
|
|
||||||
stp, err := newSubjectTokenProvider(opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := opts.client()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tp := &tokenProvider{
|
|
||||||
client: client,
|
|
||||||
opts: opts,
|
|
||||||
stp: stp,
|
|
||||||
logger: logger,
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.ServiceAccountImpersonationURL == "" {
|
|
||||||
return auth.NewCachedTokenProvider(tp, nil), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
scopes := make([]string, len(opts.Scopes))
|
|
||||||
copy(scopes, opts.Scopes)
|
|
||||||
// needed for impersonation
|
|
||||||
tp.opts.Scopes = []string{"https://www.googleapis.com/auth/cloud-platform"}
|
|
||||||
imp, err := impersonate.NewTokenProvider(&impersonate.Options{
|
|
||||||
Client: client,
|
|
||||||
URL: opts.ServiceAccountImpersonationURL,
|
|
||||||
Scopes: scopes,
|
|
||||||
Tp: auth.NewCachedTokenProvider(tp, nil),
|
|
||||||
TokenLifetimeSeconds: opts.ServiceAccountImpersonationLifetimeSeconds,
|
|
||||||
Logger: logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return auth.NewCachedTokenProvider(imp, nil), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type subjectTokenProvider interface {
|
|
||||||
subjectToken(ctx context.Context) (string, error)
|
|
||||||
providerType() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// tokenProvider is the provider that handles external credentials. It is used to retrieve Tokens.
|
|
||||||
type tokenProvider struct {
|
|
||||||
client *http.Client
|
|
||||||
logger *slog.Logger
|
|
||||||
opts *Options
|
|
||||||
stp subjectTokenProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
|
|
||||||
subjectToken, err := tp.stp.subjectToken(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stsRequest := &stsexchange.TokenRequest{
|
|
||||||
GrantType: stsexchange.GrantType,
|
|
||||||
Audience: tp.opts.Audience,
|
|
||||||
Scope: tp.opts.Scopes,
|
|
||||||
RequestedTokenType: stsexchange.TokenType,
|
|
||||||
SubjectToken: subjectToken,
|
|
||||||
SubjectTokenType: tp.opts.SubjectTokenType,
|
|
||||||
}
|
|
||||||
header := make(http.Header)
|
|
||||||
header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
header.Add("x-goog-api-client", getGoogHeaderValue(tp.opts, tp.stp))
|
|
||||||
clientAuth := stsexchange.ClientAuthentication{
|
|
||||||
AuthStyle: auth.StyleInHeader,
|
|
||||||
ClientID: tp.opts.ClientID,
|
|
||||||
ClientSecret: tp.opts.ClientSecret,
|
|
||||||
}
|
|
||||||
var options map[string]interface{}
|
|
||||||
// Do not pass workforce_pool_user_project when client authentication is used.
|
|
||||||
// The client ID is sufficient for determining the user project.
|
|
||||||
if tp.opts.WorkforcePoolUserProject != "" && tp.opts.ClientID == "" {
|
|
||||||
options = map[string]interface{}{
|
|
||||||
"userProject": tp.opts.WorkforcePoolUserProject,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stsResp, err := stsexchange.ExchangeToken(ctx, &stsexchange.Options{
|
|
||||||
Client: tp.client,
|
|
||||||
Endpoint: tp.opts.TokenURL,
|
|
||||||
Request: stsRequest,
|
|
||||||
Authentication: clientAuth,
|
|
||||||
Headers: header,
|
|
||||||
ExtraOpts: options,
|
|
||||||
Logger: tp.logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tok := &auth.Token{
|
|
||||||
Value: stsResp.AccessToken,
|
|
||||||
Type: stsResp.TokenType,
|
|
||||||
}
|
|
||||||
// The RFC8693 doesn't define the explicit 0 of "expires_in" field behavior.
|
|
||||||
if stsResp.ExpiresIn <= 0 {
|
|
||||||
return nil, fmt.Errorf("credentials: got invalid expiry from security token service")
|
|
||||||
}
|
|
||||||
tok.Expiry = Now().Add(time.Duration(stsResp.ExpiresIn) * time.Second)
|
|
||||||
return tok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newSubjectTokenProvider determines the type of credsfile.CredentialSource needed to create a
|
|
||||||
// subjectTokenProvider
|
|
||||||
func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
|
|
||||||
logger := internallog.New(o.Logger)
|
|
||||||
reqOpts := &RequestOptions{Audience: o.Audience, SubjectTokenType: o.SubjectTokenType}
|
|
||||||
if o.AwsSecurityCredentialsProvider != nil {
|
|
||||||
return &awsSubjectProvider{
|
|
||||||
securityCredentialsProvider: o.AwsSecurityCredentialsProvider,
|
|
||||||
TargetResource: o.Audience,
|
|
||||||
reqOpts: reqOpts,
|
|
||||||
logger: logger,
|
|
||||||
}, nil
|
|
||||||
} else if o.SubjectTokenProvider != nil {
|
|
||||||
return &programmaticProvider{stp: o.SubjectTokenProvider, opts: reqOpts}, nil
|
|
||||||
} else if len(o.CredentialSource.EnvironmentID) > 3 && o.CredentialSource.EnvironmentID[:3] == "aws" {
|
|
||||||
if awsVersion, err := strconv.Atoi(o.CredentialSource.EnvironmentID[3:]); err == nil {
|
|
||||||
if awsVersion != 1 {
|
|
||||||
return nil, fmt.Errorf("credentials: aws version '%d' is not supported in the current build", awsVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
awsProvider := &awsSubjectProvider{
|
|
||||||
EnvironmentID: o.CredentialSource.EnvironmentID,
|
|
||||||
RegionURL: o.CredentialSource.RegionURL,
|
|
||||||
RegionalCredVerificationURL: o.CredentialSource.RegionalCredVerificationURL,
|
|
||||||
CredVerificationURL: o.CredentialSource.URL,
|
|
||||||
TargetResource: o.Audience,
|
|
||||||
Client: o.Client,
|
|
||||||
logger: logger,
|
|
||||||
}
|
|
||||||
if o.CredentialSource.IMDSv2SessionTokenURL != "" {
|
|
||||||
awsProvider.IMDSv2SessionTokenURL = o.CredentialSource.IMDSv2SessionTokenURL
|
|
||||||
}
|
|
||||||
|
|
||||||
return awsProvider, nil
|
|
||||||
}
|
|
||||||
} else if o.CredentialSource.File != "" {
|
|
||||||
return &fileSubjectProvider{File: o.CredentialSource.File, Format: o.CredentialSource.Format}, nil
|
|
||||||
} else if o.CredentialSource.URL != "" {
|
|
||||||
return &urlSubjectProvider{
|
|
||||||
URL: o.CredentialSource.URL,
|
|
||||||
Headers: o.CredentialSource.Headers,
|
|
||||||
Format: o.CredentialSource.Format,
|
|
||||||
Client: o.Client,
|
|
||||||
Logger: logger,
|
|
||||||
}, nil
|
|
||||||
} else if o.CredentialSource.Executable != nil {
|
|
||||||
ec := o.CredentialSource.Executable
|
|
||||||
if ec.Command == "" {
|
|
||||||
return nil, errors.New("credentials: missing `command` field — executable command must be provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
execProvider := &executableSubjectProvider{}
|
|
||||||
execProvider.Command = ec.Command
|
|
||||||
if ec.TimeoutMillis == 0 {
|
|
||||||
execProvider.Timeout = executableDefaultTimeout
|
|
||||||
} else {
|
|
||||||
execProvider.Timeout = time.Duration(ec.TimeoutMillis) * time.Millisecond
|
|
||||||
if execProvider.Timeout < timeoutMinimum || execProvider.Timeout > timeoutMaximum {
|
|
||||||
return nil, fmt.Errorf("credentials: invalid `timeout_millis` field — executable timeout must be between %v and %v seconds", timeoutMinimum.Seconds(), timeoutMaximum.Seconds())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
execProvider.OutputFile = ec.OutputFile
|
|
||||||
execProvider.client = o.Client
|
|
||||||
execProvider.opts = o
|
|
||||||
execProvider.env = runtimeEnvironment{}
|
|
||||||
return execProvider, nil
|
|
||||||
} else if o.CredentialSource.Certificate != nil {
|
|
||||||
cert := o.CredentialSource.Certificate
|
|
||||||
if !cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation == "" {
|
|
||||||
return nil, errors.New("credentials: \"certificate\" object must either specify a certificate_config_location or use_default_certificate_config should be true")
|
|
||||||
}
|
|
||||||
if cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation != "" {
|
|
||||||
return nil, errors.New("credentials: \"certificate\" object cannot specify both a certificate_config_location and use_default_certificate_config=true")
|
|
||||||
}
|
|
||||||
return &x509Provider{}, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("credentials: unable to parse credential source")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGoogHeaderValue(conf *Options, p subjectTokenProvider) string {
|
|
||||||
return fmt.Sprintf("gl-go/%s auth/%s google-byoid-sdk source/%s sa-impersonation/%t config-lifetime/%t",
|
|
||||||
goVersion(),
|
|
||||||
"unknown",
|
|
||||||
p.providerType(),
|
|
||||||
conf.ServiceAccountImpersonationURL != "",
|
|
||||||
conf.ServiceAccountImpersonationLifetimeSeconds != 0)
|
|
||||||
}
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/credsfile"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
fileProviderType = "file"
|
|
||||||
)
|
|
||||||
|
|
||||||
type fileSubjectProvider struct {
|
|
||||||
File string
|
|
||||||
Format *credsfile.Format
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *fileSubjectProvider) subjectToken(context.Context) (string, error) {
|
|
||||||
tokenFile, err := os.Open(sp.File)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("credentials: failed to open credential file %q: %w", sp.File, err)
|
|
||||||
}
|
|
||||||
defer tokenFile.Close()
|
|
||||||
tokenBytes, err := internal.ReadAll(tokenFile)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("credentials: failed to read credential file: %w", err)
|
|
||||||
}
|
|
||||||
tokenBytes = bytes.TrimSpace(tokenBytes)
|
|
||||||
|
|
||||||
if sp.Format == nil {
|
|
||||||
return string(tokenBytes), nil
|
|
||||||
}
|
|
||||||
switch sp.Format.Type {
|
|
||||||
case fileTypeJSON:
|
|
||||||
jsonData := make(map[string]interface{})
|
|
||||||
err = json.Unmarshal(tokenBytes, &jsonData)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("credentials: failed to unmarshal subject token file: %w", err)
|
|
||||||
}
|
|
||||||
val, ok := jsonData[sp.Format.SubjectTokenFieldName]
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("credentials: provided subject_token_field_name not found in credentials")
|
|
||||||
}
|
|
||||||
token, ok := val.(string)
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("credentials: improperly formatted subject token")
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
case fileTypeText:
|
|
||||||
return string(tokenBytes), nil
|
|
||||||
default:
|
|
||||||
return "", errors.New("credentials: invalid credential_source file format type: " + sp.Format.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *fileSubjectProvider) providerType() string {
|
|
||||||
return fileProviderType
|
|
||||||
}
|
|
||||||
74
src/server/vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/info.go
generated
vendored
74
src/server/vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/info.go
generated
vendored
@ -1,74 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// version is a package internal global variable for testing purposes.
|
|
||||||
version = runtime.Version
|
|
||||||
)
|
|
||||||
|
|
||||||
// versionUnknown is only used when the runtime version cannot be determined.
|
|
||||||
const versionUnknown = "UNKNOWN"
|
|
||||||
|
|
||||||
// goVersion returns a Go runtime version derived from the runtime environment
|
|
||||||
// that is modified to be suitable for reporting in a header, meaning it has no
|
|
||||||
// whitespace. If it is unable to determine the Go runtime version, it returns
|
|
||||||
// versionUnknown.
|
|
||||||
func goVersion() string {
|
|
||||||
const develPrefix = "devel +"
|
|
||||||
|
|
||||||
s := version()
|
|
||||||
if strings.HasPrefix(s, develPrefix) {
|
|
||||||
s = s[len(develPrefix):]
|
|
||||||
if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
|
|
||||||
s = s[:p]
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
} else if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
|
|
||||||
s = s[:p]
|
|
||||||
}
|
|
||||||
|
|
||||||
notSemverRune := func(r rune) bool {
|
|
||||||
return !strings.ContainsRune("0123456789.", r)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(s, "go1") {
|
|
||||||
s = s[2:]
|
|
||||||
var prerelease string
|
|
||||||
if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
|
|
||||||
s, prerelease = s[:p], s[p:]
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(s, ".") {
|
|
||||||
s += "0"
|
|
||||||
} else if strings.Count(s, ".") < 2 {
|
|
||||||
s += ".0"
|
|
||||||
}
|
|
||||||
if prerelease != "" {
|
|
||||||
// Some release candidates already have a dash in them.
|
|
||||||
if !strings.HasPrefix(prerelease, "-") {
|
|
||||||
prerelease = "-" + prerelease
|
|
||||||
}
|
|
||||||
s += prerelease
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return versionUnknown
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
// Copyright 2024 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type programmaticProvider struct {
|
|
||||||
opts *RequestOptions
|
|
||||||
stp SubjectTokenProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *programmaticProvider) providerType() string {
|
|
||||||
return programmaticProviderType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *programmaticProvider) subjectToken(ctx context.Context) (string, error) {
|
|
||||||
return pp.stp.SubjectToken(ctx, pp.opts)
|
|
||||||
}
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/credsfile"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
fileTypeText = "text"
|
|
||||||
fileTypeJSON = "json"
|
|
||||||
urlProviderType = "url"
|
|
||||||
programmaticProviderType = "programmatic"
|
|
||||||
x509ProviderType = "x509"
|
|
||||||
)
|
|
||||||
|
|
||||||
type urlSubjectProvider struct {
|
|
||||||
URL string
|
|
||||||
Headers map[string]string
|
|
||||||
Format *credsfile.Format
|
|
||||||
Client *http.Client
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *urlSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", sp.URL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("credentials: HTTP request for URL-sourced credential failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, val := range sp.Headers {
|
|
||||||
req.Header.Add(key, val)
|
|
||||||
}
|
|
||||||
sp.Logger.DebugContext(ctx, "url subject token request", "request", internallog.HTTPRequest(req, nil))
|
|
||||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("credentials: invalid response when retrieving subject token: %w", err)
|
|
||||||
}
|
|
||||||
sp.Logger.DebugContext(ctx, "url subject token response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
|
||||||
return "", fmt.Errorf("credentials: status code %d: %s", c, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
if sp.Format == nil {
|
|
||||||
return string(body), nil
|
|
||||||
}
|
|
||||||
switch sp.Format.Type {
|
|
||||||
case "json":
|
|
||||||
jsonData := make(map[string]interface{})
|
|
||||||
err = json.Unmarshal(body, &jsonData)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("credentials: failed to unmarshal subject token file: %w", err)
|
|
||||||
}
|
|
||||||
val, ok := jsonData[sp.Format.SubjectTokenFieldName]
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("credentials: provided subject_token_field_name not found in credentials")
|
|
||||||
}
|
|
||||||
token, ok := val.(string)
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("credentials: improperly formatted subject token")
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
case fileTypeText:
|
|
||||||
return string(body), nil
|
|
||||||
default:
|
|
||||||
return "", errors.New("credentials: invalid credential_source file format type: " + sp.Format.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *urlSubjectProvider) providerType() string {
|
|
||||||
return urlProviderType
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
// Copyright 2024 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal/transport/cert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// x509Provider implements the subjectTokenProvider type for
|
|
||||||
// x509 workload identity credentials. Because x509 credentials
|
|
||||||
// rely on an mTLS connection to represent the 3rd party identity
|
|
||||||
// rather than a subject token, this provider will always return
|
|
||||||
// an empty string when a subject token is requested by the external account
|
|
||||||
// token provider.
|
|
||||||
type x509Provider struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (xp *x509Provider) providerType() string {
|
|
||||||
return x509ProviderType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (xp *x509Provider) subjectToken(ctx context.Context) (string, error) {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createX509Client creates a new client that is configured with mTLS, using the
|
|
||||||
// certificate configuration specified in the credential source.
|
|
||||||
func createX509Client(certificateConfigLocation string) (*http.Client, error) {
|
|
||||||
certProvider, err := cert.NewWorkloadX509CertProvider(certificateConfigLocation)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
trans := http.DefaultTransport.(*http.Transport).Clone()
|
|
||||||
|
|
||||||
trans.TLSClientConfig = &tls.Config{
|
|
||||||
GetClientCertificate: certProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a client with default settings plus the X509 workload cert and key.
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: trans,
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
@ -1,115 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package externalaccountuser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/credentials/internal/stsexchange"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options stores the configuration for fetching tokens with external authorized
|
|
||||||
// user credentials.
|
|
||||||
type Options struct {
|
|
||||||
// Audience is the Secure Token Service (STS) audience which contains the
|
|
||||||
// resource name for the workforce pool and the provider identifier in that
|
|
||||||
// pool.
|
|
||||||
Audience string
|
|
||||||
// RefreshToken is the OAuth 2.0 refresh token.
|
|
||||||
RefreshToken string
|
|
||||||
// TokenURL is the STS token exchange endpoint for refresh.
|
|
||||||
TokenURL string
|
|
||||||
// TokenInfoURL is the STS endpoint URL for token introspection. Optional.
|
|
||||||
TokenInfoURL string
|
|
||||||
// ClientID is only required in conjunction with ClientSecret, as described
|
|
||||||
// below.
|
|
||||||
ClientID string
|
|
||||||
// ClientSecret is currently only required if token_info endpoint also needs
|
|
||||||
// to be called with the generated a cloud access token. When provided, STS
|
|
||||||
// will be called with additional basic authentication using client_id as
|
|
||||||
// username and client_secret as password.
|
|
||||||
ClientSecret string
|
|
||||||
// Scopes contains the desired scopes for the returned access token.
|
|
||||||
Scopes []string
|
|
||||||
|
|
||||||
// Client for token request.
|
|
||||||
Client *http.Client
|
|
||||||
// Logger for logging.
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Options) validate() bool {
|
|
||||||
return c.ClientID != "" && c.ClientSecret != "" && c.RefreshToken != "" && c.TokenURL != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider]
|
|
||||||
// configured with the provided options.
|
|
||||||
func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
|
||||||
if !opts.validate() {
|
|
||||||
return nil, errors.New("credentials: invalid external_account_authorized_user configuration")
|
|
||||||
}
|
|
||||||
|
|
||||||
tp := &tokenProvider{
|
|
||||||
o: opts,
|
|
||||||
}
|
|
||||||
return auth.NewCachedTokenProvider(tp, nil), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type tokenProvider struct {
|
|
||||||
o *Options
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
|
|
||||||
opts := tp.o
|
|
||||||
|
|
||||||
clientAuth := stsexchange.ClientAuthentication{
|
|
||||||
AuthStyle: auth.StyleInHeader,
|
|
||||||
ClientID: opts.ClientID,
|
|
||||||
ClientSecret: opts.ClientSecret,
|
|
||||||
}
|
|
||||||
headers := make(http.Header)
|
|
||||||
headers.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
stsResponse, err := stsexchange.RefreshAccessToken(ctx, &stsexchange.Options{
|
|
||||||
Client: opts.Client,
|
|
||||||
Endpoint: opts.TokenURL,
|
|
||||||
RefreshToken: opts.RefreshToken,
|
|
||||||
Authentication: clientAuth,
|
|
||||||
Headers: headers,
|
|
||||||
Logger: internallog.New(tp.o.Logger),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if stsResponse.ExpiresIn < 0 {
|
|
||||||
return nil, errors.New("credentials: invalid expiry from security token service")
|
|
||||||
}
|
|
||||||
|
|
||||||
// guarded by the wrapping with CachedTokenProvider
|
|
||||||
if stsResponse.RefreshToken != "" {
|
|
||||||
opts.RefreshToken = stsResponse.RefreshToken
|
|
||||||
}
|
|
||||||
return &auth.Token{
|
|
||||||
Value: stsResponse.AccessToken,
|
|
||||||
Expiry: time.Now().UTC().Add(time.Duration(stsResponse.ExpiresIn) * time.Second),
|
|
||||||
Type: internal.TokenTypeBearer,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
191
src/server/vendor/cloud.google.com/go/auth/credentials/internal/gdch/gdch.go
generated
vendored
191
src/server/vendor/cloud.google.com/go/auth/credentials/internal/gdch/gdch.go
generated
vendored
@ -1,191 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package gdch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto"
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/credsfile"
|
|
||||||
"cloud.google.com/go/auth/internal/jwt"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// GrantType is the grant type for the token request.
|
|
||||||
GrantType = "urn:ietf:params:oauth:token-type:token-exchange"
|
|
||||||
requestTokenType = "urn:ietf:params:oauth:token-type:access_token"
|
|
||||||
subjectTokenType = "urn:k8s:params:oauth:token-type:serviceaccount"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
gdchSupportFormatVersions map[string]bool = map[string]bool{
|
|
||||||
"1": true,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options for [NewTokenProvider].
|
|
||||||
type Options struct {
|
|
||||||
STSAudience string
|
|
||||||
Client *http.Client
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider] from a
|
|
||||||
// GDCH cred file.
|
|
||||||
func NewTokenProvider(f *credsfile.GDCHServiceAccountFile, o *Options) (auth.TokenProvider, error) {
|
|
||||||
if !gdchSupportFormatVersions[f.FormatVersion] {
|
|
||||||
return nil, fmt.Errorf("credentials: unsupported gdch_service_account format %q", f.FormatVersion)
|
|
||||||
}
|
|
||||||
if o.STSAudience == "" {
|
|
||||||
return nil, errors.New("credentials: STSAudience must be set for the GDCH auth flows")
|
|
||||||
}
|
|
||||||
signer, err := internal.ParseKey([]byte(f.PrivateKey))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
certPool, err := loadCertPool(f.CertPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tp := gdchProvider{
|
|
||||||
serviceIdentity: fmt.Sprintf("system:serviceaccount:%s:%s", f.Project, f.Name),
|
|
||||||
tokenURL: f.TokenURL,
|
|
||||||
aud: o.STSAudience,
|
|
||||||
signer: signer,
|
|
||||||
pkID: f.PrivateKeyID,
|
|
||||||
certPool: certPool,
|
|
||||||
client: o.Client,
|
|
||||||
logger: internallog.New(o.Logger),
|
|
||||||
}
|
|
||||||
return tp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadCertPool(path string) (*x509.CertPool, error) {
|
|
||||||
pool := x509.NewCertPool()
|
|
||||||
pem, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: failed to read certificate: %w", err)
|
|
||||||
}
|
|
||||||
pool.AppendCertsFromPEM(pem)
|
|
||||||
return pool, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type gdchProvider struct {
|
|
||||||
serviceIdentity string
|
|
||||||
tokenURL string
|
|
||||||
aud string
|
|
||||||
signer crypto.Signer
|
|
||||||
pkID string
|
|
||||||
certPool *x509.CertPool
|
|
||||||
|
|
||||||
client *http.Client
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
|
|
||||||
addCertToTransport(g.client, g.certPool)
|
|
||||||
iat := time.Now()
|
|
||||||
exp := iat.Add(time.Hour)
|
|
||||||
claims := jwt.Claims{
|
|
||||||
Iss: g.serviceIdentity,
|
|
||||||
Sub: g.serviceIdentity,
|
|
||||||
Aud: g.tokenURL,
|
|
||||||
Iat: iat.Unix(),
|
|
||||||
Exp: exp.Unix(),
|
|
||||||
}
|
|
||||||
h := jwt.Header{
|
|
||||||
Algorithm: jwt.HeaderAlgRSA256,
|
|
||||||
Type: jwt.HeaderType,
|
|
||||||
KeyID: string(g.pkID),
|
|
||||||
}
|
|
||||||
payload, err := jwt.EncodeJWS(&h, &claims, g.signer)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
v := url.Values{}
|
|
||||||
v.Set("grant_type", GrantType)
|
|
||||||
v.Set("audience", g.aud)
|
|
||||||
v.Set("requested_token_type", requestTokenType)
|
|
||||||
v.Set("subject_token", payload)
|
|
||||||
v.Set("subject_token_type", subjectTokenType)
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", g.tokenURL, strings.NewReader(v.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
g.logger.DebugContext(ctx, "gdch token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
|
||||||
resp, body, err := internal.DoRequest(g.client, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
|
||||||
}
|
|
||||||
g.logger.DebugContext(ctx, "gdch token response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
|
|
||||||
return nil, &auth.Error{
|
|
||||||
Response: resp,
|
|
||||||
Body: body,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenRes struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
ExpiresIn int64 `json:"expires_in"` // relative seconds from now
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(body, &tokenRes); err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
|
||||||
}
|
|
||||||
token := &auth.Token{
|
|
||||||
Value: tokenRes.AccessToken,
|
|
||||||
Type: tokenRes.TokenType,
|
|
||||||
}
|
|
||||||
raw := make(map[string]interface{})
|
|
||||||
json.Unmarshal(body, &raw) // no error checks for optional fields
|
|
||||||
token.Metadata = raw
|
|
||||||
|
|
||||||
if secs := tokenRes.ExpiresIn; secs > 0 {
|
|
||||||
token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// addCertToTransport makes a best effort attempt at adding in the cert info to
|
|
||||||
// the client. It tries to keep all configured transport settings if the
|
|
||||||
// underlying transport is an http.Transport. Or else it overwrites the
|
|
||||||
// transport with defaults adding in the certs.
|
|
||||||
func addCertToTransport(hc *http.Client, certPool *x509.CertPool) {
|
|
||||||
trans, ok := hc.Transport.(*http.Transport)
|
|
||||||
if !ok {
|
|
||||||
trans = http.DefaultTransport.(*http.Transport).Clone()
|
|
||||||
}
|
|
||||||
trans.TLSClientConfig = &tls.Config{
|
|
||||||
RootCAs: certPool,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
105
src/server/vendor/cloud.google.com/go/auth/credentials/internal/impersonate/idtoken.go
generated
vendored
105
src/server/vendor/cloud.google.com/go/auth/credentials/internal/impersonate/idtoken.go
generated
vendored
@ -1,105 +0,0 @@
|
|||||||
// Copyright 2025 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package impersonate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
|
|
||||||
iamCredentialsUniverseDomainEndpoint = "https://iamcredentials.UNIVERSE_DOMAIN"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IDTokenIAMOptions provides configuration for [IDTokenIAMOptions.Token].
|
|
||||||
type IDTokenIAMOptions struct {
|
|
||||||
// Client is required.
|
|
||||||
Client *http.Client
|
|
||||||
// Logger is required.
|
|
||||||
Logger *slog.Logger
|
|
||||||
UniverseDomain auth.CredentialsPropertyProvider
|
|
||||||
ServiceAccountEmail string
|
|
||||||
GenerateIDTokenRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateIDTokenRequest holds the request to the IAM generateIdToken RPC.
|
|
||||||
type GenerateIDTokenRequest struct {
|
|
||||||
Audience string `json:"audience"`
|
|
||||||
IncludeEmail bool `json:"includeEmail"`
|
|
||||||
// Delegates are the ordered, fully-qualified resource name for service
|
|
||||||
// accounts in a delegation chain. Each service account must be granted
|
|
||||||
// roles/iam.serviceAccountTokenCreator on the next service account in the
|
|
||||||
// chain. The delegates must have the following format:
|
|
||||||
// projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}. The - wildcard
|
|
||||||
// character is required; replacing it with a project ID is invalid.
|
|
||||||
// Optional.
|
|
||||||
Delegates []string `json:"delegates,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateIDTokenResponse holds the response from the IAM generateIdToken RPC.
|
|
||||||
type GenerateIDTokenResponse struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token call IAM generateIdToken with the configuration provided in [IDTokenIAMOptions].
|
|
||||||
func (o IDTokenIAMOptions) Token(ctx context.Context) (*auth.Token, error) {
|
|
||||||
universeDomain, err := o.UniverseDomain.GetProperty(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
endpoint := strings.Replace(iamCredentialsUniverseDomainEndpoint, universeDomainPlaceholder, universeDomain, 1)
|
|
||||||
url := fmt.Sprintf("%s/v1/%s:generateIdToken", endpoint, internal.FormatIAMServiceAccountResource(o.ServiceAccountEmail))
|
|
||||||
|
|
||||||
bodyBytes, err := json.Marshal(o.GenerateIDTokenRequest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("impersonate: unable to marshal request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(bodyBytes))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("impersonate: unable to create request: %w", err)
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
o.Logger.DebugContext(ctx, "impersonated idtoken request", "request", internallog.HTTPRequest(req, bodyBytes))
|
|
||||||
resp, body, err := internal.DoRequest(o.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("impersonate: unable to generate ID token: %w", err)
|
|
||||||
}
|
|
||||||
o.Logger.DebugContext(ctx, "impersonated idtoken response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if c := resp.StatusCode; c < 200 || c > 299 {
|
|
||||||
return nil, fmt.Errorf("impersonate: status code %d: %s", c, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenResp GenerateIDTokenResponse
|
|
||||||
if err := json.Unmarshal(body, &tokenResp); err != nil {
|
|
||||||
return nil, fmt.Errorf("impersonate: unable to parse response: %w", err)
|
|
||||||
}
|
|
||||||
return &auth.Token{
|
|
||||||
Value: tokenResp.Token,
|
|
||||||
// Generated ID tokens are good for one hour.
|
|
||||||
Expiry: time.Now().Add(1 * time.Hour),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
156
src/server/vendor/cloud.google.com/go/auth/credentials/internal/impersonate/impersonate.go
generated
vendored
156
src/server/vendor/cloud.google.com/go/auth/credentials/internal/impersonate/impersonate.go
generated
vendored
@ -1,156 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package impersonate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultTokenLifetime = "3600s"
|
|
||||||
authHeaderKey = "Authorization"
|
|
||||||
)
|
|
||||||
|
|
||||||
// generateAccesstokenReq is used for service account impersonation
|
|
||||||
type generateAccessTokenReq struct {
|
|
||||||
Delegates []string `json:"delegates,omitempty"`
|
|
||||||
Lifetime string `json:"lifetime,omitempty"`
|
|
||||||
Scope []string `json:"scope,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type impersonateTokenResponse struct {
|
|
||||||
AccessToken string `json:"accessToken"`
|
|
||||||
ExpireTime string `json:"expireTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTokenProvider uses a source credential, stored in Ts, to request an access token to the provided URL.
|
|
||||||
// Scopes can be defined when the access token is requested.
|
|
||||||
func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
|
||||||
if err := opts.validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return opts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options for [NewTokenProvider].
|
|
||||||
type Options struct {
|
|
||||||
// Tp is the source credential used to generate a token on the
|
|
||||||
// impersonated service account. Required.
|
|
||||||
Tp auth.TokenProvider
|
|
||||||
|
|
||||||
// URL is the endpoint to call to generate a token
|
|
||||||
// on behalf of the service account. Required.
|
|
||||||
URL string
|
|
||||||
// Scopes that the impersonated credential should have. Required.
|
|
||||||
Scopes []string
|
|
||||||
// Delegates are the service account email addresses in a delegation chain.
|
|
||||||
// Each service account must be granted roles/iam.serviceAccountTokenCreator
|
|
||||||
// on the next service account in the chain. Optional.
|
|
||||||
Delegates []string
|
|
||||||
// TokenLifetimeSeconds is the number of seconds the impersonation token will
|
|
||||||
// be valid for. Defaults to 1 hour if unset. Optional.
|
|
||||||
TokenLifetimeSeconds int
|
|
||||||
// Client configures the underlying client used to make network requests
|
|
||||||
// when fetching tokens. Required.
|
|
||||||
Client *http.Client
|
|
||||||
// Logger is used for debug logging. If provided, logging will be enabled
|
|
||||||
// at the loggers configured level. By default logging is disabled unless
|
|
||||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
|
||||||
// logger will be used. Optional.
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options) validate() error {
|
|
||||||
if o.Tp == nil {
|
|
||||||
return errors.New("credentials: missing required 'source_credentials' field in impersonated credentials")
|
|
||||||
}
|
|
||||||
if o.URL == "" {
|
|
||||||
return errors.New("credentials: missing required 'service_account_impersonation_url' field in impersonated credentials")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token performs the exchange to get a temporary service account token to allow access to GCP.
|
|
||||||
func (o *Options) Token(ctx context.Context) (*auth.Token, error) {
|
|
||||||
logger := internallog.New(o.Logger)
|
|
||||||
lifetime := defaultTokenLifetime
|
|
||||||
if o.TokenLifetimeSeconds != 0 {
|
|
||||||
lifetime = fmt.Sprintf("%ds", o.TokenLifetimeSeconds)
|
|
||||||
}
|
|
||||||
reqBody := generateAccessTokenReq{
|
|
||||||
Lifetime: lifetime,
|
|
||||||
Scope: o.Scopes,
|
|
||||||
Delegates: o.Delegates,
|
|
||||||
}
|
|
||||||
b, err := json.Marshal(reqBody)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: unable to marshal request: %w", err)
|
|
||||||
}
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", o.URL, bytes.NewReader(b))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: unable to create impersonation request: %w", err)
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
if err := setAuthHeader(ctx, o.Tp, req); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logger.DebugContext(ctx, "impersonated token request", "request", internallog.HTTPRequest(req, b))
|
|
||||||
resp, body, err := internal.DoRequest(o.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: unable to generate access token: %w", err)
|
|
||||||
}
|
|
||||||
logger.DebugContext(ctx, "impersonated token response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
|
||||||
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
var accessTokenResp impersonateTokenResponse
|
|
||||||
if err := json.Unmarshal(body, &accessTokenResp); err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: unable to parse response: %w", err)
|
|
||||||
}
|
|
||||||
expiry, err := time.Parse(time.RFC3339, accessTokenResp.ExpireTime)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: unable to parse expiry: %w", err)
|
|
||||||
}
|
|
||||||
return &auth.Token{
|
|
||||||
Value: accessTokenResp.AccessToken,
|
|
||||||
Expiry: expiry,
|
|
||||||
Type: internal.TokenTypeBearer,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setAuthHeader(ctx context.Context, tp auth.TokenProvider, r *http.Request) error {
|
|
||||||
t, err := tp.Token(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
typ := t.Type
|
|
||||||
if typ == "" {
|
|
||||||
typ = internal.TokenTypeBearer
|
|
||||||
}
|
|
||||||
r.Header.Set(authHeaderKey, typ+" "+t.Value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
167
src/server/vendor/cloud.google.com/go/auth/credentials/internal/stsexchange/sts_exchange.go
generated
vendored
167
src/server/vendor/cloud.google.com/go/auth/credentials/internal/stsexchange/sts_exchange.go
generated
vendored
@ -1,167 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package stsexchange
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// GrantType for a sts exchange.
|
|
||||||
GrantType = "urn:ietf:params:oauth:grant-type:token-exchange"
|
|
||||||
// TokenType for a sts exchange.
|
|
||||||
TokenType = "urn:ietf:params:oauth:token-type:access_token"
|
|
||||||
|
|
||||||
jwtTokenType = "urn:ietf:params:oauth:token-type:jwt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options stores the configuration for making an sts exchange request.
|
|
||||||
type Options struct {
|
|
||||||
Client *http.Client
|
|
||||||
Logger *slog.Logger
|
|
||||||
Endpoint string
|
|
||||||
Request *TokenRequest
|
|
||||||
Authentication ClientAuthentication
|
|
||||||
Headers http.Header
|
|
||||||
// ExtraOpts are optional fields marshalled into the `options` field of the
|
|
||||||
// request body.
|
|
||||||
ExtraOpts map[string]interface{}
|
|
||||||
RefreshToken string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RefreshAccessToken performs the token exchange using a refresh token flow.
|
|
||||||
func RefreshAccessToken(ctx context.Context, opts *Options) (*TokenResponse, error) {
|
|
||||||
data := url.Values{}
|
|
||||||
data.Set("grant_type", "refresh_token")
|
|
||||||
data.Set("refresh_token", opts.RefreshToken)
|
|
||||||
return doRequest(ctx, opts, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExchangeToken performs an oauth2 token exchange with the provided endpoint.
|
|
||||||
func ExchangeToken(ctx context.Context, opts *Options) (*TokenResponse, error) {
|
|
||||||
data := url.Values{}
|
|
||||||
data.Set("audience", opts.Request.Audience)
|
|
||||||
data.Set("grant_type", GrantType)
|
|
||||||
data.Set("requested_token_type", TokenType)
|
|
||||||
data.Set("subject_token_type", opts.Request.SubjectTokenType)
|
|
||||||
data.Set("subject_token", opts.Request.SubjectToken)
|
|
||||||
data.Set("scope", strings.Join(opts.Request.Scope, " "))
|
|
||||||
if opts.ExtraOpts != nil {
|
|
||||||
opts, err := json.Marshal(opts.ExtraOpts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: failed to marshal additional options: %w", err)
|
|
||||||
}
|
|
||||||
data.Set("options", string(opts))
|
|
||||||
}
|
|
||||||
return doRequest(ctx, opts, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func doRequest(ctx context.Context, opts *Options, data url.Values) (*TokenResponse, error) {
|
|
||||||
opts.Authentication.InjectAuthentication(data, opts.Headers)
|
|
||||||
encodedData := data.Encode()
|
|
||||||
logger := internallog.New(opts.Logger)
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", opts.Endpoint, strings.NewReader(encodedData))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: failed to properly build http request: %w", err)
|
|
||||||
|
|
||||||
}
|
|
||||||
for key, list := range opts.Headers {
|
|
||||||
for _, val := range list {
|
|
||||||
req.Header.Add(key, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Length", strconv.Itoa(len(encodedData)))
|
|
||||||
|
|
||||||
logger.DebugContext(ctx, "sts token request", "request", internallog.HTTPRequest(req, []byte(encodedData)))
|
|
||||||
resp, body, err := internal.DoRequest(opts.Client, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: invalid response from Secure Token Server: %w", err)
|
|
||||||
}
|
|
||||||
logger.DebugContext(ctx, "sts token response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
|
|
||||||
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
|
|
||||||
}
|
|
||||||
var stsResp TokenResponse
|
|
||||||
if err := json.Unmarshal(body, &stsResp); err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: failed to unmarshal response body from Secure Token Server: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &stsResp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenRequest contains fields necessary to make an oauth2 token
|
|
||||||
// exchange.
|
|
||||||
type TokenRequest struct {
|
|
||||||
ActingParty struct {
|
|
||||||
ActorToken string
|
|
||||||
ActorTokenType string
|
|
||||||
}
|
|
||||||
GrantType string
|
|
||||||
Resource string
|
|
||||||
Audience string
|
|
||||||
Scope []string
|
|
||||||
RequestedTokenType string
|
|
||||||
SubjectToken string
|
|
||||||
SubjectTokenType string
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenResponse is used to decode the remote server response during
|
|
||||||
// an oauth2 token exchange.
|
|
||||||
type TokenResponse struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
IssuedTokenType string `json:"issued_token_type"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
ExpiresIn int `json:"expires_in"`
|
|
||||||
Scope string `json:"scope"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientAuthentication represents an OAuth client ID and secret and the
|
|
||||||
// mechanism for passing these credentials as stated in rfc6749#2.3.1.
|
|
||||||
type ClientAuthentication struct {
|
|
||||||
AuthStyle auth.Style
|
|
||||||
ClientID string
|
|
||||||
ClientSecret string
|
|
||||||
}
|
|
||||||
|
|
||||||
// InjectAuthentication is used to add authentication to a Secure Token Service
|
|
||||||
// exchange request. It modifies either the passed url.Values or http.Header
|
|
||||||
// depending on the desired authentication format.
|
|
||||||
func (c *ClientAuthentication) InjectAuthentication(values url.Values, headers http.Header) {
|
|
||||||
if c.ClientID == "" || c.ClientSecret == "" || values == nil || headers == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch c.AuthStyle {
|
|
||||||
case auth.StyleInHeader:
|
|
||||||
plainHeader := c.ClientID + ":" + c.ClientSecret
|
|
||||||
headers.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(plainHeader)))
|
|
||||||
default:
|
|
||||||
values.Set("client_id", c.ClientID)
|
|
||||||
values.Set("client_secret", c.ClientSecret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
89
src/server/vendor/cloud.google.com/go/auth/credentials/selfsignedjwt.go
generated
vendored
89
src/server/vendor/cloud.google.com/go/auth/credentials/selfsignedjwt.go
generated
vendored
@ -1,89 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package credentials
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/credsfile"
|
|
||||||
"cloud.google.com/go/auth/internal/jwt"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// for testing
|
|
||||||
now func() time.Time = time.Now
|
|
||||||
)
|
|
||||||
|
|
||||||
// configureSelfSignedJWT uses the private key in the service account to create
|
|
||||||
// a JWT without making a network call.
|
|
||||||
func configureSelfSignedJWT(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
|
||||||
if len(opts.scopes()) == 0 && opts.Audience == "" {
|
|
||||||
return nil, errors.New("credentials: both scopes and audience are empty")
|
|
||||||
}
|
|
||||||
signer, err := internal.ParseKey([]byte(f.PrivateKey))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: could not parse key: %w", err)
|
|
||||||
}
|
|
||||||
return &selfSignedTokenProvider{
|
|
||||||
email: f.ClientEmail,
|
|
||||||
audience: opts.Audience,
|
|
||||||
scopes: opts.scopes(),
|
|
||||||
signer: signer,
|
|
||||||
pkID: f.PrivateKeyID,
|
|
||||||
logger: opts.logger(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type selfSignedTokenProvider struct {
|
|
||||||
email string
|
|
||||||
audience string
|
|
||||||
scopes []string
|
|
||||||
signer crypto.Signer
|
|
||||||
pkID string
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *selfSignedTokenProvider) Token(context.Context) (*auth.Token, error) {
|
|
||||||
iat := now()
|
|
||||||
exp := iat.Add(time.Hour)
|
|
||||||
scope := strings.Join(tp.scopes, " ")
|
|
||||||
c := &jwt.Claims{
|
|
||||||
Iss: tp.email,
|
|
||||||
Sub: tp.email,
|
|
||||||
Aud: tp.audience,
|
|
||||||
Scope: scope,
|
|
||||||
Iat: iat.Unix(),
|
|
||||||
Exp: exp.Unix(),
|
|
||||||
}
|
|
||||||
h := &jwt.Header{
|
|
||||||
Algorithm: jwt.HeaderAlgRSA256,
|
|
||||||
Type: jwt.HeaderType,
|
|
||||||
KeyID: string(tp.pkID),
|
|
||||||
}
|
|
||||||
tok, err := jwt.EncodeJWS(h, c, tp.signer)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("credentials: could not encode JWT: %w", err)
|
|
||||||
}
|
|
||||||
tp.logger.Debug("created self-signed JWT", "token", tok)
|
|
||||||
return &auth.Token{Value: tok, Type: internal.TokenTypeBearer, Expiry: exp}, nil
|
|
||||||
}
|
|
||||||
247
src/server/vendor/cloud.google.com/go/auth/httptransport/httptransport.go
generated
vendored
247
src/server/vendor/cloud.google.com/go/auth/httptransport/httptransport.go
generated
vendored
@ -1,247 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package httptransport provides functionality for managing HTTP client
|
|
||||||
// connections to Google Cloud services.
|
|
||||||
package httptransport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
detect "cloud.google.com/go/auth/credentials"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/transport"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ClientCertProvider is a function that returns a TLS client certificate to be
|
|
||||||
// used when opening TLS connections. It follows the same semantics as
|
|
||||||
// [crypto/tls.Config.GetClientCertificate].
|
|
||||||
type ClientCertProvider = func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
|
|
||||||
|
|
||||||
// Options used to configure a [net/http.Client] from [NewClient].
|
|
||||||
type Options struct {
|
|
||||||
// DisableTelemetry disables default telemetry (OpenTelemetry). An example
|
|
||||||
// reason to do so would be to bind custom telemetry that overrides the
|
|
||||||
// defaults.
|
|
||||||
DisableTelemetry bool
|
|
||||||
// DisableAuthentication specifies that no authentication should be used. It
|
|
||||||
// is suitable only for testing and for accessing public resources, like
|
|
||||||
// public Google Cloud Storage buckets.
|
|
||||||
DisableAuthentication bool
|
|
||||||
// Headers are extra HTTP headers that will be appended to every outgoing
|
|
||||||
// request.
|
|
||||||
Headers http.Header
|
|
||||||
// BaseRoundTripper overrides the base transport used for serving requests.
|
|
||||||
// If specified ClientCertProvider is ignored.
|
|
||||||
BaseRoundTripper http.RoundTripper
|
|
||||||
// Endpoint overrides the default endpoint to be used for a service.
|
|
||||||
Endpoint string
|
|
||||||
// APIKey specifies an API key to be used as the basis for authentication.
|
|
||||||
// If set DetectOpts are ignored.
|
|
||||||
APIKey string
|
|
||||||
// Credentials used to add Authorization header to all requests. If set
|
|
||||||
// DetectOpts are ignored.
|
|
||||||
Credentials *auth.Credentials
|
|
||||||
// ClientCertProvider is a function that returns a TLS client certificate to
|
|
||||||
// be used when opening TLS connections. It follows the same semantics as
|
|
||||||
// crypto/tls.Config.GetClientCertificate.
|
|
||||||
ClientCertProvider ClientCertProvider
|
|
||||||
// DetectOpts configures settings for detect Application Default
|
|
||||||
// Credentials.
|
|
||||||
DetectOpts *detect.DetectOptions
|
|
||||||
// UniverseDomain is the default service domain for a given Cloud universe.
|
|
||||||
// The default value is "googleapis.com". This is the universe domain
|
|
||||||
// configured for the client, which will be compared to the universe domain
|
|
||||||
// that is separately configured for the credentials.
|
|
||||||
UniverseDomain string
|
|
||||||
// Logger is used for debug logging. If provided, logging will be enabled
|
|
||||||
// at the loggers configured level. By default logging is disabled unless
|
|
||||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
|
||||||
// logger will be used. Optional.
|
|
||||||
Logger *slog.Logger
|
|
||||||
|
|
||||||
// InternalOptions are NOT meant to be set directly by consumers of this
|
|
||||||
// package, they should only be set by generated client code.
|
|
||||||
InternalOptions *InternalOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options) validate() error {
|
|
||||||
if o == nil {
|
|
||||||
return errors.New("httptransport: opts required to be non-nil")
|
|
||||||
}
|
|
||||||
if o.InternalOptions != nil && o.InternalOptions.SkipValidation {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
hasCreds := o.APIKey != "" ||
|
|
||||||
o.Credentials != nil ||
|
|
||||||
(o.DetectOpts != nil && len(o.DetectOpts.CredentialsJSON) > 0) ||
|
|
||||||
(o.DetectOpts != nil && o.DetectOpts.CredentialsFile != "")
|
|
||||||
if o.DisableAuthentication && hasCreds {
|
|
||||||
return errors.New("httptransport: DisableAuthentication is incompatible with options that set or detect credentials")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// client returns the client a user set for the detect options or nil if one was
|
|
||||||
// not set.
|
|
||||||
func (o *Options) client() *http.Client {
|
|
||||||
if o.DetectOpts != nil && o.DetectOpts.Client != nil {
|
|
||||||
return o.DetectOpts.Client
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options) logger() *slog.Logger {
|
|
||||||
return internallog.New(o.Logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options) resolveDetectOptions() *detect.DetectOptions {
|
|
||||||
io := o.InternalOptions
|
|
||||||
// soft-clone these so we are not updating a ref the user holds and may reuse
|
|
||||||
do := transport.CloneDetectOptions(o.DetectOpts)
|
|
||||||
|
|
||||||
// If scoped JWTs are enabled user provided an aud, allow self-signed JWT.
|
|
||||||
if (io != nil && io.EnableJWTWithScope) || do.Audience != "" {
|
|
||||||
do.UseSelfSignedJWT = true
|
|
||||||
}
|
|
||||||
// Only default scopes if user did not also set an audience.
|
|
||||||
if len(do.Scopes) == 0 && do.Audience == "" && io != nil && len(io.DefaultScopes) > 0 {
|
|
||||||
do.Scopes = make([]string, len(io.DefaultScopes))
|
|
||||||
copy(do.Scopes, io.DefaultScopes)
|
|
||||||
}
|
|
||||||
if len(do.Scopes) == 0 && do.Audience == "" && io != nil {
|
|
||||||
do.Audience = o.InternalOptions.DefaultAudience
|
|
||||||
}
|
|
||||||
if o.ClientCertProvider != nil {
|
|
||||||
tlsConfig := &tls.Config{
|
|
||||||
GetClientCertificate: o.ClientCertProvider,
|
|
||||||
}
|
|
||||||
do.Client = transport.DefaultHTTPClientWithTLS(tlsConfig)
|
|
||||||
do.TokenURL = detect.GoogleMTLSTokenURL
|
|
||||||
}
|
|
||||||
if do.Logger == nil {
|
|
||||||
do.Logger = o.logger()
|
|
||||||
}
|
|
||||||
return do
|
|
||||||
}
|
|
||||||
|
|
||||||
// InternalOptions are only meant to be set by generated client code. These are
|
|
||||||
// not meant to be set directly by consumers of this package. Configuration in
|
|
||||||
// this type is considered EXPERIMENTAL and may be removed at any time in the
|
|
||||||
// future without warning.
|
|
||||||
type InternalOptions struct {
|
|
||||||
// EnableJWTWithScope specifies if scope can be used with self-signed JWT.
|
|
||||||
EnableJWTWithScope bool
|
|
||||||
// DefaultAudience specifies a default audience to be used as the audience
|
|
||||||
// field ("aud") for the JWT token authentication.
|
|
||||||
DefaultAudience string
|
|
||||||
// DefaultEndpointTemplate combined with UniverseDomain specifies the
|
|
||||||
// default endpoint.
|
|
||||||
DefaultEndpointTemplate string
|
|
||||||
// DefaultMTLSEndpoint specifies the default mTLS endpoint.
|
|
||||||
DefaultMTLSEndpoint string
|
|
||||||
// DefaultScopes specifies the default OAuth2 scopes to be used for a
|
|
||||||
// service.
|
|
||||||
DefaultScopes []string
|
|
||||||
// SkipValidation bypasses validation on Options. It should only be used
|
|
||||||
// internally for clients that need more control over their transport.
|
|
||||||
SkipValidation bool
|
|
||||||
// SkipUniverseDomainValidation skips the verification that the universe
|
|
||||||
// domain configured for the client matches the universe domain configured
|
|
||||||
// for the credentials. It should only be used internally for clients that
|
|
||||||
// need more control over their transport. The default is false.
|
|
||||||
SkipUniverseDomainValidation bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddAuthorizationMiddleware adds a middleware to the provided client's
|
|
||||||
// transport that sets the Authorization header with the value produced by the
|
|
||||||
// provided [cloud.google.com/go/auth.Credentials]. An error is returned only
|
|
||||||
// if client or creds is nil.
|
|
||||||
//
|
|
||||||
// This function does not support setting a universe domain value on the client.
|
|
||||||
func AddAuthorizationMiddleware(client *http.Client, creds *auth.Credentials) error {
|
|
||||||
if client == nil || creds == nil {
|
|
||||||
return fmt.Errorf("httptransport: client and tp must not be nil")
|
|
||||||
}
|
|
||||||
base := client.Transport
|
|
||||||
if base == nil {
|
|
||||||
if dt, ok := http.DefaultTransport.(*http.Transport); ok {
|
|
||||||
base = dt.Clone()
|
|
||||||
} else {
|
|
||||||
// Directly reuse the DefaultTransport if the application has
|
|
||||||
// replaced it with an implementation of RoundTripper other than
|
|
||||||
// http.Transport.
|
|
||||||
base = http.DefaultTransport
|
|
||||||
}
|
|
||||||
}
|
|
||||||
client.Transport = &authTransport{
|
|
||||||
creds: creds,
|
|
||||||
base: base,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient returns a [net/http.Client] that can be used to communicate with a
|
|
||||||
// Google cloud service, configured with the provided [Options]. It
|
|
||||||
// automatically appends Authorization headers to all outgoing requests.
|
|
||||||
func NewClient(opts *Options) (*http.Client, error) {
|
|
||||||
if err := opts.validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tOpts := &transport.Options{
|
|
||||||
Endpoint: opts.Endpoint,
|
|
||||||
ClientCertProvider: opts.ClientCertProvider,
|
|
||||||
Client: opts.client(),
|
|
||||||
UniverseDomain: opts.UniverseDomain,
|
|
||||||
Logger: opts.logger(),
|
|
||||||
}
|
|
||||||
if io := opts.InternalOptions; io != nil {
|
|
||||||
tOpts.DefaultEndpointTemplate = io.DefaultEndpointTemplate
|
|
||||||
tOpts.DefaultMTLSEndpoint = io.DefaultMTLSEndpoint
|
|
||||||
}
|
|
||||||
clientCertProvider, dialTLSContext, err := transport.GetHTTPTransportConfig(tOpts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
baseRoundTripper := opts.BaseRoundTripper
|
|
||||||
if baseRoundTripper == nil {
|
|
||||||
baseRoundTripper = defaultBaseTransport(clientCertProvider, dialTLSContext)
|
|
||||||
}
|
|
||||||
// Ensure the token exchange transport uses the same ClientCertProvider as the API transport.
|
|
||||||
opts.ClientCertProvider = clientCertProvider
|
|
||||||
trans, err := newTransport(baseRoundTripper, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &http.Client{
|
|
||||||
Transport: trans,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAuthHeader uses the provided token to set the Authorization header on a
|
|
||||||
// request. If the token.Type is empty, the type is assumed to be Bearer.
|
|
||||||
func SetAuthHeader(token *auth.Token, req *http.Request) {
|
|
||||||
typ := token.Type
|
|
||||||
if typ == "" {
|
|
||||||
typ = internal.TokenTypeBearer
|
|
||||||
}
|
|
||||||
req.Header.Set("Authorization", typ+" "+token.Value)
|
|
||||||
}
|
|
||||||
234
src/server/vendor/cloud.google.com/go/auth/httptransport/transport.go
generated
vendored
234
src/server/vendor/cloud.google.com/go/auth/httptransport/transport.go
generated
vendored
@ -1,234 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package httptransport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"cloud.google.com/go/auth/credentials"
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/transport"
|
|
||||||
"cloud.google.com/go/auth/internal/transport/cert"
|
|
||||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
quotaProjectHeaderKey = "X-goog-user-project"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, error) {
|
|
||||||
var headers = opts.Headers
|
|
||||||
ht := &headerTransport{
|
|
||||||
base: base,
|
|
||||||
headers: headers,
|
|
||||||
}
|
|
||||||
var trans http.RoundTripper = ht
|
|
||||||
trans = addOpenTelemetryTransport(trans, opts)
|
|
||||||
switch {
|
|
||||||
case opts.DisableAuthentication:
|
|
||||||
// Do nothing.
|
|
||||||
case opts.APIKey != "":
|
|
||||||
qp := internal.GetQuotaProject(nil, opts.Headers.Get(quotaProjectHeaderKey))
|
|
||||||
if qp != "" {
|
|
||||||
if headers == nil {
|
|
||||||
headers = make(map[string][]string, 1)
|
|
||||||
}
|
|
||||||
headers.Set(quotaProjectHeaderKey, qp)
|
|
||||||
}
|
|
||||||
trans = &apiKeyTransport{
|
|
||||||
Transport: trans,
|
|
||||||
Key: opts.APIKey,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
var creds *auth.Credentials
|
|
||||||
if opts.Credentials != nil {
|
|
||||||
creds = opts.Credentials
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
creds, err = credentials.DetectDefault(opts.resolveDetectOptions())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qp, err := creds.QuotaProjectID(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if qp != "" {
|
|
||||||
if headers == nil {
|
|
||||||
headers = make(map[string][]string, 1)
|
|
||||||
}
|
|
||||||
// Don't overwrite user specified quota
|
|
||||||
if v := headers.Get(quotaProjectHeaderKey); v == "" {
|
|
||||||
headers.Set(quotaProjectHeaderKey, qp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var skipUD bool
|
|
||||||
if iOpts := opts.InternalOptions; iOpts != nil {
|
|
||||||
skipUD = iOpts.SkipUniverseDomainValidation
|
|
||||||
}
|
|
||||||
creds.TokenProvider = auth.NewCachedTokenProvider(creds.TokenProvider, nil)
|
|
||||||
trans = &authTransport{
|
|
||||||
base: trans,
|
|
||||||
creds: creds,
|
|
||||||
clientUniverseDomain: opts.UniverseDomain,
|
|
||||||
skipUniverseDomainValidation: skipUD,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return trans, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultBaseTransport returns the base HTTP transport.
|
|
||||||
// On App Engine, this is urlfetch.Transport.
|
|
||||||
// Otherwise, use a default transport, taking most defaults from
|
|
||||||
// http.DefaultTransport.
|
|
||||||
// If TLSCertificate is available, set TLSClientConfig as well.
|
|
||||||
func defaultBaseTransport(clientCertSource cert.Provider, dialTLSContext func(context.Context, string, string) (net.Conn, error)) http.RoundTripper {
|
|
||||||
defaultTransport, ok := http.DefaultTransport.(*http.Transport)
|
|
||||||
if !ok {
|
|
||||||
defaultTransport = transport.BaseTransport()
|
|
||||||
}
|
|
||||||
trans := defaultTransport.Clone()
|
|
||||||
trans.MaxIdleConnsPerHost = 100
|
|
||||||
|
|
||||||
if clientCertSource != nil {
|
|
||||||
trans.TLSClientConfig = &tls.Config{
|
|
||||||
GetClientCertificate: clientCertSource,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dialTLSContext != nil {
|
|
||||||
// If DialTLSContext is set, TLSClientConfig wil be ignored
|
|
||||||
trans.DialTLSContext = dialTLSContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configures the ReadIdleTimeout HTTP/2 option for the
|
|
||||||
// transport. This allows broken idle connections to be pruned more quickly,
|
|
||||||
// preventing the client from attempting to re-use connections that will no
|
|
||||||
// longer work.
|
|
||||||
http2Trans, err := http2.ConfigureTransports(trans)
|
|
||||||
if err == nil {
|
|
||||||
http2Trans.ReadIdleTimeout = time.Second * 31
|
|
||||||
}
|
|
||||||
|
|
||||||
return trans
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiKeyTransport struct {
|
|
||||||
// Key is the API Key to set on requests.
|
|
||||||
Key string
|
|
||||||
// Transport is the underlying HTTP transport.
|
|
||||||
// If nil, http.DefaultTransport is used.
|
|
||||||
Transport http.RoundTripper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *apiKeyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
newReq := *req
|
|
||||||
args := newReq.URL.Query()
|
|
||||||
args.Set("key", t.Key)
|
|
||||||
newReq.URL.RawQuery = args.Encode()
|
|
||||||
return t.Transport.RoundTrip(&newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
type headerTransport struct {
|
|
||||||
headers http.Header
|
|
||||||
base http.RoundTripper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
rt := t.base
|
|
||||||
newReq := *req
|
|
||||||
newReq.Header = make(http.Header)
|
|
||||||
for k, vv := range req.Header {
|
|
||||||
newReq.Header[k] = vv
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range t.headers {
|
|
||||||
newReq.Header[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return rt.RoundTrip(&newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addOpenTelemetryTransport(trans http.RoundTripper, opts *Options) http.RoundTripper {
|
|
||||||
if opts.DisableTelemetry {
|
|
||||||
return trans
|
|
||||||
}
|
|
||||||
return otelhttp.NewTransport(trans)
|
|
||||||
}
|
|
||||||
|
|
||||||
type authTransport struct {
|
|
||||||
creds *auth.Credentials
|
|
||||||
base http.RoundTripper
|
|
||||||
clientUniverseDomain string
|
|
||||||
skipUniverseDomainValidation bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// getClientUniverseDomain returns the default service domain for a given Cloud
|
|
||||||
// universe, with the following precedence:
|
|
||||||
//
|
|
||||||
// 1. A non-empty option.WithUniverseDomain or similar client option.
|
|
||||||
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
|
|
||||||
// 3. The default value "googleapis.com".
|
|
||||||
//
|
|
||||||
// This is the universe domain configured for the client, which will be compared
|
|
||||||
// to the universe domain that is separately configured for the credentials.
|
|
||||||
func (t *authTransport) getClientUniverseDomain() string {
|
|
||||||
if t.clientUniverseDomain != "" {
|
|
||||||
return t.clientUniverseDomain
|
|
||||||
}
|
|
||||||
if envUD := os.Getenv(internal.UniverseDomainEnvVar); envUD != "" {
|
|
||||||
return envUD
|
|
||||||
}
|
|
||||||
return internal.DefaultUniverseDomain
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoundTrip authorizes and authenticates the request with an
|
|
||||||
// access token from Transport's Source. Per the RoundTripper contract we must
|
|
||||||
// not modify the initial request, so we clone it, and we must close the body
|
|
||||||
// on any errors that happens during our token logic.
|
|
||||||
func (t *authTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
reqBodyClosed := false
|
|
||||||
if req.Body != nil {
|
|
||||||
defer func() {
|
|
||||||
if !reqBodyClosed {
|
|
||||||
req.Body.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
token, err := t.creds.Token(req.Context())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !t.skipUniverseDomainValidation && token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
|
||||||
credentialsUniverseDomain, err := t.creds.UniverseDomain(req.Context())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := transport.ValidateUniverseDomain(t.getClientUniverseDomain(), credentialsUniverseDomain); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req2 := req.Clone(req.Context())
|
|
||||||
SetAuthHeader(token, req2)
|
|
||||||
reqBodyClosed = true
|
|
||||||
return t.base.RoundTrip(req2)
|
|
||||||
}
|
|
||||||
107
src/server/vendor/cloud.google.com/go/auth/internal/credsfile/credsfile.go
generated
vendored
107
src/server/vendor/cloud.google.com/go/auth/internal/credsfile/credsfile.go
generated
vendored
@ -1,107 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package credsfile is meant to hide implementation details from the pubic
|
|
||||||
// surface of the detect package. It should not import any other packages in
|
|
||||||
// this module. It is located under the main internal package so other
|
|
||||||
// sub-packages can use these parsed types as well.
|
|
||||||
package credsfile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// GoogleAppCredsEnvVar is the environment variable for setting the
|
|
||||||
// application default credentials.
|
|
||||||
GoogleAppCredsEnvVar = "GOOGLE_APPLICATION_CREDENTIALS"
|
|
||||||
userCredsFilename = "application_default_credentials.json"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CredentialType represents different credential filetypes Google credentials
|
|
||||||
// can be.
|
|
||||||
type CredentialType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// UnknownCredType is an unidentified file type.
|
|
||||||
UnknownCredType CredentialType = iota
|
|
||||||
// UserCredentialsKey represents a user creds file type.
|
|
||||||
UserCredentialsKey
|
|
||||||
// ServiceAccountKey represents a service account file type.
|
|
||||||
ServiceAccountKey
|
|
||||||
// ImpersonatedServiceAccountKey represents a impersonated service account
|
|
||||||
// file type.
|
|
||||||
ImpersonatedServiceAccountKey
|
|
||||||
// ExternalAccountKey represents a external account file type.
|
|
||||||
ExternalAccountKey
|
|
||||||
// GDCHServiceAccountKey represents a GDCH file type.
|
|
||||||
GDCHServiceAccountKey
|
|
||||||
// ExternalAccountAuthorizedUserKey represents a external account authorized
|
|
||||||
// user file type.
|
|
||||||
ExternalAccountAuthorizedUserKey
|
|
||||||
)
|
|
||||||
|
|
||||||
// parseCredentialType returns the associated filetype based on the parsed
|
|
||||||
// typeString provided.
|
|
||||||
func parseCredentialType(typeString string) CredentialType {
|
|
||||||
switch typeString {
|
|
||||||
case "service_account":
|
|
||||||
return ServiceAccountKey
|
|
||||||
case "authorized_user":
|
|
||||||
return UserCredentialsKey
|
|
||||||
case "impersonated_service_account":
|
|
||||||
return ImpersonatedServiceAccountKey
|
|
||||||
case "external_account":
|
|
||||||
return ExternalAccountKey
|
|
||||||
case "external_account_authorized_user":
|
|
||||||
return ExternalAccountAuthorizedUserKey
|
|
||||||
case "gdch_service_account":
|
|
||||||
return GDCHServiceAccountKey
|
|
||||||
default:
|
|
||||||
return UnknownCredType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFileNameFromEnv returns the override if provided or detects a filename
|
|
||||||
// from the environment.
|
|
||||||
func GetFileNameFromEnv(override string) string {
|
|
||||||
if override != "" {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
return os.Getenv(GoogleAppCredsEnvVar)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWellKnownFileName tries to locate the filepath for the user credential
|
|
||||||
// file based on the environment.
|
|
||||||
func GetWellKnownFileName() string {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
return filepath.Join(os.Getenv("APPDATA"), "gcloud", userCredsFilename)
|
|
||||||
}
|
|
||||||
return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", userCredsFilename)
|
|
||||||
}
|
|
||||||
|
|
||||||
// guessUnixHomeDir default to checking for HOME, but not all unix systems have
|
|
||||||
// this set, do have a fallback.
|
|
||||||
func guessUnixHomeDir() string {
|
|
||||||
if v := os.Getenv("HOME"); v != "" {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
if u, err := user.Current(); err == nil {
|
|
||||||
return u.HomeDir
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
157
src/server/vendor/cloud.google.com/go/auth/internal/credsfile/filetype.go
generated
vendored
157
src/server/vendor/cloud.google.com/go/auth/internal/credsfile/filetype.go
generated
vendored
@ -1,157 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package credsfile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config3LO is the internals of a client creds file.
|
|
||||||
type Config3LO struct {
|
|
||||||
ClientID string `json:"client_id"`
|
|
||||||
ClientSecret string `json:"client_secret"`
|
|
||||||
RedirectURIs []string `json:"redirect_uris"`
|
|
||||||
AuthURI string `json:"auth_uri"`
|
|
||||||
TokenURI string `json:"token_uri"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientCredentialsFile representation.
|
|
||||||
type ClientCredentialsFile struct {
|
|
||||||
Web *Config3LO `json:"web"`
|
|
||||||
Installed *Config3LO `json:"installed"`
|
|
||||||
UniverseDomain string `json:"universe_domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceAccountFile representation.
|
|
||||||
type ServiceAccountFile struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ProjectID string `json:"project_id"`
|
|
||||||
PrivateKeyID string `json:"private_key_id"`
|
|
||||||
PrivateKey string `json:"private_key"`
|
|
||||||
ClientEmail string `json:"client_email"`
|
|
||||||
ClientID string `json:"client_id"`
|
|
||||||
AuthURL string `json:"auth_uri"`
|
|
||||||
TokenURL string `json:"token_uri"`
|
|
||||||
UniverseDomain string `json:"universe_domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserCredentialsFile representation.
|
|
||||||
type UserCredentialsFile struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ClientID string `json:"client_id"`
|
|
||||||
ClientSecret string `json:"client_secret"`
|
|
||||||
QuotaProjectID string `json:"quota_project_id"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
UniverseDomain string `json:"universe_domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExternalAccountFile representation.
|
|
||||||
type ExternalAccountFile struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ClientID string `json:"client_id"`
|
|
||||||
ClientSecret string `json:"client_secret"`
|
|
||||||
Audience string `json:"audience"`
|
|
||||||
SubjectTokenType string `json:"subject_token_type"`
|
|
||||||
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
|
|
||||||
TokenURL string `json:"token_url"`
|
|
||||||
CredentialSource *CredentialSource `json:"credential_source,omitempty"`
|
|
||||||
TokenInfoURL string `json:"token_info_url"`
|
|
||||||
ServiceAccountImpersonation *ServiceAccountImpersonationInfo `json:"service_account_impersonation,omitempty"`
|
|
||||||
QuotaProjectID string `json:"quota_project_id"`
|
|
||||||
WorkforcePoolUserProject string `json:"workforce_pool_user_project"`
|
|
||||||
UniverseDomain string `json:"universe_domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExternalAccountAuthorizedUserFile representation.
|
|
||||||
type ExternalAccountAuthorizedUserFile struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Audience string `json:"audience"`
|
|
||||||
ClientID string `json:"client_id"`
|
|
||||||
ClientSecret string `json:"client_secret"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
TokenURL string `json:"token_url"`
|
|
||||||
TokenInfoURL string `json:"token_info_url"`
|
|
||||||
RevokeURL string `json:"revoke_url"`
|
|
||||||
QuotaProjectID string `json:"quota_project_id"`
|
|
||||||
UniverseDomain string `json:"universe_domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CredentialSource stores the information necessary to retrieve the credentials for the STS exchange.
|
|
||||||
//
|
|
||||||
// One field amongst File, URL, Certificate, and Executable should be filled, depending on the kind of credential in question.
|
|
||||||
// The EnvironmentID should start with AWS if being used for an AWS credential.
|
|
||||||
type CredentialSource struct {
|
|
||||||
File string `json:"file"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Headers map[string]string `json:"headers"`
|
|
||||||
Executable *ExecutableConfig `json:"executable,omitempty"`
|
|
||||||
Certificate *CertificateConfig `json:"certificate"`
|
|
||||||
EnvironmentID string `json:"environment_id"` // TODO: Make type for this
|
|
||||||
RegionURL string `json:"region_url"`
|
|
||||||
RegionalCredVerificationURL string `json:"regional_cred_verification_url"`
|
|
||||||
CredVerificationURL string `json:"cred_verification_url"`
|
|
||||||
IMDSv2SessionTokenURL string `json:"imdsv2_session_token_url"`
|
|
||||||
Format *Format `json:"format,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format describes the format of a [CredentialSource].
|
|
||||||
type Format struct {
|
|
||||||
// Type is either "text" or "json". When not provided "text" type is assumed.
|
|
||||||
Type string `json:"type"`
|
|
||||||
// SubjectTokenFieldName is only required for JSON format. This would be "access_token" for azure.
|
|
||||||
SubjectTokenFieldName string `json:"subject_token_field_name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecutableConfig represents the command to run for an executable
|
|
||||||
// [CredentialSource].
|
|
||||||
type ExecutableConfig struct {
|
|
||||||
Command string `json:"command"`
|
|
||||||
TimeoutMillis int `json:"timeout_millis"`
|
|
||||||
OutputFile string `json:"output_file"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CertificateConfig represents the options used to set up X509 based workload
|
|
||||||
// [CredentialSource]
|
|
||||||
type CertificateConfig struct {
|
|
||||||
UseDefaultCertificateConfig bool `json:"use_default_certificate_config"`
|
|
||||||
CertificateConfigLocation string `json:"certificate_config_location"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceAccountImpersonationInfo has impersonation configuration.
|
|
||||||
type ServiceAccountImpersonationInfo struct {
|
|
||||||
TokenLifetimeSeconds int `json:"token_lifetime_seconds"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImpersonatedServiceAccountFile representation.
|
|
||||||
type ImpersonatedServiceAccountFile struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
|
|
||||||
Delegates []string `json:"delegates"`
|
|
||||||
CredSource json.RawMessage `json:"source_credentials"`
|
|
||||||
UniverseDomain string `json:"universe_domain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GDCHServiceAccountFile represents the Google Distributed Cloud Hosted (GDCH) service identity file.
|
|
||||||
type GDCHServiceAccountFile struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
FormatVersion string `json:"format_version"`
|
|
||||||
Project string `json:"project"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
CertPath string `json:"ca_cert_path"`
|
|
||||||
PrivateKeyID string `json:"private_key_id"`
|
|
||||||
PrivateKey string `json:"private_key"`
|
|
||||||
TokenURL string `json:"token_uri"`
|
|
||||||
UniverseDomain string `json:"universe_domain"`
|
|
||||||
}
|
|
||||||
98
src/server/vendor/cloud.google.com/go/auth/internal/credsfile/parse.go
generated
vendored
98
src/server/vendor/cloud.google.com/go/auth/internal/credsfile/parse.go
generated
vendored
@ -1,98 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package credsfile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseServiceAccount parses bytes into a [ServiceAccountFile].
|
|
||||||
func ParseServiceAccount(b []byte) (*ServiceAccountFile, error) {
|
|
||||||
var f *ServiceAccountFile
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseClientCredentials parses bytes into a
|
|
||||||
// [credsfile.ClientCredentialsFile].
|
|
||||||
func ParseClientCredentials(b []byte) (*ClientCredentialsFile, error) {
|
|
||||||
var f *ClientCredentialsFile
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseUserCredentials parses bytes into a [UserCredentialsFile].
|
|
||||||
func ParseUserCredentials(b []byte) (*UserCredentialsFile, error) {
|
|
||||||
var f *UserCredentialsFile
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseExternalAccount parses bytes into a [ExternalAccountFile].
|
|
||||||
func ParseExternalAccount(b []byte) (*ExternalAccountFile, error) {
|
|
||||||
var f *ExternalAccountFile
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseExternalAccountAuthorizedUser parses bytes into a
|
|
||||||
// [ExternalAccountAuthorizedUserFile].
|
|
||||||
func ParseExternalAccountAuthorizedUser(b []byte) (*ExternalAccountAuthorizedUserFile, error) {
|
|
||||||
var f *ExternalAccountAuthorizedUserFile
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseImpersonatedServiceAccount parses bytes into a
|
|
||||||
// [ImpersonatedServiceAccountFile].
|
|
||||||
func ParseImpersonatedServiceAccount(b []byte) (*ImpersonatedServiceAccountFile, error) {
|
|
||||||
var f *ImpersonatedServiceAccountFile
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseGDCHServiceAccount parses bytes into a [GDCHServiceAccountFile].
|
|
||||||
func ParseGDCHServiceAccount(b []byte) (*GDCHServiceAccountFile, error) {
|
|
||||||
var f *GDCHServiceAccountFile
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type fileTypeChecker struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseFileType determines the [CredentialType] based on bytes provided.
|
|
||||||
func ParseFileType(b []byte) (CredentialType, error) {
|
|
||||||
var f fileTypeChecker
|
|
||||||
if err := json.Unmarshal(b, &f); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return parseCredentialType(f.Type), nil
|
|
||||||
}
|
|
||||||
225
src/server/vendor/cloud.google.com/go/auth/internal/internal.go
generated
vendored
225
src/server/vendor/cloud.google.com/go/auth/internal/internal.go
generated
vendored
@ -1,225 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/json"
|
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/compute/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TokenTypeBearer is the auth header prefix for bearer tokens.
|
|
||||||
TokenTypeBearer = "Bearer"
|
|
||||||
|
|
||||||
// QuotaProjectEnvVar is the environment variable for setting the quota
|
|
||||||
// project.
|
|
||||||
QuotaProjectEnvVar = "GOOGLE_CLOUD_QUOTA_PROJECT"
|
|
||||||
// UniverseDomainEnvVar is the environment variable for setting the default
|
|
||||||
// service domain for a given Cloud universe.
|
|
||||||
UniverseDomainEnvVar = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"
|
|
||||||
projectEnvVar = "GOOGLE_CLOUD_PROJECT"
|
|
||||||
maxBodySize = 1 << 20
|
|
||||||
|
|
||||||
// DefaultUniverseDomain is the default value for universe domain.
|
|
||||||
// Universe domain is the default service domain for a given Cloud universe.
|
|
||||||
DefaultUniverseDomain = "googleapis.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
type clonableTransport interface {
|
|
||||||
Clone() *http.Transport
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultClient returns an [http.Client] with some defaults set. If
|
|
||||||
// the current [http.DefaultTransport] is a [clonableTransport], as
|
|
||||||
// is the case for an [*http.Transport], the clone will be used.
|
|
||||||
// Otherwise the [http.DefaultTransport] is used directly.
|
|
||||||
func DefaultClient() *http.Client {
|
|
||||||
if transport, ok := http.DefaultTransport.(clonableTransport); ok {
|
|
||||||
return &http.Client{
|
|
||||||
Transport: transport.Clone(),
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &http.Client{
|
|
||||||
Transport: http.DefaultTransport,
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseKey converts the binary contents of a private key file
|
|
||||||
// to an crypto.Signer. It detects whether the private key is in a
|
|
||||||
// PEM container or not. If so, it extracts the the private key
|
|
||||||
// from PEM container before conversion. It only supports PEM
|
|
||||||
// containers with no passphrase.
|
|
||||||
func ParseKey(key []byte) (crypto.Signer, error) {
|
|
||||||
block, _ := pem.Decode(key)
|
|
||||||
if block != nil {
|
|
||||||
key = block.Bytes
|
|
||||||
}
|
|
||||||
var parsedKey crypto.PrivateKey
|
|
||||||
var err error
|
|
||||||
parsedKey, err = x509.ParsePKCS8PrivateKey(key)
|
|
||||||
if err != nil {
|
|
||||||
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parsed, ok := parsedKey.(crypto.Signer)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("private key is not a signer")
|
|
||||||
}
|
|
||||||
return parsed, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetQuotaProject retrieves quota project with precedence being: override,
|
|
||||||
// environment variable, creds json file.
|
|
||||||
func GetQuotaProject(b []byte, override string) string {
|
|
||||||
if override != "" {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
if env := os.Getenv(QuotaProjectEnvVar); env != "" {
|
|
||||||
return env
|
|
||||||
}
|
|
||||||
if b == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
var v struct {
|
|
||||||
QuotaProject string `json:"quota_project_id"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(b, &v); err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return v.QuotaProject
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProjectID retrieves project with precedence being: override,
|
|
||||||
// environment variable, creds json file.
|
|
||||||
func GetProjectID(b []byte, override string) string {
|
|
||||||
if override != "" {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
if env := os.Getenv(projectEnvVar); env != "" {
|
|
||||||
return env
|
|
||||||
}
|
|
||||||
if b == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
var v struct {
|
|
||||||
ProjectID string `json:"project_id"` // standard service account key
|
|
||||||
Project string `json:"project"` // gdch key
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(b, &v); err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if v.ProjectID != "" {
|
|
||||||
return v.ProjectID
|
|
||||||
}
|
|
||||||
return v.Project
|
|
||||||
}
|
|
||||||
|
|
||||||
// DoRequest executes the provided req with the client. It reads the response
|
|
||||||
// body, closes it, and returns it.
|
|
||||||
func DoRequest(client *http.Client, req *http.Request) (*http.Response, []byte, error) {
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ReadAll(io.LimitReader(resp.Body, maxBodySize))
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return resp, body, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadAll consumes the whole reader and safely reads the content of its body
|
|
||||||
// with some overflow protection.
|
|
||||||
func ReadAll(r io.Reader) ([]byte, error) {
|
|
||||||
return io.ReadAll(io.LimitReader(r, maxBodySize))
|
|
||||||
}
|
|
||||||
|
|
||||||
// StaticCredentialsProperty is a helper for creating static credentials
|
|
||||||
// properties.
|
|
||||||
func StaticCredentialsProperty(s string) StaticProperty {
|
|
||||||
return StaticProperty(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StaticProperty always returns that value of the underlying string.
|
|
||||||
type StaticProperty string
|
|
||||||
|
|
||||||
// GetProperty loads the properly value provided the given context.
|
|
||||||
func (p StaticProperty) GetProperty(context.Context) (string, error) {
|
|
||||||
return string(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputeUniverseDomainProvider fetches the credentials universe domain from
|
|
||||||
// the google cloud metadata service.
|
|
||||||
type ComputeUniverseDomainProvider struct {
|
|
||||||
MetadataClient *metadata.Client
|
|
||||||
universeDomainOnce sync.Once
|
|
||||||
universeDomain string
|
|
||||||
universeDomainErr error
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProperty fetches the credentials universe domain from the google cloud
|
|
||||||
// metadata service.
|
|
||||||
func (c *ComputeUniverseDomainProvider) GetProperty(ctx context.Context) (string, error) {
|
|
||||||
c.universeDomainOnce.Do(func() {
|
|
||||||
c.universeDomain, c.universeDomainErr = getMetadataUniverseDomain(ctx, c.MetadataClient)
|
|
||||||
})
|
|
||||||
if c.universeDomainErr != nil {
|
|
||||||
return "", c.universeDomainErr
|
|
||||||
}
|
|
||||||
return c.universeDomain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpGetMetadataUniverseDomain is a package var for unit test substitution.
|
|
||||||
var httpGetMetadataUniverseDomain = func(ctx context.Context, client *metadata.Client) (string, error) {
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
return client.GetWithContext(ctx, "universe/universe-domain")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMetadataUniverseDomain(ctx context.Context, client *metadata.Client) (string, error) {
|
|
||||||
universeDomain, err := httpGetMetadataUniverseDomain(ctx, client)
|
|
||||||
if err == nil {
|
|
||||||
return universeDomain, nil
|
|
||||||
}
|
|
||||||
if _, ok := err.(metadata.NotDefinedError); ok {
|
|
||||||
// http.StatusNotFound (404)
|
|
||||||
return DefaultUniverseDomain, nil
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatIAMServiceAccountResource sets a service account name in an IAM resource
|
|
||||||
// name.
|
|
||||||
func FormatIAMServiceAccountResource(name string) string {
|
|
||||||
return fmt.Sprintf("projects/-/serviceAccounts/%s", name)
|
|
||||||
}
|
|
||||||
171
src/server/vendor/cloud.google.com/go/auth/internal/jwt/jwt.go
generated
vendored
171
src/server/vendor/cloud.google.com/go/auth/internal/jwt/jwt.go
generated
vendored
@ -1,171 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package jwt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// HeaderAlgRSA256 is the RS256 [Header.Algorithm].
|
|
||||||
HeaderAlgRSA256 = "RS256"
|
|
||||||
// HeaderAlgES256 is the ES256 [Header.Algorithm].
|
|
||||||
HeaderAlgES256 = "ES256"
|
|
||||||
// HeaderType is the standard [Header.Type].
|
|
||||||
HeaderType = "JWT"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Header represents a JWT header.
|
|
||||||
type Header struct {
|
|
||||||
Algorithm string `json:"alg"`
|
|
||||||
Type string `json:"typ"`
|
|
||||||
KeyID string `json:"kid"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Header) encode() (string, error) {
|
|
||||||
b, err := json.Marshal(h)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claims represents the claims set of a JWT.
|
|
||||||
type Claims struct {
|
|
||||||
// Iss is the issuer JWT claim.
|
|
||||||
Iss string `json:"iss"`
|
|
||||||
// Scope is the scope JWT claim.
|
|
||||||
Scope string `json:"scope,omitempty"`
|
|
||||||
// Exp is the expiry JWT claim. If unset, default is in one hour from now.
|
|
||||||
Exp int64 `json:"exp"`
|
|
||||||
// Iat is the subject issued at claim. If unset, default is now.
|
|
||||||
Iat int64 `json:"iat"`
|
|
||||||
// Aud is the audience JWT claim. Optional.
|
|
||||||
Aud string `json:"aud"`
|
|
||||||
// Sub is the subject JWT claim. Optional.
|
|
||||||
Sub string `json:"sub,omitempty"`
|
|
||||||
// AdditionalClaims contains any additional non-standard JWT claims. Optional.
|
|
||||||
AdditionalClaims map[string]interface{} `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Claims) encode() (string, error) {
|
|
||||||
// Compensate for skew
|
|
||||||
now := time.Now().Add(-10 * time.Second)
|
|
||||||
if c.Iat == 0 {
|
|
||||||
c.Iat = now.Unix()
|
|
||||||
}
|
|
||||||
if c.Exp == 0 {
|
|
||||||
c.Exp = now.Add(time.Hour).Unix()
|
|
||||||
}
|
|
||||||
if c.Exp < c.Iat {
|
|
||||||
return "", fmt.Errorf("jwt: invalid Exp = %d; must be later than Iat = %d", c.Exp, c.Iat)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(c)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.AdditionalClaims) == 0 {
|
|
||||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal private claim set and then append it to b.
|
|
||||||
prv, err := json.Marshal(c.AdditionalClaims)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("invalid map of additional claims %v: %w", c.AdditionalClaims, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concatenate public and private claim JSON objects.
|
|
||||||
if !bytes.HasSuffix(b, []byte{'}'}) {
|
|
||||||
return "", fmt.Errorf("invalid JSON %s", b)
|
|
||||||
}
|
|
||||||
if !bytes.HasPrefix(prv, []byte{'{'}) {
|
|
||||||
return "", fmt.Errorf("invalid JSON %s", prv)
|
|
||||||
}
|
|
||||||
b[len(b)-1] = ',' // Replace closing curly brace with a comma.
|
|
||||||
b = append(b, prv[1:]...) // Append private claims.
|
|
||||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeJWS encodes the data using the provided key as a JSON web signature.
|
|
||||||
func EncodeJWS(header *Header, c *Claims, signer crypto.Signer) (string, error) {
|
|
||||||
head, err := header.encode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
claims, err := c.encode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
ss := fmt.Sprintf("%s.%s", head, claims)
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write([]byte(ss))
|
|
||||||
sig, err := signer.Sign(rand.Reader, h.Sum(nil), crypto.SHA256)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeJWS decodes a claim set from a JWS payload.
|
|
||||||
func DecodeJWS(payload string) (*Claims, error) {
|
|
||||||
// decode returned id token to get expiry
|
|
||||||
s := strings.Split(payload, ".")
|
|
||||||
if len(s) < 2 {
|
|
||||||
return nil, errors.New("invalid token received")
|
|
||||||
}
|
|
||||||
decoded, err := base64.RawURLEncoding.DecodeString(s[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c := &Claims{}
|
|
||||||
if err := json.NewDecoder(bytes.NewBuffer(decoded)).Decode(c); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := json.NewDecoder(bytes.NewBuffer(decoded)).Decode(&c.AdditionalClaims); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyJWS tests whether the provided JWT token's signature was produced by
|
|
||||||
// the private key associated with the provided public key.
|
|
||||||
func VerifyJWS(token string, key *rsa.PublicKey) error {
|
|
||||||
parts := strings.Split(token, ".")
|
|
||||||
if len(parts) != 3 {
|
|
||||||
return errors.New("jwt: invalid token received, token must have 3 parts")
|
|
||||||
}
|
|
||||||
|
|
||||||
signedContent := parts[0] + "." + parts[1]
|
|
||||||
signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write([]byte(signedContent))
|
|
||||||
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString)
|
|
||||||
}
|
|
||||||
368
src/server/vendor/cloud.google.com/go/auth/internal/transport/cba.go
generated
vendored
368
src/server/vendor/cloud.google.com/go/auth/internal/transport/cba.go
generated
vendored
@ -1,368 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"log/slog"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"cloud.google.com/go/auth/internal/transport/cert"
|
|
||||||
"github.com/google/s2a-go"
|
|
||||||
"github.com/google/s2a-go/fallback"
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
mTLSModeAlways = "always"
|
|
||||||
mTLSModeNever = "never"
|
|
||||||
mTLSModeAuto = "auto"
|
|
||||||
|
|
||||||
// Experimental: if true, the code will try MTLS with S2A as the default for transport security. Default value is false.
|
|
||||||
googleAPIUseS2AEnv = "EXPERIMENTAL_GOOGLE_API_USE_S2A"
|
|
||||||
googleAPIUseCertSource = "GOOGLE_API_USE_CLIENT_CERTIFICATE"
|
|
||||||
googleAPIUseMTLS = "GOOGLE_API_USE_MTLS_ENDPOINT"
|
|
||||||
googleAPIUseMTLSOld = "GOOGLE_API_USE_MTLS"
|
|
||||||
|
|
||||||
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
|
|
||||||
|
|
||||||
mtlsMDSRoot = "/run/google-mds-mtls/root.crt"
|
|
||||||
mtlsMDSKey = "/run/google-mds-mtls/client.key"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options is a struct that is duplicated information from the individual
|
|
||||||
// transport packages in order to avoid cyclic deps. It correlates 1:1 with
|
|
||||||
// fields on httptransport.Options and grpctransport.Options.
|
|
||||||
type Options struct {
|
|
||||||
Endpoint string
|
|
||||||
DefaultEndpointTemplate string
|
|
||||||
DefaultMTLSEndpoint string
|
|
||||||
ClientCertProvider cert.Provider
|
|
||||||
Client *http.Client
|
|
||||||
UniverseDomain string
|
|
||||||
EnableDirectPath bool
|
|
||||||
EnableDirectPathXds bool
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// getUniverseDomain returns the default service domain for a given Cloud
|
|
||||||
// universe.
|
|
||||||
func (o *Options) getUniverseDomain() string {
|
|
||||||
if o.UniverseDomain == "" {
|
|
||||||
return internal.DefaultUniverseDomain
|
|
||||||
}
|
|
||||||
return o.UniverseDomain
|
|
||||||
}
|
|
||||||
|
|
||||||
// isUniverseDomainGDU returns true if the universe domain is the default Google
|
|
||||||
// universe.
|
|
||||||
func (o *Options) isUniverseDomainGDU() bool {
|
|
||||||
return o.getUniverseDomain() == internal.DefaultUniverseDomain
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultEndpoint returns the DefaultEndpointTemplate merged with the
|
|
||||||
// universe domain if the DefaultEndpointTemplate is set, otherwise returns an
|
|
||||||
// empty string.
|
|
||||||
func (o *Options) defaultEndpoint() string {
|
|
||||||
if o.DefaultEndpointTemplate == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return strings.Replace(o.DefaultEndpointTemplate, universeDomainPlaceholder, o.getUniverseDomain(), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultMTLSEndpoint returns the DefaultMTLSEndpointTemplate merged with the
|
|
||||||
// universe domain if the DefaultMTLSEndpointTemplate is set, otherwise returns an
|
|
||||||
// empty string.
|
|
||||||
func (o *Options) defaultMTLSEndpoint() string {
|
|
||||||
if o.DefaultMTLSEndpoint == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return strings.Replace(o.DefaultMTLSEndpoint, universeDomainPlaceholder, o.getUniverseDomain(), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mergedEndpoint merges a user-provided Endpoint of format host[:port] with the
|
|
||||||
// default endpoint.
|
|
||||||
func (o *Options) mergedEndpoint() (string, error) {
|
|
||||||
defaultEndpoint := o.defaultEndpoint()
|
|
||||||
u, err := url.Parse(fixScheme(defaultEndpoint))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return strings.Replace(defaultEndpoint, u.Host, o.Endpoint, 1), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func fixScheme(baseURL string) string {
|
|
||||||
if !strings.Contains(baseURL, "://") {
|
|
||||||
baseURL = "https://" + baseURL
|
|
||||||
}
|
|
||||||
return baseURL
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGRPCTransportCredsAndEndpoint returns an instance of
|
|
||||||
// [google.golang.org/grpc/credentials.TransportCredentials], and the
|
|
||||||
// corresponding endpoint to use for GRPC client.
|
|
||||||
func GetGRPCTransportCredsAndEndpoint(opts *Options) (credentials.TransportCredentials, string, error) {
|
|
||||||
config, err := getTransportConfig(opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultTransportCreds := credentials.NewTLS(&tls.Config{
|
|
||||||
GetClientCertificate: config.clientCertSource,
|
|
||||||
})
|
|
||||||
|
|
||||||
var s2aAddr string
|
|
||||||
var transportCredsForS2A credentials.TransportCredentials
|
|
||||||
|
|
||||||
if config.mtlsS2AAddress != "" {
|
|
||||||
s2aAddr = config.mtlsS2AAddress
|
|
||||||
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Loading MTLS MDS credentials failed: %v", err)
|
|
||||||
if config.s2aAddress != "" {
|
|
||||||
s2aAddr = config.s2aAddress
|
|
||||||
} else {
|
|
||||||
return defaultTransportCreds, config.endpoint, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if config.s2aAddress != "" {
|
|
||||||
s2aAddr = config.s2aAddress
|
|
||||||
} else {
|
|
||||||
return defaultTransportCreds, config.endpoint, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var fallbackOpts *s2a.FallbackOptions
|
|
||||||
// In case of S2A failure, fall back to the endpoint that would've been used without S2A.
|
|
||||||
if fallbackHandshake, err := fallback.DefaultFallbackClientHandshakeFunc(config.endpoint); err == nil {
|
|
||||||
fallbackOpts = &s2a.FallbackOptions{
|
|
||||||
FallbackClientHandshakeFunc: fallbackHandshake,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s2aTransportCreds, err := s2a.NewClientCreds(&s2a.ClientOptions{
|
|
||||||
S2AAddress: s2aAddr,
|
|
||||||
TransportCreds: transportCredsForS2A,
|
|
||||||
FallbackOpts: fallbackOpts,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
// Use default if we cannot initialize S2A client transport credentials.
|
|
||||||
return defaultTransportCreds, config.endpoint, nil
|
|
||||||
}
|
|
||||||
return s2aTransportCreds, config.s2aMTLSEndpoint, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPTransportConfig returns a client certificate source and a function for
|
|
||||||
// dialing MTLS with S2A.
|
|
||||||
func GetHTTPTransportConfig(opts *Options) (cert.Provider, func(context.Context, string, string) (net.Conn, error), error) {
|
|
||||||
config, err := getTransportConfig(opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var s2aAddr string
|
|
||||||
var transportCredsForS2A credentials.TransportCredentials
|
|
||||||
|
|
||||||
if config.mtlsS2AAddress != "" {
|
|
||||||
s2aAddr = config.mtlsS2AAddress
|
|
||||||
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Loading MTLS MDS credentials failed: %v", err)
|
|
||||||
if config.s2aAddress != "" {
|
|
||||||
s2aAddr = config.s2aAddress
|
|
||||||
} else {
|
|
||||||
return config.clientCertSource, nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if config.s2aAddress != "" {
|
|
||||||
s2aAddr = config.s2aAddress
|
|
||||||
} else {
|
|
||||||
return config.clientCertSource, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var fallbackOpts *s2a.FallbackOptions
|
|
||||||
// In case of S2A failure, fall back to the endpoint that would've been used without S2A.
|
|
||||||
if fallbackURL, err := url.Parse(config.endpoint); err == nil {
|
|
||||||
if fallbackDialer, fallbackServerAddr, err := fallback.DefaultFallbackDialerAndAddress(fallbackURL.Hostname()); err == nil {
|
|
||||||
fallbackOpts = &s2a.FallbackOptions{
|
|
||||||
FallbackDialer: &s2a.FallbackDialer{
|
|
||||||
Dialer: fallbackDialer,
|
|
||||||
ServerAddr: fallbackServerAddr,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialTLSContextFunc := s2a.NewS2ADialTLSContextFunc(&s2a.ClientOptions{
|
|
||||||
S2AAddress: s2aAddr,
|
|
||||||
TransportCreds: transportCredsForS2A,
|
|
||||||
FallbackOpts: fallbackOpts,
|
|
||||||
})
|
|
||||||
return nil, dialTLSContextFunc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadMTLSMDSTransportCreds(mtlsMDSRootFile, mtlsMDSKeyFile string) (credentials.TransportCredentials, error) {
|
|
||||||
rootPEM, err := os.ReadFile(mtlsMDSRootFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
caCertPool := x509.NewCertPool()
|
|
||||||
ok := caCertPool.AppendCertsFromPEM(rootPEM)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("failed to load MTLS MDS root certificate")
|
|
||||||
}
|
|
||||||
// The mTLS MDS credentials are formatted as the concatenation of a PEM-encoded certificate chain
|
|
||||||
// followed by a PEM-encoded private key. For this reason, the concatenation is passed in to the
|
|
||||||
// tls.X509KeyPair function as both the certificate chain and private key arguments.
|
|
||||||
cert, err := tls.LoadX509KeyPair(mtlsMDSKeyFile, mtlsMDSKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tlsConfig := tls.Config{
|
|
||||||
RootCAs: caCertPool,
|
|
||||||
Certificates: []tls.Certificate{cert},
|
|
||||||
MinVersion: tls.VersionTLS13,
|
|
||||||
}
|
|
||||||
return credentials.NewTLS(&tlsConfig), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTransportConfig(opts *Options) (*transportConfig, error) {
|
|
||||||
clientCertSource, err := GetClientCertificateProvider(opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
endpoint, err := getEndpoint(opts, clientCertSource)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defaultTransportConfig := transportConfig{
|
|
||||||
clientCertSource: clientCertSource,
|
|
||||||
endpoint: endpoint,
|
|
||||||
}
|
|
||||||
|
|
||||||
if !shouldUseS2A(clientCertSource, opts) {
|
|
||||||
return &defaultTransportConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
s2aAddress := GetS2AAddress(opts.Logger)
|
|
||||||
mtlsS2AAddress := GetMTLSS2AAddress(opts.Logger)
|
|
||||||
if s2aAddress == "" && mtlsS2AAddress == "" {
|
|
||||||
return &defaultTransportConfig, nil
|
|
||||||
}
|
|
||||||
return &transportConfig{
|
|
||||||
clientCertSource: clientCertSource,
|
|
||||||
endpoint: endpoint,
|
|
||||||
s2aAddress: s2aAddress,
|
|
||||||
mtlsS2AAddress: mtlsS2AAddress,
|
|
||||||
s2aMTLSEndpoint: opts.defaultMTLSEndpoint(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetClientCertificateProvider returns a default client certificate source, if
|
|
||||||
// not provided by the user.
|
|
||||||
//
|
|
||||||
// A nil default source can be returned if the source does not exist. Any exceptions
|
|
||||||
// encountered while initializing the default source will be reported as client
|
|
||||||
// error (ex. corrupt metadata file).
|
|
||||||
func GetClientCertificateProvider(opts *Options) (cert.Provider, error) {
|
|
||||||
if !isClientCertificateEnabled(opts) {
|
|
||||||
return nil, nil
|
|
||||||
} else if opts.ClientCertProvider != nil {
|
|
||||||
return opts.ClientCertProvider, nil
|
|
||||||
}
|
|
||||||
return cert.DefaultProvider()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// isClientCertificateEnabled returns true by default for all GDU universe domain, unless explicitly overridden by env var
|
|
||||||
func isClientCertificateEnabled(opts *Options) bool {
|
|
||||||
if value, ok := os.LookupEnv(googleAPIUseCertSource); ok {
|
|
||||||
// error as false is OK
|
|
||||||
b, _ := strconv.ParseBool(value)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
return opts.isUniverseDomainGDU()
|
|
||||||
}
|
|
||||||
|
|
||||||
type transportConfig struct {
|
|
||||||
// The client certificate source.
|
|
||||||
clientCertSource cert.Provider
|
|
||||||
// The corresponding endpoint to use based on client certificate source.
|
|
||||||
endpoint string
|
|
||||||
// The plaintext S2A address if it can be used, otherwise an empty string.
|
|
||||||
s2aAddress string
|
|
||||||
// The MTLS S2A address if it can be used, otherwise an empty string.
|
|
||||||
mtlsS2AAddress string
|
|
||||||
// The MTLS endpoint to use with S2A.
|
|
||||||
s2aMTLSEndpoint string
|
|
||||||
}
|
|
||||||
|
|
||||||
// getEndpoint returns the endpoint for the service, taking into account the
|
|
||||||
// user-provided endpoint override "settings.Endpoint".
|
|
||||||
//
|
|
||||||
// If no endpoint override is specified, we will either return the default
|
|
||||||
// endpoint or the default mTLS endpoint if a client certificate is available.
|
|
||||||
//
|
|
||||||
// You can override the default endpoint choice (mTLS vs. regular) by setting
|
|
||||||
// the GOOGLE_API_USE_MTLS_ENDPOINT environment variable.
|
|
||||||
//
|
|
||||||
// If the endpoint override is an address (host:port) rather than full base
|
|
||||||
// URL (ex. https://...), then the user-provided address will be merged into
|
|
||||||
// the default endpoint. For example, WithEndpoint("myhost:8000") and
|
|
||||||
// DefaultEndpointTemplate("https://UNIVERSE_DOMAIN/bar/baz") will return
|
|
||||||
// "https://myhost:8080/bar/baz". Note that this does not apply to the mTLS
|
|
||||||
// endpoint.
|
|
||||||
func getEndpoint(opts *Options, clientCertSource cert.Provider) (string, error) {
|
|
||||||
if opts.Endpoint == "" {
|
|
||||||
mtlsMode := getMTLSMode()
|
|
||||||
if mtlsMode == mTLSModeAlways || (clientCertSource != nil && mtlsMode == mTLSModeAuto) {
|
|
||||||
return opts.defaultMTLSEndpoint(), nil
|
|
||||||
}
|
|
||||||
return opts.defaultEndpoint(), nil
|
|
||||||
}
|
|
||||||
if strings.Contains(opts.Endpoint, "://") {
|
|
||||||
// User passed in a full URL path, use it verbatim.
|
|
||||||
return opts.Endpoint, nil
|
|
||||||
}
|
|
||||||
if opts.defaultEndpoint() == "" {
|
|
||||||
// If DefaultEndpointTemplate is not configured,
|
|
||||||
// use the user provided endpoint verbatim. This allows a naked
|
|
||||||
// "host[:port]" URL to be used with GRPC Direct Path.
|
|
||||||
return opts.Endpoint, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume user-provided endpoint is host[:port], merge it with the default endpoint.
|
|
||||||
return opts.mergedEndpoint()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMTLSMode() string {
|
|
||||||
mode := os.Getenv(googleAPIUseMTLS)
|
|
||||||
if mode == "" {
|
|
||||||
mode = os.Getenv(googleAPIUseMTLSOld) // Deprecated.
|
|
||||||
}
|
|
||||||
if mode == "" {
|
|
||||||
return mTLSModeAuto
|
|
||||||
}
|
|
||||||
return strings.ToLower(mode)
|
|
||||||
}
|
|
||||||
65
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/default_cert.go
generated
vendored
65
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/default_cert.go
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package cert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// defaultCertData holds all the variables pertaining to
|
|
||||||
// the default certificate provider created by [DefaultProvider].
|
|
||||||
//
|
|
||||||
// A singleton model is used to allow the provider to be reused
|
|
||||||
// by the transport layer. As mentioned in [DefaultProvider] (provider nil, nil)
|
|
||||||
// may be returned to indicate a default provider could not be found, which
|
|
||||||
// will skip extra tls config in the transport layer .
|
|
||||||
type defaultCertData struct {
|
|
||||||
once sync.Once
|
|
||||||
provider Provider
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
defaultCert defaultCertData
|
|
||||||
)
|
|
||||||
|
|
||||||
// Provider is a function that can be passed into crypto/tls.Config.GetClientCertificate.
|
|
||||||
type Provider func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
|
|
||||||
|
|
||||||
// errSourceUnavailable is a sentinel error to indicate certificate source is unavailable.
|
|
||||||
var errSourceUnavailable = errors.New("certificate source is unavailable")
|
|
||||||
|
|
||||||
// DefaultProvider returns a certificate source using the preferred EnterpriseCertificateProxySource.
|
|
||||||
// If EnterpriseCertificateProxySource is not available, fall back to the legacy SecureConnectSource.
|
|
||||||
//
|
|
||||||
// If neither source is available (due to missing configurations), a nil Source and a nil Error are
|
|
||||||
// returned to indicate that a default certificate source is unavailable.
|
|
||||||
func DefaultProvider() (Provider, error) {
|
|
||||||
defaultCert.once.Do(func() {
|
|
||||||
defaultCert.provider, defaultCert.err = NewWorkloadX509CertProvider("")
|
|
||||||
if errors.Is(defaultCert.err, errSourceUnavailable) {
|
|
||||||
defaultCert.provider, defaultCert.err = NewEnterpriseCertificateProxyProvider("")
|
|
||||||
if errors.Is(defaultCert.err, errSourceUnavailable) {
|
|
||||||
defaultCert.provider, defaultCert.err = NewSecureConnectProvider("")
|
|
||||||
if errors.Is(defaultCert.err, errSourceUnavailable) {
|
|
||||||
defaultCert.provider, defaultCert.err = nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return defaultCert.provider, defaultCert.err
|
|
||||||
}
|
|
||||||
54
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/enterprise_cert.go
generated
vendored
54
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/enterprise_cert.go
generated
vendored
@ -1,54 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package cert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
|
|
||||||
"github.com/googleapis/enterprise-certificate-proxy/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ecpSource struct {
|
|
||||||
key *client.Key
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEnterpriseCertificateProxyProvider creates a certificate source
|
|
||||||
// using the Enterprise Certificate Proxy client, which delegates
|
|
||||||
// certifcate related operations to an OS-specific "signer binary"
|
|
||||||
// that communicates with the native keystore (ex. keychain on MacOS).
|
|
||||||
//
|
|
||||||
// The configFilePath points to a config file containing relevant parameters
|
|
||||||
// such as the certificate issuer and the location of the signer binary.
|
|
||||||
// If configFilePath is empty, the client will attempt to load the config from
|
|
||||||
// a well-known gcloud location.
|
|
||||||
func NewEnterpriseCertificateProxyProvider(configFilePath string) (Provider, error) {
|
|
||||||
key, err := client.Cred(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
// TODO(codyoss): once this is fixed upstream can handle this error a
|
|
||||||
// little better here. But be safe for now and assume unavailable.
|
|
||||||
return nil, errSourceUnavailable
|
|
||||||
}
|
|
||||||
|
|
||||||
return (&ecpSource{
|
|
||||||
key: key,
|
|
||||||
}).getClientCertificate, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ecpSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
|
||||||
var cert tls.Certificate
|
|
||||||
cert.PrivateKey = s.key
|
|
||||||
cert.Certificate = s.key.CertificateChain()
|
|
||||||
return &cert, nil
|
|
||||||
}
|
|
||||||
124
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/secureconnect_cert.go
generated
vendored
124
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/secureconnect_cert.go
generated
vendored
@ -1,124 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package cert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
metadataPath = ".secureConnect"
|
|
||||||
metadataFile = "context_aware_metadata.json"
|
|
||||||
)
|
|
||||||
|
|
||||||
type secureConnectSource struct {
|
|
||||||
metadata secureConnectMetadata
|
|
||||||
|
|
||||||
// Cache the cert to avoid executing helper command repeatedly.
|
|
||||||
cachedCertMutex sync.Mutex
|
|
||||||
cachedCert *tls.Certificate
|
|
||||||
}
|
|
||||||
|
|
||||||
type secureConnectMetadata struct {
|
|
||||||
Cmd []string `json:"cert_provider_command"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSecureConnectProvider creates a certificate source using
|
|
||||||
// the Secure Connect Helper and its associated metadata file.
|
|
||||||
//
|
|
||||||
// The configFilePath points to the location of the context aware metadata file.
|
|
||||||
// If configFilePath is empty, use the default context aware metadata location.
|
|
||||||
func NewSecureConnectProvider(configFilePath string) (Provider, error) {
|
|
||||||
if configFilePath == "" {
|
|
||||||
user, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
// Error locating the default config means Secure Connect is not supported.
|
|
||||||
return nil, errSourceUnavailable
|
|
||||||
}
|
|
||||||
configFilePath = filepath.Join(user.HomeDir, metadataPath, metadataFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.ReadFile(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
// Config file missing means Secure Connect is not supported.
|
|
||||||
// There are non-os.ErrNotExist errors that may be returned.
|
|
||||||
// (e.g. if the home directory is /dev/null, *nix systems will
|
|
||||||
// return ENOTDIR instead of ENOENT)
|
|
||||||
return nil, errSourceUnavailable
|
|
||||||
}
|
|
||||||
|
|
||||||
var metadata secureConnectMetadata
|
|
||||||
if err := json.Unmarshal(file, &metadata); err != nil {
|
|
||||||
return nil, fmt.Errorf("cert: could not parse JSON in %q: %w", configFilePath, err)
|
|
||||||
}
|
|
||||||
if err := validateMetadata(metadata); err != nil {
|
|
||||||
return nil, fmt.Errorf("cert: invalid config in %q: %w", configFilePath, err)
|
|
||||||
}
|
|
||||||
return (&secureConnectSource{
|
|
||||||
metadata: metadata,
|
|
||||||
}).getClientCertificate, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateMetadata(metadata secureConnectMetadata) error {
|
|
||||||
if len(metadata.Cmd) == 0 {
|
|
||||||
return errors.New("empty cert_provider_command")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *secureConnectSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
|
||||||
s.cachedCertMutex.Lock()
|
|
||||||
defer s.cachedCertMutex.Unlock()
|
|
||||||
if s.cachedCert != nil && !isCertificateExpired(s.cachedCert) {
|
|
||||||
return s.cachedCert, nil
|
|
||||||
}
|
|
||||||
// Expand OS environment variables in the cert provider command such as "$HOME".
|
|
||||||
for i := 0; i < len(s.metadata.Cmd); i++ {
|
|
||||||
s.metadata.Cmd[i] = os.ExpandEnv(s.metadata.Cmd[i])
|
|
||||||
}
|
|
||||||
command := s.metadata.Cmd
|
|
||||||
data, err := exec.Command(command[0], command[1:]...).Output()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cert, err := tls.X509KeyPair(data, data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s.cachedCert = &cert
|
|
||||||
return &cert, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isCertificateExpired returns true if the given cert is expired or invalid.
|
|
||||||
func isCertificateExpired(cert *tls.Certificate) bool {
|
|
||||||
if len(cert.Certificate) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
parsed, err := x509.ParseCertificate(cert.Certificate[0])
|
|
||||||
if err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return time.Now().After(parsed.NotAfter)
|
|
||||||
}
|
|
||||||
114
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/workload_cert.go
generated
vendored
114
src/server/vendor/cloud.google.com/go/auth/internal/transport/cert/workload_cert.go
generated
vendored
@ -1,114 +0,0 @@
|
|||||||
// Copyright 2024 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package cert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/googleapis/enterprise-certificate-proxy/client/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
type certConfigs struct {
|
|
||||||
Workload *workloadSource `json:"workload"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type workloadSource struct {
|
|
||||||
CertPath string `json:"cert_path"`
|
|
||||||
KeyPath string `json:"key_path"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type certificateConfig struct {
|
|
||||||
CertConfigs certConfigs `json:"cert_configs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWorkloadX509CertProvider creates a certificate source
|
|
||||||
// that reads a certificate and private key file from the local file system.
|
|
||||||
// This is intended to be used for workload identity federation.
|
|
||||||
//
|
|
||||||
// The configFilePath points to a config file containing relevant parameters
|
|
||||||
// such as the certificate and key file paths.
|
|
||||||
// If configFilePath is empty, the client will attempt to load the config from
|
|
||||||
// a well-known gcloud location.
|
|
||||||
func NewWorkloadX509CertProvider(configFilePath string) (Provider, error) {
|
|
||||||
if configFilePath == "" {
|
|
||||||
envFilePath := util.GetConfigFilePathFromEnv()
|
|
||||||
if envFilePath != "" {
|
|
||||||
configFilePath = envFilePath
|
|
||||||
} else {
|
|
||||||
configFilePath = util.GetDefaultConfigFilePath()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
certFile, keyFile, err := getCertAndKeyFiles(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
source := &workloadSource{
|
|
||||||
CertPath: certFile,
|
|
||||||
KeyPath: keyFile,
|
|
||||||
}
|
|
||||||
return source.getClientCertificate, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getClientCertificate attempts to load the certificate and key from the files specified in the
|
|
||||||
// certificate config.
|
|
||||||
func (s *workloadSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
|
||||||
cert, err := tls.LoadX509KeyPair(s.CertPath, s.KeyPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &cert, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCertAndKeyFiles attempts to read the provided config file and return the certificate and private
|
|
||||||
// key file paths.
|
|
||||||
func getCertAndKeyFiles(configFilePath string) (string, string, error) {
|
|
||||||
jsonFile, err := os.Open(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", errSourceUnavailable
|
|
||||||
}
|
|
||||||
|
|
||||||
byteValue, err := io.ReadAll(jsonFile)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var config certificateConfig
|
|
||||||
if err := json.Unmarshal(byteValue, &config); err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.CertConfigs.Workload == nil {
|
|
||||||
return "", "", errSourceUnavailable
|
|
||||||
}
|
|
||||||
|
|
||||||
certFile := config.CertConfigs.Workload.CertPath
|
|
||||||
keyFile := config.CertConfigs.Workload.KeyPath
|
|
||||||
|
|
||||||
if certFile == "" {
|
|
||||||
return "", "", errors.New("certificate configuration is missing the certificate file location")
|
|
||||||
}
|
|
||||||
|
|
||||||
if keyFile == "" {
|
|
||||||
return "", "", errors.New("certificate configuration is missing the key file location")
|
|
||||||
}
|
|
||||||
|
|
||||||
return certFile, keyFile, nil
|
|
||||||
}
|
|
||||||
138
src/server/vendor/cloud.google.com/go/auth/internal/transport/s2a.go
generated
vendored
138
src/server/vendor/cloud.google.com/go/auth/internal/transport/s2a.go
generated
vendored
@ -1,138 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal/transport/cert"
|
|
||||||
"cloud.google.com/go/compute/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
configEndpointSuffix = "instance/platform-security/auto-mtls-configuration"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
mtlsConfiguration *mtlsConfig
|
|
||||||
|
|
||||||
mtlsOnce sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetS2AAddress returns the S2A address to be reached via plaintext connection.
|
|
||||||
// Returns empty string if not set or invalid.
|
|
||||||
func GetS2AAddress(logger *slog.Logger) string {
|
|
||||||
getMetadataMTLSAutoConfig(logger)
|
|
||||||
if !mtlsConfiguration.valid() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return mtlsConfiguration.S2A.PlaintextAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMTLSS2AAddress returns the S2A address to be reached via MTLS connection.
|
|
||||||
// Returns empty string if not set or invalid.
|
|
||||||
func GetMTLSS2AAddress(logger *slog.Logger) string {
|
|
||||||
getMetadataMTLSAutoConfig(logger)
|
|
||||||
if !mtlsConfiguration.valid() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return mtlsConfiguration.S2A.MTLSAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
// mtlsConfig contains the configuration for establishing MTLS connections with Google APIs.
|
|
||||||
type mtlsConfig struct {
|
|
||||||
S2A *s2aAddresses `json:"s2a"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *mtlsConfig) valid() bool {
|
|
||||||
return c != nil && c.S2A != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// s2aAddresses contains the plaintext and/or MTLS S2A addresses.
|
|
||||||
type s2aAddresses struct {
|
|
||||||
// PlaintextAddress is the plaintext address to reach S2A
|
|
||||||
PlaintextAddress string `json:"plaintext_address"`
|
|
||||||
// MTLSAddress is the MTLS address to reach S2A
|
|
||||||
MTLSAddress string `json:"mtls_address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMetadataMTLSAutoConfig(logger *slog.Logger) {
|
|
||||||
var err error
|
|
||||||
mtlsOnce.Do(func() {
|
|
||||||
mtlsConfiguration, err = queryConfig(logger)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Getting MTLS config failed: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var httpGetMetadataMTLSConfig = func(logger *slog.Logger) (string, error) {
|
|
||||||
metadataClient := metadata.NewWithOptions(&metadata.Options{
|
|
||||||
Logger: logger,
|
|
||||||
})
|
|
||||||
return metadataClient.GetWithContext(context.Background(), configEndpointSuffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
func queryConfig(logger *slog.Logger) (*mtlsConfig, error) {
|
|
||||||
resp, err := httpGetMetadataMTLSConfig(logger)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("querying MTLS config from MDS endpoint failed: %w", err)
|
|
||||||
}
|
|
||||||
var config mtlsConfig
|
|
||||||
err = json.Unmarshal([]byte(resp), &config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unmarshalling MTLS config from MDS endpoint failed: %w", err)
|
|
||||||
}
|
|
||||||
if config.S2A == nil {
|
|
||||||
return nil, fmt.Errorf("returned MTLS config from MDS endpoint is invalid: %v", config)
|
|
||||||
}
|
|
||||||
return &config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldUseS2A(clientCertSource cert.Provider, opts *Options) bool {
|
|
||||||
// If client cert is found, use that over S2A.
|
|
||||||
if clientCertSource != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// If EXPERIMENTAL_GOOGLE_API_USE_S2A is not set to true, skip S2A.
|
|
||||||
if !isGoogleS2AEnabled() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// If DefaultMTLSEndpoint is not set or has endpoint override, skip S2A.
|
|
||||||
if opts.DefaultMTLSEndpoint == "" || opts.Endpoint != "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// If custom HTTP client is provided, skip S2A.
|
|
||||||
if opts.Client != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// If directPath is enabled, skip S2A.
|
|
||||||
return !opts.EnableDirectPath && !opts.EnableDirectPathXds
|
|
||||||
}
|
|
||||||
|
|
||||||
func isGoogleS2AEnabled() bool {
|
|
||||||
b, err := strconv.ParseBool(os.Getenv(googleAPIUseS2AEnv))
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
106
src/server/vendor/cloud.google.com/go/auth/internal/transport/transport.go
generated
vendored
106
src/server/vendor/cloud.google.com/go/auth/internal/transport/transport.go
generated
vendored
@ -1,106 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package transport provided internal helpers for the two transport packages
|
|
||||||
// (grpctransport and httptransport).
|
|
||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/credentials"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CloneDetectOptions clones a user set detect option into some new memory that
|
|
||||||
// we can internally manipulate before sending onto the detect package.
|
|
||||||
func CloneDetectOptions(oldDo *credentials.DetectOptions) *credentials.DetectOptions {
|
|
||||||
if oldDo == nil {
|
|
||||||
// it is valid for users not to set this, but we will need to to default
|
|
||||||
// some options for them in this case so return some initialized memory
|
|
||||||
// to work with.
|
|
||||||
return &credentials.DetectOptions{}
|
|
||||||
}
|
|
||||||
newDo := &credentials.DetectOptions{
|
|
||||||
// Simple types
|
|
||||||
Audience: oldDo.Audience,
|
|
||||||
Subject: oldDo.Subject,
|
|
||||||
EarlyTokenRefresh: oldDo.EarlyTokenRefresh,
|
|
||||||
TokenURL: oldDo.TokenURL,
|
|
||||||
STSAudience: oldDo.STSAudience,
|
|
||||||
CredentialsFile: oldDo.CredentialsFile,
|
|
||||||
UseSelfSignedJWT: oldDo.UseSelfSignedJWT,
|
|
||||||
UniverseDomain: oldDo.UniverseDomain,
|
|
||||||
|
|
||||||
// These fields are are pointer types that we just want to use exactly
|
|
||||||
// as the user set, copy the ref
|
|
||||||
Client: oldDo.Client,
|
|
||||||
Logger: oldDo.Logger,
|
|
||||||
AuthHandlerOptions: oldDo.AuthHandlerOptions,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Smartly size this memory and copy below.
|
|
||||||
if len(oldDo.CredentialsJSON) > 0 {
|
|
||||||
newDo.CredentialsJSON = make([]byte, len(oldDo.CredentialsJSON))
|
|
||||||
copy(newDo.CredentialsJSON, oldDo.CredentialsJSON)
|
|
||||||
}
|
|
||||||
if len(oldDo.Scopes) > 0 {
|
|
||||||
newDo.Scopes = make([]string, len(oldDo.Scopes))
|
|
||||||
copy(newDo.Scopes, oldDo.Scopes)
|
|
||||||
}
|
|
||||||
|
|
||||||
return newDo
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateUniverseDomain verifies that the universe domain configured for the
|
|
||||||
// client matches the universe domain configured for the credentials.
|
|
||||||
func ValidateUniverseDomain(clientUniverseDomain, credentialsUniverseDomain string) error {
|
|
||||||
if clientUniverseDomain != credentialsUniverseDomain {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"the configured universe domain (%q) does not match the universe "+
|
|
||||||
"domain found in the credentials (%q). If you haven't configured "+
|
|
||||||
"the universe domain explicitly, \"googleapis.com\" is the default",
|
|
||||||
clientUniverseDomain,
|
|
||||||
credentialsUniverseDomain)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultHTTPClientWithTLS constructs an HTTPClient using the provided tlsConfig, to support mTLS.
|
|
||||||
func DefaultHTTPClientWithTLS(tlsConfig *tls.Config) *http.Client {
|
|
||||||
trans := BaseTransport()
|
|
||||||
trans.TLSClientConfig = tlsConfig
|
|
||||||
return &http.Client{Transport: trans}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BaseTransport returns a default [http.Transport] which can be used if
|
|
||||||
// [http.DefaultTransport] has been overwritten.
|
|
||||||
func BaseTransport() *http.Transport {
|
|
||||||
return &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
DialContext: (&net.Dialer{
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
KeepAlive: 30 * time.Second,
|
|
||||||
DualStack: true,
|
|
||||||
}).DialContext,
|
|
||||||
MaxIdleConns: 100,
|
|
||||||
MaxIdleConnsPerHost: 100,
|
|
||||||
IdleConnTimeout: 90 * time.Second,
|
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
75
src/server/vendor/cloud.google.com/go/auth/oauth2adapt/CHANGES.md
generated
vendored
75
src/server/vendor/cloud.google.com/go/auth/oauth2adapt/CHANGES.md
generated
vendored
@ -1,75 +0,0 @@
|
|||||||
# Changelog
|
|
||||||
|
|
||||||
## [0.2.7](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.6...auth/oauth2adapt/v0.2.7) (2025-01-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
|
|
||||||
|
|
||||||
## [0.2.6](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.5...auth/oauth2adapt/v0.2.6) (2024-11-21)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Copy map in tokenSourceAdapter.Token ([#11164](https://github.com/googleapis/google-cloud-go/issues/11164)) ([8cb0cbc](https://github.com/googleapis/google-cloud-go/commit/8cb0cbccdc32886dfb3af49fee04012937d114d2)), refs [#11161](https://github.com/googleapis/google-cloud-go/issues/11161)
|
|
||||||
|
|
||||||
## [0.2.5](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.4...auth/oauth2adapt/v0.2.5) (2024-10-30)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Convert token metadata where possible ([#11062](https://github.com/googleapis/google-cloud-go/issues/11062)) ([34bf1c1](https://github.com/googleapis/google-cloud-go/commit/34bf1c164465d66745c0cfdf7cd10a8e2da92e52))
|
|
||||||
|
|
||||||
## [0.2.4](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.3...auth/oauth2adapt/v0.2.4) (2024-08-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
|
||||||
|
|
||||||
## [0.2.3](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.2...auth/oauth2adapt/v0.2.3) (2024-07-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Bump google.golang.org/api@v0.187.0 ([8fa9e39](https://github.com/googleapis/google-cloud-go/commit/8fa9e398e512fd8533fd49060371e61b5725a85b))
|
|
||||||
|
|
||||||
## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.1...auth/oauth2adapt/v0.2.2) (2024-04-23)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Bump x/net to v0.24.0 ([ba31ed5](https://github.com/googleapis/google-cloud-go/commit/ba31ed5fda2c9664f2e1cf972469295e63deb5b4))
|
|
||||||
|
|
||||||
## [0.2.1](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.0...auth/oauth2adapt/v0.2.1) (2024-04-18)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Adapt Token Types to be translated ([#9801](https://github.com/googleapis/google-cloud-go/issues/9801)) ([70f4115](https://github.com/googleapis/google-cloud-go/commit/70f411555ebbf2b71e6d425cc8d2030644c6b438)), refs [#9800](https://github.com/googleapis/google-cloud-go/issues/9800)
|
|
||||||
|
|
||||||
## [0.2.0](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.1.0...auth/oauth2adapt/v0.2.0) (2024-04-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Add helpers for working with credentials types ([#9694](https://github.com/googleapis/google-cloud-go/issues/9694)) ([cf33b55](https://github.com/googleapis/google-cloud-go/commit/cf33b5514423a2ac5c2a323a1cd99aac34fd4233))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update protobuf dep to v1.33.0 ([30b038d](https://github.com/googleapis/google-cloud-go/commit/30b038d8cac0b8cd5dd4761c87f3f298760dd33a))
|
|
||||||
|
|
||||||
## 0.1.0 (2023-10-19)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Adds a new module to translate types ([#8595](https://github.com/googleapis/google-cloud-go/issues/8595)) ([6933c5a](https://github.com/googleapis/google-cloud-go/commit/6933c5a0c1fc8e58cbfff8bbca439d671b94672f))
|
|
||||||
* **auth/oauth2adapt:** Fixup deps for release ([#8747](https://github.com/googleapis/google-cloud-go/issues/8747)) ([749d243](https://github.com/googleapis/google-cloud-go/commit/749d243862b025a6487a4d2d339219889b4cfe70))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **auth/oauth2adapt:** Update golang.org/x/net to v0.17.0 ([174da47](https://github.com/googleapis/google-cloud-go/commit/174da47254fefb12921bbfc65b7829a453af6f5d))
|
|
||||||
202
src/server/vendor/cloud.google.com/go/auth/oauth2adapt/LICENSE
generated
vendored
202
src/server/vendor/cloud.google.com/go/auth/oauth2adapt/LICENSE
generated
vendored
@ -1,202 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
200
src/server/vendor/cloud.google.com/go/auth/oauth2adapt/oauth2adapt.go
generated
vendored
200
src/server/vendor/cloud.google.com/go/auth/oauth2adapt/oauth2adapt.go
generated
vendored
@ -1,200 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package oauth2adapt helps converts types used in [cloud.google.com/go/auth]
|
|
||||||
// and [golang.org/x/oauth2].
|
|
||||||
package oauth2adapt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth"
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
"golang.org/x/oauth2/google"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
oauth2TokenSourceKey = "oauth2.google.tokenSource"
|
|
||||||
oauth2ServiceAccountKey = "oauth2.google.serviceAccount"
|
|
||||||
authTokenSourceKey = "auth.google.tokenSource"
|
|
||||||
authServiceAccountKey = "auth.google.serviceAccount"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TokenProviderFromTokenSource converts any [golang.org/x/oauth2.TokenSource]
|
|
||||||
// into a [cloud.google.com/go/auth.TokenProvider].
|
|
||||||
func TokenProviderFromTokenSource(ts oauth2.TokenSource) auth.TokenProvider {
|
|
||||||
return &tokenProviderAdapter{ts: ts}
|
|
||||||
}
|
|
||||||
|
|
||||||
type tokenProviderAdapter struct {
|
|
||||||
ts oauth2.TokenSource
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token fulfills the [cloud.google.com/go/auth.TokenProvider] interface. It
|
|
||||||
// is a light wrapper around the underlying TokenSource.
|
|
||||||
func (tp *tokenProviderAdapter) Token(context.Context) (*auth.Token, error) {
|
|
||||||
tok, err := tp.ts.Token()
|
|
||||||
if err != nil {
|
|
||||||
var err2 *oauth2.RetrieveError
|
|
||||||
if ok := errors.As(err, &err2); ok {
|
|
||||||
return nil, AuthErrorFromRetrieveError(err2)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Preserve compute token metadata, for both types of tokens.
|
|
||||||
metadata := map[string]interface{}{}
|
|
||||||
if val, ok := tok.Extra(oauth2TokenSourceKey).(string); ok {
|
|
||||||
metadata[authTokenSourceKey] = val
|
|
||||||
metadata[oauth2TokenSourceKey] = val
|
|
||||||
}
|
|
||||||
if val, ok := tok.Extra(oauth2ServiceAccountKey).(string); ok {
|
|
||||||
metadata[authServiceAccountKey] = val
|
|
||||||
metadata[oauth2ServiceAccountKey] = val
|
|
||||||
}
|
|
||||||
return &auth.Token{
|
|
||||||
Value: tok.AccessToken,
|
|
||||||
Type: tok.Type(),
|
|
||||||
Expiry: tok.Expiry,
|
|
||||||
Metadata: metadata,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenSourceFromTokenProvider converts any
|
|
||||||
// [cloud.google.com/go/auth.TokenProvider] into a
|
|
||||||
// [golang.org/x/oauth2.TokenSource].
|
|
||||||
func TokenSourceFromTokenProvider(tp auth.TokenProvider) oauth2.TokenSource {
|
|
||||||
return &tokenSourceAdapter{tp: tp}
|
|
||||||
}
|
|
||||||
|
|
||||||
type tokenSourceAdapter struct {
|
|
||||||
tp auth.TokenProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token fulfills the [golang.org/x/oauth2.TokenSource] interface. It
|
|
||||||
// is a light wrapper around the underlying TokenProvider.
|
|
||||||
func (ts *tokenSourceAdapter) Token() (*oauth2.Token, error) {
|
|
||||||
tok, err := ts.tp.Token(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
var err2 *auth.Error
|
|
||||||
if ok := errors.As(err, &err2); ok {
|
|
||||||
return nil, AddRetrieveErrorToAuthError(err2)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tok2 := &oauth2.Token{
|
|
||||||
AccessToken: tok.Value,
|
|
||||||
TokenType: tok.Type,
|
|
||||||
Expiry: tok.Expiry,
|
|
||||||
}
|
|
||||||
// Preserve token metadata.
|
|
||||||
m := tok.Metadata
|
|
||||||
if m != nil {
|
|
||||||
// Copy map to avoid concurrent map writes error (#11161).
|
|
||||||
metadata := make(map[string]interface{}, len(m)+2)
|
|
||||||
for k, v := range m {
|
|
||||||
metadata[k] = v
|
|
||||||
}
|
|
||||||
// Append compute token metadata in converted form.
|
|
||||||
if val, ok := metadata[authTokenSourceKey].(string); ok && val != "" {
|
|
||||||
metadata[oauth2TokenSourceKey] = val
|
|
||||||
}
|
|
||||||
if val, ok := metadata[authServiceAccountKey].(string); ok && val != "" {
|
|
||||||
metadata[oauth2ServiceAccountKey] = val
|
|
||||||
}
|
|
||||||
tok2 = tok2.WithExtra(metadata)
|
|
||||||
}
|
|
||||||
return tok2, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthCredentialsFromOauth2Credentials converts a [golang.org/x/oauth2/google.Credentials]
|
|
||||||
// to a [cloud.google.com/go/auth.Credentials].
|
|
||||||
func AuthCredentialsFromOauth2Credentials(creds *google.Credentials) *auth.Credentials {
|
|
||||||
if creds == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return auth.NewCredentials(&auth.CredentialsOptions{
|
|
||||||
TokenProvider: TokenProviderFromTokenSource(creds.TokenSource),
|
|
||||||
JSON: creds.JSON,
|
|
||||||
ProjectIDProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
|
|
||||||
return creds.ProjectID, nil
|
|
||||||
}),
|
|
||||||
UniverseDomainProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
|
|
||||||
return creds.GetUniverseDomain()
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Oauth2CredentialsFromAuthCredentials converts a [cloud.google.com/go/auth.Credentials]
|
|
||||||
// to a [golang.org/x/oauth2/google.Credentials].
|
|
||||||
func Oauth2CredentialsFromAuthCredentials(creds *auth.Credentials) *google.Credentials {
|
|
||||||
if creds == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Throw away errors as old credentials are not request aware. Also, no
|
|
||||||
// network requests are currently happening for this use case.
|
|
||||||
projectID, _ := creds.ProjectID(context.Background())
|
|
||||||
|
|
||||||
return &google.Credentials{
|
|
||||||
TokenSource: TokenSourceFromTokenProvider(creds.TokenProvider),
|
|
||||||
ProjectID: projectID,
|
|
||||||
JSON: creds.JSON(),
|
|
||||||
UniverseDomainProvider: func() (string, error) {
|
|
||||||
return creds.UniverseDomain(context.Background())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type oauth2Error struct {
|
|
||||||
ErrorCode string `json:"error"`
|
|
||||||
ErrorDescription string `json:"error_description"`
|
|
||||||
ErrorURI string `json:"error_uri"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRetrieveErrorToAuthError returns the same error provided and adds a
|
|
||||||
// [golang.org/x/oauth2.RetrieveError] to the error chain by setting the `Err` field on the
|
|
||||||
// [cloud.google.com/go/auth.Error].
|
|
||||||
func AddRetrieveErrorToAuthError(err *auth.Error) *auth.Error {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
e := &oauth2.RetrieveError{
|
|
||||||
Response: err.Response,
|
|
||||||
Body: err.Body,
|
|
||||||
}
|
|
||||||
err.Err = e
|
|
||||||
if len(err.Body) > 0 {
|
|
||||||
var oErr oauth2Error
|
|
||||||
// ignore the error as it only fills in extra details
|
|
||||||
json.Unmarshal(err.Body, &oErr)
|
|
||||||
e.ErrorCode = oErr.ErrorCode
|
|
||||||
e.ErrorDescription = oErr.ErrorDescription
|
|
||||||
e.ErrorURI = oErr.ErrorURI
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthErrorFromRetrieveError returns an [cloud.google.com/go/auth.Error] that
|
|
||||||
// wraps the provided [golang.org/x/oauth2.RetrieveError].
|
|
||||||
func AuthErrorFromRetrieveError(err *oauth2.RetrieveError) *auth.Error {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &auth.Error{
|
|
||||||
Response: err.Response,
|
|
||||||
Body: err.Body,
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
382
src/server/vendor/cloud.google.com/go/auth/threelegged.go
generated
vendored
382
src/server/vendor/cloud.google.com/go/auth/threelegged.go
generated
vendored
@ -1,382 +0,0 @@
|
|||||||
// Copyright 2023 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/auth/internal"
|
|
||||||
"github.com/googleapis/gax-go/v2/internallog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AuthorizationHandler is a 3-legged-OAuth helper that prompts the user for
|
|
||||||
// OAuth consent at the specified auth code URL and returns an auth code and
|
|
||||||
// state upon approval.
|
|
||||||
type AuthorizationHandler func(authCodeURL string) (code string, state string, err error)
|
|
||||||
|
|
||||||
// Options3LO are the options for doing a 3-legged OAuth2 flow.
|
|
||||||
type Options3LO struct {
|
|
||||||
// ClientID is the application's ID.
|
|
||||||
ClientID string
|
|
||||||
// ClientSecret is the application's secret. Not required if AuthHandlerOpts
|
|
||||||
// is set.
|
|
||||||
ClientSecret string
|
|
||||||
// AuthURL is the URL for authenticating.
|
|
||||||
AuthURL string
|
|
||||||
// TokenURL is the URL for retrieving a token.
|
|
||||||
TokenURL string
|
|
||||||
// AuthStyle is used to describe how to client info in the token request.
|
|
||||||
AuthStyle Style
|
|
||||||
// RefreshToken is the token used to refresh the credential. Not required
|
|
||||||
// if AuthHandlerOpts is set.
|
|
||||||
RefreshToken string
|
|
||||||
// RedirectURL is the URL to redirect users to. Optional.
|
|
||||||
RedirectURL string
|
|
||||||
// Scopes specifies requested permissions for the Token. Optional.
|
|
||||||
Scopes []string
|
|
||||||
|
|
||||||
// URLParams are the set of values to apply to the token exchange. Optional.
|
|
||||||
URLParams url.Values
|
|
||||||
// Client is the client to be used to make the underlying token requests.
|
|
||||||
// Optional.
|
|
||||||
Client *http.Client
|
|
||||||
// EarlyTokenExpiry is the time before the token expires that it should be
|
|
||||||
// refreshed. If not set the default value is 3 minutes and 45 seconds.
|
|
||||||
// Optional.
|
|
||||||
EarlyTokenExpiry time.Duration
|
|
||||||
|
|
||||||
// AuthHandlerOpts provides a set of options for doing a
|
|
||||||
// 3-legged OAuth2 flow with a custom [AuthorizationHandler]. Optional.
|
|
||||||
AuthHandlerOpts *AuthorizationHandlerOptions
|
|
||||||
// Logger is used for debug logging. If provided, logging will be enabled
|
|
||||||
// at the loggers configured level. By default logging is disabled unless
|
|
||||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
|
||||||
// logger will be used. Optional.
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options3LO) validate() error {
|
|
||||||
if o == nil {
|
|
||||||
return errors.New("auth: options must be provided")
|
|
||||||
}
|
|
||||||
if o.ClientID == "" {
|
|
||||||
return errors.New("auth: client ID must be provided")
|
|
||||||
}
|
|
||||||
if o.AuthHandlerOpts == nil && o.ClientSecret == "" {
|
|
||||||
return errors.New("auth: client secret must be provided")
|
|
||||||
}
|
|
||||||
if o.AuthURL == "" {
|
|
||||||
return errors.New("auth: auth URL must be provided")
|
|
||||||
}
|
|
||||||
if o.TokenURL == "" {
|
|
||||||
return errors.New("auth: token URL must be provided")
|
|
||||||
}
|
|
||||||
if o.AuthStyle == StyleUnknown {
|
|
||||||
return errors.New("auth: auth style must be provided")
|
|
||||||
}
|
|
||||||
if o.AuthHandlerOpts == nil && o.RefreshToken == "" {
|
|
||||||
return errors.New("auth: refresh token must be provided")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options3LO) logger() *slog.Logger {
|
|
||||||
return internallog.New(o.Logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PKCEOptions holds parameters to support PKCE.
|
|
||||||
type PKCEOptions struct {
|
|
||||||
// Challenge is the un-padded, base64-url-encoded string of the encrypted code verifier.
|
|
||||||
Challenge string // The un-padded, base64-url-encoded string of the encrypted code verifier.
|
|
||||||
// ChallengeMethod is the encryption method (ex. S256).
|
|
||||||
ChallengeMethod string
|
|
||||||
// Verifier is the original, non-encrypted secret.
|
|
||||||
Verifier string // The original, non-encrypted secret.
|
|
||||||
}
|
|
||||||
|
|
||||||
type tokenJSON struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
ExpiresIn int `json:"expires_in"`
|
|
||||||
// error fields
|
|
||||||
ErrorCode string `json:"error"`
|
|
||||||
ErrorDescription string `json:"error_description"`
|
|
||||||
ErrorURI string `json:"error_uri"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *tokenJSON) expiry() (t time.Time) {
|
|
||||||
if v := e.ExpiresIn; v != 0 {
|
|
||||||
return time.Now().Add(time.Duration(v) * time.Second)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options3LO) client() *http.Client {
|
|
||||||
if o.Client != nil {
|
|
||||||
return o.Client
|
|
||||||
}
|
|
||||||
return internal.DefaultClient()
|
|
||||||
}
|
|
||||||
|
|
||||||
// authCodeURL returns a URL that points to a OAuth2 consent page.
|
|
||||||
func (o *Options3LO) authCodeURL(state string, values url.Values) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
buf.WriteString(o.AuthURL)
|
|
||||||
v := url.Values{
|
|
||||||
"response_type": {"code"},
|
|
||||||
"client_id": {o.ClientID},
|
|
||||||
}
|
|
||||||
if o.RedirectURL != "" {
|
|
||||||
v.Set("redirect_uri", o.RedirectURL)
|
|
||||||
}
|
|
||||||
if len(o.Scopes) > 0 {
|
|
||||||
v.Set("scope", strings.Join(o.Scopes, " "))
|
|
||||||
}
|
|
||||||
if state != "" {
|
|
||||||
v.Set("state", state)
|
|
||||||
}
|
|
||||||
if o.AuthHandlerOpts != nil {
|
|
||||||
if o.AuthHandlerOpts.PKCEOpts != nil &&
|
|
||||||
o.AuthHandlerOpts.PKCEOpts.Challenge != "" {
|
|
||||||
v.Set(codeChallengeKey, o.AuthHandlerOpts.PKCEOpts.Challenge)
|
|
||||||
}
|
|
||||||
if o.AuthHandlerOpts.PKCEOpts != nil &&
|
|
||||||
o.AuthHandlerOpts.PKCEOpts.ChallengeMethod != "" {
|
|
||||||
v.Set(codeChallengeMethodKey, o.AuthHandlerOpts.PKCEOpts.ChallengeMethod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k := range values {
|
|
||||||
v.Set(k, v.Get(k))
|
|
||||||
}
|
|
||||||
if strings.Contains(o.AuthURL, "?") {
|
|
||||||
buf.WriteByte('&')
|
|
||||||
} else {
|
|
||||||
buf.WriteByte('?')
|
|
||||||
}
|
|
||||||
buf.WriteString(v.Encode())
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// New3LOTokenProvider returns a [TokenProvider] based on the 3-legged OAuth2
|
|
||||||
// configuration. The TokenProvider is caches and auto-refreshes tokens by
|
|
||||||
// default.
|
|
||||||
func New3LOTokenProvider(opts *Options3LO) (TokenProvider, error) {
|
|
||||||
if err := opts.validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if opts.AuthHandlerOpts != nil {
|
|
||||||
return new3LOTokenProviderWithAuthHandler(opts), nil
|
|
||||||
}
|
|
||||||
return NewCachedTokenProvider(&tokenProvider3LO{opts: opts, refreshToken: opts.RefreshToken, client: opts.client()}, &CachedTokenProviderOptions{
|
|
||||||
ExpireEarly: opts.EarlyTokenExpiry,
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthorizationHandlerOptions provides a set of options to specify for doing a
|
|
||||||
// 3-legged OAuth2 flow with a custom [AuthorizationHandler].
|
|
||||||
type AuthorizationHandlerOptions struct {
|
|
||||||
// AuthorizationHandler specifies the handler used to for the authorization
|
|
||||||
// part of the flow.
|
|
||||||
Handler AuthorizationHandler
|
|
||||||
// State is used verify that the "state" is identical in the request and
|
|
||||||
// response before exchanging the auth code for OAuth2 token.
|
|
||||||
State string
|
|
||||||
// PKCEOpts allows setting configurations for PKCE. Optional.
|
|
||||||
PKCEOpts *PKCEOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func new3LOTokenProviderWithAuthHandler(opts *Options3LO) TokenProvider {
|
|
||||||
return NewCachedTokenProvider(&tokenProviderWithHandler{opts: opts, state: opts.AuthHandlerOpts.State}, &CachedTokenProviderOptions{
|
|
||||||
ExpireEarly: opts.EarlyTokenExpiry,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// exchange handles the final exchange portion of the 3lo flow. Returns a Token,
|
|
||||||
// refreshToken, and error.
|
|
||||||
func (o *Options3LO) exchange(ctx context.Context, code string) (*Token, string, error) {
|
|
||||||
// Build request
|
|
||||||
v := url.Values{
|
|
||||||
"grant_type": {"authorization_code"},
|
|
||||||
"code": {code},
|
|
||||||
}
|
|
||||||
if o.RedirectURL != "" {
|
|
||||||
v.Set("redirect_uri", o.RedirectURL)
|
|
||||||
}
|
|
||||||
if o.AuthHandlerOpts != nil &&
|
|
||||||
o.AuthHandlerOpts.PKCEOpts != nil &&
|
|
||||||
o.AuthHandlerOpts.PKCEOpts.Verifier != "" {
|
|
||||||
v.Set(codeVerifierKey, o.AuthHandlerOpts.PKCEOpts.Verifier)
|
|
||||||
}
|
|
||||||
for k := range o.URLParams {
|
|
||||||
v.Set(k, o.URLParams.Get(k))
|
|
||||||
}
|
|
||||||
return fetchToken(ctx, o, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This struct is not safe for concurrent access alone, but the way it is used
|
|
||||||
// in this package by wrapping it with a cachedTokenProvider makes it so.
|
|
||||||
type tokenProvider3LO struct {
|
|
||||||
opts *Options3LO
|
|
||||||
client *http.Client
|
|
||||||
refreshToken string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *tokenProvider3LO) Token(ctx context.Context) (*Token, error) {
|
|
||||||
if tp.refreshToken == "" {
|
|
||||||
return nil, errors.New("auth: token expired and refresh token is not set")
|
|
||||||
}
|
|
||||||
v := url.Values{
|
|
||||||
"grant_type": {"refresh_token"},
|
|
||||||
"refresh_token": {tp.refreshToken},
|
|
||||||
}
|
|
||||||
for k := range tp.opts.URLParams {
|
|
||||||
v.Set(k, tp.opts.URLParams.Get(k))
|
|
||||||
}
|
|
||||||
|
|
||||||
tk, rt, err := fetchToken(ctx, tp.opts, v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if tp.refreshToken != rt && rt != "" {
|
|
||||||
tp.refreshToken = rt
|
|
||||||
}
|
|
||||||
return tk, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type tokenProviderWithHandler struct {
|
|
||||||
opts *Options3LO
|
|
||||||
state string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp tokenProviderWithHandler) Token(ctx context.Context) (*Token, error) {
|
|
||||||
url := tp.opts.authCodeURL(tp.state, nil)
|
|
||||||
code, state, err := tp.opts.AuthHandlerOpts.Handler(url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if state != tp.state {
|
|
||||||
return nil, errors.New("auth: state mismatch in 3-legged-OAuth flow")
|
|
||||||
}
|
|
||||||
tok, _, err := tp.opts.exchange(ctx, code)
|
|
||||||
return tok, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetchToken returns a Token, refresh token, and/or an error.
|
|
||||||
func fetchToken(ctx context.Context, o *Options3LO, v url.Values) (*Token, string, error) {
|
|
||||||
var refreshToken string
|
|
||||||
if o.AuthStyle == StyleInParams {
|
|
||||||
if o.ClientID != "" {
|
|
||||||
v.Set("client_id", o.ClientID)
|
|
||||||
}
|
|
||||||
if o.ClientSecret != "" {
|
|
||||||
v.Set("client_secret", o.ClientSecret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", o.TokenURL, strings.NewReader(v.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, refreshToken, err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
if o.AuthStyle == StyleInHeader {
|
|
||||||
req.SetBasicAuth(url.QueryEscape(o.ClientID), url.QueryEscape(o.ClientSecret))
|
|
||||||
}
|
|
||||||
logger := o.logger()
|
|
||||||
|
|
||||||
logger.DebugContext(ctx, "3LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
|
||||||
// Make request
|
|
||||||
resp, body, err := internal.DoRequest(o.client(), req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, refreshToken, err
|
|
||||||
}
|
|
||||||
logger.DebugContext(ctx, "3LO token response", "response", internallog.HTTPResponse(resp, body))
|
|
||||||
failureStatus := resp.StatusCode < 200 || resp.StatusCode > 299
|
|
||||||
tokError := &Error{
|
|
||||||
Response: resp,
|
|
||||||
Body: body,
|
|
||||||
}
|
|
||||||
|
|
||||||
var token *Token
|
|
||||||
// errors ignored because of default switch on content
|
|
||||||
content, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
|
||||||
switch content {
|
|
||||||
case "application/x-www-form-urlencoded", "text/plain":
|
|
||||||
// some endpoints return a query string
|
|
||||||
vals, err := url.ParseQuery(string(body))
|
|
||||||
if err != nil {
|
|
||||||
if failureStatus {
|
|
||||||
return nil, refreshToken, tokError
|
|
||||||
}
|
|
||||||
return nil, refreshToken, fmt.Errorf("auth: cannot parse response: %w", err)
|
|
||||||
}
|
|
||||||
tokError.code = vals.Get("error")
|
|
||||||
tokError.description = vals.Get("error_description")
|
|
||||||
tokError.uri = vals.Get("error_uri")
|
|
||||||
token = &Token{
|
|
||||||
Value: vals.Get("access_token"),
|
|
||||||
Type: vals.Get("token_type"),
|
|
||||||
Metadata: make(map[string]interface{}, len(vals)),
|
|
||||||
}
|
|
||||||
for k, v := range vals {
|
|
||||||
token.Metadata[k] = v
|
|
||||||
}
|
|
||||||
refreshToken = vals.Get("refresh_token")
|
|
||||||
e := vals.Get("expires_in")
|
|
||||||
expires, _ := strconv.Atoi(e)
|
|
||||||
if expires != 0 {
|
|
||||||
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
var tj tokenJSON
|
|
||||||
if err = json.Unmarshal(body, &tj); err != nil {
|
|
||||||
if failureStatus {
|
|
||||||
return nil, refreshToken, tokError
|
|
||||||
}
|
|
||||||
return nil, refreshToken, fmt.Errorf("auth: cannot parse json: %w", err)
|
|
||||||
}
|
|
||||||
tokError.code = tj.ErrorCode
|
|
||||||
tokError.description = tj.ErrorDescription
|
|
||||||
tokError.uri = tj.ErrorURI
|
|
||||||
token = &Token{
|
|
||||||
Value: tj.AccessToken,
|
|
||||||
Type: tj.TokenType,
|
|
||||||
Expiry: tj.expiry(),
|
|
||||||
Metadata: make(map[string]interface{}),
|
|
||||||
}
|
|
||||||
json.Unmarshal(body, &token.Metadata) // optional field, skip err check
|
|
||||||
refreshToken = tj.RefreshToken
|
|
||||||
}
|
|
||||||
// according to spec, servers should respond status 400 in error case
|
|
||||||
// https://www.rfc-editor.org/rfc/rfc6749#section-5.2
|
|
||||||
// but some unorthodox servers respond 200 in error case
|
|
||||||
if failureStatus || tokError.code != "" {
|
|
||||||
return nil, refreshToken, tokError
|
|
||||||
}
|
|
||||||
if token.Value == "" {
|
|
||||||
return nil, refreshToken, errors.New("auth: server response missing access_token")
|
|
||||||
}
|
|
||||||
return token, refreshToken, nil
|
|
||||||
}
|
|
||||||
66
src/server/vendor/cloud.google.com/go/compute/metadata/CHANGES.md
generated
vendored
66
src/server/vendor/cloud.google.com/go/compute/metadata/CHANGES.md
generated
vendored
@ -1,66 +0,0 @@
|
|||||||
# Changes
|
|
||||||
|
|
||||||
## [0.6.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.2...compute/metadata/v0.6.0) (2024-12-13)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **compute/metadata:** Add debug logging ([#11078](https://github.com/googleapis/google-cloud-go/issues/11078)) ([a816814](https://github.com/googleapis/google-cloud-go/commit/a81681463906e4473570a2f426eb0dc2de64e53f))
|
|
||||||
|
|
||||||
## [0.5.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.1...compute/metadata/v0.5.2) (2024-09-20)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compute/metadata:** Close Response Body for failed request ([#10891](https://github.com/googleapis/google-cloud-go/issues/10891)) ([e91d45e](https://github.com/googleapis/google-cloud-go/commit/e91d45e4757a9e354114509ba9800085d9e0ff1f))
|
|
||||||
|
|
||||||
## [0.5.1](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.0...compute/metadata/v0.5.1) (2024-09-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compute/metadata:** Check error chain for retryable error ([#10840](https://github.com/googleapis/google-cloud-go/issues/10840)) ([2bdedef](https://github.com/googleapis/google-cloud-go/commit/2bdedeff621b223d63cebc4355fcf83bc68412cd))
|
|
||||||
|
|
||||||
## [0.5.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.4.0...compute/metadata/v0.5.0) (2024-07-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **compute/metadata:** Add sys check for windows OnGCE ([#10521](https://github.com/googleapis/google-cloud-go/issues/10521)) ([3b9a830](https://github.com/googleapis/google-cloud-go/commit/3b9a83063960d2a2ac20beb47cc15818a68bd302))
|
|
||||||
|
|
||||||
## [0.4.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.3.0...compute/metadata/v0.4.0) (2024-07-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **compute/metadata:** Add context for all functions/methods ([#10370](https://github.com/googleapis/google-cloud-go/issues/10370)) ([66b8efe](https://github.com/googleapis/google-cloud-go/commit/66b8efe7ad877e052b2987bb4475477e38c67bb3))
|
|
||||||
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
* **compute/metadata:** Update OnGCE description ([#10408](https://github.com/googleapis/google-cloud-go/issues/10408)) ([6a46dca](https://github.com/googleapis/google-cloud-go/commit/6a46dca4eae4f88ec6f88822e01e5bf8aeca787f))
|
|
||||||
|
|
||||||
## [0.3.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.3...compute/metadata/v0.3.0) (2024-04-15)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **compute/metadata:** Add context aware functions ([#9733](https://github.com/googleapis/google-cloud-go/issues/9733)) ([e4eb5b4](https://github.com/googleapis/google-cloud-go/commit/e4eb5b46ee2aec9d2fc18300bfd66015e25a0510))
|
|
||||||
|
|
||||||
## [0.2.3](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.2...compute/metadata/v0.2.3) (2022-12-15)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compute/metadata:** Switch DNS lookup to an absolute lookup ([119b410](https://github.com/googleapis/google-cloud-go/commit/119b41060c7895e45e48aee5621ad35607c4d021)), refs [#7165](https://github.com/googleapis/google-cloud-go/issues/7165)
|
|
||||||
|
|
||||||
## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.1...compute/metadata/v0.2.2) (2022-12-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compute/metadata:** Set IdleConnTimeout for http.Client ([#7084](https://github.com/googleapis/google-cloud-go/issues/7084)) ([766516a](https://github.com/googleapis/google-cloud-go/commit/766516aaf3816bfb3159efeea65aa3d1d205a3e2)), refs [#5430](https://github.com/googleapis/google-cloud-go/issues/5430)
|
|
||||||
|
|
||||||
## [0.1.0] (2022-10-26)
|
|
||||||
|
|
||||||
Initial release of metadata being it's own module.
|
|
||||||
202
src/server/vendor/cloud.google.com/go/compute/metadata/LICENSE
generated
vendored
202
src/server/vendor/cloud.google.com/go/compute/metadata/LICENSE
generated
vendored
@ -1,202 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
27
src/server/vendor/cloud.google.com/go/compute/metadata/README.md
generated
vendored
27
src/server/vendor/cloud.google.com/go/compute/metadata/README.md
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
# Compute API
|
|
||||||
|
|
||||||
[](https://pkg.go.dev/cloud.google.com/go/compute/metadata)
|
|
||||||
|
|
||||||
This is a utility library for communicating with Google Cloud metadata service
|
|
||||||
on Google Cloud.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go get cloud.google.com/go/compute/metadata
|
|
||||||
```
|
|
||||||
|
|
||||||
## Go Version Support
|
|
||||||
|
|
||||||
See the [Go Versions Supported](https://github.com/googleapis/google-cloud-go#go-versions-supported)
|
|
||||||
section in the root directory's README.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions are welcome. Please, see the [CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
|
|
||||||
document for details.
|
|
||||||
|
|
||||||
Please note that this project is released with a Contributor Code of Conduct.
|
|
||||||
By participating in this project you agree to abide by its terms. See
|
|
||||||
[Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
|
|
||||||
for more information.
|
|
||||||
149
src/server/vendor/cloud.google.com/go/compute/metadata/log.go
generated
vendored
149
src/server/vendor/cloud.google.com/go/compute/metadata/log.go
generated
vendored
@ -1,149 +0,0 @@
|
|||||||
// Copyright 2024 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package metadata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Code below this point is copied from github.com/googleapis/gax-go/v2/internallog
|
|
||||||
// to avoid the dependency. The compute/metadata module is used by too many
|
|
||||||
// non-client library modules that can't justify the dependency.
|
|
||||||
|
|
||||||
// The handler returned if logging is not enabled.
|
|
||||||
type noOpHandler struct{}
|
|
||||||
|
|
||||||
func (h noOpHandler) Enabled(_ context.Context, _ slog.Level) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h noOpHandler) Handle(_ context.Context, _ slog.Record) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h noOpHandler) WithAttrs(_ []slog.Attr) slog.Handler {
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h noOpHandler) WithGroup(_ string) slog.Handler {
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpRequest returns a lazily evaluated [slog.LogValuer] for a
|
|
||||||
// [http.Request] and the associated body.
|
|
||||||
func httpRequest(req *http.Request, body []byte) slog.LogValuer {
|
|
||||||
return &request{
|
|
||||||
req: req,
|
|
||||||
payload: body,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type request struct {
|
|
||||||
req *http.Request
|
|
||||||
payload []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *request) LogValue() slog.Value {
|
|
||||||
if r == nil || r.req == nil {
|
|
||||||
return slog.Value{}
|
|
||||||
}
|
|
||||||
var groupValueAttrs []slog.Attr
|
|
||||||
groupValueAttrs = append(groupValueAttrs, slog.String("method", r.req.Method))
|
|
||||||
groupValueAttrs = append(groupValueAttrs, slog.String("url", r.req.URL.String()))
|
|
||||||
|
|
||||||
var headerAttr []slog.Attr
|
|
||||||
for k, val := range r.req.Header {
|
|
||||||
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
|
|
||||||
}
|
|
||||||
if len(headerAttr) > 0 {
|
|
||||||
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(r.payload) > 0 {
|
|
||||||
if attr, ok := processPayload(r.payload); ok {
|
|
||||||
groupValueAttrs = append(groupValueAttrs, attr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return slog.GroupValue(groupValueAttrs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpResponse returns a lazily evaluated [slog.LogValuer] for a
|
|
||||||
// [http.Response] and the associated body.
|
|
||||||
func httpResponse(resp *http.Response, body []byte) slog.LogValuer {
|
|
||||||
return &response{
|
|
||||||
resp: resp,
|
|
||||||
payload: body,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type response struct {
|
|
||||||
resp *http.Response
|
|
||||||
payload []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *response) LogValue() slog.Value {
|
|
||||||
if r == nil {
|
|
||||||
return slog.Value{}
|
|
||||||
}
|
|
||||||
var groupValueAttrs []slog.Attr
|
|
||||||
groupValueAttrs = append(groupValueAttrs, slog.String("status", fmt.Sprint(r.resp.StatusCode)))
|
|
||||||
|
|
||||||
var headerAttr []slog.Attr
|
|
||||||
for k, val := range r.resp.Header {
|
|
||||||
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
|
|
||||||
}
|
|
||||||
if len(headerAttr) > 0 {
|
|
||||||
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(r.payload) > 0 {
|
|
||||||
if attr, ok := processPayload(r.payload); ok {
|
|
||||||
groupValueAttrs = append(groupValueAttrs, attr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return slog.GroupValue(groupValueAttrs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func processPayload(payload []byte) (slog.Attr, bool) {
|
|
||||||
peekChar := payload[0]
|
|
||||||
if peekChar == '{' {
|
|
||||||
// JSON object
|
|
||||||
var m map[string]any
|
|
||||||
if err := json.Unmarshal(payload, &m); err == nil {
|
|
||||||
return slog.Any("payload", m), true
|
|
||||||
}
|
|
||||||
} else if peekChar == '[' {
|
|
||||||
// JSON array
|
|
||||||
var m []any
|
|
||||||
if err := json.Unmarshal(payload, &m); err == nil {
|
|
||||||
return slog.Any("payload", m), true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Everything else
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
if err := json.Compact(buf, payload); err != nil {
|
|
||||||
// Write raw payload incase of error
|
|
||||||
buf.Write(payload)
|
|
||||||
}
|
|
||||||
return slog.String("payload", buf.String()), true
|
|
||||||
}
|
|
||||||
return slog.Attr{}, false
|
|
||||||
}
|
|
||||||
872
src/server/vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
872
src/server/vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
@ -1,872 +0,0 @@
|
|||||||
// Copyright 2014 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package metadata provides access to Google Compute Engine (GCE)
|
|
||||||
// metadata and API service accounts.
|
|
||||||
//
|
|
||||||
// This package is a wrapper around the GCE metadata service,
|
|
||||||
// as documented at https://cloud.google.com/compute/docs/metadata/overview.
|
|
||||||
package metadata // import "cloud.google.com/go/compute/metadata"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log/slog"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// metadataIP is the documented metadata server IP address.
|
|
||||||
metadataIP = "169.254.169.254"
|
|
||||||
|
|
||||||
// metadataHostEnv is the environment variable specifying the
|
|
||||||
// GCE metadata hostname. If empty, the default value of
|
|
||||||
// metadataIP ("169.254.169.254") is used instead.
|
|
||||||
// This is variable name is not defined by any spec, as far as
|
|
||||||
// I know; it was made up for the Go package.
|
|
||||||
metadataHostEnv = "GCE_METADATA_HOST"
|
|
||||||
|
|
||||||
userAgent = "gcloud-golang/0.1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type cachedValue struct {
|
|
||||||
k string
|
|
||||||
trim bool
|
|
||||||
mu sync.Mutex
|
|
||||||
v string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
projID = &cachedValue{k: "project/project-id", trim: true}
|
|
||||||
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
|
||||||
instID = &cachedValue{k: "instance/id", trim: true}
|
|
||||||
)
|
|
||||||
|
|
||||||
var defaultClient = &Client{
|
|
||||||
hc: newDefaultHTTPClient(),
|
|
||||||
logger: slog.New(noOpHandler{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDefaultHTTPClient() *http.Client {
|
|
||||||
return &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Dial: (&net.Dialer{
|
|
||||||
Timeout: 2 * time.Second,
|
|
||||||
KeepAlive: 30 * time.Second,
|
|
||||||
}).Dial,
|
|
||||||
IdleConnTimeout: 60 * time.Second,
|
|
||||||
},
|
|
||||||
Timeout: 5 * time.Second,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotDefinedError is returned when requested metadata is not defined.
|
|
||||||
//
|
|
||||||
// The underlying string is the suffix after "/computeMetadata/v1/".
|
|
||||||
//
|
|
||||||
// This error is not returned if the value is defined to be the empty
|
|
||||||
// string.
|
|
||||||
type NotDefinedError string
|
|
||||||
|
|
||||||
func (suffix NotDefinedError) Error() string {
|
|
||||||
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cachedValue) get(ctx context.Context, cl *Client) (v string, err error) {
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.mu.Lock()
|
|
||||||
if c.v != "" {
|
|
||||||
return c.v, nil
|
|
||||||
}
|
|
||||||
if c.trim {
|
|
||||||
v, err = cl.getTrimmed(ctx, c.k)
|
|
||||||
} else {
|
|
||||||
v, err = cl.GetWithContext(ctx, c.k)
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
c.v = v
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
onGCEOnce sync.Once
|
|
||||||
onGCE bool
|
|
||||||
)
|
|
||||||
|
|
||||||
// OnGCE reports whether this process is running on Google Compute Platforms.
|
|
||||||
// NOTE: True returned from `OnGCE` does not guarantee that the metadata server
|
|
||||||
// is accessible from this process and have all the metadata defined.
|
|
||||||
func OnGCE() bool {
|
|
||||||
onGCEOnce.Do(initOnGCE)
|
|
||||||
return onGCE
|
|
||||||
}
|
|
||||||
|
|
||||||
func initOnGCE() {
|
|
||||||
onGCE = testOnGCE()
|
|
||||||
}
|
|
||||||
|
|
||||||
func testOnGCE() bool {
|
|
||||||
// The user explicitly said they're on GCE, so trust them.
|
|
||||||
if os.Getenv(metadataHostEnv) != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
resc := make(chan bool, 2)
|
|
||||||
|
|
||||||
// Try two strategies in parallel.
|
|
||||||
// See https://github.com/googleapis/google-cloud-go/issues/194
|
|
||||||
go func() {
|
|
||||||
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
|
||||||
req.Header.Set("User-Agent", userAgent)
|
|
||||||
res, err := newDefaultHTTPClient().Do(req.WithContext(ctx))
|
|
||||||
if err != nil {
|
|
||||||
resc <- false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
resolver := &net.Resolver{}
|
|
||||||
addrs, err := resolver.LookupHost(ctx, "metadata.google.internal.")
|
|
||||||
if err != nil || len(addrs) == 0 {
|
|
||||||
resc <- false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resc <- strsContains(addrs, metadataIP)
|
|
||||||
}()
|
|
||||||
|
|
||||||
tryHarder := systemInfoSuggestsGCE()
|
|
||||||
if tryHarder {
|
|
||||||
res := <-resc
|
|
||||||
if res {
|
|
||||||
// The first strategy succeeded, so let's use it.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Wait for either the DNS or metadata server probe to
|
|
||||||
// contradict the other one and say we are running on
|
|
||||||
// GCE. Give it a lot of time to do so, since the system
|
|
||||||
// info already suggests we're running on a GCE BIOS.
|
|
||||||
timer := time.NewTimer(5 * time.Second)
|
|
||||||
defer timer.Stop()
|
|
||||||
select {
|
|
||||||
case res = <-resc:
|
|
||||||
return res
|
|
||||||
case <-timer.C:
|
|
||||||
// Too slow. Who knows what this system is.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's no hint from the system info that we're running on
|
|
||||||
// GCE, so use the first probe's result as truth, whether it's
|
|
||||||
// true or false. The goal here is to optimize for speed for
|
|
||||||
// users who are NOT running on GCE. We can't assume that
|
|
||||||
// either a DNS lookup or an HTTP request to a blackholed IP
|
|
||||||
// address is fast. Worst case this should return when the
|
|
||||||
// metaClient's Transport.ResponseHeaderTimeout or
|
|
||||||
// Transport.Dial.Timeout fires (in two seconds).
|
|
||||||
return <-resc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe calls Client.SubscribeWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [SubscribeWithContext].
|
|
||||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
|
||||||
return defaultClient.SubscribeWithContext(context.Background(), suffix, func(ctx context.Context, v string, ok bool) error { return fn(v, ok) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubscribeWithContext calls Client.SubscribeWithContext on the default client.
|
|
||||||
func SubscribeWithContext(ctx context.Context, suffix string, fn func(ctx context.Context, v string, ok bool) error) error {
|
|
||||||
return defaultClient.SubscribeWithContext(ctx, suffix, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get calls Client.GetWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [GetWithContext].
|
|
||||||
func Get(suffix string) (string, error) {
|
|
||||||
return defaultClient.GetWithContext(context.Background(), suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWithContext calls Client.GetWithContext on the default client.
|
|
||||||
func GetWithContext(ctx context.Context, suffix string) (string, error) {
|
|
||||||
return defaultClient.GetWithContext(ctx, suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectID returns the current instance's project ID string.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [ProjectIDWithContext].
|
|
||||||
func ProjectID() (string, error) {
|
|
||||||
return defaultClient.ProjectIDWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectIDWithContext returns the current instance's project ID string.
|
|
||||||
func ProjectIDWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.ProjectIDWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NumericProjectID returns the current instance's numeric project ID.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [NumericProjectIDWithContext].
|
|
||||||
func NumericProjectID() (string, error) {
|
|
||||||
return defaultClient.NumericProjectIDWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NumericProjectIDWithContext returns the current instance's numeric project ID.
|
|
||||||
func NumericProjectIDWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.NumericProjectIDWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InternalIP returns the instance's primary internal IP address.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [InternalIPWithContext].
|
|
||||||
func InternalIP() (string, error) {
|
|
||||||
return defaultClient.InternalIPWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InternalIPWithContext returns the instance's primary internal IP address.
|
|
||||||
func InternalIPWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.InternalIPWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExternalIP returns the instance's primary external (public) IP address.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [ExternalIPWithContext].
|
|
||||||
func ExternalIP() (string, error) {
|
|
||||||
return defaultClient.ExternalIPWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExternalIPWithContext returns the instance's primary external (public) IP address.
|
|
||||||
func ExternalIPWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.ExternalIPWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email calls Client.EmailWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [EmailWithContext].
|
|
||||||
func Email(serviceAccount string) (string, error) {
|
|
||||||
return defaultClient.EmailWithContext(context.Background(), serviceAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmailWithContext calls Client.EmailWithContext on the default client.
|
|
||||||
func EmailWithContext(ctx context.Context, serviceAccount string) (string, error) {
|
|
||||||
return defaultClient.EmailWithContext(ctx, serviceAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hostname returns the instance's hostname. This will be of the form
|
|
||||||
// "<instanceID>.c.<projID>.internal".
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [HostnameWithContext].
|
|
||||||
func Hostname() (string, error) {
|
|
||||||
return defaultClient.HostnameWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// HostnameWithContext returns the instance's hostname. This will be of the form
|
|
||||||
// "<instanceID>.c.<projID>.internal".
|
|
||||||
func HostnameWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.HostnameWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceTags returns the list of user-defined instance tags,
|
|
||||||
// assigned when initially creating a GCE instance.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [InstanceTagsWithContext].
|
|
||||||
func InstanceTags() ([]string, error) {
|
|
||||||
return defaultClient.InstanceTagsWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceTagsWithContext returns the list of user-defined instance tags,
|
|
||||||
// assigned when initially creating a GCE instance.
|
|
||||||
func InstanceTagsWithContext(ctx context.Context) ([]string, error) {
|
|
||||||
return defaultClient.InstanceTagsWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceID returns the current VM's numeric instance ID.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [InstanceIDWithContext].
|
|
||||||
func InstanceID() (string, error) {
|
|
||||||
return defaultClient.InstanceIDWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceIDWithContext returns the current VM's numeric instance ID.
|
|
||||||
func InstanceIDWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.InstanceIDWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceName returns the current VM's instance ID string.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [InstanceNameWithContext].
|
|
||||||
func InstanceName() (string, error) {
|
|
||||||
return defaultClient.InstanceNameWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceNameWithContext returns the current VM's instance ID string.
|
|
||||||
func InstanceNameWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.InstanceNameWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [ZoneWithContext].
|
|
||||||
func Zone() (string, error) {
|
|
||||||
return defaultClient.ZoneWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZoneWithContext returns the current VM's zone, such as "us-central1-b".
|
|
||||||
func ZoneWithContext(ctx context.Context) (string, error) {
|
|
||||||
return defaultClient.ZoneWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributes calls Client.InstanceAttributesWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [InstanceAttributesWithContext.
|
|
||||||
func InstanceAttributes() ([]string, error) {
|
|
||||||
return defaultClient.InstanceAttributesWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributesWithContext calls Client.ProjectAttributesWithContext on the default client.
|
|
||||||
func InstanceAttributesWithContext(ctx context.Context) ([]string, error) {
|
|
||||||
return defaultClient.InstanceAttributesWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributes calls Client.ProjectAttributesWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [ProjectAttributesWithContext].
|
|
||||||
func ProjectAttributes() ([]string, error) {
|
|
||||||
return defaultClient.ProjectAttributesWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributesWithContext calls Client.ProjectAttributesWithContext on the default client.
|
|
||||||
func ProjectAttributesWithContext(ctx context.Context) ([]string, error) {
|
|
||||||
return defaultClient.ProjectAttributesWithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributeValue calls Client.InstanceAttributeValueWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [InstanceAttributeValueWithContext].
|
|
||||||
func InstanceAttributeValue(attr string) (string, error) {
|
|
||||||
return defaultClient.InstanceAttributeValueWithContext(context.Background(), attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributeValueWithContext calls Client.InstanceAttributeValueWithContext on the default client.
|
|
||||||
func InstanceAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
|
||||||
return defaultClient.InstanceAttributeValueWithContext(ctx, attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributeValue calls Client.ProjectAttributeValueWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [ProjectAttributeValueWithContext].
|
|
||||||
func ProjectAttributeValue(attr string) (string, error) {
|
|
||||||
return defaultClient.ProjectAttributeValueWithContext(context.Background(), attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributeValueWithContext calls Client.ProjectAttributeValueWithContext on the default client.
|
|
||||||
func ProjectAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
|
||||||
return defaultClient.ProjectAttributeValueWithContext(ctx, attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scopes calls Client.ScopesWithContext on the default client.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [ScopesWithContext].
|
|
||||||
func Scopes(serviceAccount string) ([]string, error) {
|
|
||||||
return defaultClient.ScopesWithContext(context.Background(), serviceAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScopesWithContext calls Client.ScopesWithContext on the default client.
|
|
||||||
func ScopesWithContext(ctx context.Context, serviceAccount string) ([]string, error) {
|
|
||||||
return defaultClient.ScopesWithContext(ctx, serviceAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func strsContains(ss []string, s string) bool {
|
|
||||||
for _, v := range ss {
|
|
||||||
if v == s {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Client provides metadata.
|
|
||||||
type Client struct {
|
|
||||||
hc *http.Client
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options for configuring a [Client].
|
|
||||||
type Options struct {
|
|
||||||
// Client is the HTTP client used to make requests. Optional.
|
|
||||||
Client *http.Client
|
|
||||||
// Logger is used to log information about HTTP request and responses.
|
|
||||||
// If not provided, nothing will be logged. Optional.
|
|
||||||
Logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient returns a Client that can be used to fetch metadata.
|
|
||||||
// Returns the client that uses the specified http.Client for HTTP requests.
|
|
||||||
// If nil is specified, returns the default client.
|
|
||||||
func NewClient(c *http.Client) *Client {
|
|
||||||
return NewWithOptions(&Options{
|
|
||||||
Client: c,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWithOptions returns a Client that is configured with the provided Options.
|
|
||||||
func NewWithOptions(opts *Options) *Client {
|
|
||||||
if opts == nil {
|
|
||||||
return defaultClient
|
|
||||||
}
|
|
||||||
client := opts.Client
|
|
||||||
if client == nil {
|
|
||||||
client = newDefaultHTTPClient()
|
|
||||||
}
|
|
||||||
logger := opts.Logger
|
|
||||||
if logger == nil {
|
|
||||||
logger = slog.New(noOpHandler{})
|
|
||||||
}
|
|
||||||
return &Client{hc: client, logger: logger}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getETag returns a value from the metadata service as well as the associated ETag.
|
|
||||||
// This func is otherwise equivalent to Get.
|
|
||||||
func (c *Client) getETag(ctx context.Context, suffix string) (value, etag string, err error) {
|
|
||||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
|
||||||
// a container, which is an important use-case for local testing of cloud
|
|
||||||
// deployments. To enable spoofing of the metadata service, the environment
|
|
||||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
|
||||||
// requests shall go.
|
|
||||||
host := os.Getenv(metadataHostEnv)
|
|
||||||
if host == "" {
|
|
||||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
|
||||||
// binaries built with the "netgo" tag and without cgo won't
|
|
||||||
// know the search suffix for "metadata" is
|
|
||||||
// ".google.internal", and this IP address is documented as
|
|
||||||
// being stable anyway.
|
|
||||||
host = metadataIP
|
|
||||||
}
|
|
||||||
suffix = strings.TrimLeft(suffix, "/")
|
|
||||||
u := "http://" + host + "/computeMetadata/v1/" + suffix
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", u, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
req.Header.Set("Metadata-Flavor", "Google")
|
|
||||||
req.Header.Set("User-Agent", userAgent)
|
|
||||||
var res *http.Response
|
|
||||||
var reqErr error
|
|
||||||
var body []byte
|
|
||||||
retryer := newRetryer()
|
|
||||||
for {
|
|
||||||
c.logger.DebugContext(ctx, "metadata request", "request", httpRequest(req, nil))
|
|
||||||
res, reqErr = c.hc.Do(req)
|
|
||||||
var code int
|
|
||||||
if res != nil {
|
|
||||||
code = res.StatusCode
|
|
||||||
body, err = io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
res.Body.Close()
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
c.logger.DebugContext(ctx, "metadata response", "response", httpResponse(res, body))
|
|
||||||
res.Body.Close()
|
|
||||||
}
|
|
||||||
if delay, shouldRetry := retryer.Retry(code, reqErr); shouldRetry {
|
|
||||||
if res != nil && res.Body != nil {
|
|
||||||
res.Body.Close()
|
|
||||||
}
|
|
||||||
if err := sleep(ctx, delay); err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if reqErr != nil {
|
|
||||||
return "", "", reqErr
|
|
||||||
}
|
|
||||||
if res.StatusCode == http.StatusNotFound {
|
|
||||||
return "", "", NotDefinedError(suffix)
|
|
||||||
}
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
return "", "", &Error{Code: res.StatusCode, Message: string(body)}
|
|
||||||
}
|
|
||||||
return string(body), res.Header.Get("Etag"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns a value from the metadata service.
|
|
||||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
|
||||||
//
|
|
||||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
|
||||||
// 169.254.169.254 will be used instead.
|
|
||||||
//
|
|
||||||
// If the requested metadata is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.GetWithContext].
|
|
||||||
func (c *Client) Get(suffix string) (string, error) {
|
|
||||||
return c.GetWithContext(context.Background(), suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWithContext returns a value from the metadata service.
|
|
||||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
|
||||||
//
|
|
||||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
|
||||||
// 169.254.169.254 will be used instead.
|
|
||||||
//
|
|
||||||
// If the requested metadata is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// NOTE: Without an extra deadline in the context this call can take in the
|
|
||||||
// worst case, with internal backoff retries, up to 15 seconds (e.g. when server
|
|
||||||
// is responding slowly). Pass context with additional timeouts when needed.
|
|
||||||
func (c *Client) GetWithContext(ctx context.Context, suffix string) (string, error) {
|
|
||||||
val, _, err := c.getETag(ctx, suffix)
|
|
||||||
return val, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) getTrimmed(ctx context.Context, suffix string) (s string, err error) {
|
|
||||||
s, err = c.GetWithContext(ctx, suffix)
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) lines(ctx context.Context, suffix string) ([]string, error) {
|
|
||||||
j, err := c.GetWithContext(ctx, suffix)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
|
||||||
for i := range s {
|
|
||||||
s[i] = strings.TrimSpace(s[i])
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectID returns the current instance's project ID string.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.ProjectIDWithContext].
|
|
||||||
func (c *Client) ProjectID() (string, error) { return c.ProjectIDWithContext(context.Background()) }
|
|
||||||
|
|
||||||
// ProjectIDWithContext returns the current instance's project ID string.
|
|
||||||
func (c *Client) ProjectIDWithContext(ctx context.Context) (string, error) { return projID.get(ctx, c) }
|
|
||||||
|
|
||||||
// NumericProjectID returns the current instance's numeric project ID.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.NumericProjectIDWithContext].
|
|
||||||
func (c *Client) NumericProjectID() (string, error) {
|
|
||||||
return c.NumericProjectIDWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NumericProjectIDWithContext returns the current instance's numeric project ID.
|
|
||||||
func (c *Client) NumericProjectIDWithContext(ctx context.Context) (string, error) {
|
|
||||||
return projNum.get(ctx, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceID returns the current VM's numeric instance ID.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.InstanceIDWithContext].
|
|
||||||
func (c *Client) InstanceID() (string, error) {
|
|
||||||
return c.InstanceIDWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceIDWithContext returns the current VM's numeric instance ID.
|
|
||||||
func (c *Client) InstanceIDWithContext(ctx context.Context) (string, error) {
|
|
||||||
return instID.get(ctx, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InternalIP returns the instance's primary internal IP address.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.InternalIPWithContext].
|
|
||||||
func (c *Client) InternalIP() (string, error) {
|
|
||||||
return c.InternalIPWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InternalIPWithContext returns the instance's primary internal IP address.
|
|
||||||
func (c *Client) InternalIPWithContext(ctx context.Context) (string, error) {
|
|
||||||
return c.getTrimmed(ctx, "instance/network-interfaces/0/ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email returns the email address associated with the service account.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.EmailWithContext].
|
|
||||||
func (c *Client) Email(serviceAccount string) (string, error) {
|
|
||||||
return c.EmailWithContext(context.Background(), serviceAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmailWithContext returns the email address associated with the service account.
|
|
||||||
// The serviceAccount parameter default value (empty string or "default" value)
|
|
||||||
// will use the instance's main account.
|
|
||||||
func (c *Client) EmailWithContext(ctx context.Context, serviceAccount string) (string, error) {
|
|
||||||
if serviceAccount == "" {
|
|
||||||
serviceAccount = "default"
|
|
||||||
}
|
|
||||||
return c.getTrimmed(ctx, "instance/service-accounts/"+serviceAccount+"/email")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExternalIP returns the instance's primary external (public) IP address.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.ExternalIPWithContext].
|
|
||||||
func (c *Client) ExternalIP() (string, error) {
|
|
||||||
return c.ExternalIPWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExternalIPWithContext returns the instance's primary external (public) IP address.
|
|
||||||
func (c *Client) ExternalIPWithContext(ctx context.Context) (string, error) {
|
|
||||||
return c.getTrimmed(ctx, "instance/network-interfaces/0/access-configs/0/external-ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hostname returns the instance's hostname. This will be of the form
|
|
||||||
// "<instanceID>.c.<projID>.internal".
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.HostnameWithContext].
|
|
||||||
func (c *Client) Hostname() (string, error) {
|
|
||||||
return c.HostnameWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// HostnameWithContext returns the instance's hostname. This will be of the form
|
|
||||||
// "<instanceID>.c.<projID>.internal".
|
|
||||||
func (c *Client) HostnameWithContext(ctx context.Context) (string, error) {
|
|
||||||
return c.getTrimmed(ctx, "instance/hostname")
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceTags returns the list of user-defined instance tags.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.InstanceTagsWithContext].
|
|
||||||
func (c *Client) InstanceTags() ([]string, error) {
|
|
||||||
return c.InstanceTagsWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceTagsWithContext returns the list of user-defined instance tags,
|
|
||||||
// assigned when initially creating a GCE instance.
|
|
||||||
func (c *Client) InstanceTagsWithContext(ctx context.Context) ([]string, error) {
|
|
||||||
var s []string
|
|
||||||
j, err := c.GetWithContext(ctx, "instance/tags")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceName returns the current VM's instance ID string.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.InstanceNameWithContext].
|
|
||||||
func (c *Client) InstanceName() (string, error) {
|
|
||||||
return c.InstanceNameWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceNameWithContext returns the current VM's instance ID string.
|
|
||||||
func (c *Client) InstanceNameWithContext(ctx context.Context) (string, error) {
|
|
||||||
return c.getTrimmed(ctx, "instance/name")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.ZoneWithContext].
|
|
||||||
func (c *Client) Zone() (string, error) {
|
|
||||||
return c.ZoneWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZoneWithContext returns the current VM's zone, such as "us-central1-b".
|
|
||||||
func (c *Client) ZoneWithContext(ctx context.Context) (string, error) {
|
|
||||||
zone, err := c.getTrimmed(ctx, "instance/zone")
|
|
||||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributes returns the list of user-defined attributes,
|
|
||||||
// assigned when initially creating a GCE VM instance. The value of an
|
|
||||||
// attribute can be obtained with InstanceAttributeValue.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.InstanceAttributesWithContext].
|
|
||||||
func (c *Client) InstanceAttributes() ([]string, error) {
|
|
||||||
return c.InstanceAttributesWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributesWithContext returns the list of user-defined attributes,
|
|
||||||
// assigned when initially creating a GCE VM instance. The value of an
|
|
||||||
// attribute can be obtained with InstanceAttributeValue.
|
|
||||||
func (c *Client) InstanceAttributesWithContext(ctx context.Context) ([]string, error) {
|
|
||||||
return c.lines(ctx, "instance/attributes/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributes returns the list of user-defined attributes
|
|
||||||
// applying to the project as a whole, not just this VM. The value of
|
|
||||||
// an attribute can be obtained with ProjectAttributeValue.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.ProjectAttributesWithContext].
|
|
||||||
func (c *Client) ProjectAttributes() ([]string, error) {
|
|
||||||
return c.ProjectAttributesWithContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributesWithContext returns the list of user-defined attributes
|
|
||||||
// applying to the project as a whole, not just this VM. The value of
|
|
||||||
// an attribute can be obtained with ProjectAttributeValue.
|
|
||||||
func (c *Client) ProjectAttributesWithContext(ctx context.Context) ([]string, error) {
|
|
||||||
return c.lines(ctx, "project/attributes/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributeValue returns the value of the provided VM
|
|
||||||
// instance attribute.
|
|
||||||
//
|
|
||||||
// If the requested attribute is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
|
||||||
// defined to be the empty string.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.InstanceAttributeValueWithContext].
|
|
||||||
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
|
|
||||||
return c.InstanceAttributeValueWithContext(context.Background(), attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributeValueWithContext returns the value of the provided VM
|
|
||||||
// instance attribute.
|
|
||||||
//
|
|
||||||
// If the requested attribute is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
|
||||||
// defined to be the empty string.
|
|
||||||
func (c *Client) InstanceAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
|
||||||
return c.GetWithContext(ctx, "instance/attributes/"+attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributeValue returns the value of the provided
|
|
||||||
// project attribute.
|
|
||||||
//
|
|
||||||
// If the requested attribute is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
|
||||||
// defined to be the empty string.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.ProjectAttributeValueWithContext].
|
|
||||||
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
|
|
||||||
return c.ProjectAttributeValueWithContext(context.Background(), attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributeValueWithContext returns the value of the provided
|
|
||||||
// project attribute.
|
|
||||||
//
|
|
||||||
// If the requested attribute is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
|
||||||
// defined to be the empty string.
|
|
||||||
func (c *Client) ProjectAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
|
||||||
return c.GetWithContext(ctx, "project/attributes/"+attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scopes returns the service account scopes for the given account.
|
|
||||||
// The account may be empty or the string "default" to use the instance's
|
|
||||||
// main account.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.ScopesWithContext].
|
|
||||||
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
|
|
||||||
return c.ScopesWithContext(context.Background(), serviceAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScopesWithContext returns the service account scopes for the given account.
|
|
||||||
// The account may be empty or the string "default" to use the instance's
|
|
||||||
// main account.
|
|
||||||
func (c *Client) ScopesWithContext(ctx context.Context, serviceAccount string) ([]string, error) {
|
|
||||||
if serviceAccount == "" {
|
|
||||||
serviceAccount = "default"
|
|
||||||
}
|
|
||||||
return c.lines(ctx, "instance/service-accounts/"+serviceAccount+"/scopes")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe subscribes to a value from the metadata service.
|
|
||||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
|
||||||
// The suffix may contain query parameters.
|
|
||||||
//
|
|
||||||
// Deprecated: Please use the context aware variant [Client.SubscribeWithContext].
|
|
||||||
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
|
||||||
return c.SubscribeWithContext(context.Background(), suffix, func(ctx context.Context, v string, ok bool) error { return fn(v, ok) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubscribeWithContext subscribes to a value from the metadata service.
|
|
||||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
|
||||||
// The suffix may contain query parameters.
|
|
||||||
//
|
|
||||||
// SubscribeWithContext calls fn with the latest metadata value indicated by the
|
|
||||||
// provided suffix. If the metadata value is deleted, fn is called with the
|
|
||||||
// empty string and ok false. Subscribe blocks until fn returns a non-nil error
|
|
||||||
// or the value is deleted. Subscribe returns the error value returned from the
|
|
||||||
// last call to fn, which may be nil when ok == false.
|
|
||||||
func (c *Client) SubscribeWithContext(ctx context.Context, suffix string, fn func(ctx context.Context, v string, ok bool) error) error {
|
|
||||||
const failedSubscribeSleep = time.Second * 5
|
|
||||||
|
|
||||||
// First check to see if the metadata value exists at all.
|
|
||||||
val, lastETag, err := c.getETag(ctx, suffix)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := fn(ctx, val, true); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := true
|
|
||||||
if strings.ContainsRune(suffix, '?') {
|
|
||||||
suffix += "&wait_for_change=true&last_etag="
|
|
||||||
} else {
|
|
||||||
suffix += "?wait_for_change=true&last_etag="
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
val, etag, err := c.getETag(ctx, suffix+url.QueryEscape(lastETag))
|
|
||||||
if err != nil {
|
|
||||||
if _, deleted := err.(NotDefinedError); !deleted {
|
|
||||||
time.Sleep(failedSubscribeSleep)
|
|
||||||
continue // Retry on other errors.
|
|
||||||
}
|
|
||||||
ok = false
|
|
||||||
}
|
|
||||||
lastETag = etag
|
|
||||||
|
|
||||||
if err := fn(ctx, val, ok); err != nil || !ok {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error contains an error response from the server.
|
|
||||||
type Error struct {
|
|
||||||
// Code is the HTTP response status code.
|
|
||||||
Code int
|
|
||||||
// Message is the server response message.
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
|
||||||
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
|
|
||||||
}
|
|
||||||
114
src/server/vendor/cloud.google.com/go/compute/metadata/retry.go
generated
vendored
114
src/server/vendor/cloud.google.com/go/compute/metadata/retry.go
generated
vendored
@ -1,114 +0,0 @@
|
|||||||
// Copyright 2021 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package metadata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxRetryAttempts = 5
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
syscallRetryable = func(error) bool { return false }
|
|
||||||
)
|
|
||||||
|
|
||||||
// defaultBackoff is basically equivalent to gax.Backoff without the need for
|
|
||||||
// the dependency.
|
|
||||||
type defaultBackoff struct {
|
|
||||||
max time.Duration
|
|
||||||
mul float64
|
|
||||||
cur time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *defaultBackoff) Pause() time.Duration {
|
|
||||||
d := time.Duration(1 + rand.Int63n(int64(b.cur)))
|
|
||||||
b.cur = time.Duration(float64(b.cur) * b.mul)
|
|
||||||
if b.cur > b.max {
|
|
||||||
b.cur = b.max
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
// sleep is the equivalent of gax.Sleep without the need for the dependency.
|
|
||||||
func sleep(ctx context.Context, d time.Duration) error {
|
|
||||||
t := time.NewTimer(d)
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
t.Stop()
|
|
||||||
return ctx.Err()
|
|
||||||
case <-t.C:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRetryer() *metadataRetryer {
|
|
||||||
return &metadataRetryer{bo: &defaultBackoff{
|
|
||||||
cur: 100 * time.Millisecond,
|
|
||||||
max: 30 * time.Second,
|
|
||||||
mul: 2,
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
type backoff interface {
|
|
||||||
Pause() time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type metadataRetryer struct {
|
|
||||||
bo backoff
|
|
||||||
attempts int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *metadataRetryer) Retry(status int, err error) (time.Duration, bool) {
|
|
||||||
if status == http.StatusOK {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
retryOk := shouldRetry(status, err)
|
|
||||||
if !retryOk {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
if r.attempts == maxRetryAttempts {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
r.attempts++
|
|
||||||
return r.bo.Pause(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldRetry(status int, err error) bool {
|
|
||||||
if 500 <= status && status <= 599 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err == io.ErrUnexpectedEOF {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Transient network errors should be retried.
|
|
||||||
if syscallRetryable(err) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err, ok := err.(interface{ Temporary() bool }); ok {
|
|
||||||
if err.Temporary() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err, ok := err.(interface{ Unwrap() error }); ok {
|
|
||||||
return shouldRetry(status, err.Unwrap())
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
31
src/server/vendor/cloud.google.com/go/compute/metadata/retry_linux.go
generated
vendored
31
src/server/vendor/cloud.google.com/go/compute/metadata/retry_linux.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
// Copyright 2021 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
//go:build linux
|
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package metadata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Initialize syscallRetryable to return true on transient socket-level
|
|
||||||
// errors. These errors are specific to Linux.
|
|
||||||
syscallRetryable = func(err error) bool {
|
|
||||||
return errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.ECONNREFUSED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
26
src/server/vendor/cloud.google.com/go/compute/metadata/syscheck.go
generated
vendored
26
src/server/vendor/cloud.google.com/go/compute/metadata/syscheck.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
// Copyright 2024 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
//go:build !windows && !linux
|
|
||||||
|
|
||||||
package metadata
|
|
||||||
|
|
||||||
// systemInfoSuggestsGCE reports whether the local system (without
|
|
||||||
// doing network requests) suggests that we're running on GCE. If this
|
|
||||||
// returns true, testOnGCE tries a bit harder to reach its metadata
|
|
||||||
// server.
|
|
||||||
func systemInfoSuggestsGCE() bool {
|
|
||||||
// We don't currently have checks for other GOOS
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
28
src/server/vendor/cloud.google.com/go/compute/metadata/syscheck_linux.go
generated
vendored
28
src/server/vendor/cloud.google.com/go/compute/metadata/syscheck_linux.go
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
// Copyright 2024 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
//go:build linux
|
|
||||||
|
|
||||||
package metadata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func systemInfoSuggestsGCE() bool {
|
|
||||||
b, _ := os.ReadFile("/sys/class/dmi/id/product_name")
|
|
||||||
name := strings.TrimSpace(string(b))
|
|
||||||
return name == "Google" || name == "Google Compute Engine"
|
|
||||||
}
|
|
||||||
38
src/server/vendor/cloud.google.com/go/compute/metadata/syscheck_windows.go
generated
vendored
38
src/server/vendor/cloud.google.com/go/compute/metadata/syscheck_windows.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
// Copyright 2024 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
//go:build windows
|
|
||||||
|
|
||||||
package metadata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
func systemInfoSuggestsGCE() bool {
|
|
||||||
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\HardwareConfig\Current`, registry.QUERY_VALUE)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
defer k.Close()
|
|
||||||
|
|
||||||
s, _, err := k.GetStringValue("SystemProductName")
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
return strings.HasPrefix(s, "Google")
|
|
||||||
}
|
|
||||||
0
src/server/vendor/github.com/felixge/httpsnoop/.gitignore
generated
vendored
0
src/server/vendor/github.com/felixge/httpsnoop/.gitignore
generated
vendored
19
src/server/vendor/github.com/felixge/httpsnoop/LICENSE.txt
generated
vendored
19
src/server/vendor/github.com/felixge/httpsnoop/LICENSE.txt
generated
vendored
@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2016 Felix Geisendörfer (felix@debuggable.com)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
10
src/server/vendor/github.com/felixge/httpsnoop/Makefile
generated
vendored
10
src/server/vendor/github.com/felixge/httpsnoop/Makefile
generated
vendored
@ -1,10 +0,0 @@
|
|||||||
.PHONY: ci generate clean
|
|
||||||
|
|
||||||
ci: clean generate
|
|
||||||
go test -race -v ./...
|
|
||||||
|
|
||||||
generate:
|
|
||||||
go generate .
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf *_generated*.go
|
|
||||||
95
src/server/vendor/github.com/felixge/httpsnoop/README.md
generated
vendored
95
src/server/vendor/github.com/felixge/httpsnoop/README.md
generated
vendored
@ -1,95 +0,0 @@
|
|||||||
# httpsnoop
|
|
||||||
|
|
||||||
Package httpsnoop provides an easy way to capture http related metrics (i.e.
|
|
||||||
response time, bytes written, and http status code) from your application's
|
|
||||||
http.Handlers.
|
|
||||||
|
|
||||||
Doing this requires non-trivial wrapping of the http.ResponseWriter interface,
|
|
||||||
which is also exposed for users interested in a more low-level API.
|
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/felixge/httpsnoop)
|
|
||||||
[](https://github.com/felixge/httpsnoop/actions/workflows/main.yaml)
|
|
||||||
|
|
||||||
## Usage Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
// myH is your app's http handler, perhaps a http.ServeMux or similar.
|
|
||||||
var myH http.Handler
|
|
||||||
// wrappedH wraps myH in order to log every request.
|
|
||||||
wrappedH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
m := httpsnoop.CaptureMetrics(myH, w, r)
|
|
||||||
log.Printf(
|
|
||||||
"%s %s (code=%d dt=%s written=%d)",
|
|
||||||
r.Method,
|
|
||||||
r.URL,
|
|
||||||
m.Code,
|
|
||||||
m.Duration,
|
|
||||||
m.Written,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
http.ListenAndServe(":8080", wrappedH)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Why this package exists
|
|
||||||
|
|
||||||
Instrumenting an application's http.Handler is surprisingly difficult.
|
|
||||||
|
|
||||||
However if you google for e.g. "capture ResponseWriter status code" you'll find
|
|
||||||
lots of advise and code examples that suggest it to be a fairly trivial
|
|
||||||
undertaking. Unfortunately everything I've seen so far has a high chance of
|
|
||||||
breaking your application.
|
|
||||||
|
|
||||||
The main problem is that a `http.ResponseWriter` often implements additional
|
|
||||||
interfaces such as `http.Flusher`, `http.CloseNotifier`, `http.Hijacker`, `http.Pusher`, and
|
|
||||||
`io.ReaderFrom`. So the naive approach of just wrapping `http.ResponseWriter`
|
|
||||||
in your own struct that also implements the `http.ResponseWriter` interface
|
|
||||||
will hide the additional interfaces mentioned above. This has a high change of
|
|
||||||
introducing subtle bugs into any non-trivial application.
|
|
||||||
|
|
||||||
Another approach I've seen people take is to return a struct that implements
|
|
||||||
all of the interfaces above. However, that's also problematic, because it's
|
|
||||||
difficult to fake some of these interfaces behaviors when the underlying
|
|
||||||
`http.ResponseWriter` doesn't have an implementation. It's also dangerous,
|
|
||||||
because an application may choose to operate differently, merely because it
|
|
||||||
detects the presence of these additional interfaces.
|
|
||||||
|
|
||||||
This package solves this problem by checking which additional interfaces a
|
|
||||||
`http.ResponseWriter` implements, returning a wrapped version implementing the
|
|
||||||
exact same set of interfaces.
|
|
||||||
|
|
||||||
Additionally this package properly handles edge cases such as `WriteHeader` not
|
|
||||||
being called, or called more than once, as well as concurrent calls to
|
|
||||||
`http.ResponseWriter` methods, and even calls happening after the wrapped
|
|
||||||
`ServeHTTP` has already returned.
|
|
||||||
|
|
||||||
Unfortunately this package is not perfect either. It's possible that it is
|
|
||||||
still missing some interfaces provided by the go core (let me know if you find
|
|
||||||
one), and it won't work for applications adding their own interfaces into the
|
|
||||||
mix. You can however use `httpsnoop.Unwrap(w)` to access the underlying
|
|
||||||
`http.ResponseWriter` and type-assert the result to its other interfaces.
|
|
||||||
|
|
||||||
However, hopefully the explanation above has sufficiently scared you of rolling
|
|
||||||
your own solution to this problem. httpsnoop may still break your application,
|
|
||||||
but at least it tries to avoid it as much as possible.
|
|
||||||
|
|
||||||
Anyway, the real problem here is that smuggling additional interfaces inside
|
|
||||||
`http.ResponseWriter` is a problematic design choice, but it probably goes as
|
|
||||||
deep as the Go language specification itself. But that's okay, I still prefer
|
|
||||||
Go over the alternatives ;).
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
```
|
|
||||||
BenchmarkBaseline-8 20000 94912 ns/op
|
|
||||||
BenchmarkCaptureMetrics-8 20000 95461 ns/op
|
|
||||||
```
|
|
||||||
|
|
||||||
As you can see, using `CaptureMetrics` on a vanilla http.Handler introduces an
|
|
||||||
overhead of ~500 ns per http request on my machine. However, the margin of
|
|
||||||
error appears to be larger than that, therefor it should be reasonable to
|
|
||||||
assume that the overhead introduced by `CaptureMetrics` is absolutely
|
|
||||||
negligible.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
86
src/server/vendor/github.com/felixge/httpsnoop/capture_metrics.go
generated
vendored
86
src/server/vendor/github.com/felixge/httpsnoop/capture_metrics.go
generated
vendored
@ -1,86 +0,0 @@
|
|||||||
package httpsnoop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Metrics holds metrics captured from CaptureMetrics.
|
|
||||||
type Metrics struct {
|
|
||||||
// Code is the first http response code passed to the WriteHeader func of
|
|
||||||
// the ResponseWriter. If no such call is made, a default code of 200 is
|
|
||||||
// assumed instead.
|
|
||||||
Code int
|
|
||||||
// Duration is the time it took to execute the handler.
|
|
||||||
Duration time.Duration
|
|
||||||
// Written is the number of bytes successfully written by the Write or
|
|
||||||
// ReadFrom function of the ResponseWriter. ResponseWriters may also write
|
|
||||||
// data to their underlaying connection directly (e.g. headers), but those
|
|
||||||
// are not tracked. Therefor the number of Written bytes will usually match
|
|
||||||
// the size of the response body.
|
|
||||||
Written int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// CaptureMetrics wraps the given hnd, executes it with the given w and r, and
|
|
||||||
// returns the metrics it captured from it.
|
|
||||||
func CaptureMetrics(hnd http.Handler, w http.ResponseWriter, r *http.Request) Metrics {
|
|
||||||
return CaptureMetricsFn(w, func(ww http.ResponseWriter) {
|
|
||||||
hnd.ServeHTTP(ww, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// CaptureMetricsFn wraps w and calls fn with the wrapped w and returns the
|
|
||||||
// resulting metrics. This is very similar to CaptureMetrics (which is just
|
|
||||||
// sugar on top of this func), but is a more usable interface if your
|
|
||||||
// application doesn't use the Go http.Handler interface.
|
|
||||||
func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metrics {
|
|
||||||
m := Metrics{Code: http.StatusOK}
|
|
||||||
m.CaptureMetrics(w, fn)
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// CaptureMetrics wraps w and calls fn with the wrapped w and updates
|
|
||||||
// Metrics m with the resulting metrics. This is similar to CaptureMetricsFn,
|
|
||||||
// but allows one to customize starting Metrics object.
|
|
||||||
func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWriter)) {
|
|
||||||
var (
|
|
||||||
start = time.Now()
|
|
||||||
headerWritten bool
|
|
||||||
hooks = Hooks{
|
|
||||||
WriteHeader: func(next WriteHeaderFunc) WriteHeaderFunc {
|
|
||||||
return func(code int) {
|
|
||||||
next(code)
|
|
||||||
|
|
||||||
if !(code >= 100 && code <= 199) && !headerWritten {
|
|
||||||
m.Code = code
|
|
||||||
headerWritten = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Write: func(next WriteFunc) WriteFunc {
|
|
||||||
return func(p []byte) (int, error) {
|
|
||||||
n, err := next(p)
|
|
||||||
|
|
||||||
m.Written += int64(n)
|
|
||||||
headerWritten = true
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ReadFrom: func(next ReadFromFunc) ReadFromFunc {
|
|
||||||
return func(src io.Reader) (int64, error) {
|
|
||||||
n, err := next(src)
|
|
||||||
|
|
||||||
headerWritten = true
|
|
||||||
m.Written += n
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
fn(Wrap(w, hooks))
|
|
||||||
m.Duration += time.Since(start)
|
|
||||||
}
|
|
||||||
10
src/server/vendor/github.com/felixge/httpsnoop/docs.go
generated
vendored
10
src/server/vendor/github.com/felixge/httpsnoop/docs.go
generated
vendored
@ -1,10 +0,0 @@
|
|||||||
// Package httpsnoop provides an easy way to capture http related metrics (i.e.
|
|
||||||
// response time, bytes written, and http status code) from your application's
|
|
||||||
// http.Handlers.
|
|
||||||
//
|
|
||||||
// Doing this requires non-trivial wrapping of the http.ResponseWriter
|
|
||||||
// interface, which is also exposed for users interested in a more low-level
|
|
||||||
// API.
|
|
||||||
package httpsnoop
|
|
||||||
|
|
||||||
//go:generate go run codegen/main.go
|
|
||||||
436
src/server/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go
generated
vendored
436
src/server/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go
generated
vendored
@ -1,436 +0,0 @@
|
|||||||
// +build go1.8
|
|
||||||
// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package httpsnoop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HeaderFunc is part of the http.ResponseWriter interface.
|
|
||||||
type HeaderFunc func() http.Header
|
|
||||||
|
|
||||||
// WriteHeaderFunc is part of the http.ResponseWriter interface.
|
|
||||||
type WriteHeaderFunc func(code int)
|
|
||||||
|
|
||||||
// WriteFunc is part of the http.ResponseWriter interface.
|
|
||||||
type WriteFunc func(b []byte) (int, error)
|
|
||||||
|
|
||||||
// FlushFunc is part of the http.Flusher interface.
|
|
||||||
type FlushFunc func()
|
|
||||||
|
|
||||||
// CloseNotifyFunc is part of the http.CloseNotifier interface.
|
|
||||||
type CloseNotifyFunc func() <-chan bool
|
|
||||||
|
|
||||||
// HijackFunc is part of the http.Hijacker interface.
|
|
||||||
type HijackFunc func() (net.Conn, *bufio.ReadWriter, error)
|
|
||||||
|
|
||||||
// ReadFromFunc is part of the io.ReaderFrom interface.
|
|
||||||
type ReadFromFunc func(src io.Reader) (int64, error)
|
|
||||||
|
|
||||||
// PushFunc is part of the http.Pusher interface.
|
|
||||||
type PushFunc func(target string, opts *http.PushOptions) error
|
|
||||||
|
|
||||||
// Hooks defines a set of method interceptors for methods included in
|
|
||||||
// http.ResponseWriter as well as some others. You can think of them as
|
|
||||||
// middleware for the function calls they target. See Wrap for more details.
|
|
||||||
type Hooks struct {
|
|
||||||
Header func(HeaderFunc) HeaderFunc
|
|
||||||
WriteHeader func(WriteHeaderFunc) WriteHeaderFunc
|
|
||||||
Write func(WriteFunc) WriteFunc
|
|
||||||
Flush func(FlushFunc) FlushFunc
|
|
||||||
CloseNotify func(CloseNotifyFunc) CloseNotifyFunc
|
|
||||||
Hijack func(HijackFunc) HijackFunc
|
|
||||||
ReadFrom func(ReadFromFunc) ReadFromFunc
|
|
||||||
Push func(PushFunc) PushFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap returns a wrapped version of w that provides the exact same interface
|
|
||||||
// as w. Specifically if w implements any combination of:
|
|
||||||
//
|
|
||||||
// - http.Flusher
|
|
||||||
// - http.CloseNotifier
|
|
||||||
// - http.Hijacker
|
|
||||||
// - io.ReaderFrom
|
|
||||||
// - http.Pusher
|
|
||||||
//
|
|
||||||
// The wrapped version will implement the exact same combination. If no hooks
|
|
||||||
// are set, the wrapped version also behaves exactly as w. Hooks targeting
|
|
||||||
// methods not supported by w are ignored. Any other hooks will intercept the
|
|
||||||
// method they target and may modify the call's arguments and/or return values.
|
|
||||||
// The CaptureMetrics implementation serves as a working example for how the
|
|
||||||
// hooks can be used.
|
|
||||||
func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {
|
|
||||||
rw := &rw{w: w, h: hooks}
|
|
||||||
_, i0 := w.(http.Flusher)
|
|
||||||
_, i1 := w.(http.CloseNotifier)
|
|
||||||
_, i2 := w.(http.Hijacker)
|
|
||||||
_, i3 := w.(io.ReaderFrom)
|
|
||||||
_, i4 := w.(http.Pusher)
|
|
||||||
switch {
|
|
||||||
// combination 1/32
|
|
||||||
case !i0 && !i1 && !i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
}{rw, rw}
|
|
||||||
// combination 2/32
|
|
||||||
case !i0 && !i1 && !i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 3/32
|
|
||||||
case !i0 && !i1 && !i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 4/32
|
|
||||||
case !i0 && !i1 && !i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 5/32
|
|
||||||
case !i0 && !i1 && i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 6/32
|
|
||||||
case !i0 && !i1 && i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Hijacker
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 7/32
|
|
||||||
case !i0 && !i1 && i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 8/32
|
|
||||||
case !i0 && !i1 && i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 9/32
|
|
||||||
case !i0 && i1 && !i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 10/32
|
|
||||||
case !i0 && i1 && !i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 11/32
|
|
||||||
case !i0 && i1 && !i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 12/32
|
|
||||||
case !i0 && i1 && !i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 13/32
|
|
||||||
case !i0 && i1 && i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 14/32
|
|
||||||
case !i0 && i1 && i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 15/32
|
|
||||||
case !i0 && i1 && i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 16/32
|
|
||||||
case !i0 && i1 && i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw, rw}
|
|
||||||
// combination 17/32
|
|
||||||
case i0 && !i1 && !i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 18/32
|
|
||||||
case i0 && !i1 && !i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 19/32
|
|
||||||
case i0 && !i1 && !i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 20/32
|
|
||||||
case i0 && !i1 && !i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 21/32
|
|
||||||
case i0 && !i1 && i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 22/32
|
|
||||||
case i0 && !i1 && i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.Hijacker
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 23/32
|
|
||||||
case i0 && !i1 && i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 24/32
|
|
||||||
case i0 && !i1 && i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw, rw}
|
|
||||||
// combination 25/32
|
|
||||||
case i0 && i1 && !i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 26/32
|
|
||||||
case i0 && i1 && !i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 27/32
|
|
||||||
case i0 && i1 && !i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 28/32
|
|
||||||
case i0 && i1 && !i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw, rw}
|
|
||||||
// combination 29/32
|
|
||||||
case i0 && i1 && i2 && !i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 30/32
|
|
||||||
case i0 && i1 && i2 && !i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw, rw}
|
|
||||||
// combination 31/32
|
|
||||||
case i0 && i1 && i2 && i3 && !i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw, rw}
|
|
||||||
// combination 32/32
|
|
||||||
case i0 && i1 && i2 && i3 && i4:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
http.Pusher
|
|
||||||
}{rw, rw, rw, rw, rw, rw, rw}
|
|
||||||
}
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
||||||
|
|
||||||
type rw struct {
|
|
||||||
w http.ResponseWriter
|
|
||||||
h Hooks
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Unwrap() http.ResponseWriter {
|
|
||||||
return w.w
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Header() http.Header {
|
|
||||||
f := w.w.(http.ResponseWriter).Header
|
|
||||||
if w.h.Header != nil {
|
|
||||||
f = w.h.Header(f)
|
|
||||||
}
|
|
||||||
return f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) WriteHeader(code int) {
|
|
||||||
f := w.w.(http.ResponseWriter).WriteHeader
|
|
||||||
if w.h.WriteHeader != nil {
|
|
||||||
f = w.h.WriteHeader(f)
|
|
||||||
}
|
|
||||||
f(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Write(b []byte) (int, error) {
|
|
||||||
f := w.w.(http.ResponseWriter).Write
|
|
||||||
if w.h.Write != nil {
|
|
||||||
f = w.h.Write(f)
|
|
||||||
}
|
|
||||||
return f(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Flush() {
|
|
||||||
f := w.w.(http.Flusher).Flush
|
|
||||||
if w.h.Flush != nil {
|
|
||||||
f = w.h.Flush(f)
|
|
||||||
}
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) CloseNotify() <-chan bool {
|
|
||||||
f := w.w.(http.CloseNotifier).CloseNotify
|
|
||||||
if w.h.CloseNotify != nil {
|
|
||||||
f = w.h.CloseNotify(f)
|
|
||||||
}
|
|
||||||
return f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
||||||
f := w.w.(http.Hijacker).Hijack
|
|
||||||
if w.h.Hijack != nil {
|
|
||||||
f = w.h.Hijack(f)
|
|
||||||
}
|
|
||||||
return f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) ReadFrom(src io.Reader) (int64, error) {
|
|
||||||
f := w.w.(io.ReaderFrom).ReadFrom
|
|
||||||
if w.h.ReadFrom != nil {
|
|
||||||
f = w.h.ReadFrom(f)
|
|
||||||
}
|
|
||||||
return f(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Push(target string, opts *http.PushOptions) error {
|
|
||||||
f := w.w.(http.Pusher).Push
|
|
||||||
if w.h.Push != nil {
|
|
||||||
f = w.h.Push(f)
|
|
||||||
}
|
|
||||||
return f(target, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Unwrapper interface {
|
|
||||||
Unwrap() http.ResponseWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the underlying http.ResponseWriter from within zero or more
|
|
||||||
// layers of httpsnoop wrappers.
|
|
||||||
func Unwrap(w http.ResponseWriter) http.ResponseWriter {
|
|
||||||
if rw, ok := w.(Unwrapper); ok {
|
|
||||||
// recurse until rw.Unwrap() returns a non-Unwrapper
|
|
||||||
return Unwrap(rw.Unwrap())
|
|
||||||
} else {
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
}
|
|
||||||
278
src/server/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go
generated
vendored
278
src/server/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go
generated
vendored
@ -1,278 +0,0 @@
|
|||||||
// +build !go1.8
|
|
||||||
// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package httpsnoop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HeaderFunc is part of the http.ResponseWriter interface.
|
|
||||||
type HeaderFunc func() http.Header
|
|
||||||
|
|
||||||
// WriteHeaderFunc is part of the http.ResponseWriter interface.
|
|
||||||
type WriteHeaderFunc func(code int)
|
|
||||||
|
|
||||||
// WriteFunc is part of the http.ResponseWriter interface.
|
|
||||||
type WriteFunc func(b []byte) (int, error)
|
|
||||||
|
|
||||||
// FlushFunc is part of the http.Flusher interface.
|
|
||||||
type FlushFunc func()
|
|
||||||
|
|
||||||
// CloseNotifyFunc is part of the http.CloseNotifier interface.
|
|
||||||
type CloseNotifyFunc func() <-chan bool
|
|
||||||
|
|
||||||
// HijackFunc is part of the http.Hijacker interface.
|
|
||||||
type HijackFunc func() (net.Conn, *bufio.ReadWriter, error)
|
|
||||||
|
|
||||||
// ReadFromFunc is part of the io.ReaderFrom interface.
|
|
||||||
type ReadFromFunc func(src io.Reader) (int64, error)
|
|
||||||
|
|
||||||
// Hooks defines a set of method interceptors for methods included in
|
|
||||||
// http.ResponseWriter as well as some others. You can think of them as
|
|
||||||
// middleware for the function calls they target. See Wrap for more details.
|
|
||||||
type Hooks struct {
|
|
||||||
Header func(HeaderFunc) HeaderFunc
|
|
||||||
WriteHeader func(WriteHeaderFunc) WriteHeaderFunc
|
|
||||||
Write func(WriteFunc) WriteFunc
|
|
||||||
Flush func(FlushFunc) FlushFunc
|
|
||||||
CloseNotify func(CloseNotifyFunc) CloseNotifyFunc
|
|
||||||
Hijack func(HijackFunc) HijackFunc
|
|
||||||
ReadFrom func(ReadFromFunc) ReadFromFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap returns a wrapped version of w that provides the exact same interface
|
|
||||||
// as w. Specifically if w implements any combination of:
|
|
||||||
//
|
|
||||||
// - http.Flusher
|
|
||||||
// - http.CloseNotifier
|
|
||||||
// - http.Hijacker
|
|
||||||
// - io.ReaderFrom
|
|
||||||
//
|
|
||||||
// The wrapped version will implement the exact same combination. If no hooks
|
|
||||||
// are set, the wrapped version also behaves exactly as w. Hooks targeting
|
|
||||||
// methods not supported by w are ignored. Any other hooks will intercept the
|
|
||||||
// method they target and may modify the call's arguments and/or return values.
|
|
||||||
// The CaptureMetrics implementation serves as a working example for how the
|
|
||||||
// hooks can be used.
|
|
||||||
func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {
|
|
||||||
rw := &rw{w: w, h: hooks}
|
|
||||||
_, i0 := w.(http.Flusher)
|
|
||||||
_, i1 := w.(http.CloseNotifier)
|
|
||||||
_, i2 := w.(http.Hijacker)
|
|
||||||
_, i3 := w.(io.ReaderFrom)
|
|
||||||
switch {
|
|
||||||
// combination 1/16
|
|
||||||
case !i0 && !i1 && !i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
}{rw, rw}
|
|
||||||
// combination 2/16
|
|
||||||
case !i0 && !i1 && !i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 3/16
|
|
||||||
case !i0 && !i1 && i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 4/16
|
|
||||||
case !i0 && !i1 && i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 5/16
|
|
||||||
case !i0 && i1 && !i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 6/16
|
|
||||||
case !i0 && i1 && !i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 7/16
|
|
||||||
case !i0 && i1 && i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 8/16
|
|
||||||
case !i0 && i1 && i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 9/16
|
|
||||||
case i0 && !i1 && !i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
}{rw, rw, rw}
|
|
||||||
// combination 10/16
|
|
||||||
case i0 && !i1 && !i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 11/16
|
|
||||||
case i0 && !i1 && i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 12/16
|
|
||||||
case i0 && !i1 && i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 13/16
|
|
||||||
case i0 && i1 && !i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
}{rw, rw, rw, rw}
|
|
||||||
// combination 14/16
|
|
||||||
case i0 && i1 && !i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 15/16
|
|
||||||
case i0 && i1 && i2 && !i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
}{rw, rw, rw, rw, rw}
|
|
||||||
// combination 16/16
|
|
||||||
case i0 && i1 && i2 && i3:
|
|
||||||
return struct {
|
|
||||||
Unwrapper
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
http.CloseNotifier
|
|
||||||
http.Hijacker
|
|
||||||
io.ReaderFrom
|
|
||||||
}{rw, rw, rw, rw, rw, rw}
|
|
||||||
}
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
||||||
|
|
||||||
type rw struct {
|
|
||||||
w http.ResponseWriter
|
|
||||||
h Hooks
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Unwrap() http.ResponseWriter {
|
|
||||||
return w.w
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Header() http.Header {
|
|
||||||
f := w.w.(http.ResponseWriter).Header
|
|
||||||
if w.h.Header != nil {
|
|
||||||
f = w.h.Header(f)
|
|
||||||
}
|
|
||||||
return f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) WriteHeader(code int) {
|
|
||||||
f := w.w.(http.ResponseWriter).WriteHeader
|
|
||||||
if w.h.WriteHeader != nil {
|
|
||||||
f = w.h.WriteHeader(f)
|
|
||||||
}
|
|
||||||
f(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Write(b []byte) (int, error) {
|
|
||||||
f := w.w.(http.ResponseWriter).Write
|
|
||||||
if w.h.Write != nil {
|
|
||||||
f = w.h.Write(f)
|
|
||||||
}
|
|
||||||
return f(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Flush() {
|
|
||||||
f := w.w.(http.Flusher).Flush
|
|
||||||
if w.h.Flush != nil {
|
|
||||||
f = w.h.Flush(f)
|
|
||||||
}
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) CloseNotify() <-chan bool {
|
|
||||||
f := w.w.(http.CloseNotifier).CloseNotify
|
|
||||||
if w.h.CloseNotify != nil {
|
|
||||||
f = w.h.CloseNotify(f)
|
|
||||||
}
|
|
||||||
return f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
||||||
f := w.w.(http.Hijacker).Hijack
|
|
||||||
if w.h.Hijack != nil {
|
|
||||||
f = w.h.Hijack(f)
|
|
||||||
}
|
|
||||||
return f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *rw) ReadFrom(src io.Reader) (int64, error) {
|
|
||||||
f := w.w.(io.ReaderFrom).ReadFrom
|
|
||||||
if w.h.ReadFrom != nil {
|
|
||||||
f = w.h.ReadFrom(f)
|
|
||||||
}
|
|
||||||
return f(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Unwrapper interface {
|
|
||||||
Unwrap() http.ResponseWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the underlying http.ResponseWriter from within zero or more
|
|
||||||
// layers of httpsnoop wrappers.
|
|
||||||
func Unwrap(w http.ResponseWriter) http.ResponseWriter {
|
|
||||||
if rw, ok := w.(Unwrapper); ok {
|
|
||||||
// recurse until rw.Unwrap() returns a non-Unwrapper
|
|
||||||
return Unwrap(rw.Unwrap())
|
|
||||||
} else {
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
}
|
|
||||||
26
src/server/vendor/github.com/go-logr/logr/.golangci.yaml
generated
vendored
26
src/server/vendor/github.com/go-logr/logr/.golangci.yaml
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
run:
|
|
||||||
timeout: 1m
|
|
||||||
tests: true
|
|
||||||
|
|
||||||
linters:
|
|
||||||
disable-all: true
|
|
||||||
enable:
|
|
||||||
- asciicheck
|
|
||||||
- errcheck
|
|
||||||
- forcetypeassert
|
|
||||||
- gocritic
|
|
||||||
- gofmt
|
|
||||||
- goimports
|
|
||||||
- gosimple
|
|
||||||
- govet
|
|
||||||
- ineffassign
|
|
||||||
- misspell
|
|
||||||
- revive
|
|
||||||
- staticcheck
|
|
||||||
- typecheck
|
|
||||||
- unused
|
|
||||||
|
|
||||||
issues:
|
|
||||||
exclude-use-default: false
|
|
||||||
max-issues-per-linter: 0
|
|
||||||
max-same-issues: 10
|
|
||||||
6
src/server/vendor/github.com/go-logr/logr/CHANGELOG.md
generated
vendored
6
src/server/vendor/github.com/go-logr/logr/CHANGELOG.md
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
# CHANGELOG
|
|
||||||
|
|
||||||
## v1.0.0-rc1
|
|
||||||
|
|
||||||
This is the first logged release. Major changes (including breaking changes)
|
|
||||||
have occurred since earlier tags.
|
|
||||||
17
src/server/vendor/github.com/go-logr/logr/CONTRIBUTING.md
generated
vendored
17
src/server/vendor/github.com/go-logr/logr/CONTRIBUTING.md
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
Logr is open to pull-requests, provided they fit within the intended scope of
|
|
||||||
the project. Specifically, this library aims to be VERY small and minimalist,
|
|
||||||
with no external dependencies.
|
|
||||||
|
|
||||||
## Compatibility
|
|
||||||
|
|
||||||
This project intends to follow [semantic versioning](http://semver.org) and
|
|
||||||
is very strict about compatibility. Any proposed changes MUST follow those
|
|
||||||
rules.
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
As a logging library, logr must be as light-weight as possible. Any proposed
|
|
||||||
code change must include results of running the [benchmark](./benchmark)
|
|
||||||
before and after the change.
|
|
||||||
201
src/server/vendor/github.com/go-logr/logr/LICENSE
generated
vendored
201
src/server/vendor/github.com/go-logr/logr/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
407
src/server/vendor/github.com/go-logr/logr/README.md
generated
vendored
407
src/server/vendor/github.com/go-logr/logr/README.md
generated
vendored
@ -1,407 +0,0 @@
|
|||||||
# A minimal logging API for Go
|
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/go-logr/logr)
|
|
||||||
[](https://goreportcard.com/report/github.com/go-logr/logr)
|
|
||||||
[](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr)
|
|
||||||
|
|
||||||
logr offers an(other) opinion on how Go programs and libraries can do logging
|
|
||||||
without becoming coupled to a particular logging implementation. This is not
|
|
||||||
an implementation of logging - it is an API. In fact it is two APIs with two
|
|
||||||
different sets of users.
|
|
||||||
|
|
||||||
The `Logger` type is intended for application and library authors. It provides
|
|
||||||
a relatively small API which can be used everywhere you want to emit logs. It
|
|
||||||
defers the actual act of writing logs (to files, to stdout, or whatever) to the
|
|
||||||
`LogSink` interface.
|
|
||||||
|
|
||||||
The `LogSink` interface is intended for logging library implementers. It is a
|
|
||||||
pure interface which can be implemented by logging frameworks to provide the actual logging
|
|
||||||
functionality.
|
|
||||||
|
|
||||||
This decoupling allows application and library developers to write code in
|
|
||||||
terms of `logr.Logger` (which has very low dependency fan-out) while the
|
|
||||||
implementation of logging is managed "up stack" (e.g. in or near `main()`.)
|
|
||||||
Application developers can then switch out implementations as necessary.
|
|
||||||
|
|
||||||
Many people assert that libraries should not be logging, and as such efforts
|
|
||||||
like this are pointless. Those people are welcome to convince the authors of
|
|
||||||
the tens-of-thousands of libraries that *DO* write logs that they are all
|
|
||||||
wrong. In the meantime, logr takes a more practical approach.
|
|
||||||
|
|
||||||
## Typical usage
|
|
||||||
|
|
||||||
Somewhere, early in an application's life, it will make a decision about which
|
|
||||||
logging library (implementation) it actually wants to use. Something like:
|
|
||||||
|
|
||||||
```
|
|
||||||
func main() {
|
|
||||||
// ... other setup code ...
|
|
||||||
|
|
||||||
// Create the "root" logger. We have chosen the "logimpl" implementation,
|
|
||||||
// which takes some initial parameters and returns a logr.Logger.
|
|
||||||
logger := logimpl.New(param1, param2)
|
|
||||||
|
|
||||||
// ... other setup code ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Most apps will call into other libraries, create structures to govern the flow,
|
|
||||||
etc. The `logr.Logger` object can be passed to these other libraries, stored
|
|
||||||
in structs, or even used as a package-global variable, if needed. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
app := createTheAppObject(logger)
|
|
||||||
app.Run()
|
|
||||||
```
|
|
||||||
|
|
||||||
Outside of this early setup, no other packages need to know about the choice of
|
|
||||||
implementation. They write logs in terms of the `logr.Logger` that they
|
|
||||||
received:
|
|
||||||
|
|
||||||
```
|
|
||||||
type appObject struct {
|
|
||||||
// ... other fields ...
|
|
||||||
logger logr.Logger
|
|
||||||
// ... other fields ...
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app *appObject) Run() {
|
|
||||||
app.logger.Info("starting up", "timestamp", time.Now())
|
|
||||||
|
|
||||||
// ... app code ...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
If the Go standard library had defined an interface for logging, this project
|
|
||||||
probably would not be needed. Alas, here we are.
|
|
||||||
|
|
||||||
When the Go developers started developing such an interface with
|
|
||||||
[slog](https://github.com/golang/go/issues/56345), they adopted some of the
|
|
||||||
logr design but also left out some parts and changed others:
|
|
||||||
|
|
||||||
| Feature | logr | slog |
|
|
||||||
|---------|------|------|
|
|
||||||
| High-level API | `Logger` (passed by value) | `Logger` (passed by [pointer](https://github.com/golang/go/issues/59126)) |
|
|
||||||
| Low-level API | `LogSink` | `Handler` |
|
|
||||||
| Stack unwinding | done by `LogSink` | done by `Logger` |
|
|
||||||
| Skipping helper functions | `WithCallDepth`, `WithCallStackHelper` | [not supported by Logger](https://github.com/golang/go/issues/59145) |
|
|
||||||
| Generating a value for logging on demand | `Marshaler` | `LogValuer` |
|
|
||||||
| Log levels | >= 0, higher meaning "less important" | positive and negative, with 0 for "info" and higher meaning "more important" |
|
|
||||||
| Error log entries | always logged, don't have a verbosity level | normal log entries with level >= `LevelError` |
|
|
||||||
| Passing logger via context | `NewContext`, `FromContext` | no API |
|
|
||||||
| Adding a name to a logger | `WithName` | no API |
|
|
||||||
| Modify verbosity of log entries in a call chain | `V` | no API |
|
|
||||||
| Grouping of key/value pairs | not supported | `WithGroup`, `GroupValue` |
|
|
||||||
| Pass context for extracting additional values | no API | API variants like `InfoCtx` |
|
|
||||||
|
|
||||||
The high-level slog API is explicitly meant to be one of many different APIs
|
|
||||||
that can be layered on top of a shared `slog.Handler`. logr is one such
|
|
||||||
alternative API, with [interoperability](#slog-interoperability) provided by
|
|
||||||
some conversion functions.
|
|
||||||
|
|
||||||
### Inspiration
|
|
||||||
|
|
||||||
Before you consider this package, please read [this blog post by the
|
|
||||||
inimitable Dave Cheney][warning-makes-no-sense]. We really appreciate what
|
|
||||||
he has to say, and it largely aligns with our own experiences.
|
|
||||||
|
|
||||||
### Differences from Dave's ideas
|
|
||||||
|
|
||||||
The main differences are:
|
|
||||||
|
|
||||||
1. Dave basically proposes doing away with the notion of a logging API in favor
|
|
||||||
of `fmt.Printf()`. We disagree, especially when you consider things like output
|
|
||||||
locations, timestamps, file and line decorations, and structured logging. This
|
|
||||||
package restricts the logging API to just 2 types of logs: info and error.
|
|
||||||
|
|
||||||
Info logs are things you want to tell the user which are not errors. Error
|
|
||||||
logs are, well, errors. If your code receives an `error` from a subordinate
|
|
||||||
function call and is logging that `error` *and not returning it*, use error
|
|
||||||
logs.
|
|
||||||
|
|
||||||
2. Verbosity-levels on info logs. This gives developers a chance to indicate
|
|
||||||
arbitrary grades of importance for info logs, without assigning names with
|
|
||||||
semantic meaning such as "warning", "trace", and "debug." Superficially this
|
|
||||||
may feel very similar, but the primary difference is the lack of semantics.
|
|
||||||
Because verbosity is a numerical value, it's safe to assume that an app running
|
|
||||||
with higher verbosity means more (and less important) logs will be generated.
|
|
||||||
|
|
||||||
## Implementations (non-exhaustive)
|
|
||||||
|
|
||||||
There are implementations for the following logging libraries:
|
|
||||||
|
|
||||||
- **a function** (can bridge to non-structured libraries): [funcr](https://github.com/go-logr/logr/tree/master/funcr)
|
|
||||||
- **a testing.T** (for use in Go tests, with JSON-like output): [testr](https://github.com/go-logr/logr/tree/master/testr)
|
|
||||||
- **github.com/google/glog**: [glogr](https://github.com/go-logr/glogr)
|
|
||||||
- **k8s.io/klog** (for Kubernetes): [klogr](https://git.k8s.io/klog/klogr)
|
|
||||||
- **a testing.T** (with klog-like text output): [ktesting](https://git.k8s.io/klog/ktesting)
|
|
||||||
- **go.uber.org/zap**: [zapr](https://github.com/go-logr/zapr)
|
|
||||||
- **log** (the Go standard library logger): [stdr](https://github.com/go-logr/stdr)
|
|
||||||
- **github.com/sirupsen/logrus**: [logrusr](https://github.com/bombsimon/logrusr)
|
|
||||||
- **github.com/wojas/genericr**: [genericr](https://github.com/wojas/genericr) (makes it easy to implement your own backend)
|
|
||||||
- **logfmt** (Heroku style [logging](https://www.brandur.org/logfmt)): [logfmtr](https://github.com/iand/logfmtr)
|
|
||||||
- **github.com/rs/zerolog**: [zerologr](https://github.com/go-logr/zerologr)
|
|
||||||
- **github.com/go-kit/log**: [gokitlogr](https://github.com/tonglil/gokitlogr) (also compatible with github.com/go-kit/kit/log since v0.12.0)
|
|
||||||
- **bytes.Buffer** (writing to a buffer): [bufrlogr](https://github.com/tonglil/buflogr) (useful for ensuring values were logged, like during testing)
|
|
||||||
|
|
||||||
## slog interoperability
|
|
||||||
|
|
||||||
Interoperability goes both ways, using the `logr.Logger` API with a `slog.Handler`
|
|
||||||
and using the `slog.Logger` API with a `logr.LogSink`. `FromSlogHandler` and
|
|
||||||
`ToSlogHandler` convert between a `logr.Logger` and a `slog.Handler`.
|
|
||||||
As usual, `slog.New` can be used to wrap such a `slog.Handler` in the high-level
|
|
||||||
slog API.
|
|
||||||
|
|
||||||
### Using a `logr.LogSink` as backend for slog
|
|
||||||
|
|
||||||
Ideally, a logr sink implementation should support both logr and slog by
|
|
||||||
implementing both the normal logr interface(s) and `SlogSink`. Because
|
|
||||||
of a conflict in the parameters of the common `Enabled` method, it is [not
|
|
||||||
possible to implement both slog.Handler and logr.Sink in the same
|
|
||||||
type](https://github.com/golang/go/issues/59110).
|
|
||||||
|
|
||||||
If both are supported, log calls can go from the high-level APIs to the backend
|
|
||||||
without the need to convert parameters. `FromSlogHandler` and `ToSlogHandler` can
|
|
||||||
convert back and forth without adding additional wrappers, with one exception:
|
|
||||||
when `Logger.V` was used to adjust the verbosity for a `slog.Handler`, then
|
|
||||||
`ToSlogHandler` has to use a wrapper which adjusts the verbosity for future
|
|
||||||
log calls.
|
|
||||||
|
|
||||||
Such an implementation should also support values that implement specific
|
|
||||||
interfaces from both packages for logging (`logr.Marshaler`, `slog.LogValuer`,
|
|
||||||
`slog.GroupValue`). logr does not convert those.
|
|
||||||
|
|
||||||
Not supporting slog has several drawbacks:
|
|
||||||
- Recording source code locations works correctly if the handler gets called
|
|
||||||
through `slog.Logger`, but may be wrong in other cases. That's because a
|
|
||||||
`logr.Sink` does its own stack unwinding instead of using the program counter
|
|
||||||
provided by the high-level API.
|
|
||||||
- slog levels <= 0 can be mapped to logr levels by negating the level without a
|
|
||||||
loss of information. But all slog levels > 0 (e.g. `slog.LevelWarning` as
|
|
||||||
used by `slog.Logger.Warn`) must be mapped to 0 before calling the sink
|
|
||||||
because logr does not support "more important than info" levels.
|
|
||||||
- The slog group concept is supported by prefixing each key in a key/value
|
|
||||||
pair with the group names, separated by a dot. For structured output like
|
|
||||||
JSON it would be better to group the key/value pairs inside an object.
|
|
||||||
- Special slog values and interfaces don't work as expected.
|
|
||||||
- The overhead is likely to be higher.
|
|
||||||
|
|
||||||
These drawbacks are severe enough that applications using a mixture of slog and
|
|
||||||
logr should switch to a different backend.
|
|
||||||
|
|
||||||
### Using a `slog.Handler` as backend for logr
|
|
||||||
|
|
||||||
Using a plain `slog.Handler` without support for logr works better than the
|
|
||||||
other direction:
|
|
||||||
- All logr verbosity levels can be mapped 1:1 to their corresponding slog level
|
|
||||||
by negating them.
|
|
||||||
- Stack unwinding is done by the `SlogSink` and the resulting program
|
|
||||||
counter is passed to the `slog.Handler`.
|
|
||||||
- Names added via `Logger.WithName` are gathered and recorded in an additional
|
|
||||||
attribute with `logger` as key and the names separated by slash as value.
|
|
||||||
- `Logger.Error` is turned into a log record with `slog.LevelError` as level
|
|
||||||
and an additional attribute with `err` as key, if an error was provided.
|
|
||||||
|
|
||||||
The main drawback is that `logr.Marshaler` will not be supported. Types should
|
|
||||||
ideally support both `logr.Marshaler` and `slog.Valuer`. If compatibility
|
|
||||||
with logr implementations without slog support is not important, then
|
|
||||||
`slog.Valuer` is sufficient.
|
|
||||||
|
|
||||||
### Context support for slog
|
|
||||||
|
|
||||||
Storing a logger in a `context.Context` is not supported by
|
|
||||||
slog. `NewContextWithSlogLogger` and `FromContextAsSlogLogger` can be
|
|
||||||
used to fill this gap. They store and retrieve a `slog.Logger` pointer
|
|
||||||
under the same context key that is also used by `NewContext` and
|
|
||||||
`FromContext` for `logr.Logger` value.
|
|
||||||
|
|
||||||
When `NewContextWithSlogLogger` is followed by `FromContext`, the latter will
|
|
||||||
automatically convert the `slog.Logger` to a
|
|
||||||
`logr.Logger`. `FromContextAsSlogLogger` does the same for the other direction.
|
|
||||||
|
|
||||||
With this approach, binaries which use either slog or logr are as efficient as
|
|
||||||
possible with no unnecessary allocations. This is also why the API stores a
|
|
||||||
`slog.Logger` pointer: when storing a `slog.Handler`, creating a `slog.Logger`
|
|
||||||
on retrieval would need to allocate one.
|
|
||||||
|
|
||||||
The downside is that switching back and forth needs more allocations. Because
|
|
||||||
logr is the API that is already in use by different packages, in particular
|
|
||||||
Kubernetes, the recommendation is to use the `logr.Logger` API in code which
|
|
||||||
uses contextual logging.
|
|
||||||
|
|
||||||
An alternative to adding values to a logger and storing that logger in the
|
|
||||||
context is to store the values in the context and to configure a logging
|
|
||||||
backend to extract those values when emitting log entries. This only works when
|
|
||||||
log calls are passed the context, which is not supported by the logr API.
|
|
||||||
|
|
||||||
With the slog API, it is possible, but not
|
|
||||||
required. https://github.com/veqryn/slog-context is a package for slog which
|
|
||||||
provides additional support code for this approach. It also contains wrappers
|
|
||||||
for the context functions in logr, so developers who prefer to not use the logr
|
|
||||||
APIs directly can use those instead and the resulting code will still be
|
|
||||||
interoperable with logr.
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
### Conceptual
|
|
||||||
|
|
||||||
#### Why structured logging?
|
|
||||||
|
|
||||||
- **Structured logs are more easily queryable**: Since you've got
|
|
||||||
key-value pairs, it's much easier to query your structured logs for
|
|
||||||
particular values by filtering on the contents of a particular key --
|
|
||||||
think searching request logs for error codes, Kubernetes reconcilers for
|
|
||||||
the name and namespace of the reconciled object, etc.
|
|
||||||
|
|
||||||
- **Structured logging makes it easier to have cross-referenceable logs**:
|
|
||||||
Similarly to searchability, if you maintain conventions around your
|
|
||||||
keys, it becomes easy to gather all log lines related to a particular
|
|
||||||
concept.
|
|
||||||
|
|
||||||
- **Structured logs allow better dimensions of filtering**: if you have
|
|
||||||
structure to your logs, you've got more precise control over how much
|
|
||||||
information is logged -- you might choose in a particular configuration
|
|
||||||
to log certain keys but not others, only log lines where a certain key
|
|
||||||
matches a certain value, etc., instead of just having v-levels and names
|
|
||||||
to key off of.
|
|
||||||
|
|
||||||
- **Structured logs better represent structured data**: sometimes, the
|
|
||||||
data that you want to log is inherently structured (think tuple-link
|
|
||||||
objects.) Structured logs allow you to preserve that structure when
|
|
||||||
outputting.
|
|
||||||
|
|
||||||
#### Why V-levels?
|
|
||||||
|
|
||||||
**V-levels give operators an easy way to control the chattiness of log
|
|
||||||
operations**. V-levels provide a way for a given package to distinguish
|
|
||||||
the relative importance or verbosity of a given log message. Then, if
|
|
||||||
a particular logger or package is logging too many messages, the user
|
|
||||||
of the package can simply change the v-levels for that library.
|
|
||||||
|
|
||||||
#### Why not named levels, like Info/Warning/Error?
|
|
||||||
|
|
||||||
Read [Dave Cheney's post][warning-makes-no-sense]. Then read [Differences
|
|
||||||
from Dave's ideas](#differences-from-daves-ideas).
|
|
||||||
|
|
||||||
#### Why not allow format strings, too?
|
|
||||||
|
|
||||||
**Format strings negate many of the benefits of structured logs**:
|
|
||||||
|
|
||||||
- They're not easily searchable without resorting to fuzzy searching,
|
|
||||||
regular expressions, etc.
|
|
||||||
|
|
||||||
- They don't store structured data well, since contents are flattened into
|
|
||||||
a string.
|
|
||||||
|
|
||||||
- They're not cross-referenceable.
|
|
||||||
|
|
||||||
- They don't compress easily, since the message is not constant.
|
|
||||||
|
|
||||||
(Unless you turn positional parameters into key-value pairs with numerical
|
|
||||||
keys, at which point you've gotten key-value logging with meaningless
|
|
||||||
keys.)
|
|
||||||
|
|
||||||
### Practical
|
|
||||||
|
|
||||||
#### Why key-value pairs, and not a map?
|
|
||||||
|
|
||||||
Key-value pairs are *much* easier to optimize, especially around
|
|
||||||
allocations. Zap (a structured logger that inspired logr's interface) has
|
|
||||||
[performance measurements](https://github.com/uber-go/zap#performance)
|
|
||||||
that show this quite nicely.
|
|
||||||
|
|
||||||
While the interface ends up being a little less obvious, you get
|
|
||||||
potentially better performance, plus avoid making users type
|
|
||||||
`map[string]string{}` every time they want to log.
|
|
||||||
|
|
||||||
#### What if my V-levels differ between libraries?
|
|
||||||
|
|
||||||
That's fine. Control your V-levels on a per-logger basis, and use the
|
|
||||||
`WithName` method to pass different loggers to different libraries.
|
|
||||||
|
|
||||||
Generally, you should take care to ensure that you have relatively
|
|
||||||
consistent V-levels within a given logger, however, as this makes deciding
|
|
||||||
on what verbosity of logs to request easier.
|
|
||||||
|
|
||||||
#### But I really want to use a format string!
|
|
||||||
|
|
||||||
That's not actually a question. Assuming your question is "how do
|
|
||||||
I convert my mental model of logging with format strings to logging with
|
|
||||||
constant messages":
|
|
||||||
|
|
||||||
1. Figure out what the error actually is, as you'd write in a TL;DR style,
|
|
||||||
and use that as a message.
|
|
||||||
|
|
||||||
2. For every place you'd write a format specifier, look to the word before
|
|
||||||
it, and add that as a key value pair.
|
|
||||||
|
|
||||||
For instance, consider the following examples (all taken from spots in the
|
|
||||||
Kubernetes codebase):
|
|
||||||
|
|
||||||
- `klog.V(4).Infof("Client is returning errors: code %v, error %v",
|
|
||||||
responseCode, err)` becomes `logger.Error(err, "client returned an
|
|
||||||
error", "code", responseCode)`
|
|
||||||
|
|
||||||
- `klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v",
|
|
||||||
seconds, retries, url)` becomes `logger.V(4).Info("got a retry-after
|
|
||||||
response when requesting url", "attempt", retries, "after
|
|
||||||
seconds", seconds, "url", url)`
|
|
||||||
|
|
||||||
If you *really* must use a format string, use it in a key's value, and
|
|
||||||
call `fmt.Sprintf` yourself. For instance: `log.Printf("unable to
|
|
||||||
reflect over type %T")` becomes `logger.Info("unable to reflect over
|
|
||||||
type", "type", fmt.Sprintf("%T"))`. In general though, the cases where
|
|
||||||
this is necessary should be few and far between.
|
|
||||||
|
|
||||||
#### How do I choose my V-levels?
|
|
||||||
|
|
||||||
This is basically the only hard constraint: increase V-levels to denote
|
|
||||||
more verbose or more debug-y logs.
|
|
||||||
|
|
||||||
Otherwise, you can start out with `0` as "you always want to see this",
|
|
||||||
`1` as "common logging that you might *possibly* want to turn off", and
|
|
||||||
`10` as "I would like to performance-test your log collection stack."
|
|
||||||
|
|
||||||
Then gradually choose levels in between as you need them, working your way
|
|
||||||
down from 10 (for debug and trace style logs) and up from 1 (for chattier
|
|
||||||
info-type logs). For reference, slog pre-defines -4 for debug logs
|
|
||||||
(corresponds to 4 in logr), which matches what is
|
|
||||||
[recommended for Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md#what-method-to-use).
|
|
||||||
|
|
||||||
#### How do I choose my keys?
|
|
||||||
|
|
||||||
Keys are fairly flexible, and can hold more or less any string
|
|
||||||
value. For best compatibility with implementations and consistency
|
|
||||||
with existing code in other projects, there are a few conventions you
|
|
||||||
should consider.
|
|
||||||
|
|
||||||
- Make your keys human-readable.
|
|
||||||
- Constant keys are generally a good idea.
|
|
||||||
- Be consistent across your codebase.
|
|
||||||
- Keys should naturally match parts of the message string.
|
|
||||||
- Use lower case for simple keys and
|
|
||||||
[lowerCamelCase](https://en.wiktionary.org/wiki/lowerCamelCase) for
|
|
||||||
more complex ones. Kubernetes is one example of a project that has
|
|
||||||
[adopted that
|
|
||||||
convention](https://github.com/kubernetes/community/blob/HEAD/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments).
|
|
||||||
|
|
||||||
While key names are mostly unrestricted (and spaces are acceptable),
|
|
||||||
it's generally a good idea to stick to printable ascii characters, or at
|
|
||||||
least match the general character set of your log lines.
|
|
||||||
|
|
||||||
#### Why should keys be constant values?
|
|
||||||
|
|
||||||
The point of structured logging is to make later log processing easier. Your
|
|
||||||
keys are, effectively, the schema of each log message. If you use different
|
|
||||||
keys across instances of the same log line, you will make your structured logs
|
|
||||||
much harder to use. `Sprintf()` is for values, not for keys!
|
|
||||||
|
|
||||||
#### Why is this not a pure interface?
|
|
||||||
|
|
||||||
The Logger type is implemented as a struct in order to allow the Go compiler to
|
|
||||||
optimize things like high-V `Info` logs that are not triggered. Not all of
|
|
||||||
these implementations are implemented yet, but this structure was suggested as
|
|
||||||
a way to ensure they *can* be implemented. All of the real work is behind the
|
|
||||||
`LogSink` interface.
|
|
||||||
|
|
||||||
[warning-makes-no-sense]: http://dave.cheney.net/2015/11/05/lets-talk-about-logging
|
|
||||||
18
src/server/vendor/github.com/go-logr/logr/SECURITY.md
generated
vendored
18
src/server/vendor/github.com/go-logr/logr/SECURITY.md
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
If you have discovered a security vulnerability in this project, please report it
|
|
||||||
privately. **Do not disclose it as a public issue.** This gives us time to work with you
|
|
||||||
to fix the issue before public exposure, reducing the chance that the exploit will be
|
|
||||||
used before a patch is released.
|
|
||||||
|
|
||||||
You may submit the report in the following ways:
|
|
||||||
|
|
||||||
- send an email to go-logr-security@googlegroups.com
|
|
||||||
- send us a [private vulnerability report](https://github.com/go-logr/logr/security/advisories/new)
|
|
||||||
|
|
||||||
Please provide the following information in your report:
|
|
||||||
|
|
||||||
- A description of the vulnerability and its impact
|
|
||||||
- How to reproduce the issue
|
|
||||||
|
|
||||||
We ask that you give us 90 days to work on a fix before public exposure.
|
|
||||||
33
src/server/vendor/github.com/go-logr/logr/context.go
generated
vendored
33
src/server/vendor/github.com/go-logr/logr/context.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2023 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package logr
|
|
||||||
|
|
||||||
// contextKey is how we find Loggers in a context.Context. With Go < 1.21,
|
|
||||||
// the value is always a Logger value. With Go >= 1.21, the value can be a
|
|
||||||
// Logger value or a slog.Logger pointer.
|
|
||||||
type contextKey struct{}
|
|
||||||
|
|
||||||
// notFoundError exists to carry an IsNotFound method.
|
|
||||||
type notFoundError struct{}
|
|
||||||
|
|
||||||
func (notFoundError) Error() string {
|
|
||||||
return "no logr.Logger was present"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (notFoundError) IsNotFound() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
49
src/server/vendor/github.com/go-logr/logr/context_noslog.go
generated
vendored
49
src/server/vendor/github.com/go-logr/logr/context_noslog.go
generated
vendored
@ -1,49 +0,0 @@
|
|||||||
//go:build !go1.21
|
|
||||||
// +build !go1.21
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2019 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package logr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FromContext returns a Logger from ctx or an error if no Logger is found.
|
|
||||||
func FromContext(ctx context.Context) (Logger, error) {
|
|
||||||
if v, ok := ctx.Value(contextKey{}).(Logger); ok {
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return Logger{}, notFoundError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this
|
|
||||||
// returns a Logger that discards all log messages.
|
|
||||||
func FromContextOrDiscard(ctx context.Context) Logger {
|
|
||||||
if v, ok := ctx.Value(contextKey{}).(Logger); ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
return Discard()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContext returns a new Context, derived from ctx, which carries the
|
|
||||||
// provided Logger.
|
|
||||||
func NewContext(ctx context.Context, logger Logger) context.Context {
|
|
||||||
return context.WithValue(ctx, contextKey{}, logger)
|
|
||||||
}
|
|
||||||
83
src/server/vendor/github.com/go-logr/logr/context_slog.go
generated
vendored
83
src/server/vendor/github.com/go-logr/logr/context_slog.go
generated
vendored
@ -1,83 +0,0 @@
|
|||||||
//go:build go1.21
|
|
||||||
// +build go1.21
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2019 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package logr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FromContext returns a Logger from ctx or an error if no Logger is found.
|
|
||||||
func FromContext(ctx context.Context) (Logger, error) {
|
|
||||||
v := ctx.Value(contextKey{})
|
|
||||||
if v == nil {
|
|
||||||
return Logger{}, notFoundError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v := v.(type) {
|
|
||||||
case Logger:
|
|
||||||
return v, nil
|
|
||||||
case *slog.Logger:
|
|
||||||
return FromSlogHandler(v.Handler()), nil
|
|
||||||
default:
|
|
||||||
// Not reached.
|
|
||||||
panic(fmt.Sprintf("unexpected value type for logr context key: %T", v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromContextAsSlogLogger returns a slog.Logger from ctx or nil if no such Logger is found.
|
|
||||||
func FromContextAsSlogLogger(ctx context.Context) *slog.Logger {
|
|
||||||
v := ctx.Value(contextKey{})
|
|
||||||
if v == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v := v.(type) {
|
|
||||||
case Logger:
|
|
||||||
return slog.New(ToSlogHandler(v))
|
|
||||||
case *slog.Logger:
|
|
||||||
return v
|
|
||||||
default:
|
|
||||||
// Not reached.
|
|
||||||
panic(fmt.Sprintf("unexpected value type for logr context key: %T", v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this
|
|
||||||
// returns a Logger that discards all log messages.
|
|
||||||
func FromContextOrDiscard(ctx context.Context) Logger {
|
|
||||||
if logger, err := FromContext(ctx); err == nil {
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
return Discard()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContext returns a new Context, derived from ctx, which carries the
|
|
||||||
// provided Logger.
|
|
||||||
func NewContext(ctx context.Context, logger Logger) context.Context {
|
|
||||||
return context.WithValue(ctx, contextKey{}, logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContextWithSlogLogger returns a new Context, derived from ctx, which carries the
|
|
||||||
// provided slog.Logger.
|
|
||||||
func NewContextWithSlogLogger(ctx context.Context, logger *slog.Logger) context.Context {
|
|
||||||
return context.WithValue(ctx, contextKey{}, logger)
|
|
||||||
}
|
|
||||||
24
src/server/vendor/github.com/go-logr/logr/discard.go
generated
vendored
24
src/server/vendor/github.com/go-logr/logr/discard.go
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2020 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package logr
|
|
||||||
|
|
||||||
// Discard returns a Logger that discards all messages logged to it. It can be
|
|
||||||
// used whenever the caller is not interested in the logs. Logger instances
|
|
||||||
// produced by this function always compare as equal.
|
|
||||||
func Discard() Logger {
|
|
||||||
return New(nil)
|
|
||||||
}
|
|
||||||
914
src/server/vendor/github.com/go-logr/logr/funcr/funcr.go
generated
vendored
914
src/server/vendor/github.com/go-logr/logr/funcr/funcr.go
generated
vendored
@ -1,914 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2021 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package funcr implements formatting of structured log messages and
|
|
||||||
// optionally captures the call site and timestamp.
|
|
||||||
//
|
|
||||||
// The simplest way to use it is via its implementation of a
|
|
||||||
// github.com/go-logr/logr.LogSink with output through an arbitrary
|
|
||||||
// "write" function. See New and NewJSON for details.
|
|
||||||
//
|
|
||||||
// # Custom LogSinks
|
|
||||||
//
|
|
||||||
// For users who need more control, a funcr.Formatter can be embedded inside
|
|
||||||
// your own custom LogSink implementation. This is useful when the LogSink
|
|
||||||
// needs to implement additional methods, for example.
|
|
||||||
//
|
|
||||||
// # Formatting
|
|
||||||
//
|
|
||||||
// This will respect logr.Marshaler, fmt.Stringer, and error interfaces for
|
|
||||||
// values which are being logged. When rendering a struct, funcr will use Go's
|
|
||||||
// standard JSON tags (all except "string").
|
|
||||||
package funcr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
)
|
|
||||||
|
|
||||||
// New returns a logr.Logger which is implemented by an arbitrary function.
|
|
||||||
func New(fn func(prefix, args string), opts Options) logr.Logger {
|
|
||||||
return logr.New(newSink(fn, NewFormatter(opts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewJSON returns a logr.Logger which is implemented by an arbitrary function
|
|
||||||
// and produces JSON output.
|
|
||||||
func NewJSON(fn func(obj string), opts Options) logr.Logger {
|
|
||||||
fnWrapper := func(_, obj string) {
|
|
||||||
fn(obj)
|
|
||||||
}
|
|
||||||
return logr.New(newSink(fnWrapper, NewFormatterJSON(opts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Underlier exposes access to the underlying logging function. Since
|
|
||||||
// callers only have a logr.Logger, they have to know which
|
|
||||||
// implementation is in use, so this interface is less of an
|
|
||||||
// abstraction and more of a way to test type conversion.
|
|
||||||
type Underlier interface {
|
|
||||||
GetUnderlying() func(prefix, args string)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSink(fn func(prefix, args string), formatter Formatter) logr.LogSink {
|
|
||||||
l := &fnlogger{
|
|
||||||
Formatter: formatter,
|
|
||||||
write: fn,
|
|
||||||
}
|
|
||||||
// For skipping fnlogger.Info and fnlogger.Error.
|
|
||||||
l.Formatter.AddCallDepth(1)
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options carries parameters which influence the way logs are generated.
|
|
||||||
type Options struct {
|
|
||||||
// LogCaller tells funcr to add a "caller" key to some or all log lines.
|
|
||||||
// This has some overhead, so some users might not want it.
|
|
||||||
LogCaller MessageClass
|
|
||||||
|
|
||||||
// LogCallerFunc tells funcr to also log the calling function name. This
|
|
||||||
// has no effect if caller logging is not enabled (see Options.LogCaller).
|
|
||||||
LogCallerFunc bool
|
|
||||||
|
|
||||||
// LogTimestamp tells funcr to add a "ts" key to log lines. This has some
|
|
||||||
// overhead, so some users might not want it.
|
|
||||||
LogTimestamp bool
|
|
||||||
|
|
||||||
// TimestampFormat tells funcr how to render timestamps when LogTimestamp
|
|
||||||
// is enabled. If not specified, a default format will be used. For more
|
|
||||||
// details, see docs for Go's time.Layout.
|
|
||||||
TimestampFormat string
|
|
||||||
|
|
||||||
// LogInfoLevel tells funcr what key to use to log the info level.
|
|
||||||
// If not specified, the info level will be logged as "level".
|
|
||||||
// If this is set to "", the info level will not be logged at all.
|
|
||||||
LogInfoLevel *string
|
|
||||||
|
|
||||||
// Verbosity tells funcr which V logs to produce. Higher values enable
|
|
||||||
// more logs. Info logs at or below this level will be written, while logs
|
|
||||||
// above this level will be discarded.
|
|
||||||
Verbosity int
|
|
||||||
|
|
||||||
// RenderBuiltinsHook allows users to mutate the list of key-value pairs
|
|
||||||
// while a log line is being rendered. The kvList argument follows logr
|
|
||||||
// conventions - each pair of slice elements is comprised of a string key
|
|
||||||
// and an arbitrary value (verified and sanitized before calling this
|
|
||||||
// hook). The value returned must follow the same conventions. This hook
|
|
||||||
// can be used to audit or modify logged data. For example, you might want
|
|
||||||
// to prefix all of funcr's built-in keys with some string. This hook is
|
|
||||||
// only called for built-in (provided by funcr itself) key-value pairs.
|
|
||||||
// Equivalent hooks are offered for key-value pairs saved via
|
|
||||||
// logr.Logger.WithValues or Formatter.AddValues (see RenderValuesHook) and
|
|
||||||
// for user-provided pairs (see RenderArgsHook).
|
|
||||||
RenderBuiltinsHook func(kvList []any) []any
|
|
||||||
|
|
||||||
// RenderValuesHook is the same as RenderBuiltinsHook, except that it is
|
|
||||||
// only called for key-value pairs saved via logr.Logger.WithValues. See
|
|
||||||
// RenderBuiltinsHook for more details.
|
|
||||||
RenderValuesHook func(kvList []any) []any
|
|
||||||
|
|
||||||
// RenderArgsHook is the same as RenderBuiltinsHook, except that it is only
|
|
||||||
// called for key-value pairs passed directly to Info and Error. See
|
|
||||||
// RenderBuiltinsHook for more details.
|
|
||||||
RenderArgsHook func(kvList []any) []any
|
|
||||||
|
|
||||||
// MaxLogDepth tells funcr how many levels of nested fields (e.g. a struct
|
|
||||||
// that contains a struct, etc.) it may log. Every time it finds a struct,
|
|
||||||
// slice, array, or map the depth is increased by one. When the maximum is
|
|
||||||
// reached, the value will be converted to a string indicating that the max
|
|
||||||
// depth has been exceeded. If this field is not specified, a default
|
|
||||||
// value will be used.
|
|
||||||
MaxLogDepth int
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageClass indicates which category or categories of messages to consider.
|
|
||||||
type MessageClass int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// None ignores all message classes.
|
|
||||||
None MessageClass = iota
|
|
||||||
// All considers all message classes.
|
|
||||||
All
|
|
||||||
// Info only considers info messages.
|
|
||||||
Info
|
|
||||||
// Error only considers error messages.
|
|
||||||
Error
|
|
||||||
)
|
|
||||||
|
|
||||||
// fnlogger inherits some of its LogSink implementation from Formatter
|
|
||||||
// and just needs to add some glue code.
|
|
||||||
type fnlogger struct {
|
|
||||||
Formatter
|
|
||||||
write func(prefix, args string)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) WithName(name string) logr.LogSink {
|
|
||||||
l.Formatter.AddName(name)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) WithValues(kvList ...any) logr.LogSink {
|
|
||||||
l.Formatter.AddValues(kvList)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) WithCallDepth(depth int) logr.LogSink {
|
|
||||||
l.Formatter.AddCallDepth(depth)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) Info(level int, msg string, kvList ...any) {
|
|
||||||
prefix, args := l.FormatInfo(level, msg, kvList)
|
|
||||||
l.write(prefix, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) Error(err error, msg string, kvList ...any) {
|
|
||||||
prefix, args := l.FormatError(err, msg, kvList)
|
|
||||||
l.write(prefix, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) GetUnderlying() func(prefix, args string) {
|
|
||||||
return l.write
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert conformance to the interfaces.
|
|
||||||
var _ logr.LogSink = &fnlogger{}
|
|
||||||
var _ logr.CallDepthLogSink = &fnlogger{}
|
|
||||||
var _ Underlier = &fnlogger{}
|
|
||||||
|
|
||||||
// NewFormatter constructs a Formatter which emits a JSON-like key=value format.
|
|
||||||
func NewFormatter(opts Options) Formatter {
|
|
||||||
return newFormatter(opts, outputKeyValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFormatterJSON constructs a Formatter which emits strict JSON.
|
|
||||||
func NewFormatterJSON(opts Options) Formatter {
|
|
||||||
return newFormatter(opts, outputJSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defaults for Options.
|
|
||||||
const defaultTimestampFormat = "2006-01-02 15:04:05.000000"
|
|
||||||
const defaultMaxLogDepth = 16
|
|
||||||
|
|
||||||
func newFormatter(opts Options, outfmt outputFormat) Formatter {
|
|
||||||
if opts.TimestampFormat == "" {
|
|
||||||
opts.TimestampFormat = defaultTimestampFormat
|
|
||||||
}
|
|
||||||
if opts.MaxLogDepth == 0 {
|
|
||||||
opts.MaxLogDepth = defaultMaxLogDepth
|
|
||||||
}
|
|
||||||
if opts.LogInfoLevel == nil {
|
|
||||||
opts.LogInfoLevel = new(string)
|
|
||||||
*opts.LogInfoLevel = "level"
|
|
||||||
}
|
|
||||||
f := Formatter{
|
|
||||||
outputFormat: outfmt,
|
|
||||||
prefix: "",
|
|
||||||
values: nil,
|
|
||||||
depth: 0,
|
|
||||||
opts: &opts,
|
|
||||||
}
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Formatter is an opaque struct which can be embedded in a LogSink
|
|
||||||
// implementation. It should be constructed with NewFormatter. Some of
|
|
||||||
// its methods directly implement logr.LogSink.
|
|
||||||
type Formatter struct {
|
|
||||||
outputFormat outputFormat
|
|
||||||
prefix string
|
|
||||||
values []any
|
|
||||||
valuesStr string
|
|
||||||
depth int
|
|
||||||
opts *Options
|
|
||||||
groupName string // for slog groups
|
|
||||||
groups []groupDef
|
|
||||||
}
|
|
||||||
|
|
||||||
// outputFormat indicates which outputFormat to use.
|
|
||||||
type outputFormat int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// outputKeyValue emits a JSON-like key=value format, but not strict JSON.
|
|
||||||
outputKeyValue outputFormat = iota
|
|
||||||
// outputJSON emits strict JSON.
|
|
||||||
outputJSON
|
|
||||||
)
|
|
||||||
|
|
||||||
// groupDef represents a saved group. The values may be empty, but we don't
|
|
||||||
// know if we need to render the group until the final record is rendered.
|
|
||||||
type groupDef struct {
|
|
||||||
name string
|
|
||||||
values string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PseudoStruct is a list of key-value pairs that gets logged as a struct.
|
|
||||||
type PseudoStruct []any
|
|
||||||
|
|
||||||
// render produces a log line, ready to use.
|
|
||||||
func (f Formatter) render(builtins, args []any) string {
|
|
||||||
// Empirically bytes.Buffer is faster than strings.Builder for this.
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
||||||
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
buf.WriteByte('{') // for the whole record
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render builtins
|
|
||||||
vals := builtins
|
|
||||||
if hook := f.opts.RenderBuiltinsHook; hook != nil {
|
|
||||||
vals = hook(f.sanitize(vals))
|
|
||||||
}
|
|
||||||
f.flatten(buf, vals, false) // keys are ours, no need to escape
|
|
||||||
continuing := len(builtins) > 0
|
|
||||||
|
|
||||||
// Turn the inner-most group into a string
|
|
||||||
argsStr := func() string {
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
||||||
|
|
||||||
vals = args
|
|
||||||
if hook := f.opts.RenderArgsHook; hook != nil {
|
|
||||||
vals = hook(f.sanitize(vals))
|
|
||||||
}
|
|
||||||
f.flatten(buf, vals, true) // escape user-provided keys
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Render the stack of groups from the inside out.
|
|
||||||
bodyStr := f.renderGroup(f.groupName, f.valuesStr, argsStr)
|
|
||||||
for i := len(f.groups) - 1; i >= 0; i-- {
|
|
||||||
grp := &f.groups[i]
|
|
||||||
if grp.values == "" && bodyStr == "" {
|
|
||||||
// no contents, so we must elide the whole group
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
bodyStr = f.renderGroup(grp.name, grp.values, bodyStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if bodyStr != "" {
|
|
||||||
if continuing {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
buf.WriteString(bodyStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
buf.WriteByte('}') // for the whole record
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderGroup returns a string representation of the named group with rendered
|
|
||||||
// values and args. If the name is empty, this will return the values and args,
|
|
||||||
// joined. If the name is not empty, this will return a single key-value pair,
|
|
||||||
// where the value is a grouping of the values and args. If the values and
|
|
||||||
// args are both empty, this will return an empty string, even if the name was
|
|
||||||
// specified.
|
|
||||||
func (f Formatter) renderGroup(name string, values string, args string) string {
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
||||||
|
|
||||||
needClosingBrace := false
|
|
||||||
if name != "" && (values != "" || args != "") {
|
|
||||||
buf.WriteString(f.quoted(name, true)) // escape user-provided keys
|
|
||||||
buf.WriteByte(f.colon())
|
|
||||||
buf.WriteByte('{')
|
|
||||||
needClosingBrace = true
|
|
||||||
}
|
|
||||||
|
|
||||||
continuing := false
|
|
||||||
if values != "" {
|
|
||||||
buf.WriteString(values)
|
|
||||||
continuing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if args != "" {
|
|
||||||
if continuing {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
buf.WriteString(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
if needClosingBrace {
|
|
||||||
buf.WriteByte('}')
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// flatten renders a list of key-value pairs into a buffer. If escapeKeys is
|
|
||||||
// true, the keys are assumed to have non-JSON-compatible characters in them
|
|
||||||
// and must be evaluated for escapes.
|
|
||||||
//
|
|
||||||
// This function returns a potentially modified version of kvList, which
|
|
||||||
// ensures that there is a value for every key (adding a value if needed) and
|
|
||||||
// that each key is a string (substituting a key if needed).
|
|
||||||
func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, escapeKeys bool) []any {
|
|
||||||
// This logic overlaps with sanitize() but saves one type-cast per key,
|
|
||||||
// which can be measurable.
|
|
||||||
if len(kvList)%2 != 0 {
|
|
||||||
kvList = append(kvList, noValue)
|
|
||||||
}
|
|
||||||
copied := false
|
|
||||||
for i := 0; i < len(kvList); i += 2 {
|
|
||||||
k, ok := kvList[i].(string)
|
|
||||||
if !ok {
|
|
||||||
if !copied {
|
|
||||||
newList := make([]any, len(kvList))
|
|
||||||
copy(newList, kvList)
|
|
||||||
kvList = newList
|
|
||||||
copied = true
|
|
||||||
}
|
|
||||||
k = f.nonStringKey(kvList[i])
|
|
||||||
kvList[i] = k
|
|
||||||
}
|
|
||||||
v := kvList[i+1]
|
|
||||||
|
|
||||||
if i > 0 {
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
} else {
|
|
||||||
// In theory the format could be something we don't understand. In
|
|
||||||
// practice, we control it, so it won't be.
|
|
||||||
buf.WriteByte(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString(f.quoted(k, escapeKeys))
|
|
||||||
buf.WriteByte(f.colon())
|
|
||||||
buf.WriteString(f.pretty(v))
|
|
||||||
}
|
|
||||||
return kvList
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Formatter) quoted(str string, escape bool) string {
|
|
||||||
if escape {
|
|
||||||
return prettyString(str)
|
|
||||||
}
|
|
||||||
// this is faster
|
|
||||||
return `"` + str + `"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Formatter) comma() byte {
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
return ','
|
|
||||||
}
|
|
||||||
return ' '
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Formatter) colon() byte {
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
return ':'
|
|
||||||
}
|
|
||||||
return '='
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Formatter) pretty(value any) string {
|
|
||||||
return f.prettyWithFlags(value, 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
flagRawStruct = 0x1 // do not print braces on structs
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: This is not fast. Most of the overhead goes here.
|
|
||||||
func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string {
|
|
||||||
if depth > f.opts.MaxLogDepth {
|
|
||||||
return `"<max-log-depth-exceeded>"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle types that take full control of logging.
|
|
||||||
if v, ok := value.(logr.Marshaler); ok {
|
|
||||||
// Replace the value with what the type wants to get logged.
|
|
||||||
// That then gets handled below via reflection.
|
|
||||||
value = invokeMarshaler(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle types that want to format themselves.
|
|
||||||
switch v := value.(type) {
|
|
||||||
case fmt.Stringer:
|
|
||||||
value = invokeStringer(v)
|
|
||||||
case error:
|
|
||||||
value = invokeError(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handling the most common types without reflect is a small perf win.
|
|
||||||
switch v := value.(type) {
|
|
||||||
case bool:
|
|
||||||
return strconv.FormatBool(v)
|
|
||||||
case string:
|
|
||||||
return prettyString(v)
|
|
||||||
case int:
|
|
||||||
return strconv.FormatInt(int64(v), 10)
|
|
||||||
case int8:
|
|
||||||
return strconv.FormatInt(int64(v), 10)
|
|
||||||
case int16:
|
|
||||||
return strconv.FormatInt(int64(v), 10)
|
|
||||||
case int32:
|
|
||||||
return strconv.FormatInt(int64(v), 10)
|
|
||||||
case int64:
|
|
||||||
return strconv.FormatInt(int64(v), 10)
|
|
||||||
case uint:
|
|
||||||
return strconv.FormatUint(uint64(v), 10)
|
|
||||||
case uint8:
|
|
||||||
return strconv.FormatUint(uint64(v), 10)
|
|
||||||
case uint16:
|
|
||||||
return strconv.FormatUint(uint64(v), 10)
|
|
||||||
case uint32:
|
|
||||||
return strconv.FormatUint(uint64(v), 10)
|
|
||||||
case uint64:
|
|
||||||
return strconv.FormatUint(v, 10)
|
|
||||||
case uintptr:
|
|
||||||
return strconv.FormatUint(uint64(v), 10)
|
|
||||||
case float32:
|
|
||||||
return strconv.FormatFloat(float64(v), 'f', -1, 32)
|
|
||||||
case float64:
|
|
||||||
return strconv.FormatFloat(v, 'f', -1, 64)
|
|
||||||
case complex64:
|
|
||||||
return `"` + strconv.FormatComplex(complex128(v), 'f', -1, 64) + `"`
|
|
||||||
case complex128:
|
|
||||||
return `"` + strconv.FormatComplex(v, 'f', -1, 128) + `"`
|
|
||||||
case PseudoStruct:
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
||||||
v = f.sanitize(v)
|
|
||||||
if flags&flagRawStruct == 0 {
|
|
||||||
buf.WriteByte('{')
|
|
||||||
}
|
|
||||||
for i := 0; i < len(v); i += 2 {
|
|
||||||
if i > 0 {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
k, _ := v[i].(string) // sanitize() above means no need to check success
|
|
||||||
// arbitrary keys might need escaping
|
|
||||||
buf.WriteString(prettyString(k))
|
|
||||||
buf.WriteByte(f.colon())
|
|
||||||
buf.WriteString(f.prettyWithFlags(v[i+1], 0, depth+1))
|
|
||||||
}
|
|
||||||
if flags&flagRawStruct == 0 {
|
|
||||||
buf.WriteByte('}')
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 256))
|
|
||||||
t := reflect.TypeOf(value)
|
|
||||||
if t == nil {
|
|
||||||
return "null"
|
|
||||||
}
|
|
||||||
v := reflect.ValueOf(value)
|
|
||||||
switch t.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return strconv.FormatBool(v.Bool())
|
|
||||||
case reflect.String:
|
|
||||||
return prettyString(v.String())
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return strconv.FormatInt(int64(v.Int()), 10)
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return strconv.FormatUint(uint64(v.Uint()), 10)
|
|
||||||
case reflect.Float32:
|
|
||||||
return strconv.FormatFloat(float64(v.Float()), 'f', -1, 32)
|
|
||||||
case reflect.Float64:
|
|
||||||
return strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
|
||||||
case reflect.Complex64:
|
|
||||||
return `"` + strconv.FormatComplex(complex128(v.Complex()), 'f', -1, 64) + `"`
|
|
||||||
case reflect.Complex128:
|
|
||||||
return `"` + strconv.FormatComplex(v.Complex(), 'f', -1, 128) + `"`
|
|
||||||
case reflect.Struct:
|
|
||||||
if flags&flagRawStruct == 0 {
|
|
||||||
buf.WriteByte('{')
|
|
||||||
}
|
|
||||||
printComma := false // testing i>0 is not enough because of JSON omitted fields
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
fld := t.Field(i)
|
|
||||||
if fld.PkgPath != "" {
|
|
||||||
// reflect says this field is only defined for non-exported fields.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !v.Field(i).CanInterface() {
|
|
||||||
// reflect isn't clear exactly what this means, but we can't use it.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name := ""
|
|
||||||
omitempty := false
|
|
||||||
if tag, found := fld.Tag.Lookup("json"); found {
|
|
||||||
if tag == "-" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if comma := strings.Index(tag, ","); comma != -1 {
|
|
||||||
if n := tag[:comma]; n != "" {
|
|
||||||
name = n
|
|
||||||
}
|
|
||||||
rest := tag[comma:]
|
|
||||||
if strings.Contains(rest, ",omitempty,") || strings.HasSuffix(rest, ",omitempty") {
|
|
||||||
omitempty = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
name = tag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if omitempty && isEmpty(v.Field(i)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if printComma {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
printComma = true // if we got here, we are rendering a field
|
|
||||||
if fld.Anonymous && fld.Type.Kind() == reflect.Struct && name == "" {
|
|
||||||
buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), flags|flagRawStruct, depth+1))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if name == "" {
|
|
||||||
name = fld.Name
|
|
||||||
}
|
|
||||||
// field names can't contain characters which need escaping
|
|
||||||
buf.WriteString(f.quoted(name, false))
|
|
||||||
buf.WriteByte(f.colon())
|
|
||||||
buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), 0, depth+1))
|
|
||||||
}
|
|
||||||
if flags&flagRawStruct == 0 {
|
|
||||||
buf.WriteByte('}')
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
case reflect.Slice, reflect.Array:
|
|
||||||
// If this is outputing as JSON make sure this isn't really a json.RawMessage.
|
|
||||||
// If so just emit "as-is" and don't pretty it as that will just print
|
|
||||||
// it as [X,Y,Z,...] which isn't terribly useful vs the string form you really want.
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
if rm, ok := value.(json.RawMessage); ok {
|
|
||||||
// If it's empty make sure we emit an empty value as the array style would below.
|
|
||||||
if len(rm) > 0 {
|
|
||||||
buf.Write(rm)
|
|
||||||
} else {
|
|
||||||
buf.WriteString("null")
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.WriteByte('[')
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
if i > 0 {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
e := v.Index(i)
|
|
||||||
buf.WriteString(f.prettyWithFlags(e.Interface(), 0, depth+1))
|
|
||||||
}
|
|
||||||
buf.WriteByte(']')
|
|
||||||
return buf.String()
|
|
||||||
case reflect.Map:
|
|
||||||
buf.WriteByte('{')
|
|
||||||
// This does not sort the map keys, for best perf.
|
|
||||||
it := v.MapRange()
|
|
||||||
i := 0
|
|
||||||
for it.Next() {
|
|
||||||
if i > 0 {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
// If a map key supports TextMarshaler, use it.
|
|
||||||
keystr := ""
|
|
||||||
if m, ok := it.Key().Interface().(encoding.TextMarshaler); ok {
|
|
||||||
txt, err := m.MarshalText()
|
|
||||||
if err != nil {
|
|
||||||
keystr = fmt.Sprintf("<error-MarshalText: %s>", err.Error())
|
|
||||||
} else {
|
|
||||||
keystr = string(txt)
|
|
||||||
}
|
|
||||||
keystr = prettyString(keystr)
|
|
||||||
} else {
|
|
||||||
// prettyWithFlags will produce already-escaped values
|
|
||||||
keystr = f.prettyWithFlags(it.Key().Interface(), 0, depth+1)
|
|
||||||
if t.Key().Kind() != reflect.String {
|
|
||||||
// JSON only does string keys. Unlike Go's standard JSON, we'll
|
|
||||||
// convert just about anything to a string.
|
|
||||||
keystr = prettyString(keystr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.WriteString(keystr)
|
|
||||||
buf.WriteByte(f.colon())
|
|
||||||
buf.WriteString(f.prettyWithFlags(it.Value().Interface(), 0, depth+1))
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
buf.WriteByte('}')
|
|
||||||
return buf.String()
|
|
||||||
case reflect.Ptr, reflect.Interface:
|
|
||||||
if v.IsNil() {
|
|
||||||
return "null"
|
|
||||||
}
|
|
||||||
return f.prettyWithFlags(v.Elem().Interface(), 0, depth)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(`"<unhandled-%s>"`, t.Kind().String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func prettyString(s string) string {
|
|
||||||
// Avoid escaping (which does allocations) if we can.
|
|
||||||
if needsEscape(s) {
|
|
||||||
return strconv.Quote(s)
|
|
||||||
}
|
|
||||||
b := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
||||||
b.WriteByte('"')
|
|
||||||
b.WriteString(s)
|
|
||||||
b.WriteByte('"')
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// needsEscape determines whether the input string needs to be escaped or not,
|
|
||||||
// without doing any allocations.
|
|
||||||
func needsEscape(s string) bool {
|
|
||||||
for _, r := range s {
|
|
||||||
if !strconv.IsPrint(r) || r == '\\' || r == '"' {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEmpty(v reflect.Value) bool {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
|
||||||
return v.Len() == 0
|
|
||||||
case reflect.Bool:
|
|
||||||
return !v.Bool()
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return v.Int() == 0
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return v.Uint() == 0
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return v.Float() == 0
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
return v.Complex() == 0
|
|
||||||
case reflect.Interface, reflect.Ptr:
|
|
||||||
return v.IsNil()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func invokeMarshaler(m logr.Marshaler) (ret any) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ret = fmt.Sprintf("<panic: %s>", r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return m.MarshalLog()
|
|
||||||
}
|
|
||||||
|
|
||||||
func invokeStringer(s fmt.Stringer) (ret string) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ret = fmt.Sprintf("<panic: %s>", r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return s.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func invokeError(e error) (ret string) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ret = fmt.Sprintf("<panic: %s>", r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return e.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caller represents the original call site for a log line, after considering
|
|
||||||
// logr.Logger.WithCallDepth and logr.Logger.WithCallStackHelper. The File and
|
|
||||||
// Line fields will always be provided, while the Func field is optional.
|
|
||||||
// Users can set the render hook fields in Options to examine logged key-value
|
|
||||||
// pairs, one of which will be {"caller", Caller} if the Options.LogCaller
|
|
||||||
// field is enabled for the given MessageClass.
|
|
||||||
type Caller struct {
|
|
||||||
// File is the basename of the file for this call site.
|
|
||||||
File string `json:"file"`
|
|
||||||
// Line is the line number in the file for this call site.
|
|
||||||
Line int `json:"line"`
|
|
||||||
// Func is the function name for this call site, or empty if
|
|
||||||
// Options.LogCallerFunc is not enabled.
|
|
||||||
Func string `json:"function,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Formatter) caller() Caller {
|
|
||||||
// +1 for this frame, +1 for Info/Error.
|
|
||||||
pc, file, line, ok := runtime.Caller(f.depth + 2)
|
|
||||||
if !ok {
|
|
||||||
return Caller{"<unknown>", 0, ""}
|
|
||||||
}
|
|
||||||
fn := ""
|
|
||||||
if f.opts.LogCallerFunc {
|
|
||||||
if fp := runtime.FuncForPC(pc); fp != nil {
|
|
||||||
fn = fp.Name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Caller{filepath.Base(file), line, fn}
|
|
||||||
}
|
|
||||||
|
|
||||||
const noValue = "<no-value>"
|
|
||||||
|
|
||||||
func (f Formatter) nonStringKey(v any) string {
|
|
||||||
return fmt.Sprintf("<non-string-key: %s>", f.snippet(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// snippet produces a short snippet string of an arbitrary value.
|
|
||||||
func (f Formatter) snippet(v any) string {
|
|
||||||
const snipLen = 16
|
|
||||||
|
|
||||||
snip := f.pretty(v)
|
|
||||||
if len(snip) > snipLen {
|
|
||||||
snip = snip[:snipLen]
|
|
||||||
}
|
|
||||||
return snip
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanitize ensures that a list of key-value pairs has a value for every key
|
|
||||||
// (adding a value if needed) and that each key is a string (substituting a key
|
|
||||||
// if needed).
|
|
||||||
func (f Formatter) sanitize(kvList []any) []any {
|
|
||||||
if len(kvList)%2 != 0 {
|
|
||||||
kvList = append(kvList, noValue)
|
|
||||||
}
|
|
||||||
for i := 0; i < len(kvList); i += 2 {
|
|
||||||
_, ok := kvList[i].(string)
|
|
||||||
if !ok {
|
|
||||||
kvList[i] = f.nonStringKey(kvList[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kvList
|
|
||||||
}
|
|
||||||
|
|
||||||
// startGroup opens a new group scope (basically a sub-struct), which locks all
|
|
||||||
// the current saved values and starts them anew. This is needed to satisfy
|
|
||||||
// slog.
|
|
||||||
func (f *Formatter) startGroup(name string) {
|
|
||||||
// Unnamed groups are just inlined.
|
|
||||||
if name == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
n := len(f.groups)
|
|
||||||
f.groups = append(f.groups[:n:n], groupDef{f.groupName, f.valuesStr})
|
|
||||||
|
|
||||||
// Start collecting new values.
|
|
||||||
f.groupName = name
|
|
||||||
f.valuesStr = ""
|
|
||||||
f.values = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init configures this Formatter from runtime info, such as the call depth
|
|
||||||
// imposed by logr itself.
|
|
||||||
// Note that this receiver is a pointer, so depth can be saved.
|
|
||||||
func (f *Formatter) Init(info logr.RuntimeInfo) {
|
|
||||||
f.depth += info.CallDepth
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enabled checks whether an info message at the given level should be logged.
|
|
||||||
func (f Formatter) Enabled(level int) bool {
|
|
||||||
return level <= f.opts.Verbosity
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDepth returns the current depth of this Formatter. This is useful for
|
|
||||||
// implementations which do their own caller attribution.
|
|
||||||
func (f Formatter) GetDepth() int {
|
|
||||||
return f.depth
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatInfo renders an Info log message into strings. The prefix will be
|
|
||||||
// empty when no names were set (via AddNames), or when the output is
|
|
||||||
// configured for JSON.
|
|
||||||
func (f Formatter) FormatInfo(level int, msg string, kvList []any) (prefix, argsStr string) {
|
|
||||||
args := make([]any, 0, 64) // using a constant here impacts perf
|
|
||||||
prefix = f.prefix
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
args = append(args, "logger", prefix)
|
|
||||||
prefix = ""
|
|
||||||
}
|
|
||||||
if f.opts.LogTimestamp {
|
|
||||||
args = append(args, "ts", time.Now().Format(f.opts.TimestampFormat))
|
|
||||||
}
|
|
||||||
if policy := f.opts.LogCaller; policy == All || policy == Info {
|
|
||||||
args = append(args, "caller", f.caller())
|
|
||||||
}
|
|
||||||
if key := *f.opts.LogInfoLevel; key != "" {
|
|
||||||
args = append(args, key, level)
|
|
||||||
}
|
|
||||||
args = append(args, "msg", msg)
|
|
||||||
return prefix, f.render(args, kvList)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatError renders an Error log message into strings. The prefix will be
|
|
||||||
// empty when no names were set (via AddNames), or when the output is
|
|
||||||
// configured for JSON.
|
|
||||||
func (f Formatter) FormatError(err error, msg string, kvList []any) (prefix, argsStr string) {
|
|
||||||
args := make([]any, 0, 64) // using a constant here impacts perf
|
|
||||||
prefix = f.prefix
|
|
||||||
if f.outputFormat == outputJSON {
|
|
||||||
args = append(args, "logger", prefix)
|
|
||||||
prefix = ""
|
|
||||||
}
|
|
||||||
if f.opts.LogTimestamp {
|
|
||||||
args = append(args, "ts", time.Now().Format(f.opts.TimestampFormat))
|
|
||||||
}
|
|
||||||
if policy := f.opts.LogCaller; policy == All || policy == Error {
|
|
||||||
args = append(args, "caller", f.caller())
|
|
||||||
}
|
|
||||||
args = append(args, "msg", msg)
|
|
||||||
var loggableErr any
|
|
||||||
if err != nil {
|
|
||||||
loggableErr = err.Error()
|
|
||||||
}
|
|
||||||
args = append(args, "error", loggableErr)
|
|
||||||
return prefix, f.render(args, kvList)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddName appends the specified name. funcr uses '/' characters to separate
|
|
||||||
// name elements. Callers should not pass '/' in the provided name string, but
|
|
||||||
// this library does not actually enforce that.
|
|
||||||
func (f *Formatter) AddName(name string) {
|
|
||||||
if len(f.prefix) > 0 {
|
|
||||||
f.prefix += "/"
|
|
||||||
}
|
|
||||||
f.prefix += name
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddValues adds key-value pairs to the set of saved values to be logged with
|
|
||||||
// each log line.
|
|
||||||
func (f *Formatter) AddValues(kvList []any) {
|
|
||||||
// Three slice args forces a copy.
|
|
||||||
n := len(f.values)
|
|
||||||
f.values = append(f.values[:n:n], kvList...)
|
|
||||||
|
|
||||||
vals := f.values
|
|
||||||
if hook := f.opts.RenderValuesHook; hook != nil {
|
|
||||||
vals = hook(f.sanitize(vals))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre-render values, so we don't have to do it on each Info/Error call.
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
||||||
f.flatten(buf, vals, true) // escape user-provided keys
|
|
||||||
f.valuesStr = buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddCallDepth increases the number of stack-frames to skip when attributing
|
|
||||||
// the log line to a file and line.
|
|
||||||
func (f *Formatter) AddCallDepth(depth int) {
|
|
||||||
f.depth += depth
|
|
||||||
}
|
|
||||||
105
src/server/vendor/github.com/go-logr/logr/funcr/slogsink.go
generated
vendored
105
src/server/vendor/github.com/go-logr/logr/funcr/slogsink.go
generated
vendored
@ -1,105 +0,0 @@
|
|||||||
//go:build go1.21
|
|
||||||
// +build go1.21
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2023 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package funcr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ logr.SlogSink = &fnlogger{}
|
|
||||||
|
|
||||||
const extraSlogSinkDepth = 3 // 2 for slog, 1 for SlogSink
|
|
||||||
|
|
||||||
func (l fnlogger) Handle(_ context.Context, record slog.Record) error {
|
|
||||||
kvList := make([]any, 0, 2*record.NumAttrs())
|
|
||||||
record.Attrs(func(attr slog.Attr) bool {
|
|
||||||
kvList = attrToKVs(attr, kvList)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
if record.Level >= slog.LevelError {
|
|
||||||
l.WithCallDepth(extraSlogSinkDepth).Error(nil, record.Message, kvList...)
|
|
||||||
} else {
|
|
||||||
level := l.levelFromSlog(record.Level)
|
|
||||||
l.WithCallDepth(extraSlogSinkDepth).Info(level, record.Message, kvList...)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) WithAttrs(attrs []slog.Attr) logr.SlogSink {
|
|
||||||
kvList := make([]any, 0, 2*len(attrs))
|
|
||||||
for _, attr := range attrs {
|
|
||||||
kvList = attrToKVs(attr, kvList)
|
|
||||||
}
|
|
||||||
l.AddValues(kvList)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l fnlogger) WithGroup(name string) logr.SlogSink {
|
|
||||||
l.startGroup(name)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
// attrToKVs appends a slog.Attr to a logr-style kvList. It handle slog Groups
|
|
||||||
// and other details of slog.
|
|
||||||
func attrToKVs(attr slog.Attr, kvList []any) []any {
|
|
||||||
attrVal := attr.Value.Resolve()
|
|
||||||
if attrVal.Kind() == slog.KindGroup {
|
|
||||||
groupVal := attrVal.Group()
|
|
||||||
grpKVs := make([]any, 0, 2*len(groupVal))
|
|
||||||
for _, attr := range groupVal {
|
|
||||||
grpKVs = attrToKVs(attr, grpKVs)
|
|
||||||
}
|
|
||||||
if attr.Key == "" {
|
|
||||||
// slog says we have to inline these
|
|
||||||
kvList = append(kvList, grpKVs...)
|
|
||||||
} else {
|
|
||||||
kvList = append(kvList, attr.Key, PseudoStruct(grpKVs))
|
|
||||||
}
|
|
||||||
} else if attr.Key != "" {
|
|
||||||
kvList = append(kvList, attr.Key, attrVal.Any())
|
|
||||||
}
|
|
||||||
|
|
||||||
return kvList
|
|
||||||
}
|
|
||||||
|
|
||||||
// levelFromSlog adjusts the level by the logger's verbosity and negates it.
|
|
||||||
// It ensures that the result is >= 0. This is necessary because the result is
|
|
||||||
// passed to a LogSink and that API did not historically document whether
|
|
||||||
// levels could be negative or what that meant.
|
|
||||||
//
|
|
||||||
// Some example usage:
|
|
||||||
//
|
|
||||||
// logrV0 := getMyLogger()
|
|
||||||
// logrV2 := logrV0.V(2)
|
|
||||||
// slogV2 := slog.New(logr.ToSlogHandler(logrV2))
|
|
||||||
// slogV2.Debug("msg") // =~ logrV2.V(4) =~ logrV0.V(6)
|
|
||||||
// slogV2.Info("msg") // =~ logrV2.V(0) =~ logrV0.V(2)
|
|
||||||
// slogv2.Warn("msg") // =~ logrV2.V(-4) =~ logrV0.V(0)
|
|
||||||
func (l fnlogger) levelFromSlog(level slog.Level) int {
|
|
||||||
result := -level
|
|
||||||
if result < 0 {
|
|
||||||
result = 0 // because LogSink doesn't expect negative V levels
|
|
||||||
}
|
|
||||||
return int(result)
|
|
||||||
}
|
|
||||||
520
src/server/vendor/github.com/go-logr/logr/logr.go
generated
vendored
520
src/server/vendor/github.com/go-logr/logr/logr.go
generated
vendored
@ -1,520 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This design derives from Dave Cheney's blog:
|
|
||||||
// http://dave.cheney.net/2015/11/05/lets-talk-about-logging
|
|
||||||
|
|
||||||
// Package logr defines a general-purpose logging API and abstract interfaces
|
|
||||||
// to back that API. Packages in the Go ecosystem can depend on this package,
|
|
||||||
// while callers can implement logging with whatever backend is appropriate.
|
|
||||||
//
|
|
||||||
// # Usage
|
|
||||||
//
|
|
||||||
// Logging is done using a Logger instance. Logger is a concrete type with
|
|
||||||
// methods, which defers the actual logging to a LogSink interface. The main
|
|
||||||
// methods of Logger are Info() and Error(). Arguments to Info() and Error()
|
|
||||||
// are key/value pairs rather than printf-style formatted strings, emphasizing
|
|
||||||
// "structured logging".
|
|
||||||
//
|
|
||||||
// With Go's standard log package, we might write:
|
|
||||||
//
|
|
||||||
// log.Printf("setting target value %s", targetValue)
|
|
||||||
//
|
|
||||||
// With logr's structured logging, we'd write:
|
|
||||||
//
|
|
||||||
// logger.Info("setting target", "value", targetValue)
|
|
||||||
//
|
|
||||||
// Errors are much the same. Instead of:
|
|
||||||
//
|
|
||||||
// log.Printf("failed to open the pod bay door for user %s: %v", user, err)
|
|
||||||
//
|
|
||||||
// We'd write:
|
|
||||||
//
|
|
||||||
// logger.Error(err, "failed to open the pod bay door", "user", user)
|
|
||||||
//
|
|
||||||
// Info() and Error() are very similar, but they are separate methods so that
|
|
||||||
// LogSink implementations can choose to do things like attach additional
|
|
||||||
// information (such as stack traces) on calls to Error(). Error() messages are
|
|
||||||
// always logged, regardless of the current verbosity. If there is no error
|
|
||||||
// instance available, passing nil is valid.
|
|
||||||
//
|
|
||||||
// # Verbosity
|
|
||||||
//
|
|
||||||
// Often we want to log information only when the application in "verbose
|
|
||||||
// mode". To write log lines that are more verbose, Logger has a V() method.
|
|
||||||
// The higher the V-level of a log line, the less critical it is considered.
|
|
||||||
// Log-lines with V-levels that are not enabled (as per the LogSink) will not
|
|
||||||
// be written. Level V(0) is the default, and logger.V(0).Info() has the same
|
|
||||||
// meaning as logger.Info(). Negative V-levels have the same meaning as V(0).
|
|
||||||
// Error messages do not have a verbosity level and are always logged.
|
|
||||||
//
|
|
||||||
// Where we might have written:
|
|
||||||
//
|
|
||||||
// if flVerbose >= 2 {
|
|
||||||
// log.Printf("an unusual thing happened")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// We can write:
|
|
||||||
//
|
|
||||||
// logger.V(2).Info("an unusual thing happened")
|
|
||||||
//
|
|
||||||
// # Logger Names
|
|
||||||
//
|
|
||||||
// Logger instances can have name strings so that all messages logged through
|
|
||||||
// that instance have additional context. For example, you might want to add
|
|
||||||
// a subsystem name:
|
|
||||||
//
|
|
||||||
// logger.WithName("compactor").Info("started", "time", time.Now())
|
|
||||||
//
|
|
||||||
// The WithName() method returns a new Logger, which can be passed to
|
|
||||||
// constructors or other functions for further use. Repeated use of WithName()
|
|
||||||
// will accumulate name "segments". These name segments will be joined in some
|
|
||||||
// way by the LogSink implementation. It is strongly recommended that name
|
|
||||||
// segments contain simple identifiers (letters, digits, and hyphen), and do
|
|
||||||
// not contain characters that could muddle the log output or confuse the
|
|
||||||
// joining operation (e.g. whitespace, commas, periods, slashes, brackets,
|
|
||||||
// quotes, etc).
|
|
||||||
//
|
|
||||||
// # Saved Values
|
|
||||||
//
|
|
||||||
// Logger instances can store any number of key/value pairs, which will be
|
|
||||||
// logged alongside all messages logged through that instance. For example,
|
|
||||||
// you might want to create a Logger instance per managed object:
|
|
||||||
//
|
|
||||||
// With the standard log package, we might write:
|
|
||||||
//
|
|
||||||
// log.Printf("decided to set field foo to value %q for object %s/%s",
|
|
||||||
// targetValue, object.Namespace, object.Name)
|
|
||||||
//
|
|
||||||
// With logr we'd write:
|
|
||||||
//
|
|
||||||
// // Elsewhere: set up the logger to log the object name.
|
|
||||||
// obj.logger = mainLogger.WithValues(
|
|
||||||
// "name", obj.name, "namespace", obj.namespace)
|
|
||||||
//
|
|
||||||
// // later on...
|
|
||||||
// obj.logger.Info("setting foo", "value", targetValue)
|
|
||||||
//
|
|
||||||
// # Best Practices
|
|
||||||
//
|
|
||||||
// Logger has very few hard rules, with the goal that LogSink implementations
|
|
||||||
// might have a lot of freedom to differentiate. There are, however, some
|
|
||||||
// things to consider.
|
|
||||||
//
|
|
||||||
// The log message consists of a constant message attached to the log line.
|
|
||||||
// This should generally be a simple description of what's occurring, and should
|
|
||||||
// never be a format string. Variable information can then be attached using
|
|
||||||
// named values.
|
|
||||||
//
|
|
||||||
// Keys are arbitrary strings, but should generally be constant values. Values
|
|
||||||
// may be any Go value, but how the value is formatted is determined by the
|
|
||||||
// LogSink implementation.
|
|
||||||
//
|
|
||||||
// Logger instances are meant to be passed around by value. Code that receives
|
|
||||||
// such a value can call its methods without having to check whether the
|
|
||||||
// instance is ready for use.
|
|
||||||
//
|
|
||||||
// The zero logger (= Logger{}) is identical to Discard() and discards all log
|
|
||||||
// entries. Code that receives a Logger by value can simply call it, the methods
|
|
||||||
// will never crash. For cases where passing a logger is optional, a pointer to Logger
|
|
||||||
// should be used.
|
|
||||||
//
|
|
||||||
// # Key Naming Conventions
|
|
||||||
//
|
|
||||||
// Keys are not strictly required to conform to any specification or regex, but
|
|
||||||
// it is recommended that they:
|
|
||||||
// - be human-readable and meaningful (not auto-generated or simple ordinals)
|
|
||||||
// - be constant (not dependent on input data)
|
|
||||||
// - contain only printable characters
|
|
||||||
// - not contain whitespace or punctuation
|
|
||||||
// - use lower case for simple keys and lowerCamelCase for more complex ones
|
|
||||||
//
|
|
||||||
// These guidelines help ensure that log data is processed properly regardless
|
|
||||||
// of the log implementation. For example, log implementations will try to
|
|
||||||
// output JSON data or will store data for later database (e.g. SQL) queries.
|
|
||||||
//
|
|
||||||
// While users are generally free to use key names of their choice, it's
|
|
||||||
// generally best to avoid using the following keys, as they're frequently used
|
|
||||||
// by implementations:
|
|
||||||
// - "caller": the calling information (file/line) of a particular log line
|
|
||||||
// - "error": the underlying error value in the `Error` method
|
|
||||||
// - "level": the log level
|
|
||||||
// - "logger": the name of the associated logger
|
|
||||||
// - "msg": the log message
|
|
||||||
// - "stacktrace": the stack trace associated with a particular log line or
|
|
||||||
// error (often from the `Error` message)
|
|
||||||
// - "ts": the timestamp for a log line
|
|
||||||
//
|
|
||||||
// Implementations are encouraged to make use of these keys to represent the
|
|
||||||
// above concepts, when necessary (for example, in a pure-JSON output form, it
|
|
||||||
// would be necessary to represent at least message and timestamp as ordinary
|
|
||||||
// named values).
|
|
||||||
//
|
|
||||||
// # Break Glass
|
|
||||||
//
|
|
||||||
// Implementations may choose to give callers access to the underlying
|
|
||||||
// logging implementation. The recommended pattern for this is:
|
|
||||||
//
|
|
||||||
// // Underlier exposes access to the underlying logging implementation.
|
|
||||||
// // Since callers only have a logr.Logger, they have to know which
|
|
||||||
// // implementation is in use, so this interface is less of an abstraction
|
|
||||||
// // and more of way to test type conversion.
|
|
||||||
// type Underlier interface {
|
|
||||||
// GetUnderlying() <underlying-type>
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Logger grants access to the sink to enable type assertions like this:
|
|
||||||
//
|
|
||||||
// func DoSomethingWithImpl(log logr.Logger) {
|
|
||||||
// if underlier, ok := log.GetSink().(impl.Underlier); ok {
|
|
||||||
// implLogger := underlier.GetUnderlying()
|
|
||||||
// ...
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Custom `With*` functions can be implemented by copying the complete
|
|
||||||
// Logger struct and replacing the sink in the copy:
|
|
||||||
//
|
|
||||||
// // WithFooBar changes the foobar parameter in the log sink and returns a
|
|
||||||
// // new logger with that modified sink. It does nothing for loggers where
|
|
||||||
// // the sink doesn't support that parameter.
|
|
||||||
// func WithFoobar(log logr.Logger, foobar int) logr.Logger {
|
|
||||||
// if foobarLogSink, ok := log.GetSink().(FoobarSink); ok {
|
|
||||||
// log = log.WithSink(foobarLogSink.WithFooBar(foobar))
|
|
||||||
// }
|
|
||||||
// return log
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Don't use New to construct a new Logger with a LogSink retrieved from an
|
|
||||||
// existing Logger. Source code attribution might not work correctly and
|
|
||||||
// unexported fields in Logger get lost.
|
|
||||||
//
|
|
||||||
// Beware that the same LogSink instance may be shared by different logger
|
|
||||||
// instances. Calling functions that modify the LogSink will affect all of
|
|
||||||
// those.
|
|
||||||
package logr
|
|
||||||
|
|
||||||
// New returns a new Logger instance. This is primarily used by libraries
|
|
||||||
// implementing LogSink, rather than end users. Passing a nil sink will create
|
|
||||||
// a Logger which discards all log lines.
|
|
||||||
func New(sink LogSink) Logger {
|
|
||||||
logger := Logger{}
|
|
||||||
logger.setSink(sink)
|
|
||||||
if sink != nil {
|
|
||||||
sink.Init(runtimeInfo)
|
|
||||||
}
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// setSink stores the sink and updates any related fields. It mutates the
|
|
||||||
// logger and thus is only safe to use for loggers that are not currently being
|
|
||||||
// used concurrently.
|
|
||||||
func (l *Logger) setSink(sink LogSink) {
|
|
||||||
l.sink = sink
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSink returns the stored sink.
|
|
||||||
func (l Logger) GetSink() LogSink {
|
|
||||||
return l.sink
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSink returns a copy of the logger with the new sink.
|
|
||||||
func (l Logger) WithSink(sink LogSink) Logger {
|
|
||||||
l.setSink(sink)
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger is an interface to an abstract logging implementation. This is a
|
|
||||||
// concrete type for performance reasons, but all the real work is passed on to
|
|
||||||
// a LogSink. Implementations of LogSink should provide their own constructors
|
|
||||||
// that return Logger, not LogSink.
|
|
||||||
//
|
|
||||||
// The underlying sink can be accessed through GetSink and be modified through
|
|
||||||
// WithSink. This enables the implementation of custom extensions (see "Break
|
|
||||||
// Glass" in the package documentation). Normally the sink should be used only
|
|
||||||
// indirectly.
|
|
||||||
type Logger struct {
|
|
||||||
sink LogSink
|
|
||||||
level int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enabled tests whether this Logger is enabled. For example, commandline
|
|
||||||
// flags might be used to set the logging verbosity and disable some info logs.
|
|
||||||
func (l Logger) Enabled() bool {
|
|
||||||
// Some implementations of LogSink look at the caller in Enabled (e.g.
|
|
||||||
// different verbosity levels per package or file), but we only pass one
|
|
||||||
// CallDepth in (via Init). This means that all calls from Logger to the
|
|
||||||
// LogSink's Enabled, Info, and Error methods must have the same number of
|
|
||||||
// frames. In other words, Logger methods can't call other Logger methods
|
|
||||||
// which call these LogSink methods unless we do it the same in all paths.
|
|
||||||
return l.sink != nil && l.sink.Enabled(l.level)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info logs a non-error message with the given key/value pairs as context.
|
|
||||||
//
|
|
||||||
// The msg argument should be used to add some constant description to the log
|
|
||||||
// line. The key/value pairs can then be used to add additional variable
|
|
||||||
// information. The key/value pairs must alternate string keys and arbitrary
|
|
||||||
// values.
|
|
||||||
func (l Logger) Info(msg string, keysAndValues ...any) {
|
|
||||||
if l.sink == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if l.sink.Enabled(l.level) { // see comment in Enabled
|
|
||||||
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
|
|
||||||
withHelper.GetCallStackHelper()()
|
|
||||||
}
|
|
||||||
l.sink.Info(l.level, msg, keysAndValues...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error logs an error, with the given message and key/value pairs as context.
|
|
||||||
// It functions similarly to Info, but may have unique behavior, and should be
|
|
||||||
// preferred for logging errors (see the package documentations for more
|
|
||||||
// information). The log message will always be emitted, regardless of
|
|
||||||
// verbosity level.
|
|
||||||
//
|
|
||||||
// The msg argument should be used to add context to any underlying error,
|
|
||||||
// while the err argument should be used to attach the actual error that
|
|
||||||
// triggered this log line, if present. The err parameter is optional
|
|
||||||
// and nil may be passed instead of an error instance.
|
|
||||||
func (l Logger) Error(err error, msg string, keysAndValues ...any) {
|
|
||||||
if l.sink == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
|
|
||||||
withHelper.GetCallStackHelper()()
|
|
||||||
}
|
|
||||||
l.sink.Error(err, msg, keysAndValues...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// V returns a new Logger instance for a specific verbosity level, relative to
|
|
||||||
// this Logger. In other words, V-levels are additive. A higher verbosity
|
|
||||||
// level means a log message is less important. Negative V-levels are treated
|
|
||||||
// as 0.
|
|
||||||
func (l Logger) V(level int) Logger {
|
|
||||||
if l.sink == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
if level < 0 {
|
|
||||||
level = 0
|
|
||||||
}
|
|
||||||
l.level += level
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetV returns the verbosity level of the logger. If the logger's LogSink is
|
|
||||||
// nil as in the Discard logger, this will always return 0.
|
|
||||||
func (l Logger) GetV() int {
|
|
||||||
// 0 if l.sink nil because of the if check in V above.
|
|
||||||
return l.level
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithValues returns a new Logger instance with additional key/value pairs.
|
|
||||||
// See Info for documentation on how key/value pairs work.
|
|
||||||
func (l Logger) WithValues(keysAndValues ...any) Logger {
|
|
||||||
if l.sink == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
l.setSink(l.sink.WithValues(keysAndValues...))
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithName returns a new Logger instance with the specified name element added
|
|
||||||
// to the Logger's name. Successive calls with WithName append additional
|
|
||||||
// suffixes to the Logger's name. It's strongly recommended that name segments
|
|
||||||
// contain only letters, digits, and hyphens (see the package documentation for
|
|
||||||
// more information).
|
|
||||||
func (l Logger) WithName(name string) Logger {
|
|
||||||
if l.sink == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
l.setSink(l.sink.WithName(name))
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithCallDepth returns a Logger instance that offsets the call stack by the
|
|
||||||
// specified number of frames when logging call site information, if possible.
|
|
||||||
// This is useful for users who have helper functions between the "real" call
|
|
||||||
// site and the actual calls to Logger methods. If depth is 0 the attribution
|
|
||||||
// should be to the direct caller of this function. If depth is 1 the
|
|
||||||
// attribution should skip 1 call frame, and so on. Successive calls to this
|
|
||||||
// are additive.
|
|
||||||
//
|
|
||||||
// If the underlying log implementation supports a WithCallDepth(int) method,
|
|
||||||
// it will be called and the result returned. If the implementation does not
|
|
||||||
// support CallDepthLogSink, the original Logger will be returned.
|
|
||||||
//
|
|
||||||
// To skip one level, WithCallStackHelper() should be used instead of
|
|
||||||
// WithCallDepth(1) because it works with implementions that support the
|
|
||||||
// CallDepthLogSink and/or CallStackHelperLogSink interfaces.
|
|
||||||
func (l Logger) WithCallDepth(depth int) Logger {
|
|
||||||
if l.sink == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
|
|
||||||
l.setSink(withCallDepth.WithCallDepth(depth))
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithCallStackHelper returns a new Logger instance that skips the direct
|
|
||||||
// caller when logging call site information, if possible. This is useful for
|
|
||||||
// users who have helper functions between the "real" call site and the actual
|
|
||||||
// calls to Logger methods and want to support loggers which depend on marking
|
|
||||||
// each individual helper function, like loggers based on testing.T.
|
|
||||||
//
|
|
||||||
// In addition to using that new logger instance, callers also must call the
|
|
||||||
// returned function.
|
|
||||||
//
|
|
||||||
// If the underlying log implementation supports a WithCallDepth(int) method,
|
|
||||||
// WithCallDepth(1) will be called to produce a new logger. If it supports a
|
|
||||||
// WithCallStackHelper() method, that will be also called. If the
|
|
||||||
// implementation does not support either of these, the original Logger will be
|
|
||||||
// returned.
|
|
||||||
func (l Logger) WithCallStackHelper() (func(), Logger) {
|
|
||||||
if l.sink == nil {
|
|
||||||
return func() {}, l
|
|
||||||
}
|
|
||||||
var helper func()
|
|
||||||
if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
|
|
||||||
l.setSink(withCallDepth.WithCallDepth(1))
|
|
||||||
}
|
|
||||||
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
|
|
||||||
helper = withHelper.GetCallStackHelper()
|
|
||||||
} else {
|
|
||||||
helper = func() {}
|
|
||||||
}
|
|
||||||
return helper, l
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsZero returns true if this logger is an uninitialized zero value
|
|
||||||
func (l Logger) IsZero() bool {
|
|
||||||
return l.sink == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RuntimeInfo holds information that the logr "core" library knows which
|
|
||||||
// LogSinks might want to know.
|
|
||||||
type RuntimeInfo struct {
|
|
||||||
// CallDepth is the number of call frames the logr library adds between the
|
|
||||||
// end-user and the LogSink. LogSink implementations which choose to print
|
|
||||||
// the original logging site (e.g. file & line) should climb this many
|
|
||||||
// additional frames to find it.
|
|
||||||
CallDepth int
|
|
||||||
}
|
|
||||||
|
|
||||||
// runtimeInfo is a static global. It must not be changed at run time.
|
|
||||||
var runtimeInfo = RuntimeInfo{
|
|
||||||
CallDepth: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogSink represents a logging implementation. End-users will generally not
|
|
||||||
// interact with this type.
|
|
||||||
type LogSink interface {
|
|
||||||
// Init receives optional information about the logr library for LogSink
|
|
||||||
// implementations that need it.
|
|
||||||
Init(info RuntimeInfo)
|
|
||||||
|
|
||||||
// Enabled tests whether this LogSink is enabled at the specified V-level.
|
|
||||||
// For example, commandline flags might be used to set the logging
|
|
||||||
// verbosity and disable some info logs.
|
|
||||||
Enabled(level int) bool
|
|
||||||
|
|
||||||
// Info logs a non-error message with the given key/value pairs as context.
|
|
||||||
// The level argument is provided for optional logging. This method will
|
|
||||||
// only be called when Enabled(level) is true. See Logger.Info for more
|
|
||||||
// details.
|
|
||||||
Info(level int, msg string, keysAndValues ...any)
|
|
||||||
|
|
||||||
// Error logs an error, with the given message and key/value pairs as
|
|
||||||
// context. See Logger.Error for more details.
|
|
||||||
Error(err error, msg string, keysAndValues ...any)
|
|
||||||
|
|
||||||
// WithValues returns a new LogSink with additional key/value pairs. See
|
|
||||||
// Logger.WithValues for more details.
|
|
||||||
WithValues(keysAndValues ...any) LogSink
|
|
||||||
|
|
||||||
// WithName returns a new LogSink with the specified name appended. See
|
|
||||||
// Logger.WithName for more details.
|
|
||||||
WithName(name string) LogSink
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallDepthLogSink represents a LogSink that knows how to climb the call stack
|
|
||||||
// to identify the original call site and can offset the depth by a specified
|
|
||||||
// number of frames. This is useful for users who have helper functions
|
|
||||||
// between the "real" call site and the actual calls to Logger methods.
|
|
||||||
// Implementations that log information about the call site (such as file,
|
|
||||||
// function, or line) would otherwise log information about the intermediate
|
|
||||||
// helper functions.
|
|
||||||
//
|
|
||||||
// This is an optional interface and implementations are not required to
|
|
||||||
// support it.
|
|
||||||
type CallDepthLogSink interface {
|
|
||||||
// WithCallDepth returns a LogSink that will offset the call
|
|
||||||
// stack by the specified number of frames when logging call
|
|
||||||
// site information.
|
|
||||||
//
|
|
||||||
// If depth is 0, the LogSink should skip exactly the number
|
|
||||||
// of call frames defined in RuntimeInfo.CallDepth when Info
|
|
||||||
// or Error are called, i.e. the attribution should be to the
|
|
||||||
// direct caller of Logger.Info or Logger.Error.
|
|
||||||
//
|
|
||||||
// If depth is 1 the attribution should skip 1 call frame, and so on.
|
|
||||||
// Successive calls to this are additive.
|
|
||||||
WithCallDepth(depth int) LogSink
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallStackHelperLogSink represents a LogSink that knows how to climb
|
|
||||||
// the call stack to identify the original call site and can skip
|
|
||||||
// intermediate helper functions if they mark themselves as
|
|
||||||
// helper. Go's testing package uses that approach.
|
|
||||||
//
|
|
||||||
// This is useful for users who have helper functions between the
|
|
||||||
// "real" call site and the actual calls to Logger methods.
|
|
||||||
// Implementations that log information about the call site (such as
|
|
||||||
// file, function, or line) would otherwise log information about the
|
|
||||||
// intermediate helper functions.
|
|
||||||
//
|
|
||||||
// This is an optional interface and implementations are not required
|
|
||||||
// to support it. Implementations that choose to support this must not
|
|
||||||
// simply implement it as WithCallDepth(1), because
|
|
||||||
// Logger.WithCallStackHelper will call both methods if they are
|
|
||||||
// present. This should only be implemented for LogSinks that actually
|
|
||||||
// need it, as with testing.T.
|
|
||||||
type CallStackHelperLogSink interface {
|
|
||||||
// GetCallStackHelper returns a function that must be called
|
|
||||||
// to mark the direct caller as helper function when logging
|
|
||||||
// call site information.
|
|
||||||
GetCallStackHelper() func()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshaler is an optional interface that logged values may choose to
|
|
||||||
// implement. Loggers with structured output, such as JSON, should
|
|
||||||
// log the object return by the MarshalLog method instead of the
|
|
||||||
// original value.
|
|
||||||
type Marshaler interface {
|
|
||||||
// MarshalLog can be used to:
|
|
||||||
// - ensure that structs are not logged as strings when the original
|
|
||||||
// value has a String method: return a different type without a
|
|
||||||
// String method
|
|
||||||
// - select which fields of a complex type should get logged:
|
|
||||||
// return a simpler struct with fewer fields
|
|
||||||
// - log unexported fields: return a different struct
|
|
||||||
// with exported fields
|
|
||||||
//
|
|
||||||
// It may return any value of any type.
|
|
||||||
MarshalLog() any
|
|
||||||
}
|
|
||||||
192
src/server/vendor/github.com/go-logr/logr/sloghandler.go
generated
vendored
192
src/server/vendor/github.com/go-logr/logr/sloghandler.go
generated
vendored
@ -1,192 +0,0 @@
|
|||||||
//go:build go1.21
|
|
||||||
// +build go1.21
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2023 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package logr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type slogHandler struct {
|
|
||||||
// May be nil, in which case all logs get discarded.
|
|
||||||
sink LogSink
|
|
||||||
// Non-nil if sink is non-nil and implements SlogSink.
|
|
||||||
slogSink SlogSink
|
|
||||||
|
|
||||||
// groupPrefix collects values from WithGroup calls. It gets added as
|
|
||||||
// prefix to value keys when handling a log record.
|
|
||||||
groupPrefix string
|
|
||||||
|
|
||||||
// levelBias can be set when constructing the handler to influence the
|
|
||||||
// slog.Level of log records. A positive levelBias reduces the
|
|
||||||
// slog.Level value. slog has no API to influence this value after the
|
|
||||||
// handler got created, so it can only be set indirectly through
|
|
||||||
// Logger.V.
|
|
||||||
levelBias slog.Level
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ slog.Handler = &slogHandler{}
|
|
||||||
|
|
||||||
// groupSeparator is used to concatenate WithGroup names and attribute keys.
|
|
||||||
const groupSeparator = "."
|
|
||||||
|
|
||||||
// GetLevel is used for black box unit testing.
|
|
||||||
func (l *slogHandler) GetLevel() slog.Level {
|
|
||||||
return l.levelBias
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogHandler) Enabled(_ context.Context, level slog.Level) bool {
|
|
||||||
return l.sink != nil && (level >= slog.LevelError || l.sink.Enabled(l.levelFromSlog(level)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogHandler) Handle(ctx context.Context, record slog.Record) error {
|
|
||||||
if l.slogSink != nil {
|
|
||||||
// Only adjust verbosity level of log entries < slog.LevelError.
|
|
||||||
if record.Level < slog.LevelError {
|
|
||||||
record.Level -= l.levelBias
|
|
||||||
}
|
|
||||||
return l.slogSink.Handle(ctx, record)
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to check for nil sink here because Handle will only be called
|
|
||||||
// when Enabled returned true.
|
|
||||||
|
|
||||||
kvList := make([]any, 0, 2*record.NumAttrs())
|
|
||||||
record.Attrs(func(attr slog.Attr) bool {
|
|
||||||
kvList = attrToKVs(attr, l.groupPrefix, kvList)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
if record.Level >= slog.LevelError {
|
|
||||||
l.sinkWithCallDepth().Error(nil, record.Message, kvList...)
|
|
||||||
} else {
|
|
||||||
level := l.levelFromSlog(record.Level)
|
|
||||||
l.sinkWithCallDepth().Info(level, record.Message, kvList...)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sinkWithCallDepth adjusts the stack unwinding so that when Error or Info
|
|
||||||
// are called by Handle, code in slog gets skipped.
|
|
||||||
//
|
|
||||||
// This offset currently (Go 1.21.0) works for calls through
|
|
||||||
// slog.New(ToSlogHandler(...)). There's no guarantee that the call
|
|
||||||
// chain won't change. Wrapping the handler will also break unwinding. It's
|
|
||||||
// still better than not adjusting at all....
|
|
||||||
//
|
|
||||||
// This cannot be done when constructing the handler because FromSlogHandler needs
|
|
||||||
// access to the original sink without this adjustment. A second copy would
|
|
||||||
// work, but then WithAttrs would have to be called for both of them.
|
|
||||||
func (l *slogHandler) sinkWithCallDepth() LogSink {
|
|
||||||
if sink, ok := l.sink.(CallDepthLogSink); ok {
|
|
||||||
return sink.WithCallDepth(2)
|
|
||||||
}
|
|
||||||
return l.sink
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
||||||
if l.sink == nil || len(attrs) == 0 {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
clone := *l
|
|
||||||
if l.slogSink != nil {
|
|
||||||
clone.slogSink = l.slogSink.WithAttrs(attrs)
|
|
||||||
clone.sink = clone.slogSink
|
|
||||||
} else {
|
|
||||||
kvList := make([]any, 0, 2*len(attrs))
|
|
||||||
for _, attr := range attrs {
|
|
||||||
kvList = attrToKVs(attr, l.groupPrefix, kvList)
|
|
||||||
}
|
|
||||||
clone.sink = l.sink.WithValues(kvList...)
|
|
||||||
}
|
|
||||||
return &clone
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogHandler) WithGroup(name string) slog.Handler {
|
|
||||||
if l.sink == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
if name == "" {
|
|
||||||
// slog says to inline empty groups
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
clone := *l
|
|
||||||
if l.slogSink != nil {
|
|
||||||
clone.slogSink = l.slogSink.WithGroup(name)
|
|
||||||
clone.sink = clone.slogSink
|
|
||||||
} else {
|
|
||||||
clone.groupPrefix = addPrefix(clone.groupPrefix, name)
|
|
||||||
}
|
|
||||||
return &clone
|
|
||||||
}
|
|
||||||
|
|
||||||
// attrToKVs appends a slog.Attr to a logr-style kvList. It handle slog Groups
|
|
||||||
// and other details of slog.
|
|
||||||
func attrToKVs(attr slog.Attr, groupPrefix string, kvList []any) []any {
|
|
||||||
attrVal := attr.Value.Resolve()
|
|
||||||
if attrVal.Kind() == slog.KindGroup {
|
|
||||||
groupVal := attrVal.Group()
|
|
||||||
grpKVs := make([]any, 0, 2*len(groupVal))
|
|
||||||
prefix := groupPrefix
|
|
||||||
if attr.Key != "" {
|
|
||||||
prefix = addPrefix(groupPrefix, attr.Key)
|
|
||||||
}
|
|
||||||
for _, attr := range groupVal {
|
|
||||||
grpKVs = attrToKVs(attr, prefix, grpKVs)
|
|
||||||
}
|
|
||||||
kvList = append(kvList, grpKVs...)
|
|
||||||
} else if attr.Key != "" {
|
|
||||||
kvList = append(kvList, addPrefix(groupPrefix, attr.Key), attrVal.Any())
|
|
||||||
}
|
|
||||||
|
|
||||||
return kvList
|
|
||||||
}
|
|
||||||
|
|
||||||
func addPrefix(prefix, name string) string {
|
|
||||||
if prefix == "" {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
if name == "" {
|
|
||||||
return prefix
|
|
||||||
}
|
|
||||||
return prefix + groupSeparator + name
|
|
||||||
}
|
|
||||||
|
|
||||||
// levelFromSlog adjusts the level by the logger's verbosity and negates it.
|
|
||||||
// It ensures that the result is >= 0. This is necessary because the result is
|
|
||||||
// passed to a LogSink and that API did not historically document whether
|
|
||||||
// levels could be negative or what that meant.
|
|
||||||
//
|
|
||||||
// Some example usage:
|
|
||||||
//
|
|
||||||
// logrV0 := getMyLogger()
|
|
||||||
// logrV2 := logrV0.V(2)
|
|
||||||
// slogV2 := slog.New(logr.ToSlogHandler(logrV2))
|
|
||||||
// slogV2.Debug("msg") // =~ logrV2.V(4) =~ logrV0.V(6)
|
|
||||||
// slogV2.Info("msg") // =~ logrV2.V(0) =~ logrV0.V(2)
|
|
||||||
// slogv2.Warn("msg") // =~ logrV2.V(-4) =~ logrV0.V(0)
|
|
||||||
func (l *slogHandler) levelFromSlog(level slog.Level) int {
|
|
||||||
result := -level
|
|
||||||
result += l.levelBias // in case the original Logger had a V level
|
|
||||||
if result < 0 {
|
|
||||||
result = 0 // because LogSink doesn't expect negative V levels
|
|
||||||
}
|
|
||||||
return int(result)
|
|
||||||
}
|
|
||||||
100
src/server/vendor/github.com/go-logr/logr/slogr.go
generated
vendored
100
src/server/vendor/github.com/go-logr/logr/slogr.go
generated
vendored
@ -1,100 +0,0 @@
|
|||||||
//go:build go1.21
|
|
||||||
// +build go1.21
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2023 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package logr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FromSlogHandler returns a Logger which writes to the slog.Handler.
|
|
||||||
//
|
|
||||||
// The logr verbosity level is mapped to slog levels such that V(0) becomes
|
|
||||||
// slog.LevelInfo and V(4) becomes slog.LevelDebug.
|
|
||||||
func FromSlogHandler(handler slog.Handler) Logger {
|
|
||||||
if handler, ok := handler.(*slogHandler); ok {
|
|
||||||
if handler.sink == nil {
|
|
||||||
return Discard()
|
|
||||||
}
|
|
||||||
return New(handler.sink).V(int(handler.levelBias))
|
|
||||||
}
|
|
||||||
return New(&slogSink{handler: handler})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToSlogHandler returns a slog.Handler which writes to the same sink as the Logger.
|
|
||||||
//
|
|
||||||
// The returned logger writes all records with level >= slog.LevelError as
|
|
||||||
// error log entries with LogSink.Error, regardless of the verbosity level of
|
|
||||||
// the Logger:
|
|
||||||
//
|
|
||||||
// logger := <some Logger with 0 as verbosity level>
|
|
||||||
// slog.New(ToSlogHandler(logger.V(10))).Error(...) -> logSink.Error(...)
|
|
||||||
//
|
|
||||||
// The level of all other records gets reduced by the verbosity
|
|
||||||
// level of the Logger and the result is negated. If it happens
|
|
||||||
// to be negative, then it gets replaced by zero because a LogSink
|
|
||||||
// is not expected to handled negative levels:
|
|
||||||
//
|
|
||||||
// slog.New(ToSlogHandler(logger)).Debug(...) -> logger.GetSink().Info(level=4, ...)
|
|
||||||
// slog.New(ToSlogHandler(logger)).Warning(...) -> logger.GetSink().Info(level=0, ...)
|
|
||||||
// slog.New(ToSlogHandler(logger)).Info(...) -> logger.GetSink().Info(level=0, ...)
|
|
||||||
// slog.New(ToSlogHandler(logger.V(4))).Info(...) -> logger.GetSink().Info(level=4, ...)
|
|
||||||
func ToSlogHandler(logger Logger) slog.Handler {
|
|
||||||
if sink, ok := logger.GetSink().(*slogSink); ok && logger.GetV() == 0 {
|
|
||||||
return sink.handler
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := &slogHandler{sink: logger.GetSink(), levelBias: slog.Level(logger.GetV())}
|
|
||||||
if slogSink, ok := handler.sink.(SlogSink); ok {
|
|
||||||
handler.slogSink = slogSink
|
|
||||||
}
|
|
||||||
return handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// SlogSink is an optional interface that a LogSink can implement to support
|
|
||||||
// logging through the slog.Logger or slog.Handler APIs better. It then should
|
|
||||||
// also support special slog values like slog.Group. When used as a
|
|
||||||
// slog.Handler, the advantages are:
|
|
||||||
//
|
|
||||||
// - stack unwinding gets avoided in favor of logging the pre-recorded PC,
|
|
||||||
// as intended by slog
|
|
||||||
// - proper grouping of key/value pairs via WithGroup
|
|
||||||
// - verbosity levels > slog.LevelInfo can be recorded
|
|
||||||
// - less overhead
|
|
||||||
//
|
|
||||||
// Both APIs (Logger and slog.Logger/Handler) then are supported equally
|
|
||||||
// well. Developers can pick whatever API suits them better and/or mix
|
|
||||||
// packages which use either API in the same binary with a common logging
|
|
||||||
// implementation.
|
|
||||||
//
|
|
||||||
// This interface is necessary because the type implementing the LogSink
|
|
||||||
// interface cannot also implement the slog.Handler interface due to the
|
|
||||||
// different prototype of the common Enabled method.
|
|
||||||
//
|
|
||||||
// An implementation could support both interfaces in two different types, but then
|
|
||||||
// additional interfaces would be needed to convert between those types in FromSlogHandler
|
|
||||||
// and ToSlogHandler.
|
|
||||||
type SlogSink interface {
|
|
||||||
LogSink
|
|
||||||
|
|
||||||
Handle(ctx context.Context, record slog.Record) error
|
|
||||||
WithAttrs(attrs []slog.Attr) SlogSink
|
|
||||||
WithGroup(name string) SlogSink
|
|
||||||
}
|
|
||||||
120
src/server/vendor/github.com/go-logr/logr/slogsink.go
generated
vendored
120
src/server/vendor/github.com/go-logr/logr/slogsink.go
generated
vendored
@ -1,120 +0,0 @@
|
|||||||
//go:build go1.21
|
|
||||||
// +build go1.21
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2023 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package logr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
"runtime"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ LogSink = &slogSink{}
|
|
||||||
_ CallDepthLogSink = &slogSink{}
|
|
||||||
_ Underlier = &slogSink{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Underlier is implemented by the LogSink returned by NewFromLogHandler.
|
|
||||||
type Underlier interface {
|
|
||||||
// GetUnderlying returns the Handler used by the LogSink.
|
|
||||||
GetUnderlying() slog.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// nameKey is used to log the `WithName` values as an additional attribute.
|
|
||||||
nameKey = "logger"
|
|
||||||
|
|
||||||
// errKey is used to log the error parameter of Error as an additional attribute.
|
|
||||||
errKey = "err"
|
|
||||||
)
|
|
||||||
|
|
||||||
type slogSink struct {
|
|
||||||
callDepth int
|
|
||||||
name string
|
|
||||||
handler slog.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogSink) Init(info RuntimeInfo) {
|
|
||||||
l.callDepth = info.CallDepth
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogSink) GetUnderlying() slog.Handler {
|
|
||||||
return l.handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogSink) WithCallDepth(depth int) LogSink {
|
|
||||||
newLogger := *l
|
|
||||||
newLogger.callDepth += depth
|
|
||||||
return &newLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogSink) Enabled(level int) bool {
|
|
||||||
return l.handler.Enabled(context.Background(), slog.Level(-level))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogSink) Info(level int, msg string, kvList ...interface{}) {
|
|
||||||
l.log(nil, msg, slog.Level(-level), kvList...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogSink) Error(err error, msg string, kvList ...interface{}) {
|
|
||||||
l.log(err, msg, slog.LevelError, kvList...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *slogSink) log(err error, msg string, level slog.Level, kvList ...interface{}) {
|
|
||||||
var pcs [1]uintptr
|
|
||||||
// skip runtime.Callers, this function, Info/Error, and all helper functions above that.
|
|
||||||
runtime.Callers(3+l.callDepth, pcs[:])
|
|
||||||
|
|
||||||
record := slog.NewRecord(time.Now(), level, msg, pcs[0])
|
|
||||||
if l.name != "" {
|
|
||||||
record.AddAttrs(slog.String(nameKey, l.name))
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
record.AddAttrs(slog.Any(errKey, err))
|
|
||||||
}
|
|
||||||
record.Add(kvList...)
|
|
||||||
_ = l.handler.Handle(context.Background(), record)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l slogSink) WithName(name string) LogSink {
|
|
||||||
if l.name != "" {
|
|
||||||
l.name += "/"
|
|
||||||
}
|
|
||||||
l.name += name
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l slogSink) WithValues(kvList ...interface{}) LogSink {
|
|
||||||
l.handler = l.handler.WithAttrs(kvListToAttrs(kvList...))
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func kvListToAttrs(kvList ...interface{}) []slog.Attr {
|
|
||||||
// We don't need the record itself, only its Add method.
|
|
||||||
record := slog.NewRecord(time.Time{}, 0, "", 0)
|
|
||||||
record.Add(kvList...)
|
|
||||||
attrs := make([]slog.Attr, 0, record.NumAttrs())
|
|
||||||
record.Attrs(func(attr slog.Attr) bool {
|
|
||||||
attrs = append(attrs, attr)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return attrs
|
|
||||||
}
|
|
||||||
201
src/server/vendor/github.com/go-logr/stdr/LICENSE
generated
vendored
201
src/server/vendor/github.com/go-logr/stdr/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
6
src/server/vendor/github.com/go-logr/stdr/README.md
generated
vendored
6
src/server/vendor/github.com/go-logr/stdr/README.md
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
# Minimal Go logging using logr and Go's standard library
|
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/go-logr/stdr)
|
|
||||||
|
|
||||||
This package implements the [logr interface](https://github.com/go-logr/logr)
|
|
||||||
in terms of Go's standard log package(https://pkg.go.dev/log).
|
|
||||||
170
src/server/vendor/github.com/go-logr/stdr/stdr.go
generated
vendored
170
src/server/vendor/github.com/go-logr/stdr/stdr.go
generated
vendored
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 The logr Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package stdr implements github.com/go-logr/logr.Logger in terms of
|
|
||||||
// Go's standard log package.
|
|
||||||
package stdr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"github.com/go-logr/logr/funcr"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The global verbosity level. See SetVerbosity().
|
|
||||||
var globalVerbosity int
|
|
||||||
|
|
||||||
// SetVerbosity sets the global level against which all info logs will be
|
|
||||||
// compared. If this is greater than or equal to the "V" of the logger, the
|
|
||||||
// message will be logged. A higher value here means more logs will be written.
|
|
||||||
// The previous verbosity value is returned. This is not concurrent-safe -
|
|
||||||
// callers must be sure to call it from only one goroutine.
|
|
||||||
func SetVerbosity(v int) int {
|
|
||||||
old := globalVerbosity
|
|
||||||
globalVerbosity = v
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a logr.Logger which is implemented by Go's standard log package,
|
|
||||||
// or something like it. If std is nil, this will use a default logger
|
|
||||||
// instead.
|
|
||||||
//
|
|
||||||
// Example: stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile)))
|
|
||||||
func New(std StdLogger) logr.Logger {
|
|
||||||
return NewWithOptions(std, Options{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWithOptions returns a logr.Logger which is implemented by Go's standard
|
|
||||||
// log package, or something like it. See New for details.
|
|
||||||
func NewWithOptions(std StdLogger, opts Options) logr.Logger {
|
|
||||||
if std == nil {
|
|
||||||
// Go's log.Default() is only available in 1.16 and higher.
|
|
||||||
std = log.New(os.Stderr, "", log.LstdFlags)
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Depth < 0 {
|
|
||||||
opts.Depth = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fopts := funcr.Options{
|
|
||||||
LogCaller: funcr.MessageClass(opts.LogCaller),
|
|
||||||
}
|
|
||||||
|
|
||||||
sl := &logger{
|
|
||||||
Formatter: funcr.NewFormatter(fopts),
|
|
||||||
std: std,
|
|
||||||
}
|
|
||||||
|
|
||||||
// For skipping our own logger.Info/Error.
|
|
||||||
sl.Formatter.AddCallDepth(1 + opts.Depth)
|
|
||||||
|
|
||||||
return logr.New(sl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options carries parameters which influence the way logs are generated.
|
|
||||||
type Options struct {
|
|
||||||
// Depth biases the assumed number of call frames to the "true" caller.
|
|
||||||
// This is useful when the calling code calls a function which then calls
|
|
||||||
// stdr (e.g. a logging shim to another API). Values less than zero will
|
|
||||||
// be treated as zero.
|
|
||||||
Depth int
|
|
||||||
|
|
||||||
// LogCaller tells stdr to add a "caller" key to some or all log lines.
|
|
||||||
// Go's log package has options to log this natively, too.
|
|
||||||
LogCaller MessageClass
|
|
||||||
|
|
||||||
// TODO: add an option to log the date/time
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageClass indicates which category or categories of messages to consider.
|
|
||||||
type MessageClass int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// None ignores all message classes.
|
|
||||||
None MessageClass = iota
|
|
||||||
// All considers all message classes.
|
|
||||||
All
|
|
||||||
// Info only considers info messages.
|
|
||||||
Info
|
|
||||||
// Error only considers error messages.
|
|
||||||
Error
|
|
||||||
)
|
|
||||||
|
|
||||||
// StdLogger is the subset of the Go stdlib log.Logger API that is needed for
|
|
||||||
// this adapter.
|
|
||||||
type StdLogger interface {
|
|
||||||
// Output is the same as log.Output and log.Logger.Output.
|
|
||||||
Output(calldepth int, logline string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type logger struct {
|
|
||||||
funcr.Formatter
|
|
||||||
std StdLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ logr.LogSink = &logger{}
|
|
||||||
var _ logr.CallDepthLogSink = &logger{}
|
|
||||||
|
|
||||||
func (l logger) Enabled(level int) bool {
|
|
||||||
return globalVerbosity >= level
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l logger) Info(level int, msg string, kvList ...interface{}) {
|
|
||||||
prefix, args := l.FormatInfo(level, msg, kvList)
|
|
||||||
if prefix != "" {
|
|
||||||
args = prefix + ": " + args
|
|
||||||
}
|
|
||||||
_ = l.std.Output(l.Formatter.GetDepth()+1, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l logger) Error(err error, msg string, kvList ...interface{}) {
|
|
||||||
prefix, args := l.FormatError(err, msg, kvList)
|
|
||||||
if prefix != "" {
|
|
||||||
args = prefix + ": " + args
|
|
||||||
}
|
|
||||||
_ = l.std.Output(l.Formatter.GetDepth()+1, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l logger) WithName(name string) logr.LogSink {
|
|
||||||
l.Formatter.AddName(name)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l logger) WithValues(kvList ...interface{}) logr.LogSink {
|
|
||||||
l.Formatter.AddValues(kvList)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l logger) WithCallDepth(depth int) logr.LogSink {
|
|
||||||
l.Formatter.AddCallDepth(depth)
|
|
||||||
return &l
|
|
||||||
}
|
|
||||||
|
|
||||||
// Underlier exposes access to the underlying logging implementation. Since
|
|
||||||
// callers only have a logr.Logger, they have to know which implementation is
|
|
||||||
// in use, so this interface is less of an abstraction and more of way to test
|
|
||||||
// type conversion.
|
|
||||||
type Underlier interface {
|
|
||||||
GetUnderlying() StdLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUnderlying returns the StdLogger underneath this logger. Since StdLogger
|
|
||||||
// is itself an interface, the result may or may not be a Go log.Logger.
|
|
||||||
func (l logger) GetUnderlying() StdLogger {
|
|
||||||
return l.std
|
|
||||||
}
|
|
||||||
6
src/server/vendor/github.com/google/s2a-go/.gitignore
generated
vendored
6
src/server/vendor/github.com/google/s2a-go/.gitignore
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
# Ignore binaries without extension
|
|
||||||
//example/client/client
|
|
||||||
//example/server/server
|
|
||||||
//internal/v2/fakes2av2_server/fakes2av2_server
|
|
||||||
|
|
||||||
.idea/
|
|
||||||
93
src/server/vendor/github.com/google/s2a-go/CODE_OF_CONDUCT.md
generated
vendored
93
src/server/vendor/github.com/google/s2a-go/CODE_OF_CONDUCT.md
generated
vendored
@ -1,93 +0,0 @@
|
|||||||
# Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as
|
|
||||||
contributors and maintainers pledge to making participation in our project and
|
|
||||||
our community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, disability, ethnicity, gender identity and expression, level of
|
|
||||||
experience, education, socio-economic status, nationality, personal appearance,
|
|
||||||
race, religion, or sexual identity and orientation.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment
|
|
||||||
include:
|
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
|
||||||
* Being respectful of differing viewpoints and experiences
|
|
||||||
* Gracefully accepting constructive criticism
|
|
||||||
* Focusing on what is best for the community
|
|
||||||
* Showing empathy towards other community members
|
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
||||||
advances
|
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or electronic
|
|
||||||
address, without explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
## Our Responsibilities
|
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable
|
|
||||||
behavior and are expected to take appropriate and fair corrective action in
|
|
||||||
response to any instances of unacceptable behavior.
|
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
|
||||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
||||||
not aligned to this Code of Conduct, or to ban temporarily or permanently any
|
|
||||||
contributor for other behaviors that they deem inappropriate, threatening,
|
|
||||||
offensive, or harmful.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces
|
|
||||||
when an individual is representing the project or its community. Examples of
|
|
||||||
representing a project or community include using an official project e-mail
|
|
||||||
address, posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event. Representation of a project may be
|
|
||||||
further defined and clarified by project maintainers.
|
|
||||||
|
|
||||||
This Code of Conduct also applies outside the project spaces when the Project
|
|
||||||
Steward has a reasonable belief that an individual's behavior may have a
|
|
||||||
negative impact on the project or its community.
|
|
||||||
|
|
||||||
## Conflict Resolution
|
|
||||||
|
|
||||||
We do not believe that all conflict is bad; healthy debate and disagreement
|
|
||||||
often yield positive results. However, it is never okay to be disrespectful or
|
|
||||||
to engage in behavior that violates the project’s code of conduct.
|
|
||||||
|
|
||||||
If you see someone violating the code of conduct, you are encouraged to address
|
|
||||||
the behavior directly with those involved. Many issues can be resolved quickly
|
|
||||||
and easily, and this gives people more control over the outcome of their
|
|
||||||
dispute. If you are unable to resolve the matter for any reason, or if the
|
|
||||||
behavior is threatening or harassing, report it. We are dedicated to providing
|
|
||||||
an environment where participants feel welcome and safe.
|
|
||||||
|
|
||||||
Reports should be directed to *[PROJECT STEWARD NAME(s) AND EMAIL(s)]*, the
|
|
||||||
Project Steward(s) for *[PROJECT NAME]*. It is the Project Steward’s duty to
|
|
||||||
receive and address reported violations of the code of conduct. They will then
|
|
||||||
work with a committee consisting of representatives from the Open Source
|
|
||||||
Programs Office and the Google Open Source Strategy team. If for any reason you
|
|
||||||
are uncomfortable reaching out to the Project Steward, please email
|
|
||||||
opensource@google.com.
|
|
||||||
|
|
||||||
We will investigate every complaint, but you may not receive a direct response.
|
|
||||||
We will use our discretion in determining when and how to follow up on reported
|
|
||||||
incidents, which may range from not taking action to permanent expulsion from
|
|
||||||
the project and project-sponsored spaces. We will notify the accused of the
|
|
||||||
report and provide them an opportunity to discuss it before any action is taken.
|
|
||||||
The identity of the reporter will be omitted from the details of the report
|
|
||||||
supplied to the accused. In potentially harmful situations, such as ongoing
|
|
||||||
harassment or threats to anyone's safety, we may take action without notice.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
|
|
||||||
available at
|
|
||||||
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
|
||||||
29
src/server/vendor/github.com/google/s2a-go/CONTRIBUTING.md
generated
vendored
29
src/server/vendor/github.com/google/s2a-go/CONTRIBUTING.md
generated
vendored
@ -1,29 +0,0 @@
|
|||||||
# How to Contribute
|
|
||||||
|
|
||||||
We'd love to accept your patches and contributions to this project. There are
|
|
||||||
just a few small guidelines you need to follow.
|
|
||||||
|
|
||||||
## Contributor License Agreement
|
|
||||||
|
|
||||||
Contributions to this project must be accompanied by a Contributor License
|
|
||||||
Agreement (CLA). You (or your employer) retain the copyright to your
|
|
||||||
contribution; this simply gives us permission to use and redistribute your
|
|
||||||
contributions as part of the project. Head over to
|
|
||||||
<https://cla.developers.google.com/> to see your current agreements on file or
|
|
||||||
to sign a new one.
|
|
||||||
|
|
||||||
You generally only need to submit a CLA once, so if you've already submitted one
|
|
||||||
(even if it was for a different project), you probably don't need to do it
|
|
||||||
again.
|
|
||||||
|
|
||||||
## Code reviews
|
|
||||||
|
|
||||||
All submissions, including submissions by project members, require review. We
|
|
||||||
use GitHub pull requests for this purpose. Consult
|
|
||||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
|
||||||
information on using pull requests.
|
|
||||||
|
|
||||||
## Community Guidelines
|
|
||||||
|
|
||||||
This project follows
|
|
||||||
[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
|
|
||||||
202
src/server/vendor/github.com/google/s2a-go/LICENSE.md
generated
vendored
202
src/server/vendor/github.com/google/s2a-go/LICENSE.md
generated
vendored
@ -1,202 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
14
src/server/vendor/github.com/google/s2a-go/README.md
generated
vendored
14
src/server/vendor/github.com/google/s2a-go/README.md
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
# Secure Session Agent Client Libraries
|
|
||||||
|
|
||||||
The Secure Session Agent is a service that enables a workload to offload select
|
|
||||||
operations from the mTLS handshake and protects a workload's private key
|
|
||||||
material from exfiltration. Specifically, the workload asks the Secure Session
|
|
||||||
Agent for the TLS configuration to use during the handshake, to perform private
|
|
||||||
key operations, and to validate the peer certificate chain. The Secure Session
|
|
||||||
Agent's client libraries enable applications to communicate with the Secure
|
|
||||||
Session Agent during the TLS handshake, and to encrypt traffic to the peer
|
|
||||||
after the TLS handshake is complete.
|
|
||||||
|
|
||||||
This repository contains the source code for the Secure Session Agent's Go
|
|
||||||
client libraries, which allow gRPC and HTTP Go applications to use the Secure Session
|
|
||||||
Agent.
|
|
||||||
167
src/server/vendor/github.com/google/s2a-go/fallback/s2a_fallback.go
generated
vendored
167
src/server/vendor/github.com/google/s2a-go/fallback/s2a_fallback.go
generated
vendored
@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2023 Google LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package fallback provides default implementations of fallback options when S2A fails.
|
|
||||||
package fallback
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
"google.golang.org/grpc/grpclog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
alpnProtoStrH2 = "h2"
|
|
||||||
alpnProtoStrHTTP = "http/1.1"
|
|
||||||
defaultHTTPSPort = "443"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FallbackTLSConfigGRPC is a tls.Config used by the DefaultFallbackClientHandshakeFunc function.
|
|
||||||
// It supports GRPC use case, thus the alpn is set to 'h2'.
|
|
||||||
var FallbackTLSConfigGRPC = tls.Config{
|
|
||||||
MinVersion: tls.VersionTLS13,
|
|
||||||
ClientSessionCache: nil,
|
|
||||||
NextProtos: []string{alpnProtoStrH2},
|
|
||||||
}
|
|
||||||
|
|
||||||
// FallbackTLSConfigHTTP is a tls.Config used by the DefaultFallbackDialerAndAddress func.
|
|
||||||
// It supports the HTTP use case and the alpn is set to both 'http/1.1' and 'h2'.
|
|
||||||
var FallbackTLSConfigHTTP = tls.Config{
|
|
||||||
MinVersion: tls.VersionTLS13,
|
|
||||||
ClientSessionCache: nil,
|
|
||||||
NextProtos: []string{alpnProtoStrH2, alpnProtoStrHTTP},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientHandshake establishes a TLS connection and returns it, plus its auth info.
|
|
||||||
// Inputs:
|
|
||||||
//
|
|
||||||
// targetServer: the server attempted with S2A.
|
|
||||||
// conn: the tcp connection to the server at address targetServer that was passed into S2A's ClientHandshake func.
|
|
||||||
// If fallback is successful, the `conn` should be closed.
|
|
||||||
// err: the error encountered when performing the client-side TLS handshake with S2A.
|
|
||||||
type ClientHandshake func(ctx context.Context, targetServer string, conn net.Conn, err error) (net.Conn, credentials.AuthInfo, error)
|
|
||||||
|
|
||||||
// DefaultFallbackClientHandshakeFunc returns a ClientHandshake function,
|
|
||||||
// which establishes a TLS connection to the provided fallbackAddr, returns the new connection and its auth info.
|
|
||||||
// Example use:
|
|
||||||
//
|
|
||||||
// transportCreds, _ = s2a.NewClientCreds(&s2a.ClientOptions{
|
|
||||||
// S2AAddress: s2aAddress,
|
|
||||||
// FallbackOpts: &s2a.FallbackOptions{ // optional
|
|
||||||
// FallbackClientHandshakeFunc: fallback.DefaultFallbackClientHandshakeFunc(fallbackAddr),
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// The fallback server's certificate must be verifiable using OS root store.
|
|
||||||
// The fallbackAddr is expected to be a network address, e.g. example.com:port. If port is not specified,
|
|
||||||
// it uses default port 443.
|
|
||||||
// In the returned function's TLS config, ClientSessionCache is explicitly set to nil to disable TLS resumption,
|
|
||||||
// and min TLS version is set to 1.3.
|
|
||||||
func DefaultFallbackClientHandshakeFunc(fallbackAddr string) (ClientHandshake, error) {
|
|
||||||
var fallbackDialer = tls.Dialer{Config: &FallbackTLSConfigGRPC}
|
|
||||||
return defaultFallbackClientHandshakeFuncInternal(fallbackAddr, fallbackDialer.DialContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultFallbackClientHandshakeFuncInternal(fallbackAddr string, dialContextFunc func(context.Context, string, string) (net.Conn, error)) (ClientHandshake, error) {
|
|
||||||
fallbackServerAddr, err := processFallbackAddr(fallbackAddr)
|
|
||||||
if err != nil {
|
|
||||||
if grpclog.V(1) {
|
|
||||||
grpclog.Infof("error processing fallback address [%s]: %v", fallbackAddr, err)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(ctx context.Context, targetServer string, conn net.Conn, s2aErr error) (net.Conn, credentials.AuthInfo, error) {
|
|
||||||
fbConn, fbErr := dialContextFunc(ctx, "tcp", fallbackServerAddr)
|
|
||||||
if fbErr != nil {
|
|
||||||
grpclog.Infof("dialing to fallback server %s failed: %v", fallbackServerAddr, fbErr)
|
|
||||||
return nil, nil, fmt.Errorf("dialing to fallback server %s failed: %v; S2A client handshake with %s error: %w", fallbackServerAddr, fbErr, targetServer, s2aErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
tc, success := fbConn.(*tls.Conn)
|
|
||||||
if !success {
|
|
||||||
grpclog.Infof("the connection with fallback server is expected to be tls but isn't")
|
|
||||||
return nil, nil, fmt.Errorf("the connection with fallback server is expected to be tls but isn't; S2A client handshake with %s error: %w", targetServer, s2aErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsInfo := credentials.TLSInfo{
|
|
||||||
State: tc.ConnectionState(),
|
|
||||||
CommonAuthInfo: credentials.CommonAuthInfo{
|
|
||||||
SecurityLevel: credentials.PrivacyAndIntegrity,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if grpclog.V(1) {
|
|
||||||
grpclog.Infof("ConnectionState.NegotiatedProtocol: %v", tc.ConnectionState().NegotiatedProtocol)
|
|
||||||
grpclog.Infof("ConnectionState.HandshakeComplete: %v", tc.ConnectionState().HandshakeComplete)
|
|
||||||
grpclog.Infof("ConnectionState.ServerName: %v", tc.ConnectionState().ServerName)
|
|
||||||
}
|
|
||||||
conn.Close()
|
|
||||||
return fbConn, tlsInfo, nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultFallbackDialerAndAddress returns a TLS dialer and the network address to dial.
|
|
||||||
// Example use:
|
|
||||||
//
|
|
||||||
// fallbackDialer, fallbackServerAddr := fallback.DefaultFallbackDialerAndAddress(fallbackAddr)
|
|
||||||
// dialTLSContext := s2a.NewS2aDialTLSContextFunc(&s2a.ClientOptions{
|
|
||||||
// S2AAddress: s2aAddress, // required
|
|
||||||
// FallbackOpts: &s2a.FallbackOptions{
|
|
||||||
// FallbackDialer: &s2a.FallbackDialer{
|
|
||||||
// Dialer: fallbackDialer,
|
|
||||||
// ServerAddr: fallbackServerAddr,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// The fallback server's certificate should be verifiable using OS root store.
|
|
||||||
// The fallbackAddr is expected to be a network address, e.g. example.com:port. If port is not specified,
|
|
||||||
// it uses default port 443.
|
|
||||||
// In the returned function's TLS config, ClientSessionCache is explicitly set to nil to disable TLS resumption,
|
|
||||||
// and min TLS version is set to 1.3.
|
|
||||||
func DefaultFallbackDialerAndAddress(fallbackAddr string) (*tls.Dialer, string, error) {
|
|
||||||
fallbackServerAddr, err := processFallbackAddr(fallbackAddr)
|
|
||||||
if err != nil {
|
|
||||||
if grpclog.V(1) {
|
|
||||||
grpclog.Infof("error processing fallback address [%s]: %v", fallbackAddr, err)
|
|
||||||
}
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
return &tls.Dialer{Config: &FallbackTLSConfigHTTP}, fallbackServerAddr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func processFallbackAddr(fallbackAddr string) (string, error) {
|
|
||||||
var fallbackServerAddr string
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if fallbackAddr == "" {
|
|
||||||
return "", fmt.Errorf("empty fallback address")
|
|
||||||
}
|
|
||||||
_, _, err = net.SplitHostPort(fallbackAddr)
|
|
||||||
if err != nil {
|
|
||||||
// fallbackAddr does not have port suffix
|
|
||||||
fallbackServerAddr = net.JoinHostPort(fallbackAddr, defaultHTTPSPort)
|
|
||||||
} else {
|
|
||||||
// FallbackServerAddr already has port suffix
|
|
||||||
fallbackServerAddr = fallbackAddr
|
|
||||||
}
|
|
||||||
return fallbackServerAddr, nil
|
|
||||||
}
|
|
||||||
119
src/server/vendor/github.com/google/s2a-go/internal/authinfo/authinfo.go
generated
vendored
119
src/server/vendor/github.com/google/s2a-go/internal/authinfo/authinfo.go
generated
vendored
@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2021 Google LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package authinfo provides authentication and authorization information that
|
|
||||||
// results from the TLS handshake.
|
|
||||||
package authinfo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
|
||||||
contextpb "github.com/google/s2a-go/internal/proto/s2a_context_go_proto"
|
|
||||||
grpcpb "github.com/google/s2a-go/internal/proto/s2a_go_proto"
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ credentials.AuthInfo = (*S2AAuthInfo)(nil)
|
|
||||||
|
|
||||||
const s2aAuthType = "s2a"
|
|
||||||
|
|
||||||
// S2AAuthInfo exposes authentication and authorization information from the
|
|
||||||
// S2A session result to the gRPC stack.
|
|
||||||
type S2AAuthInfo struct {
|
|
||||||
s2aContext *contextpb.S2AContext
|
|
||||||
commonAuthInfo credentials.CommonAuthInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewS2AAuthInfo returns a new S2AAuthInfo object from the S2A session result.
|
|
||||||
func NewS2AAuthInfo(result *grpcpb.SessionResult) (credentials.AuthInfo, error) {
|
|
||||||
return newS2AAuthInfo(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newS2AAuthInfo(result *grpcpb.SessionResult) (*S2AAuthInfo, error) {
|
|
||||||
if result == nil {
|
|
||||||
return nil, errors.New("NewS2aAuthInfo given nil session result")
|
|
||||||
}
|
|
||||||
return &S2AAuthInfo{
|
|
||||||
s2aContext: &contextpb.S2AContext{
|
|
||||||
ApplicationProtocol: result.GetApplicationProtocol(),
|
|
||||||
TlsVersion: result.GetState().GetTlsVersion(),
|
|
||||||
Ciphersuite: result.GetState().GetTlsCiphersuite(),
|
|
||||||
PeerIdentity: result.GetPeerIdentity(),
|
|
||||||
LocalIdentity: result.GetLocalIdentity(),
|
|
||||||
PeerCertFingerprint: result.GetPeerCertFingerprint(),
|
|
||||||
LocalCertFingerprint: result.GetLocalCertFingerprint(),
|
|
||||||
IsHandshakeResumed: result.GetState().GetIsHandshakeResumed(),
|
|
||||||
},
|
|
||||||
commonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthType returns the authentication type.
|
|
||||||
func (s *S2AAuthInfo) AuthType() string {
|
|
||||||
return s2aAuthType
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplicationProtocol returns the application protocol, e.g. "grpc".
|
|
||||||
func (s *S2AAuthInfo) ApplicationProtocol() string {
|
|
||||||
return s.s2aContext.GetApplicationProtocol()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TLSVersion returns the TLS version negotiated during the handshake.
|
|
||||||
func (s *S2AAuthInfo) TLSVersion() commonpb.TLSVersion {
|
|
||||||
return s.s2aContext.GetTlsVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ciphersuite returns the ciphersuite negotiated during the handshake.
|
|
||||||
func (s *S2AAuthInfo) Ciphersuite() commonpb.Ciphersuite {
|
|
||||||
return s.s2aContext.GetCiphersuite()
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerIdentity returns the authenticated identity of the peer.
|
|
||||||
func (s *S2AAuthInfo) PeerIdentity() *commonpb.Identity {
|
|
||||||
return s.s2aContext.GetPeerIdentity()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocalIdentity returns the local identity of the application used during
|
|
||||||
// session setup.
|
|
||||||
func (s *S2AAuthInfo) LocalIdentity() *commonpb.Identity {
|
|
||||||
return s.s2aContext.GetLocalIdentity()
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerCertFingerprint returns the SHA256 hash of the peer certificate used in
|
|
||||||
// the S2A handshake.
|
|
||||||
func (s *S2AAuthInfo) PeerCertFingerprint() []byte {
|
|
||||||
return s.s2aContext.GetPeerCertFingerprint()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocalCertFingerprint returns the SHA256 hash of the local certificate used
|
|
||||||
// in the S2A handshake.
|
|
||||||
func (s *S2AAuthInfo) LocalCertFingerprint() []byte {
|
|
||||||
return s.s2aContext.GetLocalCertFingerprint()
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsHandshakeResumed returns true if a cached session was used to resume
|
|
||||||
// the handshake.
|
|
||||||
func (s *S2AAuthInfo) IsHandshakeResumed() bool {
|
|
||||||
return s.s2aContext.GetIsHandshakeResumed()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecurityLevel returns the security level of the connection.
|
|
||||||
func (s *S2AAuthInfo) SecurityLevel() credentials.SecurityLevel {
|
|
||||||
return s.commonAuthInfo.SecurityLevel
|
|
||||||
}
|
|
||||||
438
src/server/vendor/github.com/google/s2a-go/internal/handshaker/handshaker.go
generated
vendored
438
src/server/vendor/github.com/google/s2a-go/internal/handshaker/handshaker.go
generated
vendored
@ -1,438 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2021 Google LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package handshaker communicates with the S2A handshaker service.
|
|
||||||
package handshaker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/google/s2a-go/internal/authinfo"
|
|
||||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
|
||||||
s2apb "github.com/google/s2a-go/internal/proto/s2a_go_proto"
|
|
||||||
"github.com/google/s2a-go/internal/record"
|
|
||||||
"github.com/google/s2a-go/internal/tokenmanager"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
"google.golang.org/grpc/grpclog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// appProtocol contains the application protocol accepted by the handshaker.
|
|
||||||
appProtocol = "grpc"
|
|
||||||
// frameLimit is the maximum size of a frame in bytes.
|
|
||||||
frameLimit = 1024 * 64
|
|
||||||
// peerNotRespondingError is the error thrown when the peer doesn't respond.
|
|
||||||
errPeerNotResponding = errors.New("peer is not responding and re-connection should be attempted")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Handshaker defines a handshaker interface.
|
|
||||||
type Handshaker interface {
|
|
||||||
// ClientHandshake starts and completes a TLS handshake from the client side,
|
|
||||||
// and returns a secure connection along with additional auth information.
|
|
||||||
ClientHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error)
|
|
||||||
// ServerHandshake starts and completes a TLS handshake from the server side,
|
|
||||||
// and returns a secure connection along with additional auth information.
|
|
||||||
ServerHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error)
|
|
||||||
// Close terminates the Handshaker. It should be called when the handshake
|
|
||||||
// is complete.
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientHandshakerOptions contains the options needed to configure the S2A
|
|
||||||
// handshaker service on the client-side.
|
|
||||||
type ClientHandshakerOptions struct {
|
|
||||||
// MinTLSVersion specifies the min TLS version supported by the client.
|
|
||||||
MinTLSVersion commonpb.TLSVersion
|
|
||||||
// MaxTLSVersion specifies the max TLS version supported by the client.
|
|
||||||
MaxTLSVersion commonpb.TLSVersion
|
|
||||||
// TLSCiphersuites is the ordered list of ciphersuites supported by the
|
|
||||||
// client.
|
|
||||||
TLSCiphersuites []commonpb.Ciphersuite
|
|
||||||
// TargetIdentities contains a list of allowed server identities. One of the
|
|
||||||
// target identities should match the peer identity in the handshake
|
|
||||||
// result; otherwise, the handshake fails.
|
|
||||||
TargetIdentities []*commonpb.Identity
|
|
||||||
// LocalIdentity is the local identity of the client application. If none is
|
|
||||||
// provided, then the S2A will choose the default identity.
|
|
||||||
LocalIdentity *commonpb.Identity
|
|
||||||
// TargetName is the allowed server name, which may be used for server
|
|
||||||
// authorization check by the S2A if it is provided.
|
|
||||||
TargetName string
|
|
||||||
// EnsureProcessSessionTickets allows users to wait and ensure that all
|
|
||||||
// available session tickets are sent to S2A before a process completes.
|
|
||||||
EnsureProcessSessionTickets *sync.WaitGroup
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerHandshakerOptions contains the options needed to configure the S2A
|
|
||||||
// handshaker service on the server-side.
|
|
||||||
type ServerHandshakerOptions struct {
|
|
||||||
// MinTLSVersion specifies the min TLS version supported by the server.
|
|
||||||
MinTLSVersion commonpb.TLSVersion
|
|
||||||
// MaxTLSVersion specifies the max TLS version supported by the server.
|
|
||||||
MaxTLSVersion commonpb.TLSVersion
|
|
||||||
// TLSCiphersuites is the ordered list of ciphersuites supported by the
|
|
||||||
// server.
|
|
||||||
TLSCiphersuites []commonpb.Ciphersuite
|
|
||||||
// LocalIdentities is the list of local identities that may be assumed by
|
|
||||||
// the server. If no local identity is specified, then the S2A chooses a
|
|
||||||
// default local identity.
|
|
||||||
LocalIdentities []*commonpb.Identity
|
|
||||||
}
|
|
||||||
|
|
||||||
// s2aHandshaker performs a TLS handshake using the S2A handshaker service.
|
|
||||||
type s2aHandshaker struct {
|
|
||||||
// stream is used to communicate with the S2A handshaker service.
|
|
||||||
stream s2apb.S2AService_SetUpSessionClient
|
|
||||||
// conn is the connection to the peer.
|
|
||||||
conn net.Conn
|
|
||||||
// clientOpts should be non-nil iff the handshaker is client-side.
|
|
||||||
clientOpts *ClientHandshakerOptions
|
|
||||||
// serverOpts should be non-nil iff the handshaker is server-side.
|
|
||||||
serverOpts *ServerHandshakerOptions
|
|
||||||
// isClient determines if the handshaker is client or server side.
|
|
||||||
isClient bool
|
|
||||||
// hsAddr stores the address of the S2A handshaker service.
|
|
||||||
hsAddr string
|
|
||||||
// tokenManager manages access tokens for authenticating to S2A.
|
|
||||||
tokenManager tokenmanager.AccessTokenManager
|
|
||||||
// localIdentities is the set of local identities for whom the
|
|
||||||
// tokenManager should fetch a token when preparing a request to be
|
|
||||||
// sent to S2A.
|
|
||||||
localIdentities []*commonpb.Identity
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClientHandshaker creates an s2aHandshaker instance that performs a
|
|
||||||
// client-side TLS handshake using the S2A handshaker service.
|
|
||||||
func NewClientHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, hsAddr string, opts *ClientHandshakerOptions) (Handshaker, error) {
|
|
||||||
stream, err := s2apb.NewS2AServiceClient(conn).SetUpSession(ctx, grpc.WaitForReady(true))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Infof("failed to create single token access token manager: %v", err)
|
|
||||||
}
|
|
||||||
return newClientHandshaker(stream, c, hsAddr, opts, tokenManager), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClientHandshaker(stream s2apb.S2AService_SetUpSessionClient, c net.Conn, hsAddr string, opts *ClientHandshakerOptions, tokenManager tokenmanager.AccessTokenManager) *s2aHandshaker {
|
|
||||||
var localIdentities []*commonpb.Identity
|
|
||||||
if opts != nil {
|
|
||||||
localIdentities = []*commonpb.Identity{opts.LocalIdentity}
|
|
||||||
}
|
|
||||||
return &s2aHandshaker{
|
|
||||||
stream: stream,
|
|
||||||
conn: c,
|
|
||||||
clientOpts: opts,
|
|
||||||
isClient: true,
|
|
||||||
hsAddr: hsAddr,
|
|
||||||
tokenManager: tokenManager,
|
|
||||||
localIdentities: localIdentities,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServerHandshaker creates an s2aHandshaker instance that performs a
|
|
||||||
// server-side TLS handshake using the S2A handshaker service.
|
|
||||||
func NewServerHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, hsAddr string, opts *ServerHandshakerOptions) (Handshaker, error) {
|
|
||||||
stream, err := s2apb.NewS2AServiceClient(conn).SetUpSession(ctx, grpc.WaitForReady(true))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Infof("failed to create single token access token manager: %v", err)
|
|
||||||
}
|
|
||||||
return newServerHandshaker(stream, c, hsAddr, opts, tokenManager), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newServerHandshaker(stream s2apb.S2AService_SetUpSessionClient, c net.Conn, hsAddr string, opts *ServerHandshakerOptions, tokenManager tokenmanager.AccessTokenManager) *s2aHandshaker {
|
|
||||||
var localIdentities []*commonpb.Identity
|
|
||||||
if opts != nil {
|
|
||||||
localIdentities = opts.LocalIdentities
|
|
||||||
}
|
|
||||||
return &s2aHandshaker{
|
|
||||||
stream: stream,
|
|
||||||
conn: c,
|
|
||||||
serverOpts: opts,
|
|
||||||
isClient: false,
|
|
||||||
hsAddr: hsAddr,
|
|
||||||
tokenManager: tokenManager,
|
|
||||||
localIdentities: localIdentities,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientHandshake performs a client-side TLS handshake using the S2A handshaker
|
|
||||||
// service. When complete, returns a TLS connection.
|
|
||||||
func (h *s2aHandshaker) ClientHandshake(_ context.Context) (net.Conn, credentials.AuthInfo, error) {
|
|
||||||
if !h.isClient {
|
|
||||||
return nil, nil, errors.New("only handshakers created using NewClientHandshaker can perform a client-side handshake")
|
|
||||||
}
|
|
||||||
// Extract the hostname from the target name. The target name is assumed to be an authority.
|
|
||||||
hostname, _, err := net.SplitHostPort(h.clientOpts.TargetName)
|
|
||||||
if err != nil {
|
|
||||||
// If the target name had no host port or could not be parsed, use it as is.
|
|
||||||
hostname = h.clientOpts.TargetName
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare a client start message to send to the S2A handshaker service.
|
|
||||||
req := &s2apb.SessionReq{
|
|
||||||
ReqOneof: &s2apb.SessionReq_ClientStart{
|
|
||||||
ClientStart: &s2apb.ClientSessionStartReq{
|
|
||||||
ApplicationProtocols: []string{appProtocol},
|
|
||||||
MinTlsVersion: h.clientOpts.MinTLSVersion,
|
|
||||||
MaxTlsVersion: h.clientOpts.MaxTLSVersion,
|
|
||||||
TlsCiphersuites: h.clientOpts.TLSCiphersuites,
|
|
||||||
TargetIdentities: h.clientOpts.TargetIdentities,
|
|
||||||
LocalIdentity: h.clientOpts.LocalIdentity,
|
|
||||||
TargetName: hostname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AuthMechanisms: h.getAuthMechanisms(),
|
|
||||||
}
|
|
||||||
conn, result, err := h.setUpSession(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
authInfo, err := authinfo.NewS2AAuthInfo(result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return conn, authInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerHandshake performs a server-side TLS handshake using the S2A handshaker
|
|
||||||
// service. When complete, returns a TLS connection.
|
|
||||||
func (h *s2aHandshaker) ServerHandshake(_ context.Context) (net.Conn, credentials.AuthInfo, error) {
|
|
||||||
if h.isClient {
|
|
||||||
return nil, nil, errors.New("only handshakers created using NewServerHandshaker can perform a server-side handshake")
|
|
||||||
}
|
|
||||||
p := make([]byte, frameLimit)
|
|
||||||
n, err := h.conn.Read(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
// Prepare a server start message to send to the S2A handshaker service.
|
|
||||||
req := &s2apb.SessionReq{
|
|
||||||
ReqOneof: &s2apb.SessionReq_ServerStart{
|
|
||||||
ServerStart: &s2apb.ServerSessionStartReq{
|
|
||||||
ApplicationProtocols: []string{appProtocol},
|
|
||||||
MinTlsVersion: h.serverOpts.MinTLSVersion,
|
|
||||||
MaxTlsVersion: h.serverOpts.MaxTLSVersion,
|
|
||||||
TlsCiphersuites: h.serverOpts.TLSCiphersuites,
|
|
||||||
LocalIdentities: h.serverOpts.LocalIdentities,
|
|
||||||
InBytes: p[:n],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AuthMechanisms: h.getAuthMechanisms(),
|
|
||||||
}
|
|
||||||
conn, result, err := h.setUpSession(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
authInfo, err := authinfo.NewS2AAuthInfo(result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return conn, authInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// setUpSession proxies messages between the peer and the S2A handshaker
|
|
||||||
// service.
|
|
||||||
func (h *s2aHandshaker) setUpSession(req *s2apb.SessionReq) (net.Conn, *s2apb.SessionResult, error) {
|
|
||||||
resp, err := h.accessHandshakerService(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
// Check if the returned status is an error.
|
|
||||||
if resp.GetStatus() != nil {
|
|
||||||
if got, want := resp.GetStatus().Code, uint32(codes.OK); got != want {
|
|
||||||
return nil, nil, fmt.Errorf("%v", resp.GetStatus().Details)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Calculate the extra unread bytes from the Session. Attempting to consume
|
|
||||||
// more than the bytes sent will throw an error.
|
|
||||||
var extra []byte
|
|
||||||
if req.GetServerStart() != nil {
|
|
||||||
if resp.GetBytesConsumed() > uint32(len(req.GetServerStart().GetInBytes())) {
|
|
||||||
return nil, nil, errors.New("handshaker service consumed bytes value is out-of-bounds")
|
|
||||||
}
|
|
||||||
extra = req.GetServerStart().GetInBytes()[resp.GetBytesConsumed():]
|
|
||||||
}
|
|
||||||
result, extra, err := h.processUntilDone(resp, extra)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if result.GetLocalIdentity() == nil {
|
|
||||||
return nil, nil, errors.New("local identity must be populated in session result")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new TLS record protocol using the Session Result.
|
|
||||||
newConn, err := record.NewConn(&record.ConnParameters{
|
|
||||||
NetConn: h.conn,
|
|
||||||
Ciphersuite: result.GetState().GetTlsCiphersuite(),
|
|
||||||
TLSVersion: result.GetState().GetTlsVersion(),
|
|
||||||
InTrafficSecret: result.GetState().GetInKey(),
|
|
||||||
OutTrafficSecret: result.GetState().GetOutKey(),
|
|
||||||
UnusedBuf: extra,
|
|
||||||
InSequence: result.GetState().GetInSequence(),
|
|
||||||
OutSequence: result.GetState().GetOutSequence(),
|
|
||||||
HSAddr: h.hsAddr,
|
|
||||||
ConnectionID: result.GetState().GetConnectionId(),
|
|
||||||
LocalIdentity: result.GetLocalIdentity(),
|
|
||||||
EnsureProcessSessionTickets: h.ensureProcessSessionTickets(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return newConn, result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *s2aHandshaker) ensureProcessSessionTickets() *sync.WaitGroup {
|
|
||||||
if h.clientOpts == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return h.clientOpts.EnsureProcessSessionTickets
|
|
||||||
}
|
|
||||||
|
|
||||||
// accessHandshakerService sends the session request to the S2A handshaker
|
|
||||||
// service and returns the session response.
|
|
||||||
func (h *s2aHandshaker) accessHandshakerService(req *s2apb.SessionReq) (*s2apb.SessionResp, error) {
|
|
||||||
if err := h.stream.Send(req); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := h.stream.Recv()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// processUntilDone continues proxying messages between the peer and the S2A
|
|
||||||
// handshaker service until the handshaker service returns the SessionResult at
|
|
||||||
// the end of the handshake or an error occurs.
|
|
||||||
func (h *s2aHandshaker) processUntilDone(resp *s2apb.SessionResp, unusedBytes []byte) (*s2apb.SessionResult, []byte, error) {
|
|
||||||
for {
|
|
||||||
if len(resp.OutFrames) > 0 {
|
|
||||||
if _, err := h.conn.Write(resp.OutFrames); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if resp.Result != nil {
|
|
||||||
return resp.Result, unusedBytes, nil
|
|
||||||
}
|
|
||||||
buf := make([]byte, frameLimit)
|
|
||||||
n, err := h.conn.Read(buf)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
// If there is nothing to send to the handshaker service and nothing is
|
|
||||||
// received from the peer, then we are stuck. This covers the case when
|
|
||||||
// the peer is not responding. Note that handshaker service connection
|
|
||||||
// issues are caught in accessHandshakerService before we even get
|
|
||||||
// here.
|
|
||||||
if len(resp.OutFrames) == 0 && n == 0 {
|
|
||||||
return nil, nil, errPeerNotResponding
|
|
||||||
}
|
|
||||||
// Append extra bytes from the previous interaction with the handshaker
|
|
||||||
// service with the current buffer read from conn.
|
|
||||||
p := append(unusedBytes, buf[:n]...)
|
|
||||||
// From here on, p and unusedBytes point to the same slice.
|
|
||||||
resp, err = h.accessHandshakerService(&s2apb.SessionReq{
|
|
||||||
ReqOneof: &s2apb.SessionReq_Next{
|
|
||||||
Next: &s2apb.SessionNextReq{
|
|
||||||
InBytes: p,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AuthMechanisms: h.getAuthMechanisms(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the local identity returned by S2A, if it is populated. This
|
|
||||||
// overwrites any existing local identities. This is done because, once the
|
|
||||||
// S2A has selected a local identity, then only that local identity should
|
|
||||||
// be asserted in future requests until the end of the current handshake.
|
|
||||||
if resp.GetLocalIdentity() != nil {
|
|
||||||
h.localIdentities = []*commonpb.Identity{resp.GetLocalIdentity()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set unusedBytes based on the handshaker service response.
|
|
||||||
if resp.GetBytesConsumed() > uint32(len(p)) {
|
|
||||||
return nil, nil, errors.New("handshaker service consumed bytes value is out-of-bounds")
|
|
||||||
}
|
|
||||||
unusedBytes = p[resp.GetBytesConsumed():]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close shuts down the handshaker and the stream to the S2A handshaker service
|
|
||||||
// when the handshake is complete. It should be called when the caller obtains
|
|
||||||
// the secure connection at the end of the handshake.
|
|
||||||
func (h *s2aHandshaker) Close() error {
|
|
||||||
return h.stream.CloseSend()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *s2aHandshaker) getAuthMechanisms() []*s2apb.AuthenticationMechanism {
|
|
||||||
if h.tokenManager == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// First handle the special case when no local identities have been provided
|
|
||||||
// by the application. In this case, an AuthenticationMechanism with no local
|
|
||||||
// identity will be sent.
|
|
||||||
if len(h.localIdentities) == 0 {
|
|
||||||
token, err := h.tokenManager.DefaultToken()
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Infof("unable to get token for empty local identity: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return []*s2apb.AuthenticationMechanism{
|
|
||||||
{
|
|
||||||
MechanismOneof: &s2apb.AuthenticationMechanism_Token{
|
|
||||||
Token: token,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, handle the case where the application (or the S2A) has provided
|
|
||||||
// one or more local identities.
|
|
||||||
var authMechanisms []*s2apb.AuthenticationMechanism
|
|
||||||
for _, localIdentity := range h.localIdentities {
|
|
||||||
token, err := h.tokenManager.Token(localIdentity)
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Infof("unable to get token for local identity %v: %v", localIdentity, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
authMechanism := &s2apb.AuthenticationMechanism{
|
|
||||||
Identity: localIdentity,
|
|
||||||
MechanismOneof: &s2apb.AuthenticationMechanism_Token{
|
|
||||||
Token: token,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
authMechanisms = append(authMechanisms, authMechanism)
|
|
||||||
}
|
|
||||||
return authMechanisms
|
|
||||||
}
|
|
||||||
66
src/server/vendor/github.com/google/s2a-go/internal/handshaker/service/service.go
generated
vendored
66
src/server/vendor/github.com/google/s2a-go/internal/handshaker/service/service.go
generated
vendored
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2021 Google LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package service is a utility for calling the S2A handshaker service.
|
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// mu guards hsConnMap and hsDialer.
|
|
||||||
mu sync.Mutex
|
|
||||||
// hsConnMap represents a mapping from an S2A handshaker service address
|
|
||||||
// to a corresponding connection to an S2A handshaker service instance.
|
|
||||||
hsConnMap = make(map[string]*grpc.ClientConn)
|
|
||||||
// hsDialer will be reassigned in tests.
|
|
||||||
hsDialer = grpc.DialContext
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dial dials the S2A handshaker service. If a connection has already been
|
|
||||||
// established, this function returns it. Otherwise, a new connection is
|
|
||||||
// created.
|
|
||||||
func Dial(ctx context.Context, handshakerServiceAddress string, transportCreds credentials.TransportCredentials) (*grpc.ClientConn, error) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
hsConn, ok := hsConnMap[handshakerServiceAddress]
|
|
||||||
if !ok {
|
|
||||||
// Create a new connection to the S2A handshaker service. Note that
|
|
||||||
// this connection stays open until the application is closed.
|
|
||||||
var grpcOpts []grpc.DialOption
|
|
||||||
if transportCreds != nil {
|
|
||||||
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(transportCreds))
|
|
||||||
} else {
|
|
||||||
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
hsConn, err = hsDialer(ctx, handshakerServiceAddress, grpcOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
hsConnMap[handshakerServiceAddress] = hsConn
|
|
||||||
}
|
|
||||||
return hsConn, nil
|
|
||||||
}
|
|
||||||
388
src/server/vendor/github.com/google/s2a-go/internal/proto/common_go_proto/common.pb.go
generated
vendored
388
src/server/vendor/github.com/google/s2a-go/internal/proto/common_go_proto/common.pb.go
generated
vendored
@ -1,388 +0,0 @@
|
|||||||
// Copyright 2021 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.34.2
|
|
||||||
// protoc v3.21.12
|
|
||||||
// source: internal/proto/common/common.proto
|
|
||||||
|
|
||||||
package common_go_proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
// The ciphersuites supported by S2A. The name determines the confidentiality,
|
|
||||||
// and authentication ciphers as well as the hash algorithm used for PRF in
|
|
||||||
// TLS 1.2 or HKDF in TLS 1.3. Thus, the components of the name are:
|
|
||||||
// - AEAD -- for encryption and authentication, e.g., AES_128_GCM.
|
|
||||||
// - Hash algorithm -- used in PRF or HKDF, e.g., SHA256.
|
|
||||||
type Ciphersuite int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
Ciphersuite_AES_128_GCM_SHA256 Ciphersuite = 0
|
|
||||||
Ciphersuite_AES_256_GCM_SHA384 Ciphersuite = 1
|
|
||||||
Ciphersuite_CHACHA20_POLY1305_SHA256 Ciphersuite = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for Ciphersuite.
|
|
||||||
var (
|
|
||||||
Ciphersuite_name = map[int32]string{
|
|
||||||
0: "AES_128_GCM_SHA256",
|
|
||||||
1: "AES_256_GCM_SHA384",
|
|
||||||
2: "CHACHA20_POLY1305_SHA256",
|
|
||||||
}
|
|
||||||
Ciphersuite_value = map[string]int32{
|
|
||||||
"AES_128_GCM_SHA256": 0,
|
|
||||||
"AES_256_GCM_SHA384": 1,
|
|
||||||
"CHACHA20_POLY1305_SHA256": 2,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x Ciphersuite) Enum() *Ciphersuite {
|
|
||||||
p := new(Ciphersuite)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x Ciphersuite) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Ciphersuite) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_internal_proto_common_common_proto_enumTypes[0].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Ciphersuite) Type() protoreflect.EnumType {
|
|
||||||
return &file_internal_proto_common_common_proto_enumTypes[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x Ciphersuite) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Ciphersuite.Descriptor instead.
|
|
||||||
func (Ciphersuite) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_common_common_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The TLS versions supported by S2A's handshaker module.
|
|
||||||
type TLSVersion int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TLSVersion_TLS1_2 TLSVersion = 0
|
|
||||||
TLSVersion_TLS1_3 TLSVersion = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for TLSVersion.
|
|
||||||
var (
|
|
||||||
TLSVersion_name = map[int32]string{
|
|
||||||
0: "TLS1_2",
|
|
||||||
1: "TLS1_3",
|
|
||||||
}
|
|
||||||
TLSVersion_value = map[string]int32{
|
|
||||||
"TLS1_2": 0,
|
|
||||||
"TLS1_3": 1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x TLSVersion) Enum() *TLSVersion {
|
|
||||||
p := new(TLSVersion)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x TLSVersion) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (TLSVersion) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_internal_proto_common_common_proto_enumTypes[1].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (TLSVersion) Type() protoreflect.EnumType {
|
|
||||||
return &file_internal_proto_common_common_proto_enumTypes[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x TLSVersion) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use TLSVersion.Descriptor instead.
|
|
||||||
func (TLSVersion) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_common_common_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// Types that are assignable to IdentityOneof:
|
|
||||||
//
|
|
||||||
// *Identity_SpiffeId
|
|
||||||
// *Identity_Hostname
|
|
||||||
// *Identity_Uid
|
|
||||||
// *Identity_Username
|
|
||||||
// *Identity_GcpId
|
|
||||||
IdentityOneof isIdentity_IdentityOneof `protobuf_oneof:"identity_oneof"`
|
|
||||||
// Additional identity-specific attributes.
|
|
||||||
Attributes map[string]string `protobuf:"bytes,3,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) Reset() {
|
|
||||||
*x = Identity{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_internal_proto_common_common_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Identity) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Identity) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_internal_proto_common_common_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Identity.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Identity) Descriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_common_common_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Identity) GetIdentityOneof() isIdentity_IdentityOneof {
|
|
||||||
if m != nil {
|
|
||||||
return m.IdentityOneof
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetSpiffeId() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_SpiffeId); ok {
|
|
||||||
return x.SpiffeId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetHostname() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_Hostname); ok {
|
|
||||||
return x.Hostname
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetUid() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_Uid); ok {
|
|
||||||
return x.Uid
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetUsername() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_Username); ok {
|
|
||||||
return x.Username
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetGcpId() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_GcpId); ok {
|
|
||||||
return x.GcpId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetAttributes() map[string]string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Attributes
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type isIdentity_IdentityOneof interface {
|
|
||||||
isIdentity_IdentityOneof()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_SpiffeId struct {
|
|
||||||
// The SPIFFE ID of a connection endpoint.
|
|
||||||
SpiffeId string `protobuf:"bytes,1,opt,name=spiffe_id,json=spiffeId,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_Hostname struct {
|
|
||||||
// The hostname of a connection endpoint.
|
|
||||||
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_Uid struct {
|
|
||||||
// The UID of a connection endpoint.
|
|
||||||
Uid string `protobuf:"bytes,4,opt,name=uid,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_Username struct {
|
|
||||||
// The username of a connection endpoint.
|
|
||||||
Username string `protobuf:"bytes,5,opt,name=username,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_GcpId struct {
|
|
||||||
// The GCP ID of a connection endpoint.
|
|
||||||
GcpId string `protobuf:"bytes,6,opt,name=gcp_id,json=gcpId,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Identity_SpiffeId) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_Hostname) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_Uid) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_Username) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_GcpId) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
var File_internal_proto_common_common_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_internal_proto_common_common_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
|
||||||
0xa8, 0x02, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1d, 0x0a, 0x09,
|
|
||||||
0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48,
|
|
||||||
0x00, 0x52, 0x08, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x68,
|
|
||||||
0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52,
|
|
||||||
0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x75, 0x69, 0x64,
|
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x1c, 0x0a,
|
|
||||||
0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48,
|
|
||||||
0x00, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x06, 0x67,
|
|
||||||
0x63, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x67,
|
|
||||||
0x63, 0x70, 0x49, 0x64, 0x12, 0x43, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
|
||||||
0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x41, 0x74,
|
|
||||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61,
|
|
||||||
0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74,
|
|
||||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
|
||||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
|
|
||||||
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
|
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x69, 0x64, 0x65, 0x6e,
|
|
||||||
0x74, 0x69, 0x74, 0x79, 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x2a, 0x5b, 0x0a, 0x0b, 0x43, 0x69,
|
|
||||||
0x70, 0x68, 0x65, 0x72, 0x73, 0x75, 0x69, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x45, 0x53,
|
|
||||||
0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10,
|
|
||||||
0x00, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d,
|
|
||||||
0x5f, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x48, 0x41,
|
|
||||||
0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x5f, 0x53,
|
|
||||||
0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x02, 0x2a, 0x24, 0x0a, 0x0a, 0x54, 0x4c, 0x53, 0x56, 0x65,
|
|
||||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x4c, 0x53, 0x31, 0x5f, 0x32, 0x10,
|
|
||||||
0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x4c, 0x53, 0x31, 0x5f, 0x33, 0x10, 0x01, 0x42, 0x36, 0x5a,
|
|
||||||
0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67,
|
|
||||||
0x6c, 0x65, 0x2f, 0x73, 0x32, 0x61, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x67, 0x6f, 0x5f,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_internal_proto_common_common_proto_rawDescOnce sync.Once
|
|
||||||
file_internal_proto_common_common_proto_rawDescData = file_internal_proto_common_common_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_internal_proto_common_common_proto_rawDescGZIP() []byte {
|
|
||||||
file_internal_proto_common_common_proto_rawDescOnce.Do(func() {
|
|
||||||
file_internal_proto_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_common_common_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_internal_proto_common_common_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_internal_proto_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
|
||||||
var file_internal_proto_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_internal_proto_common_common_proto_goTypes = []any{
|
|
||||||
(Ciphersuite)(0), // 0: s2a.proto.Ciphersuite
|
|
||||||
(TLSVersion)(0), // 1: s2a.proto.TLSVersion
|
|
||||||
(*Identity)(nil), // 2: s2a.proto.Identity
|
|
||||||
nil, // 3: s2a.proto.Identity.AttributesEntry
|
|
||||||
}
|
|
||||||
var file_internal_proto_common_common_proto_depIdxs = []int32{
|
|
||||||
3, // 0: s2a.proto.Identity.attributes:type_name -> s2a.proto.Identity.AttributesEntry
|
|
||||||
1, // [1:1] is the sub-list for method output_type
|
|
||||||
1, // [1:1] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_internal_proto_common_common_proto_init() }
|
|
||||||
func file_internal_proto_common_common_proto_init() {
|
|
||||||
if File_internal_proto_common_common_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_internal_proto_common_common_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
|
||||||
switch v := v.(*Identity); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_internal_proto_common_common_proto_msgTypes[0].OneofWrappers = []any{
|
|
||||||
(*Identity_SpiffeId)(nil),
|
|
||||||
(*Identity_Hostname)(nil),
|
|
||||||
(*Identity_Uid)(nil),
|
|
||||||
(*Identity_Username)(nil),
|
|
||||||
(*Identity_GcpId)(nil),
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_internal_proto_common_common_proto_rawDesc,
|
|
||||||
NumEnums: 2,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_internal_proto_common_common_proto_goTypes,
|
|
||||||
DependencyIndexes: file_internal_proto_common_common_proto_depIdxs,
|
|
||||||
EnumInfos: file_internal_proto_common_common_proto_enumTypes,
|
|
||||||
MessageInfos: file_internal_proto_common_common_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_internal_proto_common_common_proto = out.File
|
|
||||||
file_internal_proto_common_common_proto_rawDesc = nil
|
|
||||||
file_internal_proto_common_common_proto_goTypes = nil
|
|
||||||
file_internal_proto_common_common_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@ -1,267 +0,0 @@
|
|||||||
// Copyright 2021 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.34.2
|
|
||||||
// protoc v3.21.12
|
|
||||||
// source: internal/proto/s2a_context/s2a_context.proto
|
|
||||||
|
|
||||||
package s2a_context_go_proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
common_go_proto "github.com/google/s2a-go/internal/proto/common_go_proto"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type S2AContext struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// The application protocol negotiated for this connection, e.g., 'grpc'.
|
|
||||||
ApplicationProtocol string `protobuf:"bytes,1,opt,name=application_protocol,json=applicationProtocol,proto3" json:"application_protocol,omitempty"`
|
|
||||||
// The TLS version number that the S2A's handshaker module used to set up the
|
|
||||||
// session.
|
|
||||||
TlsVersion common_go_proto.TLSVersion `protobuf:"varint,2,opt,name=tls_version,json=tlsVersion,proto3,enum=s2a.proto.TLSVersion" json:"tls_version,omitempty"`
|
|
||||||
// The TLS ciphersuite negotiated by the S2A's handshaker module.
|
|
||||||
Ciphersuite common_go_proto.Ciphersuite `protobuf:"varint,3,opt,name=ciphersuite,proto3,enum=s2a.proto.Ciphersuite" json:"ciphersuite,omitempty"`
|
|
||||||
// The authenticated identity of the peer.
|
|
||||||
PeerIdentity *common_go_proto.Identity `protobuf:"bytes,4,opt,name=peer_identity,json=peerIdentity,proto3" json:"peer_identity,omitempty"`
|
|
||||||
// The local identity used during session setup. This could be:
|
|
||||||
// - The local identity that the client specifies in ClientSessionStartReq.
|
|
||||||
// - One of the local identities that the server specifies in
|
|
||||||
// ServerSessionStartReq.
|
|
||||||
// - If neither client or server specifies local identities, the S2A picks the
|
|
||||||
// default one. In this case, this field will contain that identity.
|
|
||||||
LocalIdentity *common_go_proto.Identity `protobuf:"bytes,5,opt,name=local_identity,json=localIdentity,proto3" json:"local_identity,omitempty"`
|
|
||||||
// The SHA256 hash of the peer certificate used in the handshake.
|
|
||||||
PeerCertFingerprint []byte `protobuf:"bytes,6,opt,name=peer_cert_fingerprint,json=peerCertFingerprint,proto3" json:"peer_cert_fingerprint,omitempty"`
|
|
||||||
// The SHA256 hash of the local certificate used in the handshake.
|
|
||||||
LocalCertFingerprint []byte `protobuf:"bytes,7,opt,name=local_cert_fingerprint,json=localCertFingerprint,proto3" json:"local_cert_fingerprint,omitempty"`
|
|
||||||
// Set to true if a cached session was reused to resume the handshake.
|
|
||||||
IsHandshakeResumed bool `protobuf:"varint,8,opt,name=is_handshake_resumed,json=isHandshakeResumed,proto3" json:"is_handshake_resumed,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) Reset() {
|
|
||||||
*x = S2AContext{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_internal_proto_s2a_context_s2a_context_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*S2AContext) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *S2AContext) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_internal_proto_s2a_context_s2a_context_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use S2AContext.ProtoReflect.Descriptor instead.
|
|
||||||
func (*S2AContext) Descriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_s2a_context_s2a_context_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetApplicationProtocol() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.ApplicationProtocol
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetTlsVersion() common_go_proto.TLSVersion {
|
|
||||||
if x != nil {
|
|
||||||
return x.TlsVersion
|
|
||||||
}
|
|
||||||
return common_go_proto.TLSVersion(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetCiphersuite() common_go_proto.Ciphersuite {
|
|
||||||
if x != nil {
|
|
||||||
return x.Ciphersuite
|
|
||||||
}
|
|
||||||
return common_go_proto.Ciphersuite(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetPeerIdentity() *common_go_proto.Identity {
|
|
||||||
if x != nil {
|
|
||||||
return x.PeerIdentity
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetLocalIdentity() *common_go_proto.Identity {
|
|
||||||
if x != nil {
|
|
||||||
return x.LocalIdentity
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetPeerCertFingerprint() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.PeerCertFingerprint
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetLocalCertFingerprint() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.LocalCertFingerprint
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetIsHandshakeResumed() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.IsHandshakeResumed
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_internal_proto_s2a_context_s2a_context_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_internal_proto_s2a_context_s2a_context_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x2c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x2f, 0x73, 0x32, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x73, 0x32, 0x61,
|
|
||||||
0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09,
|
|
||||||
0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
|
||||||
0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
|
||||||
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x03,
|
|
||||||
0x0a, 0x0a, 0x53, 0x32, 0x41, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x31, 0x0a, 0x14,
|
|
||||||
0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74,
|
|
||||||
0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, 0x70, 0x70, 0x6c,
|
|
||||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12,
|
|
||||||
0x36, 0x0a, 0x0b, 0x74, 0x6c, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02,
|
|
||||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x2e, 0x54, 0x4c, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x74, 0x6c, 0x73,
|
|
||||||
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65,
|
|
||||||
0x72, 0x73, 0x75, 0x69, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x73,
|
|
||||||
0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73,
|
|
||||||
0x75, 0x69, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x75, 0x69, 0x74,
|
|
||||||
0x65, 0x12, 0x38, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
|
||||||
0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0c, 0x70,
|
|
||||||
0x65, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0e, 0x6c,
|
|
||||||
0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20,
|
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
|
||||||
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49,
|
|
||||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x65, 0x65, 0x72, 0x5f,
|
|
||||||
0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
|
|
||||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x70, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74,
|
|
||||||
0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x6c,
|
|
||||||
0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72,
|
|
||||||
0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x6c, 0x6f, 0x63,
|
|
||||||
0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
|
|
||||||
0x74, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x73, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b,
|
|
||||||
0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52,
|
|
||||||
0x12, 0x69, 0x73, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x75,
|
|
||||||
0x6d, 0x65, 0x64, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
|
||||||
0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x32, 0x61, 0x2f, 0x69, 0x6e, 0x74,
|
|
||||||
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x32, 0x61, 0x5f,
|
|
||||||
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x67, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescOnce sync.Once
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescData = file_internal_proto_s2a_context_s2a_context_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_internal_proto_s2a_context_s2a_context_proto_rawDescGZIP() []byte {
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescOnce.Do(func() {
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_s2a_context_s2a_context_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_internal_proto_s2a_context_s2a_context_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_internal_proto_s2a_context_s2a_context_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_internal_proto_s2a_context_s2a_context_proto_goTypes = []any{
|
|
||||||
(*S2AContext)(nil), // 0: s2a.proto.S2AContext
|
|
||||||
(common_go_proto.TLSVersion)(0), // 1: s2a.proto.TLSVersion
|
|
||||||
(common_go_proto.Ciphersuite)(0), // 2: s2a.proto.Ciphersuite
|
|
||||||
(*common_go_proto.Identity)(nil), // 3: s2a.proto.Identity
|
|
||||||
}
|
|
||||||
var file_internal_proto_s2a_context_s2a_context_proto_depIdxs = []int32{
|
|
||||||
1, // 0: s2a.proto.S2AContext.tls_version:type_name -> s2a.proto.TLSVersion
|
|
||||||
2, // 1: s2a.proto.S2AContext.ciphersuite:type_name -> s2a.proto.Ciphersuite
|
|
||||||
3, // 2: s2a.proto.S2AContext.peer_identity:type_name -> s2a.proto.Identity
|
|
||||||
3, // 3: s2a.proto.S2AContext.local_identity:type_name -> s2a.proto.Identity
|
|
||||||
4, // [4:4] is the sub-list for method output_type
|
|
||||||
4, // [4:4] is the sub-list for method input_type
|
|
||||||
4, // [4:4] is the sub-list for extension type_name
|
|
||||||
4, // [4:4] is the sub-list for extension extendee
|
|
||||||
0, // [0:4] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_internal_proto_s2a_context_s2a_context_proto_init() }
|
|
||||||
func file_internal_proto_s2a_context_s2a_context_proto_init() {
|
|
||||||
if File_internal_proto_s2a_context_s2a_context_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
|
||||||
switch v := v.(*S2AContext); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_internal_proto_s2a_context_s2a_context_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_internal_proto_s2a_context_s2a_context_proto_goTypes,
|
|
||||||
DependencyIndexes: file_internal_proto_s2a_context_s2a_context_proto_depIdxs,
|
|
||||||
MessageInfos: file_internal_proto_s2a_context_s2a_context_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_internal_proto_s2a_context_s2a_context_proto = out.File
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_rawDesc = nil
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_goTypes = nil
|
|
||||||
file_internal_proto_s2a_context_s2a_context_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
1377
src/server/vendor/github.com/google/s2a-go/internal/proto/s2a_go_proto/s2a.pb.go
generated
vendored
1377
src/server/vendor/github.com/google/s2a-go/internal/proto/s2a_go_proto/s2a.pb.go
generated
vendored
File diff suppressed because it is too large
Load Diff
174
src/server/vendor/github.com/google/s2a-go/internal/proto/s2a_go_proto/s2a_grpc.pb.go
generated
vendored
174
src/server/vendor/github.com/google/s2a-go/internal/proto/s2a_go_proto/s2a_grpc.pb.go
generated
vendored
@ -1,174 +0,0 @@
|
|||||||
// Copyright 2021 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.4.0
|
|
||||||
// - protoc v3.21.12
|
|
||||||
// source: internal/proto/s2a/s2a.proto
|
|
||||||
|
|
||||||
package s2a_go_proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.62.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion8
|
|
||||||
|
|
||||||
const (
|
|
||||||
S2AService_SetUpSession_FullMethodName = "/s2a.proto.S2AService/SetUpSession"
|
|
||||||
)
|
|
||||||
|
|
||||||
// S2AServiceClient is the client API for S2AService service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
type S2AServiceClient interface {
|
|
||||||
// S2A service accepts a stream of session setup requests and returns a stream
|
|
||||||
// of session setup responses. The client of this service is expected to send
|
|
||||||
// exactly one client_start or server_start message followed by at least one
|
|
||||||
// next message. Applications running TLS clients can send requests with
|
|
||||||
// resumption_ticket messages only after the session is successfully set up.
|
|
||||||
//
|
|
||||||
// Every time S2A client sends a request, this service sends a response.
|
|
||||||
// However, clients do not have to wait for service response before sending
|
|
||||||
// the next request.
|
|
||||||
SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type s2AServiceClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewS2AServiceClient(cc grpc.ClientConnInterface) S2AServiceClient {
|
|
||||||
return &s2AServiceClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *s2AServiceClient) SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
stream, err := c.cc.NewStream(ctx, &S2AService_ServiceDesc.Streams[0], S2AService_SetUpSession_FullMethodName, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
x := &s2AServiceSetUpSessionClient{ClientStream: stream}
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type S2AService_SetUpSessionClient interface {
|
|
||||||
Send(*SessionReq) error
|
|
||||||
Recv() (*SessionResp, error)
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type s2AServiceSetUpSessionClient struct {
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionClient) Send(m *SessionReq) error {
|
|
||||||
return x.ClientStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionClient) Recv() (*SessionResp, error) {
|
|
||||||
m := new(SessionResp)
|
|
||||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// S2AServiceServer is the server API for S2AService service.
|
|
||||||
// All implementations must embed UnimplementedS2AServiceServer
|
|
||||||
// for forward compatibility
|
|
||||||
type S2AServiceServer interface {
|
|
||||||
// S2A service accepts a stream of session setup requests and returns a stream
|
|
||||||
// of session setup responses. The client of this service is expected to send
|
|
||||||
// exactly one client_start or server_start message followed by at least one
|
|
||||||
// next message. Applications running TLS clients can send requests with
|
|
||||||
// resumption_ticket messages only after the session is successfully set up.
|
|
||||||
//
|
|
||||||
// Every time S2A client sends a request, this service sends a response.
|
|
||||||
// However, clients do not have to wait for service response before sending
|
|
||||||
// the next request.
|
|
||||||
SetUpSession(S2AService_SetUpSessionServer) error
|
|
||||||
mustEmbedUnimplementedS2AServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedS2AServiceServer must be embedded to have forward compatible implementations.
|
|
||||||
type UnimplementedS2AServiceServer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (UnimplementedS2AServiceServer) SetUpSession(S2AService_SetUpSessionServer) error {
|
|
||||||
return status.Errorf(codes.Unimplemented, "method SetUpSession not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedS2AServiceServer) mustEmbedUnimplementedS2AServiceServer() {}
|
|
||||||
|
|
||||||
// UnsafeS2AServiceServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to S2AServiceServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeS2AServiceServer interface {
|
|
||||||
mustEmbedUnimplementedS2AServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterS2AServiceServer(s grpc.ServiceRegistrar, srv S2AServiceServer) {
|
|
||||||
s.RegisterService(&S2AService_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _S2AService_SetUpSession_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|
||||||
return srv.(S2AServiceServer).SetUpSession(&s2AServiceSetUpSessionServer{ServerStream: stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
type S2AService_SetUpSessionServer interface {
|
|
||||||
Send(*SessionResp) error
|
|
||||||
Recv() (*SessionReq, error)
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type s2AServiceSetUpSessionServer struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionServer) Send(m *SessionResp) error {
|
|
||||||
return x.ServerStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionServer) Recv() (*SessionReq, error) {
|
|
||||||
m := new(SessionReq)
|
|
||||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// S2AService_ServiceDesc is the grpc.ServiceDesc for S2AService service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var S2AService_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "s2a.proto.S2AService",
|
|
||||||
HandlerType: (*S2AServiceServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{},
|
|
||||||
Streams: []grpc.StreamDesc{
|
|
||||||
{
|
|
||||||
StreamName: "SetUpSession",
|
|
||||||
Handler: _S2AService_SetUpSession_Handler,
|
|
||||||
ServerStreams: true,
|
|
||||||
ClientStreams: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Metadata: "internal/proto/s2a/s2a.proto",
|
|
||||||
}
|
|
||||||
549
src/server/vendor/github.com/google/s2a-go/internal/proto/v2/common_go_proto/common.pb.go
generated
vendored
549
src/server/vendor/github.com/google/s2a-go/internal/proto/v2/common_go_proto/common.pb.go
generated
vendored
@ -1,549 +0,0 @@
|
|||||||
// Copyright 2022 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.34.2
|
|
||||||
// protoc v3.21.12
|
|
||||||
// source: internal/proto/v2/common/common.proto
|
|
||||||
|
|
||||||
package common_go_proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
// The TLS 1.0-1.2 ciphersuites that the application can negotiate when using
|
|
||||||
// S2A.
|
|
||||||
type Ciphersuite int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
Ciphersuite_CIPHERSUITE_UNSPECIFIED Ciphersuite = 0
|
|
||||||
Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 Ciphersuite = 1
|
|
||||||
Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 Ciphersuite = 2
|
|
||||||
Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 Ciphersuite = 3
|
|
||||||
Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256 Ciphersuite = 4
|
|
||||||
Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384 Ciphersuite = 5
|
|
||||||
Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 Ciphersuite = 6
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for Ciphersuite.
|
|
||||||
var (
|
|
||||||
Ciphersuite_name = map[int32]string{
|
|
||||||
0: "CIPHERSUITE_UNSPECIFIED",
|
|
||||||
1: "CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
2: "CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
3: "CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
|
||||||
4: "CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
5: "CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
6: "CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
|
||||||
}
|
|
||||||
Ciphersuite_value = map[string]int32{
|
|
||||||
"CIPHERSUITE_UNSPECIFIED": 0,
|
|
||||||
"CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": 1,
|
|
||||||
"CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": 2,
|
|
||||||
"CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": 3,
|
|
||||||
"CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256": 4,
|
|
||||||
"CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384": 5,
|
|
||||||
"CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": 6,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x Ciphersuite) Enum() *Ciphersuite {
|
|
||||||
p := new(Ciphersuite)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x Ciphersuite) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Ciphersuite) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_internal_proto_v2_common_common_proto_enumTypes[0].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Ciphersuite) Type() protoreflect.EnumType {
|
|
||||||
return &file_internal_proto_v2_common_common_proto_enumTypes[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x Ciphersuite) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Ciphersuite.Descriptor instead.
|
|
||||||
func (Ciphersuite) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The TLS versions supported by S2A's handshaker module.
|
|
||||||
type TLSVersion int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
TLSVersion_TLS_VERSION_UNSPECIFIED TLSVersion = 0
|
|
||||||
TLSVersion_TLS_VERSION_1_0 TLSVersion = 1
|
|
||||||
TLSVersion_TLS_VERSION_1_1 TLSVersion = 2
|
|
||||||
TLSVersion_TLS_VERSION_1_2 TLSVersion = 3
|
|
||||||
TLSVersion_TLS_VERSION_1_3 TLSVersion = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for TLSVersion.
|
|
||||||
var (
|
|
||||||
TLSVersion_name = map[int32]string{
|
|
||||||
0: "TLS_VERSION_UNSPECIFIED",
|
|
||||||
1: "TLS_VERSION_1_0",
|
|
||||||
2: "TLS_VERSION_1_1",
|
|
||||||
3: "TLS_VERSION_1_2",
|
|
||||||
4: "TLS_VERSION_1_3",
|
|
||||||
}
|
|
||||||
TLSVersion_value = map[string]int32{
|
|
||||||
"TLS_VERSION_UNSPECIFIED": 0,
|
|
||||||
"TLS_VERSION_1_0": 1,
|
|
||||||
"TLS_VERSION_1_1": 2,
|
|
||||||
"TLS_VERSION_1_2": 3,
|
|
||||||
"TLS_VERSION_1_3": 4,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x TLSVersion) Enum() *TLSVersion {
|
|
||||||
p := new(TLSVersion)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x TLSVersion) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (TLSVersion) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_internal_proto_v2_common_common_proto_enumTypes[1].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (TLSVersion) Type() protoreflect.EnumType {
|
|
||||||
return &file_internal_proto_v2_common_common_proto_enumTypes[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x TLSVersion) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use TLSVersion.Descriptor instead.
|
|
||||||
func (TLSVersion) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The side in the TLS connection.
|
|
||||||
type ConnectionSide int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
ConnectionSide_CONNECTION_SIDE_UNSPECIFIED ConnectionSide = 0
|
|
||||||
ConnectionSide_CONNECTION_SIDE_CLIENT ConnectionSide = 1
|
|
||||||
ConnectionSide_CONNECTION_SIDE_SERVER ConnectionSide = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for ConnectionSide.
|
|
||||||
var (
|
|
||||||
ConnectionSide_name = map[int32]string{
|
|
||||||
0: "CONNECTION_SIDE_UNSPECIFIED",
|
|
||||||
1: "CONNECTION_SIDE_CLIENT",
|
|
||||||
2: "CONNECTION_SIDE_SERVER",
|
|
||||||
}
|
|
||||||
ConnectionSide_value = map[string]int32{
|
|
||||||
"CONNECTION_SIDE_UNSPECIFIED": 0,
|
|
||||||
"CONNECTION_SIDE_CLIENT": 1,
|
|
||||||
"CONNECTION_SIDE_SERVER": 2,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x ConnectionSide) Enum() *ConnectionSide {
|
|
||||||
p := new(ConnectionSide)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x ConnectionSide) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ConnectionSide) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_internal_proto_v2_common_common_proto_enumTypes[2].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ConnectionSide) Type() protoreflect.EnumType {
|
|
||||||
return &file_internal_proto_v2_common_common_proto_enumTypes[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x ConnectionSide) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ConnectionSide.Descriptor instead.
|
|
||||||
func (ConnectionSide) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The ALPN protocols that the application can negotiate during a TLS handshake.
|
|
||||||
type AlpnProtocol int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
AlpnProtocol_ALPN_PROTOCOL_UNSPECIFIED AlpnProtocol = 0
|
|
||||||
AlpnProtocol_ALPN_PROTOCOL_GRPC AlpnProtocol = 1
|
|
||||||
AlpnProtocol_ALPN_PROTOCOL_HTTP2 AlpnProtocol = 2
|
|
||||||
AlpnProtocol_ALPN_PROTOCOL_HTTP1_1 AlpnProtocol = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for AlpnProtocol.
|
|
||||||
var (
|
|
||||||
AlpnProtocol_name = map[int32]string{
|
|
||||||
0: "ALPN_PROTOCOL_UNSPECIFIED",
|
|
||||||
1: "ALPN_PROTOCOL_GRPC",
|
|
||||||
2: "ALPN_PROTOCOL_HTTP2",
|
|
||||||
3: "ALPN_PROTOCOL_HTTP1_1",
|
|
||||||
}
|
|
||||||
AlpnProtocol_value = map[string]int32{
|
|
||||||
"ALPN_PROTOCOL_UNSPECIFIED": 0,
|
|
||||||
"ALPN_PROTOCOL_GRPC": 1,
|
|
||||||
"ALPN_PROTOCOL_HTTP2": 2,
|
|
||||||
"ALPN_PROTOCOL_HTTP1_1": 3,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x AlpnProtocol) Enum() *AlpnProtocol {
|
|
||||||
p := new(AlpnProtocol)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x AlpnProtocol) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (AlpnProtocol) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_internal_proto_v2_common_common_proto_enumTypes[3].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (AlpnProtocol) Type() protoreflect.EnumType {
|
|
||||||
return &file_internal_proto_v2_common_common_proto_enumTypes[3]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x AlpnProtocol) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use AlpnProtocol.Descriptor instead.
|
|
||||||
func (AlpnProtocol) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// Types that are assignable to IdentityOneof:
|
|
||||||
//
|
|
||||||
// *Identity_SpiffeId
|
|
||||||
// *Identity_Hostname
|
|
||||||
// *Identity_Uid
|
|
||||||
// *Identity_Username
|
|
||||||
// *Identity_GcpId
|
|
||||||
IdentityOneof isIdentity_IdentityOneof `protobuf_oneof:"identity_oneof"`
|
|
||||||
// Additional identity-specific attributes.
|
|
||||||
Attributes map[string]string `protobuf:"bytes,3,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) Reset() {
|
|
||||||
*x = Identity{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_internal_proto_v2_common_common_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Identity) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Identity) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_internal_proto_v2_common_common_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Identity.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Identity) Descriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Identity) GetIdentityOneof() isIdentity_IdentityOneof {
|
|
||||||
if m != nil {
|
|
||||||
return m.IdentityOneof
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetSpiffeId() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_SpiffeId); ok {
|
|
||||||
return x.SpiffeId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetHostname() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_Hostname); ok {
|
|
||||||
return x.Hostname
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetUid() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_Uid); ok {
|
|
||||||
return x.Uid
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetUsername() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_Username); ok {
|
|
||||||
return x.Username
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetGcpId() string {
|
|
||||||
if x, ok := x.GetIdentityOneof().(*Identity_GcpId); ok {
|
|
||||||
return x.GcpId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Identity) GetAttributes() map[string]string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Attributes
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type isIdentity_IdentityOneof interface {
|
|
||||||
isIdentity_IdentityOneof()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_SpiffeId struct {
|
|
||||||
// The SPIFFE ID of a connection endpoint.
|
|
||||||
SpiffeId string `protobuf:"bytes,1,opt,name=spiffe_id,json=spiffeId,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_Hostname struct {
|
|
||||||
// The hostname of a connection endpoint.
|
|
||||||
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_Uid struct {
|
|
||||||
// The UID of a connection endpoint.
|
|
||||||
Uid string `protobuf:"bytes,4,opt,name=uid,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_Username struct {
|
|
||||||
// The username of a connection endpoint.
|
|
||||||
Username string `protobuf:"bytes,5,opt,name=username,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Identity_GcpId struct {
|
|
||||||
// The GCP ID of a connection endpoint.
|
|
||||||
GcpId string `protobuf:"bytes,6,opt,name=gcp_id,json=gcpId,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Identity_SpiffeId) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_Hostname) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_Uid) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_Username) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
func (*Identity_GcpId) isIdentity_IdentityOneof() {}
|
|
||||||
|
|
||||||
var File_internal_proto_v2_common_common_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_internal_proto_v2_common_common_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x25, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
|
||||||
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x2e, 0x76, 0x32, 0x22, 0xab, 0x02, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
|
||||||
0x74, 0x79, 0x12, 0x1d, 0x0a, 0x09, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x69, 0x64, 0x18,
|
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x49,
|
|
||||||
0x64, 0x12, 0x1c, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12,
|
|
||||||
0x12, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03,
|
|
||||||
0x75, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
|
||||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
|
|
||||||
0x65, 0x12, 0x17, 0x0a, 0x06, 0x67, 0x63, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x48, 0x00, 0x52, 0x05, 0x67, 0x63, 0x70, 0x49, 0x64, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x74,
|
|
||||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26,
|
|
||||||
0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x64,
|
|
||||||
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
|
|
||||||
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
|
||||||
0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
|
||||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
|
||||||
0x01, 0x42, 0x10, 0x0a, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6f, 0x6e,
|
|
||||||
0x65, 0x6f, 0x66, 0x2a, 0xee, 0x02, 0x0a, 0x0b, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x75,
|
|
||||||
0x69, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49,
|
|
||||||
0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
|
|
||||||
0x12, 0x33, 0x0a, 0x2f, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f,
|
|
||||||
0x45, 0x43, 0x44, 0x48, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x53, 0x41, 0x5f, 0x57, 0x49, 0x54, 0x48,
|
|
||||||
0x5f, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x53, 0x48, 0x41,
|
|
||||||
0x32, 0x35, 0x36, 0x10, 0x01, 0x12, 0x33, 0x0a, 0x2f, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53,
|
|
||||||
0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x53, 0x41,
|
|
||||||
0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43,
|
|
||||||
0x4d, 0x5f, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x10, 0x02, 0x12, 0x39, 0x0a, 0x35, 0x43, 0x49,
|
|
||||||
0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f,
|
|
||||||
0x45, 0x43, 0x44, 0x53, 0x41, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x43, 0x48, 0x41, 0x43, 0x48,
|
|
||||||
0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x5f, 0x53, 0x48, 0x41,
|
|
||||||
0x32, 0x35, 0x36, 0x10, 0x03, 0x12, 0x31, 0x0a, 0x2d, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53,
|
|
||||||
0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x57,
|
|
||||||
0x49, 0x54, 0x48, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x5f,
|
|
||||||
0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x04, 0x12, 0x31, 0x0a, 0x2d, 0x43, 0x49, 0x50, 0x48,
|
|
||||||
0x45, 0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f, 0x52, 0x53,
|
|
||||||
0x41, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47,
|
|
||||||
0x43, 0x4d, 0x5f, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x10, 0x05, 0x12, 0x37, 0x0a, 0x33, 0x43,
|
|
||||||
0x49, 0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45,
|
|
||||||
0x5f, 0x52, 0x53, 0x41, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41,
|
|
||||||
0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x5f, 0x53, 0x48, 0x41, 0x32,
|
|
||||||
0x35, 0x36, 0x10, 0x06, 0x2a, 0x7d, 0x0a, 0x0a, 0x54, 0x4c, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69,
|
|
||||||
0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f,
|
|
||||||
0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
|
|
||||||
0x13, 0x0a, 0x0f, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x31,
|
|
||||||
0x5f, 0x30, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53,
|
|
||||||
0x49, 0x4f, 0x4e, 0x5f, 0x31, 0x5f, 0x31, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x4c, 0x53,
|
|
||||||
0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x31, 0x5f, 0x32, 0x10, 0x03, 0x12, 0x13,
|
|
||||||
0x0a, 0x0f, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x31, 0x5f,
|
|
||||||
0x33, 0x10, 0x04, 0x2a, 0x69, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
|
||||||
0x6e, 0x53, 0x69, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54,
|
|
||||||
0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
|
|
||||||
0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43,
|
|
||||||
0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54,
|
|
||||||
0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e,
|
|
||||||
0x5f, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x02, 0x2a, 0x79,
|
|
||||||
0x0a, 0x0c, 0x41, 0x6c, 0x70, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1d,
|
|
||||||
0x0a, 0x19, 0x41, 0x4c, 0x50, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f,
|
|
||||||
0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a,
|
|
||||||
0x12, 0x41, 0x4c, 0x50, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x47,
|
|
||||||
0x52, 0x50, 0x43, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x50, 0x4e, 0x5f, 0x50, 0x52,
|
|
||||||
0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x32, 0x10, 0x02, 0x12, 0x19,
|
|
||||||
0x0a, 0x15, 0x41, 0x4c, 0x50, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f,
|
|
||||||
0x48, 0x54, 0x54, 0x50, 0x31, 0x5f, 0x31, 0x10, 0x03, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74,
|
|
||||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73,
|
|
||||||
0x32, 0x61, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
|
||||||
0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x67, 0x6f, 0x5f, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_internal_proto_v2_common_common_proto_rawDescOnce sync.Once
|
|
||||||
file_internal_proto_v2_common_common_proto_rawDescData = file_internal_proto_v2_common_common_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_internal_proto_v2_common_common_proto_rawDescGZIP() []byte {
|
|
||||||
file_internal_proto_v2_common_common_proto_rawDescOnce.Do(func() {
|
|
||||||
file_internal_proto_v2_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_v2_common_common_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_internal_proto_v2_common_common_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_internal_proto_v2_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
|
||||||
var file_internal_proto_v2_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_internal_proto_v2_common_common_proto_goTypes = []any{
|
|
||||||
(Ciphersuite)(0), // 0: s2a.proto.v2.Ciphersuite
|
|
||||||
(TLSVersion)(0), // 1: s2a.proto.v2.TLSVersion
|
|
||||||
(ConnectionSide)(0), // 2: s2a.proto.v2.ConnectionSide
|
|
||||||
(AlpnProtocol)(0), // 3: s2a.proto.v2.AlpnProtocol
|
|
||||||
(*Identity)(nil), // 4: s2a.proto.v2.Identity
|
|
||||||
nil, // 5: s2a.proto.v2.Identity.AttributesEntry
|
|
||||||
}
|
|
||||||
var file_internal_proto_v2_common_common_proto_depIdxs = []int32{
|
|
||||||
5, // 0: s2a.proto.v2.Identity.attributes:type_name -> s2a.proto.v2.Identity.AttributesEntry
|
|
||||||
1, // [1:1] is the sub-list for method output_type
|
|
||||||
1, // [1:1] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_internal_proto_v2_common_common_proto_init() }
|
|
||||||
func file_internal_proto_v2_common_common_proto_init() {
|
|
||||||
if File_internal_proto_v2_common_common_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_internal_proto_v2_common_common_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
|
||||||
switch v := v.(*Identity); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_internal_proto_v2_common_common_proto_msgTypes[0].OneofWrappers = []any{
|
|
||||||
(*Identity_SpiffeId)(nil),
|
|
||||||
(*Identity_Hostname)(nil),
|
|
||||||
(*Identity_Uid)(nil),
|
|
||||||
(*Identity_Username)(nil),
|
|
||||||
(*Identity_GcpId)(nil),
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_internal_proto_v2_common_common_proto_rawDesc,
|
|
||||||
NumEnums: 4,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_internal_proto_v2_common_common_proto_goTypes,
|
|
||||||
DependencyIndexes: file_internal_proto_v2_common_common_proto_depIdxs,
|
|
||||||
EnumInfos: file_internal_proto_v2_common_common_proto_enumTypes,
|
|
||||||
MessageInfos: file_internal_proto_v2_common_common_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_internal_proto_v2_common_common_proto = out.File
|
|
||||||
file_internal_proto_v2_common_common_proto_rawDesc = nil
|
|
||||||
file_internal_proto_v2_common_common_proto_goTypes = nil
|
|
||||||
file_internal_proto_v2_common_common_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@ -1,249 +0,0 @@
|
|||||||
// Copyright 2022 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.34.2
|
|
||||||
// protoc v3.21.12
|
|
||||||
// source: internal/proto/v2/s2a_context/s2a_context.proto
|
|
||||||
|
|
||||||
package s2a_context_go_proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
common_go_proto "github.com/google/s2a-go/internal/proto/v2/common_go_proto"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type S2AContext struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// The SPIFFE ID from the peer leaf certificate, if present.
|
|
||||||
//
|
|
||||||
// This field is only populated if the leaf certificate is a valid SPIFFE
|
|
||||||
// SVID; in particular, there is a unique URI SAN and this URI SAN is a valid
|
|
||||||
// SPIFFE ID.
|
|
||||||
LeafCertSpiffeId string `protobuf:"bytes,1,opt,name=leaf_cert_spiffe_id,json=leafCertSpiffeId,proto3" json:"leaf_cert_spiffe_id,omitempty"`
|
|
||||||
// The URIs that are present in the SubjectAltName extension of the peer leaf
|
|
||||||
// certificate.
|
|
||||||
//
|
|
||||||
// Note that the extracted URIs are not validated and may not be properly
|
|
||||||
// formatted.
|
|
||||||
LeafCertUris []string `protobuf:"bytes,2,rep,name=leaf_cert_uris,json=leafCertUris,proto3" json:"leaf_cert_uris,omitempty"`
|
|
||||||
// The DNSNames that are present in the SubjectAltName extension of the peer
|
|
||||||
// leaf certificate.
|
|
||||||
LeafCertDnsnames []string `protobuf:"bytes,3,rep,name=leaf_cert_dnsnames,json=leafCertDnsnames,proto3" json:"leaf_cert_dnsnames,omitempty"`
|
|
||||||
// The (ordered) list of fingerprints in the certificate chain used to verify
|
|
||||||
// the given leaf certificate. The order MUST be from leaf certificate
|
|
||||||
// fingerprint to root certificate fingerprint.
|
|
||||||
//
|
|
||||||
// A fingerprint is the base-64 encoding of the SHA256 hash of the
|
|
||||||
// DER-encoding of a certificate. The list MAY be populated even if the peer
|
|
||||||
// certificate chain was NOT validated successfully.
|
|
||||||
PeerCertificateChainFingerprints []string `protobuf:"bytes,4,rep,name=peer_certificate_chain_fingerprints,json=peerCertificateChainFingerprints,proto3" json:"peer_certificate_chain_fingerprints,omitempty"`
|
|
||||||
// The local identity used during session setup.
|
|
||||||
LocalIdentity *common_go_proto.Identity `protobuf:"bytes,9,opt,name=local_identity,json=localIdentity,proto3" json:"local_identity,omitempty"`
|
|
||||||
// The SHA256 hash of the DER-encoding of the local leaf certificate used in
|
|
||||||
// the handshake.
|
|
||||||
LocalLeafCertFingerprint []byte `protobuf:"bytes,6,opt,name=local_leaf_cert_fingerprint,json=localLeafCertFingerprint,proto3" json:"local_leaf_cert_fingerprint,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) Reset() {
|
|
||||||
*x = S2AContext{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*S2AContext) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *S2AContext) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use S2AContext.ProtoReflect.Descriptor instead.
|
|
||||||
func (*S2AContext) Descriptor() ([]byte, []int) {
|
|
||||||
return file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetLeafCertSpiffeId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.LeafCertSpiffeId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetLeafCertUris() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.LeafCertUris
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetLeafCertDnsnames() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.LeafCertDnsnames
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetPeerCertificateChainFingerprints() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.PeerCertificateChainFingerprints
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetLocalIdentity() *common_go_proto.Identity {
|
|
||||||
if x != nil {
|
|
||||||
return x.LocalIdentity
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *S2AContext) GetLocalLeafCertFingerprint() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.LocalLeafCertFingerprint
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_internal_proto_v2_s2a_context_s2a_context_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x2f, 0x76, 0x32, 0x2f, 0x73, 0x32, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2f,
|
|
||||||
0x73, 0x32, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
|
||||||
0x6f, 0x12, 0x0c, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x32, 0x1a,
|
|
||||||
0x25, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
|
|
||||||
0x76, 0x32, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x02, 0x0a, 0x0a, 0x53, 0x32, 0x41, 0x43, 0x6f,
|
|
||||||
0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x2d, 0x0a, 0x13, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x63, 0x65,
|
|
||||||
0x72, 0x74, 0x5f, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x09, 0x52, 0x10, 0x6c, 0x65, 0x61, 0x66, 0x43, 0x65, 0x72, 0x74, 0x53, 0x70, 0x69, 0x66,
|
|
||||||
0x66, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x63, 0x65, 0x72,
|
|
||||||
0x74, 0x5f, 0x75, 0x72, 0x69, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x65,
|
|
||||||
0x61, 0x66, 0x43, 0x65, 0x72, 0x74, 0x55, 0x72, 0x69, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x65,
|
|
||||||
0x61, 0x66, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x6e, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x73,
|
|
||||||
0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x65, 0x61, 0x66, 0x43, 0x65, 0x72, 0x74,
|
|
||||||
0x44, 0x6e, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x4d, 0x0a, 0x23, 0x70, 0x65, 0x65, 0x72,
|
|
||||||
0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61,
|
|
||||||
0x69, 0x6e, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x18,
|
|
||||||
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x20, 0x70, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69,
|
|
||||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x69, 0x6e, 0x67, 0x65,
|
|
||||||
0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x3d, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
|
|
||||||
0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
|
||||||
0x16, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x49,
|
|
||||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64,
|
|
||||||
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x1b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f,
|
|
||||||
0x6c, 0x65, 0x61, 0x66, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72,
|
|
||||||
0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, 0x6c, 0x6f, 0x63,
|
|
||||||
0x61, 0x6c, 0x4c, 0x65, 0x61, 0x66, 0x43, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
|
|
||||||
0x70, 0x72, 0x69, 0x6e, 0x74, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10,
|
|
||||||
0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75,
|
|
||||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x32, 0x61,
|
|
||||||
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
|
|
||||||
0x76, 0x32, 0x2f, 0x73, 0x32, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x67,
|
|
||||||
0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescOnce sync.Once
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData = file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescGZIP() []byte {
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescOnce.Do(func() {
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_goTypes = []any{
|
|
||||||
(*S2AContext)(nil), // 0: s2a.proto.v2.S2AContext
|
|
||||||
(*common_go_proto.Identity)(nil), // 1: s2a.proto.v2.Identity
|
|
||||||
}
|
|
||||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_depIdxs = []int32{
|
|
||||||
1, // 0: s2a.proto.v2.S2AContext.local_identity:type_name -> s2a.proto.v2.Identity
|
|
||||||
1, // [1:1] is the sub-list for method output_type
|
|
||||||
1, // [1:1] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_internal_proto_v2_s2a_context_s2a_context_proto_init() }
|
|
||||||
func file_internal_proto_v2_s2a_context_s2a_context_proto_init() {
|
|
||||||
if File_internal_proto_v2_s2a_context_s2a_context_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
|
||||||
switch v := v.(*S2AContext); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_internal_proto_v2_s2a_context_s2a_context_proto_goTypes,
|
|
||||||
DependencyIndexes: file_internal_proto_v2_s2a_context_s2a_context_proto_depIdxs,
|
|
||||||
MessageInfos: file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_internal_proto_v2_s2a_context_s2a_context_proto = out.File
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc = nil
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_goTypes = nil
|
|
||||||
file_internal_proto_v2_s2a_context_s2a_context_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
2518
src/server/vendor/github.com/google/s2a-go/internal/proto/v2/s2a_go_proto/s2a.pb.go
generated
vendored
2518
src/server/vendor/github.com/google/s2a-go/internal/proto/v2/s2a_go_proto/s2a.pb.go
generated
vendored
File diff suppressed because it is too large
Load Diff
160
src/server/vendor/github.com/google/s2a-go/internal/proto/v2/s2a_go_proto/s2a_grpc.pb.go
generated
vendored
160
src/server/vendor/github.com/google/s2a-go/internal/proto/v2/s2a_go_proto/s2a_grpc.pb.go
generated
vendored
@ -1,160 +0,0 @@
|
|||||||
// Copyright 2022 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.4.0
|
|
||||||
// - protoc v3.21.12
|
|
||||||
// source: internal/proto/v2/s2a/s2a.proto
|
|
||||||
|
|
||||||
package s2a_go_proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.62.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion8
|
|
||||||
|
|
||||||
const (
|
|
||||||
S2AService_SetUpSession_FullMethodName = "/s2a.proto.v2.S2AService/SetUpSession"
|
|
||||||
)
|
|
||||||
|
|
||||||
// S2AServiceClient is the client API for S2AService service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
type S2AServiceClient interface {
|
|
||||||
// SetUpSession is a bidirectional stream used by applications to offload
|
|
||||||
// operations from the TLS handshake.
|
|
||||||
SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type s2AServiceClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewS2AServiceClient(cc grpc.ClientConnInterface) S2AServiceClient {
|
|
||||||
return &s2AServiceClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *s2AServiceClient) SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
stream, err := c.cc.NewStream(ctx, &S2AService_ServiceDesc.Streams[0], S2AService_SetUpSession_FullMethodName, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
x := &s2AServiceSetUpSessionClient{ClientStream: stream}
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type S2AService_SetUpSessionClient interface {
|
|
||||||
Send(*SessionReq) error
|
|
||||||
Recv() (*SessionResp, error)
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type s2AServiceSetUpSessionClient struct {
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionClient) Send(m *SessionReq) error {
|
|
||||||
return x.ClientStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionClient) Recv() (*SessionResp, error) {
|
|
||||||
m := new(SessionResp)
|
|
||||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// S2AServiceServer is the server API for S2AService service.
|
|
||||||
// All implementations must embed UnimplementedS2AServiceServer
|
|
||||||
// for forward compatibility
|
|
||||||
type S2AServiceServer interface {
|
|
||||||
// SetUpSession is a bidirectional stream used by applications to offload
|
|
||||||
// operations from the TLS handshake.
|
|
||||||
SetUpSession(S2AService_SetUpSessionServer) error
|
|
||||||
mustEmbedUnimplementedS2AServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedS2AServiceServer must be embedded to have forward compatible implementations.
|
|
||||||
type UnimplementedS2AServiceServer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (UnimplementedS2AServiceServer) SetUpSession(S2AService_SetUpSessionServer) error {
|
|
||||||
return status.Errorf(codes.Unimplemented, "method SetUpSession not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedS2AServiceServer) mustEmbedUnimplementedS2AServiceServer() {}
|
|
||||||
|
|
||||||
// UnsafeS2AServiceServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to S2AServiceServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeS2AServiceServer interface {
|
|
||||||
mustEmbedUnimplementedS2AServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterS2AServiceServer(s grpc.ServiceRegistrar, srv S2AServiceServer) {
|
|
||||||
s.RegisterService(&S2AService_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _S2AService_SetUpSession_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|
||||||
return srv.(S2AServiceServer).SetUpSession(&s2AServiceSetUpSessionServer{ServerStream: stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
type S2AService_SetUpSessionServer interface {
|
|
||||||
Send(*SessionResp) error
|
|
||||||
Recv() (*SessionReq, error)
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type s2AServiceSetUpSessionServer struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionServer) Send(m *SessionResp) error {
|
|
||||||
return x.ServerStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *s2AServiceSetUpSessionServer) Recv() (*SessionReq, error) {
|
|
||||||
m := new(SessionReq)
|
|
||||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// S2AService_ServiceDesc is the grpc.ServiceDesc for S2AService service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var S2AService_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "s2a.proto.v2.S2AService",
|
|
||||||
HandlerType: (*S2AServiceServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{},
|
|
||||||
Streams: []grpc.StreamDesc{
|
|
||||||
{
|
|
||||||
StreamName: "SetUpSession",
|
|
||||||
Handler: _S2AService_SetUpSession_Handler,
|
|
||||||
ServerStreams: true,
|
|
||||||
ClientStreams: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Metadata: "internal/proto/v2/s2a/s2a.proto",
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2021 Google LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package aeadcrypter provides the interface for AEAD cipher implementations
|
|
||||||
// used by S2A's record protocol.
|
|
||||||
package aeadcrypter
|
|
||||||
|
|
||||||
// S2AAEADCrypter is the interface for an AEAD cipher used by the S2A record
|
|
||||||
// protocol.
|
|
||||||
type S2AAEADCrypter interface {
|
|
||||||
// Encrypt encrypts the plaintext and computes the tag of dst and plaintext.
|
|
||||||
// dst and plaintext may fully overlap or not at all.
|
|
||||||
Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error)
|
|
||||||
// Decrypt decrypts ciphertext and verifies the tag. dst and ciphertext may
|
|
||||||
// fully overlap or not at all.
|
|
||||||
Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error)
|
|
||||||
// TagSize returns the tag size in bytes.
|
|
||||||
TagSize() int
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2021 Google LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package aeadcrypter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Supported key sizes in bytes.
|
|
||||||
const (
|
|
||||||
AES128GCMKeySize = 16
|
|
||||||
AES256GCMKeySize = 32
|
|
||||||
)
|
|
||||||
|
|
||||||
// aesgcm is the struct that holds an AES-GCM cipher for the S2A AEAD crypter.
|
|
||||||
type aesgcm struct {
|
|
||||||
aead cipher.AEAD
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAESGCM creates an AES-GCM crypter instance. Note that the key must be
|
|
||||||
// either 128 bits or 256 bits.
|
|
||||||
func NewAESGCM(key []byte) (S2AAEADCrypter, error) {
|
|
||||||
if len(key) != AES128GCMKeySize && len(key) != AES256GCMKeySize {
|
|
||||||
return nil, fmt.Errorf("%d or %d bytes, given: %d", AES128GCMKeySize, AES256GCMKeySize, len(key))
|
|
||||||
}
|
|
||||||
c, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
a, err := cipher.NewGCM(c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &aesgcm{aead: a}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt is the encryption function. dst can contain bytes at the beginning of
|
|
||||||
// the ciphertext that will not be encrypted but will be authenticated. If dst
|
|
||||||
// has enough capacity to hold these bytes, the ciphertext and the tag, no
|
|
||||||
// allocation and copy operations will be performed. dst and plaintext may
|
|
||||||
// fully overlap or not at all.
|
|
||||||
func (s *aesgcm) Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error) {
|
|
||||||
return encrypt(s.aead, dst, plaintext, nonce, aad)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *aesgcm) Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error) {
|
|
||||||
return decrypt(s.aead, dst, ciphertext, nonce, aad)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *aesgcm) TagSize() int {
|
|
||||||
return TagSize
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user