code.gitea.io/gitea@v1.22.3/routers/api/actions/runner/interceptor.go (about)

     1  // Copyright 2022 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package runner
     5  
     6  import (
     7  	"context"
     8  	"crypto/subtle"
     9  	"errors"
    10  	"strings"
    11  
    12  	actions_model "code.gitea.io/gitea/models/actions"
    13  	auth_model "code.gitea.io/gitea/models/auth"
    14  	"code.gitea.io/gitea/modules/log"
    15  	"code.gitea.io/gitea/modules/timeutil"
    16  	"code.gitea.io/gitea/modules/util"
    17  
    18  	"connectrpc.com/connect"
    19  	"google.golang.org/grpc/codes"
    20  	"google.golang.org/grpc/status"
    21  )
    22  
    23  const (
    24  	uuidHeaderKey  = "x-runner-uuid"
    25  	tokenHeaderKey = "x-runner-token"
    26  )
    27  
    28  var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unaryFunc connect.UnaryFunc) connect.UnaryFunc {
    29  	return func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) {
    30  		methodName := getMethodName(request)
    31  		if methodName == "Register" {
    32  			return unaryFunc(ctx, request)
    33  		}
    34  		uuid := request.Header().Get(uuidHeaderKey)
    35  		token := request.Header().Get(tokenHeaderKey)
    36  
    37  		runner, err := actions_model.GetRunnerByUUID(ctx, uuid)
    38  		if err != nil {
    39  			if errors.Is(err, util.ErrNotExist) {
    40  				return nil, status.Error(codes.Unauthenticated, "unregistered runner")
    41  			}
    42  			return nil, status.Error(codes.Internal, err.Error())
    43  		}
    44  		if subtle.ConstantTimeCompare([]byte(runner.TokenHash), []byte(auth_model.HashToken(token, runner.TokenSalt))) != 1 {
    45  			return nil, status.Error(codes.Unauthenticated, "unregistered runner")
    46  		}
    47  
    48  		cols := []string{"last_online"}
    49  		runner.LastOnline = timeutil.TimeStampNow()
    50  		if methodName == "UpdateTask" || methodName == "UpdateLog" {
    51  			runner.LastActive = timeutil.TimeStampNow()
    52  			cols = append(cols, "last_active")
    53  		}
    54  		if err := actions_model.UpdateRunner(ctx, runner, cols...); err != nil {
    55  			log.Error("can't update runner status: %v", err)
    56  		}
    57  
    58  		ctx = context.WithValue(ctx, runnerCtxKey{}, runner)
    59  		return unaryFunc(ctx, request)
    60  	}
    61  }))
    62  
    63  func getMethodName(req connect.AnyRequest) string {
    64  	splits := strings.Split(req.Spec().Procedure, "/")
    65  	if len(splits) > 0 {
    66  		return splits[len(splits)-1]
    67  	}
    68  	return ""
    69  }
    70  
    71  type runnerCtxKey struct{}
    72  
    73  func GetRunner(ctx context.Context) *actions_model.ActionRunner {
    74  	if v := ctx.Value(runnerCtxKey{}); v != nil {
    75  		if r, ok := v.(*actions_model.ActionRunner); ok {
    76  			return r
    77  		}
    78  	}
    79  	return nil
    80  }