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 }