mirror of https://github.com/docker/docs.git
Fix go vet and lint issues
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
parent
36d8ce0094
commit
6fd6773b21
|
@ -15,8 +15,11 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ADDR = ":4443"
|
// ServerAddress is the secure server address to listen on
|
||||||
const DEBUG_ADDR = "localhost:8080"
|
const ServerAddress = ":4443"
|
||||||
|
|
||||||
|
// DebugAddress is the debug server address to listen on
|
||||||
|
const DebugAddress = "localhost:8080"
|
||||||
|
|
||||||
var debug bool
|
var debug bool
|
||||||
var certFile, keyFile string
|
var certFile, keyFile string
|
||||||
|
@ -31,8 +34,8 @@ func main() {
|
||||||
flag.Usage = usage
|
flag.Usage = usage
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if DEBUG_ADDR != "" {
|
if DebugAddress != "" {
|
||||||
go debugServer(DEBUG_ADDR)
|
go debugServer(DebugAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
if certFile == "" || keyFile == "" {
|
if certFile == "" || keyFile == "" {
|
||||||
|
@ -65,13 +68,13 @@ func main() {
|
||||||
r.Methods("POST").Path("/{imageName}/{tag}").Handler(hand(handlers.AddHandler, utils.SSUpdate))
|
r.Methods("POST").Path("/{imageName}/{tag}").Handler(hand(handlers.AddHandler, utils.SSUpdate))
|
||||||
|
|
||||||
server := http.Server{
|
server := http.Server{
|
||||||
Addr: ADDR,
|
Addr: ServerAddress,
|
||||||
Handler: r,
|
Handler: r,
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
log.Println("[Vetinari Server] : Listening on", ADDR)
|
log.Println("[Vetinari Server] : Listening on", ServerAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := server.ListenAndServeTLS(certFile, keyFile)
|
err := server.ListenAndServeTLS(certFile, keyFile)
|
||||||
|
@ -81,7 +84,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
log.Println(os.Stderr, "usage:", os.Args[0], "<config>")
|
log.Println("usage:", os.Args[0], "<config>")
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HTTPError represents an application error which will map to
|
||||||
|
// an HTTP status code and returned error object.
|
||||||
type HTTPError struct {
|
type HTTPError struct {
|
||||||
HTTPStatus int
|
HTTPStatus int
|
||||||
Code int
|
Code int
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
|
|
||||||
var db = util.GetSqliteDB()
|
var db = util.GetSqliteDB()
|
||||||
|
|
||||||
|
// MainHandler is the default handler for the server
|
||||||
func MainHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
|
func MainHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
err := json.NewEncoder(w).Encode("{}")
|
err := json.NewEncoder(w).Encode("{}")
|
||||||
|
@ -24,7 +25,11 @@ func MainHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *er
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
return &errors.HTTPError{http.StatusNotFound, 9999, nil}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusNotFound,
|
||||||
|
Code: 9999,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -40,32 +45,56 @@ func AddHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *err
|
||||||
err := decoder.Decode(&meta)
|
err := decoder.Decode(&meta)
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// add to targets
|
// add to targets
|
||||||
local.AddBlob(vars["tag"], meta)
|
local.AddBlob(vars["tag"], meta)
|
||||||
tufRepo, err := repo.NewRepo(local, "sha256", "sha512")
|
tufRepo, err := repo.NewRepo(local, "sha256", "sha512")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ = tufRepo.Init(true)
|
_ = tufRepo.Init(true)
|
||||||
err = tufRepo.AddTarget(vars["tag"], json.RawMessage{})
|
err = tufRepo.AddTarget(vars["tag"], json.RawMessage{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = tufRepo.Sign("targets.json")
|
err = tufRepo.Sign("targets.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tufRepo.Snapshot(repo.CompressionTypeNone)
|
tufRepo.Snapshot(repo.CompressionTypeNone)
|
||||||
err = tufRepo.Sign("snapshot.json")
|
err = tufRepo.Sign("snapshot.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tufRepo.Timestamp()
|
tufRepo.Timestamp()
|
||||||
err = tufRepo.Sign("timestamp.json")
|
err = tufRepo.Sign("timestamp.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -79,23 +108,39 @@ func RemoveHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *
|
||||||
local.RemoveBlob(vars["tag"])
|
local.RemoveBlob(vars["tag"])
|
||||||
tufRepo, err := repo.NewRepo(local, "sha256", "sha512")
|
tufRepo, err := repo.NewRepo(local, "sha256", "sha512")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ = tufRepo.Init(true)
|
_ = tufRepo.Init(true)
|
||||||
tufRepo.RemoveTarget(vars["tag"])
|
tufRepo.RemoveTarget(vars["tag"])
|
||||||
err = tufRepo.Sign("targets.json")
|
err = tufRepo.Sign("targets.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tufRepo.Snapshot(repo.CompressionTypeNone)
|
tufRepo.Snapshot(repo.CompressionTypeNone)
|
||||||
err = tufRepo.Sign("snapshot.json")
|
err = tufRepo.Sign("snapshot.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tufRepo.Timestamp()
|
tufRepo.Timestamp()
|
||||||
err = tufRepo.Sign("timestamp.json")
|
err = tufRepo.Sign("timestamp.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -109,12 +154,17 @@ func GetHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *err
|
||||||
|
|
||||||
meta, err := local.GetMeta()
|
meta, err := local.GetMeta()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
w.Write(meta[vars["tufFile"]])
|
w.Write(meta[vars["tufFile"]])
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenKeysHandler is the handler for generate keys endpoint
|
||||||
func GenKeysHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
|
func GenKeysHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
|
||||||
log.Printf("GenKeysHandler")
|
log.Printf("GenKeysHandler")
|
||||||
// remove tag from tagets list
|
// remove tag from tagets list
|
||||||
|
@ -122,7 +172,11 @@ func GenKeysHandler(ctx utils.IContext, w http.ResponseWriter, r *http.Request)
|
||||||
local := store.DBStore(db, vars["imageName"])
|
local := store.DBStore(db, vars["imageName"])
|
||||||
tufRepo, err := repo.NewRepo(local, "sha256", "sha512")
|
tufRepo, err := repo.NewRepo(local, "sha256", "sha512")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &errors.HTTPError{http.StatusInternalServerError, 9999, err}
|
return &errors.HTTPError{
|
||||||
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
Code: 9999,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tufRepo.GenKey("root")
|
tufRepo.GenKey("root")
|
||||||
tufRepo.GenKey("targets")
|
tufRepo.GenKey("targets")
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
// IScope is an identifier scope
|
||||||
type IScope interface {
|
type IScope interface {
|
||||||
ID() string
|
ID() string
|
||||||
Compare(IScope) bool
|
Compare(IScope) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IAuthorizer is an interfaces to authorize a scope
|
||||||
type IAuthorizer interface {
|
type IAuthorizer interface {
|
||||||
// Authorize is expected to set the Authorization on the Context. If
|
// Authorize is expected to set the Authorization on the Context. If
|
||||||
// Authorization fails, an error should be returned, but additionally,
|
// Authorization fails, an error should be returned, but additionally,
|
||||||
|
@ -13,6 +15,8 @@ type IAuthorizer interface {
|
||||||
Authorize(IContext, ...IScope) error
|
Authorize(IContext, ...IScope) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IAuthorization is an interface to determine whether
|
||||||
|
// an object has a scope
|
||||||
type IAuthorization interface {
|
type IAuthorization interface {
|
||||||
HasScope(IScope) bool
|
HasScope(IScope) bool
|
||||||
}
|
}
|
||||||
|
@ -21,46 +25,66 @@ type IAuthorization interface {
|
||||||
// THESE ARE FOR DEV PURPOSES ONLY, DO NOT USE IN
|
// THESE ARE FOR DEV PURPOSES ONLY, DO NOT USE IN
|
||||||
// PRODUCTION
|
// PRODUCTION
|
||||||
|
|
||||||
// DON'T USE THIS FOR ANYTHING, IT'S VERY INSECURE
|
// InsecureAuthorizer is an insecure implementation of IAuthorizer.
|
||||||
|
// WARNING: DON'T USE THIS FOR ANYTHING, IT'S VERY INSECURE
|
||||||
type InsecureAuthorizer struct{}
|
type InsecureAuthorizer struct{}
|
||||||
|
|
||||||
// LIKE I SAID, VERY INSECURE
|
// Authorize authorizes any scope
|
||||||
|
// WARNING: LIKE I SAID, VERY INSECURE
|
||||||
func (auth *InsecureAuthorizer) Authorize(ctx IContext, scopes ...IScope) error {
|
func (auth *InsecureAuthorizer) Authorize(ctx IContext, scopes ...IScope) error {
|
||||||
ctx.SetAuthorization(&InsecureAuthorization{})
|
ctx.SetAuthorization(&InsecureAuthorization{})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ALSO DON'T USE THIS, IT'S ALSO VERY INSECURE
|
// InsecureAuthorization is an implementation of IAuthorization
|
||||||
|
// which will consider any scope authorized.
|
||||||
|
// WARNING: ALSO DON'T USE THIS, IT'S ALSO VERY INSECURE
|
||||||
type InsecureAuthorization struct {
|
type InsecureAuthorization struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// THIS IS JUST INCREDIBLY INSECURE
|
// HasScope always returns true for any scope
|
||||||
|
// WARNING: THIS IS JUST INCREDIBLY INSECURE
|
||||||
func (authzn *InsecureAuthorization) HasScope(scope IScope) bool {
|
func (authzn *InsecureAuthorization) HasScope(scope IScope) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ### END INSECURE AUTHORIZATION TOOLS ###
|
// ### END INSECURE AUTHORIZATION TOOLS ###
|
||||||
|
|
||||||
|
// NoAuthorization is an implementation of IAuthorization
|
||||||
|
// which never allows a scope to be valid.
|
||||||
type NoAuthorization struct{}
|
type NoAuthorization struct{}
|
||||||
|
|
||||||
|
// HasScope returns false for any scope
|
||||||
func (authzn *NoAuthorization) HasScope(scope IScope) bool {
|
func (authzn *NoAuthorization) HasScope(scope IScope) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SimpleScope is a simple scope represented by a string.
|
||||||
type SimpleScope string
|
type SimpleScope string
|
||||||
|
|
||||||
|
// ID returns the string representing the scope.
|
||||||
func (ss SimpleScope) ID() string {
|
func (ss SimpleScope) ID() string {
|
||||||
return string(ss)
|
return string(ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare compares to the given scope for equality.
|
||||||
func (ss SimpleScope) Compare(toCompare IScope) bool {
|
func (ss SimpleScope) Compare(toCompare IScope) bool {
|
||||||
return ss.ID() == toCompare.ID()
|
return ss.ID() == toCompare.ID()
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// SSNoAuth is the simple scope "NoAuth"
|
||||||
SSNoAuth SimpleScope = SimpleScope("NoAuth")
|
SSNoAuth SimpleScope = SimpleScope("NoAuth")
|
||||||
SSCreate = SimpleScope("Create")
|
|
||||||
SSRead = SimpleScope("Read")
|
// SSCreate is the simple scope "Create"
|
||||||
SSUpdate = SimpleScope("Update")
|
SSCreate = SimpleScope("Create")
|
||||||
SSDelete = SimpleScope("Delete")
|
|
||||||
|
// SSRead is the simple scope "Read"
|
||||||
|
SSRead = SimpleScope("Read")
|
||||||
|
|
||||||
|
// SSUpdate is the simple scope "Update"
|
||||||
|
SSUpdate = SimpleScope("Update")
|
||||||
|
|
||||||
|
// SSDelete is the simple scope "Delete"
|
||||||
|
SSDelete = SimpleScope("Delete")
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IContext defines an interface for managing authorizations.
|
||||||
type IContext interface {
|
type IContext interface {
|
||||||
// TODO: define a set of standard getters. Using getters
|
// TODO: define a set of standard getters. Using getters
|
||||||
// will allow us to easily and transparently cache
|
// will allow us to easily and transparently cache
|
||||||
|
@ -24,27 +25,36 @@ type IContext interface {
|
||||||
SetAuthorization(IAuthorization)
|
SetAuthorization(IAuthorization)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IContextFactory creates a IContext from an http request.
|
||||||
type IContextFactory func(*http.Request) IContext
|
type IContextFactory func(*http.Request) IContext
|
||||||
|
|
||||||
|
// Context represents an authorization context for a resource.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
resource string
|
resource string
|
||||||
authorization IAuthorization
|
authorization IAuthorization
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContextFactory creates a new authorization context with the
|
||||||
|
// given HTTP request path as the resource.
|
||||||
func ContextFactory(r *http.Request) IContext {
|
func ContextFactory(r *http.Request) IContext {
|
||||||
return &Context{
|
return &Context{
|
||||||
resource: r.URL.Path,
|
resource: r.URL.Path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resource returns the resource value for the context.
|
||||||
func (ctx *Context) Resource() string {
|
func (ctx *Context) Resource() string {
|
||||||
return ctx.resource
|
return ctx.resource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Authorization returns an IAuthorization implementation for
|
||||||
|
// the context.
|
||||||
func (ctx *Context) Authorization() IAuthorization {
|
func (ctx *Context) Authorization() IAuthorization {
|
||||||
return ctx.authorization
|
return ctx.authorization
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetAuthorization allows setting an IAuthorization for
|
||||||
|
// the context.
|
||||||
func (ctx *Context) SetAuthorization(authzn IAuthorization) {
|
func (ctx *Context) SetAuthorization(authzn IAuthorization) {
|
||||||
ctx.authorization = authzn
|
ctx.authorization = authzn
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// http.go contains useful http utilities.
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -7,8 +6,12 @@ import (
|
||||||
"github.com/docker/vetinari/errors"
|
"github.com/docker/vetinari/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BetterHandler defines an alterate HTTP handler interface which takes in
|
||||||
|
// a context for authorization and returns an HTTP application error.
|
||||||
type BetterHandler func(ctx IContext, w http.ResponseWriter, r *http.Request) *errors.HTTPError
|
type BetterHandler func(ctx IContext, w http.ResponseWriter, r *http.Request) *errors.HTTPError
|
||||||
|
|
||||||
|
// RootHandler is an implementation of an HTTP request handler which handles
|
||||||
|
// authorization and calling out to the defined alternate http handler.
|
||||||
type RootHandler struct {
|
type RootHandler struct {
|
||||||
handler BetterHandler
|
handler BetterHandler
|
||||||
auth IAuthorizer
|
auth IAuthorizer
|
||||||
|
@ -16,12 +19,17 @@ type RootHandler struct {
|
||||||
context IContextFactory
|
context IContextFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RootHandlerFactory creates a new RootHandler factory using the given
|
||||||
|
// Context creator and authorizer. The returned factory allows creating
|
||||||
|
// new RootHandlers from the alternate http handler BetterHandler and
|
||||||
|
// a scope.
|
||||||
func RootHandlerFactory(auth IAuthorizer, ctxFac IContextFactory) func(BetterHandler, ...IScope) *RootHandler {
|
func RootHandlerFactory(auth IAuthorizer, ctxFac IContextFactory) func(BetterHandler, ...IScope) *RootHandler {
|
||||||
return func(handler BetterHandler, scopes ...IScope) *RootHandler {
|
return func(handler BetterHandler, scopes ...IScope) *RootHandler {
|
||||||
return &RootHandler{handler, auth, scopes, ctxFac}
|
return &RootHandler{handler, auth, scopes, ctxFac}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServeHTTP serves an HTTP request and implements the http.Handler interface.
|
||||||
func (root *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (root *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := root.context(r)
|
ctx := root.context(r)
|
||||||
if err := root.auth.Authorize(ctx, root.scopes...); err != nil {
|
if err := root.auth.Authorize(ctx, root.scopes...); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue