code.gitea.io/gitea@v1.22.3/services/actions/auth.go (about)

     1  // Copyright 2024 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package actions
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"strings"
    10  	"time"
    11  
    12  	"code.gitea.io/gitea/modules/json"
    13  	"code.gitea.io/gitea/modules/log"
    14  	"code.gitea.io/gitea/modules/setting"
    15  
    16  	"github.com/golang-jwt/jwt/v5"
    17  )
    18  
    19  type actionsClaims struct {
    20  	jwt.RegisteredClaims
    21  	Scp    string `json:"scp"`
    22  	TaskID int64
    23  	RunID  int64
    24  	JobID  int64
    25  	Ac     string `json:"ac"`
    26  }
    27  
    28  type actionsCacheScope struct {
    29  	Scope      string
    30  	Permission actionsCachePermission
    31  }
    32  
    33  type actionsCachePermission int
    34  
    35  const (
    36  	actionsCachePermissionRead = 1 << iota
    37  	actionsCachePermissionWrite
    38  )
    39  
    40  func CreateAuthorizationToken(taskID, runID, jobID int64) (string, error) {
    41  	now := time.Now()
    42  
    43  	ac, err := json.Marshal(&[]actionsCacheScope{
    44  		{
    45  			Scope:      "",
    46  			Permission: actionsCachePermissionWrite,
    47  		},
    48  	})
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  
    53  	claims := actionsClaims{
    54  		RegisteredClaims: jwt.RegisteredClaims{
    55  			ExpiresAt: jwt.NewNumericDate(now.Add(24 * time.Hour)),
    56  			NotBefore: jwt.NewNumericDate(now),
    57  		},
    58  		Scp:    fmt.Sprintf("Actions.Results:%d:%d", runID, jobID),
    59  		Ac:     string(ac),
    60  		TaskID: taskID,
    61  		RunID:  runID,
    62  		JobID:  jobID,
    63  	}
    64  	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    65  
    66  	tokenString, err := token.SignedString(setting.GetGeneralTokenSigningSecret())
    67  	if err != nil {
    68  		return "", err
    69  	}
    70  
    71  	return tokenString, nil
    72  }
    73  
    74  func ParseAuthorizationToken(req *http.Request) (int64, error) {
    75  	h := req.Header.Get("Authorization")
    76  	if h == "" {
    77  		return 0, nil
    78  	}
    79  
    80  	parts := strings.SplitN(h, " ", 2)
    81  	if len(parts) != 2 {
    82  		log.Error("split token failed: %s", h)
    83  		return 0, fmt.Errorf("split token failed")
    84  	}
    85  
    86  	token, err := jwt.ParseWithClaims(parts[1], &actionsClaims{}, func(t *jwt.Token) (any, error) {
    87  		if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
    88  			return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
    89  		}
    90  		return setting.GetGeneralTokenSigningSecret(), nil
    91  	})
    92  	if err != nil {
    93  		return 0, err
    94  	}
    95  
    96  	c, ok := token.Claims.(*actionsClaims)
    97  	if !token.Valid || !ok {
    98  		return 0, fmt.Errorf("invalid token claim")
    99  	}
   100  
   101  	return c.TaskID, nil
   102  }