From cc18967e418a4229e6bb2af7db30ed8dd49e46e4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 17 Dec 2024 11:21:58 -0800 Subject: [PATCH] Support put a redefined token for Gitea actions command or API --- cmd/actions.go | 9 ++++++++- models/actions/runner_token.go | 18 +++++++++++++----- modules/private/actions.go | 8 +++++--- modules/util/util.go | 9 +++++++++ routers/api/v1/shared/runners.go | 12 ++++++++---- routers/private/actions.go | 9 ++++++--- routers/web/shared/actions/runners.go | 4 ++-- 7 files changed, 51 insertions(+), 18 deletions(-) diff --git a/cmd/actions.go b/cmd/actions.go index f582c16c81c..648783faaaa 100644 --- a/cmd/actions.go +++ b/cmd/actions.go @@ -34,6 +34,12 @@ var ( Value: "", Usage: "{owner}[/{repo}] - leave empty for a global runner", }, + &cli.StringFlag{ + Name: "put-token", + Aliases: []string{"t"}, + Value: "", + Usage: "[{token}] - leave empty will generate a new token, otherwise will update the token to database. The token MUST be a 40 digital string containing only 0-9 and a-f", + }, }, } ) @@ -45,8 +51,9 @@ func runGenerateActionsRunnerToken(c *cli.Context) error { setting.MustInstalled() scope := c.String("scope") + putToken := c.String("put-token") - respText, extra := private.GenerateActionsRunnerToken(ctx, scope) + respText, extra := private.GenerateActionsRunnerToken(ctx, scope, putToken) if extra.HasError() { return handleCliResponseExtra(extra) } diff --git a/models/actions/runner_token.go b/models/actions/runner_token.go index fd6ba7ecadb..024cc0e56a8 100644 --- a/models/actions/runner_token.go +++ b/models/actions/runner_token.go @@ -70,16 +70,24 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string // NewRunnerToken creates a new active runner token and invalidate all old tokens // ownerID will be ignored and treated as 0 if repoID is non-zero. -func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { +func NewRunnerToken(ctx context.Context, ownerID, repoID int64, preDefinedToken string) (*ActionRunnerToken, error) { if ownerID != 0 && repoID != 0 { // It's trying to create a runner token that belongs to a repository, but OwnerID has been set accidentally. // Remove OwnerID to avoid confusion; it's not worth returning an error here. ownerID = 0 } - token, err := util.CryptoRandomString(40) - if err != nil { - return nil, err + token := preDefinedToken + if token == "" { + var err error + token, err = util.CryptoRandomString(40) + if err != nil { + return nil, err + } + } else { + if len(token) != 40 || !util.IsRandomStringValid(token) { + return nil, util.NewInvalidArgumentErrorf("invalid token: %s", token) + } } runnerToken := &ActionRunnerToken{ OwnerID: ownerID, @@ -95,7 +103,7 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo return err } - _, err = db.GetEngine(ctx).Insert(runnerToken) + _, err := db.GetEngine(ctx).Insert(runnerToken) return err }) } diff --git a/modules/private/actions.go b/modules/private/actions.go index 311a2836500..1b1c019ce55 100644 --- a/modules/private/actions.go +++ b/modules/private/actions.go @@ -10,15 +10,17 @@ import ( ) type GenerateTokenRequest struct { - Scope string + Scope string + PutToken string } // GenerateActionsRunnerToken calls the internal GenerateActionsRunnerToken function -func GenerateActionsRunnerToken(ctx context.Context, scope string) (*ResponseText, ResponseExtra) { +func GenerateActionsRunnerToken(ctx context.Context, scope, putToken string) (*ResponseText, ResponseExtra) { reqURL := setting.LocalURL + "api/internal/actions/generate_actions_runner_token" req := newInternalRequest(ctx, reqURL, "POST", GenerateTokenRequest{ - Scope: scope, + Scope: scope, + PutToken: putToken, }) return requestJSONResp(req, &ResponseText{}) diff --git a/modules/util/util.go b/modules/util/util.go index 1fb4cb21cb8..7319406c4cd 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -78,6 +78,15 @@ func CryptoRandomInt(limit int64) (int64, error) { const alphanumericalChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +func IsRandomStringValid(s string) bool { + for _, c := range s { + if !strings.ContainsRune(alphanumericalChars, c) { + return false + } + } + return true +} + // CryptoRandomString generates a crypto random alphanumerical string, each byte is generated by [0,61] range func CryptoRandomString(length int64) (string, error) { buf := make([]byte, length) diff --git a/routers/api/v1/shared/runners.go b/routers/api/v1/shared/runners.go index f088e9a2d41..1fc9290b3f4 100644 --- a/routers/api/v1/shared/runners.go +++ b/routers/api/v1/shared/runners.go @@ -19,14 +19,18 @@ type RegistrationToken struct { } func GetRegistrationToken(ctx *context.APIContext, ownerID, repoID int64) { - token, err := actions_model.GetLatestRunnerToken(ctx, ownerID, repoID) - if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { - token, err = actions_model.NewRunnerToken(ctx, ownerID, repoID) + putToken := ctx.FormString("put-token") + var token *actions_model.ActionRunnerToken + var err error + if putToken == "" { + token, err = actions_model.GetLatestRunnerToken(ctx, ownerID, repoID) + } + if putToken != "" || errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { + token, err = actions_model.NewRunnerToken(ctx, ownerID, repoID, putToken) } if err != nil { ctx.InternalServerError(err) return } - ctx.JSON(http.StatusOK, RegistrationToken{Token: token.Token}) } diff --git a/routers/private/actions.go b/routers/private/actions.go index 696634b5e75..76c82853157 100644 --- a/routers/private/actions.go +++ b/routers/private/actions.go @@ -41,9 +41,12 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { }) } - token, err := actions_model.GetLatestRunnerToken(ctx, owner, repo) - if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { - token, err = actions_model.NewRunnerToken(ctx, owner, repo) + var token *actions_model.ActionRunnerToken + if genRequest.PutToken == "" { + token, err = actions_model.GetLatestRunnerToken(ctx, owner, repo) + } + if genRequest.PutToken != "" || errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { + token, err = actions_model.NewRunnerToken(ctx, owner, repo, genRequest.PutToken) if err != nil { errMsg := fmt.Sprintf("error while creating runner token: %v", err) log.Error("NewRunnerToken failed: %v", errMsg) diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index f38933226b8..81f0dfd750b 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -32,7 +32,7 @@ func RunnersList(ctx *context.Context, opts actions_model.FindRunnerOptions) { var token *actions_model.ActionRunnerToken token, err = actions_model.GetLatestRunnerToken(ctx, opts.OwnerID, opts.RepoID) if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { - token, err = actions_model.NewRunnerToken(ctx, opts.OwnerID, opts.RepoID) + token, err = actions_model.NewRunnerToken(ctx, opts.OwnerID, opts.RepoID, "") if err != nil { ctx.ServerError("CreateRunnerToken", err) return @@ -131,7 +131,7 @@ func RunnerDetailsEditPost(ctx *context.Context, runnerID, ownerID, repoID int64 // RunnerResetRegistrationToken reset registration token func RunnerResetRegistrationToken(ctx *context.Context, ownerID, repoID int64, redirectTo string) { - _, err := actions_model.NewRunnerToken(ctx, ownerID, repoID) + _, err := actions_model.NewRunnerToken(ctx, ownerID, repoID, "") if err != nil { ctx.ServerError("ResetRunnerRegistrationToken", err) return