class

GoAuthTagger

Inherits GoRpcProcedureGate < GoBeegoCasbinFilter < GoRouteGroupScope < PrefixScope < FrameworkTagger < FileHelper < Tagger < Reference < Object

Constants

ABSENCE_TEST = /\A(?:!\s*(\w+)|(\w+)\s*==\s*""|len\(\s*(\w+)\s*\)\s*==\s*0)\z/

A condition that a request-supplied value is absent (!ok, token == "", len(sudo) == 0) or present (token != "", len(sudo) > 0).

ASSIGNMENT_HEAD = /\A\s*\w+(?:\s*,\s*\w+)*\s*:?=/

A statement that opens with an assignment (authed := r.Group(...)).

AUTHISH_NAME = /auth|jwt|token|permission|login|rbac|acl/i

A name that reads as a guard, applied to a middleware argument (gin.BasicAuth, echojwt.WithConfig) only when its definition is not in the scan: a library constructor or an interface method. A definition that is found decides on its body, so LoginLogger() / TokenRefresher() that only pass the request on are not guards whatever they are called. sessions.Sessions(store) is a session store, not a check.

AUTHZ_CONDITION = /[Aa]dmin|[Rr]ole|[Pp]erm|[Oo]wner|[Mm]ember|[Cc]ollaborat|[Ss]cope|[Aa]ccess|[Pp]rivilege|[Vv]isib|[Pp]ublic|[Gg]rant|[Ww]riter|[Rr]eader|\b[Cc]an[A-Z]/

A refusal whose condition asks what the caller may do (!ctx.IsUserSiteAdmin(), !ctx.Repo.Permission.CanRead(...), !isMember) is an authorization check; any other is an authentication one.

BIND_REGISTRATION = /\A(\w+)\s*(?::?=\s*\w+(?:\s*\.\s*\w+)*\s*\.\s*Group\s*\([^()]*\)\s*)?\.\s*Bind\s*\(/

PocketBase: sg := rg.Group("/sql").Bind(mw) / sg.Bind(mw).

BODY_CALL = /(?<![\w.])([A-Za-z_]\w*)\s*\(/

An unqualified call inside a middleware body, for the one-hop lookup.

BOUND_CALL = /\A(?:(\w+)\.)?(\w+)\s*\(/
BOUND_TYPE = /\A&?\s*(?:(\w+)\.)?(\w+)\s*\{/

What a local is bound to: a struct literal or a call, by type or callee.

BRANCH_LINE = /\A(?:\}\s*)?(?:else\b|if\b|for\b|switch\b|select\b|case\b|default\s*:)/

A control-flow line: a refusal under it is conditional.

CALL_BINDING = /\A\s*(\w+)\s*(?:,\s*\w+\s*)*:?=\s*(?:(\w+)\s*\.\s*)?(\w+)\s*\(/

name := F(, name, err := pkg.F(, name = F(: the call that binds a guard's receiver variable.

CASE_ARM = /\Acase\s+(.+):\z/
CHAINED_GUARD_CALL = /\A!?\s*(?:(\w+)\s*\.\s*)?(\w+)\s*\(.*\)\s*\.\s*(\w+)\s*\([^()]*\)\z/
CLOSURE_ARG_OPEN = /\(.*\bfunc\s*\([^()]*\)\s*\{\s*\z/

A closure handed to a call that is still open at the end of the line: m.Group("/user", func() {, r.Group(func(r chi.Router) {.

CLOSURE_PARAM = /\bfunc\s*\(\s*(\w+)\s+[^()]*\)\s*\{\s*\z/

The router parameter of a closure opened at the end of a line: s.Group("/api", func(group *ghttp.RouterGroup) { -> group.

CLOSURE_PARAM_VERB = ["Middleware", "Bind", "ALLMap", "Map"] of ::String
CLOSURE_REGISTRATION = /\.\s*(?:Use|With|Group|Route)\s*\(/

Lines worth walking for closure-scoped middleware.

CLOSURE_ROUTER_PARAM = /(\w+)\s*\.\s*\w+\s*\(.*\bfunc\s*\(\s*(\w+)\b/

A closure handed to a call on a router, taking the router: r.Route("/x", func(r chi.Router) {.

CLOSURE_USE = /(\w+)\.(Use|Pre|Middleware|Bind|ALLMap|Map)\s*\(/

Middleware added inside a closure group on its router: .Use( / .Pre(, or, on the closure's own router parameter only, GoFrame's group.Middleware( and .Bind( (a PocketBase middleware, or a GoFrame controller whose routes the closure's middleware then guards); group.ALLMap(g.Map{"/x": ctrl.Profile}) binds handlers like .Bind.

CREDENTIAL_KEYS = Set {"authorization", "apikey", "xapikey", "accesstoken", "authtoken", "xauthtoken", "token", "session", "sessionid", "sessiontoken", "jwt", "bearer"}

The request keys that carry the caller's credential, lowercased without - / _ (api_key, X-Auth-Token). A request is stopped for lack of one only as authentication; a stop for lack of an Idempotency-Key or a page_token is not.

CREDENTIAL_MISMATCH = /\A(\w+)\s*!=\s*(.+)\z/

token != secret: the credential compared against an expected value.

CREDENTIAL_READ = /\A(\w+)\s*:?=\s*\w+\s*\.\s*(?:FormValue|PostFormValue|Header\s*\.\s*Get|URL\s*\.\s*Query\(\)\s*\.\s*Get|Form\s*\.\s*Get)\s*\(\s*"([^"]+)"\s*\)\z/

apiKey := r.FormValue("api_key"): a request value bound to a local.

CREDENTIAL_TEST = /cookie|session|\bsess\b|auth|bearer|jwt|user|login|token/i

A test of the caller's credential or session, as written.

CSRF_KEY = /\.\s*(?:Get|GetHeader|FormValue|PostFormValue|PostForm|Query|QueryParam|Cookie)\s*\(\s*"[^"]*(?:csrf|xsrf)[^"]*"\s*\)/i
CSRF_TEST = /csrf|xsrf/i

A test of a CSRF token: a call named for it (!csrfOK(r)) or a read of a request key named for it (Header.Get("X-CSRF-Token")).

ELSE_OPEN = /\A\}?\s*else\s*\{\z/
EQUALITY_TEST = /\A([\w.]+)\s*(==|!=)\s*"([^"]*)"\z/
FLAG_TEST = /\A(!?)\s*(\w+)\z/

required / !required: a bare (flag) parameter.

FUNC_NAME = /\Afunc\s*(?:\([^)]*\)\s*)?(\w+)/
FUNC_PARAM = /[(,]\s*(\w+)\s+func\s*\(([^()]*)\)[ \t]*(\(|[\w.*\[\]]+)?/

A parameter typed as a function, with its parameter list and the start of its result (a type, ( for several, or none).

FUNC_PARAMETERS = /\Afunc\s*(?:\([^)]*\)\s*)?\w+\s*(?:\[[^\]]*\]\s*)?\(([^)]*)\)/

a.Use(mw) on a group the function was handed (vikunja's func registerAPIRoutesV2(e *echo.Echo, a *echo.Group)). The group's prefix scope resolves a by name, which can be another function's group (RegisterRoutes' /api/v1 one), so the routes the middleware does reach are also recorded by lineage: those registered on a (or a group derived from it) below the .Use, here or in a helper handed a below it (m.Register(a)), whatever their URL.

FUNC_PARAMS = /\Afunc\s*(?:\([^)]*\)\s*)?\w+\s*\(([^)]*)\)/

The parameter list of a func name(...) / func (r T) name(...) head.

FUNC_SIGNATURE = /\Afunc\s*(?:\([^)]*\)\s*)?(\w+)\s*\(([^)]*)\)/

A one-line signature: the function name and its parameter list.

GO_MODULE_PATH = /^module\s+(\S+)/m
GO_REPLACE = /^\s*(?:replace\s+)?(\S+)(?:\s+v\S+)?\s+=>\s+(\.{1,2}\/\S*|\/\S*)\s*$/m

A replace of a module by a local directory, in a block or on its own line: example.com/lib => ../lib.

GOZERO_KEY = /\b(jwt|middleware)\s*:\s*(\w+(?:\s*,\s*\w+)*)/
GOZERO_MIDDLEWARES = /rest\s*\.\s*WithMiddlewares\s*\(\s*\[\]\s*rest\s*\.\s*Middleware\s*\{([^}]*)\}/
GOZERO_ROUTES = /\.\s*AddRoutes\s*\(/
GOZERO_SERVICE = /\Aservice\s+[\w-]+\s*\{/
GUARD_CALL = /\A!?\s*(?:(\w+)\s*\.\s*)?(\w+)\s*\([^()]*\)\z/

The call a guard condition makes: s.Abort(c), !authorized(c), and the chained Auth(c, x).Abort(c) (head call in groups 1-2).

GUARD_IF = /\Aif\s+(?:([^;{]*);\s*)?(.+?)\s*\{\z/

if <init>; <cond> { on one line.

HANDLE_CALLS = ["Handle", "HandleFunc"] of ::String

The registrars of a router that takes a bare handler (gorilla's r.Handle("/x", auth(h)).Methods("GET")).

HANDLER_ARG = /,\s*[\w.]+\s*\)((?:\s*\.\s*\w+\s*\([^()]*\))*)\s*;?\s*$/

The route call's last argument when it is a bare handler reference (r.POST("/login", AuthHandler)), plus any chained calls after it (mux's .Methods("GET")). Only the arguments between path and handler are middleware; a wrapped handler (authMiddleware(h)) is a call, so it stays.

HANDLER_CREDENTIAL_READ = /\A(\w+)\s*:?=\s*\w+(?:\s*\.\s*Request\s*\(\s*\))?\s*\.\s*(?:Header\s*\.\s*Get|GetHeader)\s*\(\s*"([^"]+)"\s*\)\z/

token := c.Request().Header.Get("Authorization"), c.GetHeader(…): a request header a handler binds to a local. Headers only: a token query or form value is as often a one-time reset/confirm token the handler checks as the caller's credential.

HANDLER_PARAM = /\b(\w+)\s+(?:\w+\.)?Handler(?:Func)?\b/

A parameter typed as a handler: next http.Handler, h http.HandlerFunc.

HANDS_ON_UNCHECKED = /^\s*if\s+([^{\n]+?)\s*\{[ \t]*(?:\/\/[^\n]*)?\n\s*return\s+(\w+)\s*(?:\/\/[^\n]*)?\n\s*\}/m

if <cond> { then return next and }.

IDENTIFIER = /\A\w+\z/
IF_OPEN = /\A(?:\}\s*)?(?:else\s+)?if\s+(?:[^;{]*;\s*)?(.+?)\s*\{\z/

if cond { / } else if x := f(); cond { and } else { on their own line.

IF_TEST = /\Aif\s+(.+?)\s*\{\z/
IMPORTED_CALL = /(?<![\w.])(\w+)\s*\.\s*(\w+)\s*\(/

A call into another scanned package: response.JSONUnauthorized(.

INLINE_AUTH_MIDDLEWARE = [/\b[Aa]uth(?:enticate|orize|Required|Middleware|Handler|Guard|Check)\b/, /\b[Rr]equire[Aa]uth\b/, /\b[Ii]s[Aa]uth(?:enticated)?\b/, /\b[Ll]ogin[Rr]equired\b/, /\b[Vv]erify[Tt]oken\b/, /\b[Cc]heck[Tt]oken\b/, /\b[Jj][Ww][Tt](?:Auth|Middleware|Verify|Check|Guard)?\b/, /\b[Aa]dmin[Oo]nly\b/, /\b[Rr]ole[Cc]heck\b/, /\b[Pp]ermission[Cc]heck\b/, /\bHertzAuth\b/, /\bIrisAuth\b/, /\bGF[Aa]uth\b/]

Auth middleware in route definition (inline middleware)

JWT_PATTERNS = [/echojwt\.\w+/, /jwtauth\.\w+/, /jwt\.New\s*\(/, /jwt\.Auth\s*\(/, /middleware\.JWT\s*\(/, /middleware\.JWTWithConfig\s*\(/]

JWT library patterns

LEADING_CALL = /\A((?:\w+\s*\.\s*)*\w+)\s*\(/

A call's callee at the start of an expression.

LITERAL_FIELD = /(\w+)\s*:\s*([^,{}]+)/

Field: value inside a call-site struct literal.

LOCAL_ASSIGNMENT = /\A(\w+)\s*:?=(?!=)/

name = / name :=: a local (re)bound.

LOCAL_BINDING = /\A\s*([\w.]+)\s*:?=\s*([\w.]+\s*\(.*)\z/

name := expr / name = expr, for a middleware held in a variable (reqSignIn := verifyAuth(&Options{SignInRequired: true})).

LOCAL_TYPE = /\b(\w+)\s*(?::?=\s*&?\s*|\s+\*?)(?:(\w+)\.)?([A-Z]\w*)\s*[{\n),]/

A local typed with a struct, so its methods resolve: authentication := auth.Auth{, var mw = &middleware.JWT{, mw *auth.Middleware.

LOGIN_REDIRECT = /(?=.*Redirect\w*\s*\().*(?:[Ll]og_?[Ii]n|[Ss]ign_?[Ii]n)/

A redirect to the login page (ctx.RedirectForLogin(...), c.Redirect(302, "/login"), response.HTMLRedirect(w, r, loginURL)), matched with string literals kept.

METHOD_RECEIVER = /\Afunc\s*\(\s*(?:\w+\s+)?\*?\s*(\w+)/

A method head's receiver type: func (m *Session) Abort( -> Session.

METHOD_RECEIVER_NAME = /\Afunc\s*\(\s*(\w+)\s+\*?\s*(\w+)\s*\)/

func (a *Auth) Name(: the receiver's name and type.

METHOD_TEST = /\A\w+\.Method\s*(==|!=)\s*(?:http\.Method(\w+)|"(\w+)")\z/
MIDDLEWARE_ARGS_START = /\.\s*(?:Use|Pre|Middleware)\s*\(|\.\s*\w+\s*\(\s*""\s*,/

Where the middleware arguments start on a code_only line (string literals blanked to ""): right after .Use( / .Pre( (GoFrame's .Middleware(), or after the path literal of a Group("/seg", ...) constructor or a route call.

MIDDLEWARE_REFERENCE = /\A((?:\w+\s*\.\s*)*)(?!func\b)(\w+)\s*(?:\(|\z)/

One middleware argument's head: AuthMiddleWare() -> {"", "AuthMiddleWare"}, auth.Required() -> {"auth", "Required"}, gin.BasicAuth(gin.Accounts{ -> {"gin", "BasicAuth"}. A closure (func(c *gin.Context) {) is excluded.

MOUNT_HEAD = /\A(\w+)\.(?:Handle|HandleFunc)\z/
MULTI_VERB_CALLS = ["Any", "Match"] of ::String
NET_HTTP_ASSIGNMENT = /\A\s*(?:var\s+)?(\w+)(?:\s+[\w.*\[\]]+)?\s*:?=(?!=)\s*/

A statement binding its right-hand side: h := x, h = x, var h T = x.

NET_HTTP_ROUTE = /\A\s*(\w+(?:\s*\.\s*\w+)*?)\s*\.\s*(?:Handle|HandleFunc)\s*\(/

mux.Handle( / mux.HandleFunc( at a statement start, with the mux.

NEW_SERVER = /\b(\w+)\s*:?=\s*(\w+)\s*\.\s*NewServer\s*\(/
OPTION_FIELD = /\A(!?)\s*(\w+)\.(\w+)\z/

options.SignInRequired / !options.SignOutRequired read off a parameter.

PACKAGE_VALUE = /\A!?\s*(\w+)(?:\.\w+)+\z/

pkg.Var.Field with no call: a package-level (configuration) value.

PASS_STATEMENT = /\A(?:[\w.]+\.Next\(\)|next\.ServeHTTP\(.*\))\z/

An if block that only lets the request through: return, optionally after handing it on (c.Next(), next.ServeHTTP(w, r)).

PATH_BINDING = /\A(\w+)\s*:=\s*(\w+)\.URL\.Path\z/
PREDICATE_CALL = /\A(\w+)\s*\(\s*\w+\s*\)\z/
PREFIX_MATCHED_MIDDLEWARE = {"go_fiber"}

Routers whose group middleware runs for every route under the group's path, whatever group registered it.

PRESENCE_TEST = /\A(?:(\w+)\s*!=\s*""|len\(\s*(\w+)\s*\)\s*(?:>|!=)\s*0)\z/
PRESENT = "<present>"
RECEIVER_STATEMENT = /\A(\w+)\s*\.\s*(\w+)\s*\(/

A statement that calls a method on a value: a.evaluateOr401(ctx, ...).

REGISTRATION_RECEIVER = /\A(\w+)\s*(?::?=\s*\w+\s*\.\s*(?:Group|Party)|\.\s*(?:Use|Pre))\s*\(/

The group variable a registration line credits: authV1 for both authV1.Use(auth) and authV1 := apiV1.Group("/", auth).

REJECTS_REQUEST = /[(,]\s*(?:\w+\.)?Status(?:Unauthorized|Forbidden)\b|[(,]\s*40[13]\s*[,)]|\b(?:\w+\.)?Err(?:Unauthorized|Forbidden)\b|[.\s(]New(?:Unauthorized|Forbidden)Error\s*\(|\.\s*(?:Unauthorized|Forbidden)Error\s*\(|[(,]\s*gcode\s*\.\s*CodeNotAuthorized\b/

A middleware body line that refuses the request: a 401/403 status handed to a reply or abort call (AbortWithStatus(http.StatusUnauthorized), c.JSON(403, ...), http.Error(w, "", 401), WriteHeader(403)) or a framework sentinel error (echo.ErrUnauthorized, fiber.ErrForbidden). Matched on code_only source, so a 401 in a comment or log string does not count, and == http.StatusUnauthorized (a comparison, as in a logging middleware) does not either. PocketBase replies with e.UnauthorizedError(...) / e.ForbiddenError(...) (before 0.23, apis.NewUnauthorizedError(...)), GoFrame with r.SetError(gerror.NewCode(gcode.CodeNotAuthorized, ...)).

RETURN_BOOL = /\Areturn\s+(true|false)\z/
RETURN_EXPR = /\A\s*return\s+(.+)\z/
RETURN_TEST = /\Areturn\s+(.+)\z/
ROOT_ROUTER_PARAM = /\*\s*(?:echo\.Echo|gin\.Engine|fiber\.App)\b/

The URL prefix of a group the caller builds from its engine (g := e.Group("/admin"), with e *echo.Echo), read up from row; nil for anything else, a group handed in included.

ROUTE_BIND = /\)\s*\.\s*Bind\s*\(/

PocketBase: sub.GET("", h).Bind(apis.RequireSuperuserAuth()).

ROUTE_CALL = /(?:\A|\.)\s*([A-Za-z]+)\s*\(/

A route call on a line: m.Post(, .GET(, or a chained Delete(.

ROUTE_RECEIVER = /\A\s*(\w+)\s*\.\s*\w+\s*\(/

The variable a route line registers on: authV1 for authV1.POST(...).

ROUTER_ASSIGNMENT = /\A(?:var\s+)?(\w+)(?:\s+[\w.*\[\]]+)?\s*:?=(?!=)\s*(.+)\z/
ROUTER_CONSTRUCTOR = /\A&?\s*(\w+)\s*\.\s*(?:New\w*|Default)\s*\(/

A library's router constructor: gin.Default(), chi.NewRouter(), fiber.New(...).

ROUTER_CONTEXT = /(?<!context)\.\s*(?:Context|Ctx|RequestCtx|RequestContext)\b/

The parameters a request handler takes: the router's context (echo.Context, *gin.Context, *fiber.Ctx), not a context.Context, or both halves of a net/http handler.

ROUTER_FROM = /\A(\w+)\s*(?:\.|\z)/

A router read off another variable: r.Group("/x"), r.PathPrefix("/api"). Subrouter(), r.With(mw), or r itself.

SELECTOR_CALL = /(?<![\w.])(\w+)((?:\s*\.\s*\w+)+)\s*\(/

A call on a value: session.Require(c), a.V.Verify(c).

SERVER_MIDDLEWARE = /\b(\w+)\s*\.\s*Middleware\s*\(/

Kratos: the http.Middleware(...) server option (under whatever alias the file imports Kratos' transport/http as), run for every route the server serves.

SKIPPER_FIELD = /\bSkipper\s*:(?!\s*(?:nil\b|(?:\w+\.)?DefaultSkipper\b))/

A middleware config's Skipper: set to anything but the default.

STRING_TEST = /\Astrings\.Has(Prefix|Suffix)\(\s*([\w.]+)\s*,\s*"([^"]*)"\s*\)\z/
SWITCH_ON = /\Aswitch\s+([\w.]+)\s*\{\z/
USE_REGISTRATION = /\.\s*(?:Use|Pre|Middleware)\s*\(|\.\s*(?:Group|Party)\s*\(\s*"[^"]*"\s*,/

A scope is only ever recorded for a line resolve_use_scope or resolve_group_middleware_scope resolves: a .Use( / .Pre( call or a Group("/seg", mw...) constructor — so a file with neither anywhere registers nothing, and the pre-scan can skip its per-line group tracking outright. Also GoFrame's group.Middleware( and Kratos' http.Middleware( server option. (PocketBase's .Bind( is gated on the file importing PocketBase: c.Bind(&req) is in every gin / echo handler file.)

WITH_CALL = /\.\s*With\s*\(/

Middleware handed to r.With(mw...) ahead of a route or group.

Constructors

new(options : Hash(String, YAML::Any))
Source

Class methods

target_techs
Source

Instance methods

perform(endpoints : Array(Endpoint)) : Array(Endpoint)

The per-endpoint shape: look at each endpoint, tag in place, hand the array back. Taggers declare only check_endpoint; those that need a pass over the whole set first (a project pre-scan, mcp's legacy prefixes) override perform and call super or loop themselves.

Source

Nested types