mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
auth_model "github.com/hanzoai/git/models/auth"
|
|
user_model "github.com/hanzoai/git/models/user"
|
|
"github.com/hanzoai/git/modules/setting"
|
|
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
func newUserGenerateAccessTokenCommand() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "generate-access-token",
|
|
Usage: "Generate an access token for a specific user",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "username",
|
|
Aliases: []string{"u"},
|
|
Usage: "Username",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "token-name",
|
|
Aliases: []string{"t"},
|
|
Usage: "Token name",
|
|
Value: "hanzo-admin",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "raw",
|
|
Usage: "Display only the token value",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "scopes",
|
|
Value: "all",
|
|
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
|
},
|
|
},
|
|
Action: runGenerateAccessToken,
|
|
}
|
|
}
|
|
|
|
func runGenerateAccessToken(ctx context.Context, c *cli.Command) error {
|
|
if !c.IsSet("username") {
|
|
return errors.New("you must provide a username to generate a token for")
|
|
}
|
|
|
|
// Guarded like every other admin command: the test harness supplies its own
|
|
// database, and initDB there re-enters MustInstalled, which fatals on a tree
|
|
// that was never "installed".
|
|
if !setting.IsInTesting {
|
|
if err := initDB(ctx); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
user, err := user_model.GetUserByName(ctx, c.String("username"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// construct token with name and user so we can make sure it is unique
|
|
t := &auth_model.AccessToken{
|
|
Name: c.String("token-name"),
|
|
UID: user.ID,
|
|
}
|
|
|
|
exist, err := auth_model.AccessTokenByNameExists(ctx, t)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exist {
|
|
return errors.New("access token name has been used already")
|
|
}
|
|
|
|
// make sure the scopes are valid
|
|
accessTokenScope, err := auth_model.AccessTokenScope(c.String("scopes")).Normalize()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid access token scope provided: %w", err)
|
|
}
|
|
if !accessTokenScope.HasPermissionScope() {
|
|
return errors.New("access token does not have any permission")
|
|
}
|
|
t.Scope = accessTokenScope
|
|
|
|
// create the token
|
|
if err := auth_model.NewAccessToken(ctx, t); err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.Bool("raw") {
|
|
fmt.Printf("%s\n", t.Token)
|
|
} else {
|
|
fmt.Printf("Access token was successfully created: %s\n", t.Token)
|
|
}
|
|
|
|
return nil
|
|
}
|