Add OTP and scopes to login (#546)

Resolves #542

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/546
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: John Olheiser <john+gitea@jolheiser.com>
Co-committed-by: John Olheiser <john+gitea@jolheiser.com>
This commit is contained in:
John Olheiser
2024-02-14 16:49:29 +00:00
committed by John Olheiser
parent d15af88f83
commit c8c8e9758b
5 changed files with 89 additions and 23 deletions

View File

@ -8,6 +8,7 @@ import (
"regexp"
"strings"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/modules/task"
"github.com/AlecAivazis/survey/v2"
@ -16,8 +17,8 @@ import (
// CreateLogin create an login interactive
func CreateLogin() error {
var (
name, token, user, passwd, sshKey, giteaURL, sshCertPrincipal, sshKeyFingerprint string
insecure, sshAgent, versionCheck bool
name, token, user, passwd, otp, scopes, sshKey, giteaURL, sshCertPrincipal, sshKeyFingerprint string
insecure, sshAgent, versionCheck bool
)
versionCheck = true
@ -73,6 +74,19 @@ func CreateLogin() error {
if err = survey.AskOne(promptPW, &passwd, survey.WithValidator(survey.Required)); err != nil {
return err
}
var tokenScopes []string
promptS := &survey.MultiSelect{Message: "Token Scopes:", Options: tokenScopeOpts}
if err := survey.AskOne(promptS, &tokenScopes, survey.WithValidator(survey.Required)); err != nil {
return err
}
scopes = strings.Join(tokenScopes, ",")
// Ask for OTP last so it's less likely to timeout
promptO := &survey.Input{Message: "OTP (if applicable)"}
if err := survey.AskOne(promptO, &otp); err != nil {
return err
}
}
case "ssh-key/certificate":
promptI = &survey.Input{Message: "SSH Key/Certificate Path (leave empty for auto-discovery in ~/.ssh and ssh-agent):"}
@ -141,5 +155,40 @@ func CreateLogin() error {
}
return task.CreateLogin(name, token, user, passwd, sshKey, giteaURL, sshCertPrincipal, sshKeyFingerprint, insecure, sshAgent, versionCheck)
return task.CreateLogin(name, token, user, passwd, otp, scopes, sshKey, giteaURL, sshCertPrincipal, sshKeyFingerprint, insecure, sshAgent, versionCheck)
}
var tokenScopeOpts = []string{
string(gitea.AccessTokenScopeAll),
string(gitea.AccessTokenScopeRepo),
string(gitea.AccessTokenScopeRepoStatus),
string(gitea.AccessTokenScopePublicRepo),
string(gitea.AccessTokenScopeAdminOrg),
string(gitea.AccessTokenScopeWriteOrg),
string(gitea.AccessTokenScopeReadOrg),
string(gitea.AccessTokenScopeAdminPublicKey),
string(gitea.AccessTokenScopeWritePublicKey),
string(gitea.AccessTokenScopeReadPublicKey),
string(gitea.AccessTokenScopeAdminRepoHook),
string(gitea.AccessTokenScopeWriteRepoHook),
string(gitea.AccessTokenScopeReadRepoHook),
string(gitea.AccessTokenScopeAdminOrgHook),
string(gitea.AccessTokenScopeAdminUserHook),
string(gitea.AccessTokenScopeNotification),
string(gitea.AccessTokenScopeUser),
string(gitea.AccessTokenScopeReadUser),
string(gitea.AccessTokenScopeUserEmail),
string(gitea.AccessTokenScopeUserFollow),
string(gitea.AccessTokenScopeDeleteRepo),
string(gitea.AccessTokenScopePackage),
string(gitea.AccessTokenScopeWritePackage),
string(gitea.AccessTokenScopeReadPackage),
string(gitea.AccessTokenScopeDeletePackage),
string(gitea.AccessTokenScopeAdminGPGKey),
string(gitea.AccessTokenScopeWriteGPGKey),
string(gitea.AccessTokenScopeReadGPGKey),
string(gitea.AccessTokenScopeAdminApplication),
string(gitea.AccessTokenScopeWriteApplication),
string(gitea.AccessTokenScopeReadApplication),
string(gitea.AccessTokenScopeSudo),
}

View File

@ -6,6 +6,7 @@ package task
import (
"fmt"
"os"
"strings"
"time"
"code.gitea.io/tea/modules/config"
@ -15,7 +16,7 @@ import (
)
// CreateLogin create a login to be stored in config
func CreateLogin(name, token, user, passwd, sshKey, giteaURL, sshCertPrincipal, sshKeyFingerprint string, insecure, sshAgent, versionCheck bool) error {
func CreateLogin(name, token, user, passwd, otp, scopes, sshKey, giteaURL, sshCertPrincipal, sshKeyFingerprint string, insecure, sshAgent, versionCheck bool) error {
// checks ...
// ... if we have a url
if len(giteaURL) == 0 {
@ -68,7 +69,7 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL, sshCertPrincipal,
}
if len(token) == 0 && sshCertPrincipal == "" && !sshAgent && sshKey == "" {
if login.Token, err = generateToken(login, user, passwd); err != nil {
if login.Token, err = generateToken(login, user, passwd, otp, scopes); err != nil {
return err
}
}
@ -109,8 +110,12 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL, sshCertPrincipal,
}
// generateToken creates a new token when given BasicAuth credentials
func generateToken(login config.Login, user, pass string) (string, error) {
client := login.Client(gitea.SetBasicAuth(user, pass))
func generateToken(login config.Login, user, pass, otp, scopes string) (string, error) {
opts := []gitea.ClientOption{gitea.SetBasicAuth(user, pass)}
if otp != "" {
opts = append(opts, gitea.SetOTP(otp))
}
client := login.Client(opts...)
tl, _, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{
ListOptions: gitea.ListOptions{Page: -1},
@ -129,7 +134,15 @@ func generateToken(login config.Login, user, pass string) (string, error) {
}
}
t, _, err := client.CreateAccessToken(gitea.CreateAccessTokenOption{Name: tokenName})
var tokenScopes []gitea.AccessTokenScope
for _, scope := range strings.Split(scopes, ",") {
tokenScopes = append(tokenScopes, gitea.AccessTokenScope(strings.TrimSpace(scope)))
}
t, _, err := client.CreateAccessToken(gitea.CreateAccessTokenOption{
Name: tokenName,
Scopes: tokenScopes,
})
return t.Token, err
}