Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AuthorizedKeysCommand should not query db directly #9371

Merged
merged 5 commits into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions cmd/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"fmt"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/private"

"github.com/urfave/cli"
)
Expand Down Expand Up @@ -62,14 +62,12 @@ func runKeys(c *cli.Context) error {
return errors.New("No key type and content provided")
}

if err := initDBDisableConsole(true); err != nil {
return err
}
setup("keys.log")

publicKey, err := models.SearchPublicKeyByContent(content)
authorizedString, err := private.AuthorizedPublicKeyByContent(content)
if err != nil {
return err
}
fmt.Println(publicKey.AuthorizedString())
fmt.Println(strings.TrimSpace(authorizedString))
return nil
}
1 change: 1 addition & 0 deletions docs/content/doc/usage/command-line.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ provided key. You should also set the value
NB: opensshd requires the gitea program to be owned by root and not
writable by group or others. The program must be specified by an absolute
path.
NB: Gitea must be running for this command to succeed.

#### migrate
Migrates the database. This command can be used to run other commands before starting the server for the first time.
Expand Down
81 changes: 41 additions & 40 deletions integrations/cmd_keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"bytes"
"flag"
"io"
"net/url"
"os"
"testing"

Expand All @@ -18,45 +19,45 @@ import (
)

func Test_CmdKeys(t *testing.T) {
defer prepareTestEnv(t)()
onGiteaRun(t, func(*testing.T, *url.URL) {
tests := []struct {
name string
args []string
wantErr bool
expectedOutput string
}{
{"test_empty_1", []string{"keys", "--username=git", "--type=test", "--content=test"}, true, ""},
{"test_empty_2", []string{"keys", "-e", "git", "-u", "git", "-t", "test", "-k", "test"}, true, ""},
{"with_key",
[]string{"keys", "-e", "git", "-u", "git", "-t", "ssh-rsa", "-k", "AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM="},
false,
"# gitea public key\ncommand=\"" + setting.AppPath + " --config='" + setting.CustomConf + "' serv key-1\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM= user2@localhost\n",
},
{"invalid", []string{"keys", "--not-a-flag=git"}, true, "Incorrect Usage: flag provided but not defined: -not-a-flag\n\n"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
realStdout := os.Stdout //Backup Stdout
r, w, _ := os.Pipe()
os.Stdout = w

tests := []struct {
name string
args []string
wantErr bool
expectedOutput string
}{
{"test_empty_1", []string{"keys", "--username=git", "--type=test", "--content=test"}, true, ""},
{"test_empty_2", []string{"keys", "-e", "git", "-u", "git", "-t", "test", "-k", "test"}, true, ""},
{"with_key",
[]string{"keys", "-e", "git", "-u", "git", "-t", "ssh-rsa", "-k", "AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM="},
false,
"# gitea public key\ncommand=\"" + setting.AppPath + " --config='" + setting.CustomConf + "' serv key-1\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM= user2@localhost\n\n",
},
{"invalid", []string{"keys", "--not-a-flag=git"}, true, "Incorrect Usage: flag provided but not defined: -not-a-flag\n\n"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
realStdout := os.Stdout //Backup Stdout
r, w, _ := os.Pipe()
os.Stdout = w

set := flag.NewFlagSet("keys", 0)
_ = set.Parse(tt.args)
context := cli.NewContext(&cli.App{Writer: os.Stdout}, set, nil)
err := cmd.CmdKeys.Run(context)
if (err != nil) != tt.wantErr {
t.Errorf("CmdKeys.Run() error = %v, wantErr %v", err, tt.wantErr)
}
w.Close()
var buf bytes.Buffer
io.Copy(&buf, r)
commandOutput := buf.String()
if tt.expectedOutput != commandOutput {
t.Errorf("expectedOutput: %#v, commandOutput: %#v", tt.expectedOutput, commandOutput)
}
//Restore stdout
os.Stdout = realStdout
})
}
set := flag.NewFlagSet("keys", 0)
_ = set.Parse(tt.args)
context := cli.NewContext(&cli.App{Writer: os.Stdout}, set, nil)
err := cmd.CmdKeys.Run(context)
if (err != nil) != tt.wantErr {
t.Errorf("CmdKeys.Run() error = %v, wantErr %v", err, tt.wantErr)
}
w.Close()
var buf bytes.Buffer
io.Copy(&buf, r)
commandOutput := buf.String()
if tt.expectedOutput != commandOutput {
t.Errorf("expectedOutput: %#v, commandOutput: %#v", tt.expectedOutput, commandOutput)
}
//Restore stdout
os.Stdout = realStdout
})
}
})
}
25 changes: 25 additions & 0 deletions modules/private/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package private

import (
"fmt"
"io/ioutil"
"net/http"

"code.gitea.io/gitea/modules/setting"
)
Expand All @@ -27,3 +29,26 @@ func UpdatePublicKeyInRepo(keyID, repoID int64) error {
}
return nil
}

// AuthorizedPublicKeyByContent searches content as prefix (leak e-mail part)
// and returns public key found.
func AuthorizedPublicKeyByContent(content string) (string, error) {
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/authorized_keys")
req := newInternalRequest(reqURL, "POST")
req.Param("content", content)
resp, err := req.Response()
if err != nil {
return "", err
}

defer resp.Body.Close()

// All 2XX status codes are accepted and others will return an error
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
}
bs, err := ioutil.ReadAll(resp.Body)

return string(bs), err
}
1 change: 1 addition & 0 deletions routers/private/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func CheckUnitUser(ctx *macaron.Context) {
// These APIs will be invoked by internal commands for example `gitea serv` and etc.
func RegisterRoutes(m *macaron.Macaron) {
m.Group("/", func() {
m.Post("/ssh/authorized_keys", AuthorizedPublicKeyByContent)
m.Post("/ssh/:id/update/:repoid", UpdatePublicKeyInRepo)
m.Get("/hook/pre-receive/:owner/:repo", HookPreReceive)
m.Get("/hook/post-receive/:owner/:repo", HookPostReceive)
Expand Down
25 changes: 21 additions & 4 deletions routers/private/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package private

import (
"net/http"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/timeutil"

Expand All @@ -17,7 +19,7 @@ func UpdatePublicKeyInRepo(ctx *macaron.Context) {
keyID := ctx.ParamsInt64(":id")
repoID := ctx.ParamsInt64(":repoid")
if err := models.UpdatePublicKeyUpdated(keyID); err != nil {
ctx.JSON(500, map[string]interface{}{
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
Expand All @@ -29,18 +31,33 @@ func UpdatePublicKeyInRepo(ctx *macaron.Context) {
ctx.PlainText(200, []byte("success"))
return
}
ctx.JSON(500, map[string]interface{}{
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}
deployKey.UpdatedUnix = timeutil.TimeStampNow()
if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil {
ctx.JSON(500, map[string]interface{}{
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}

ctx.PlainText(200, []byte("success"))
ctx.PlainText(http.StatusOK, []byte("success"))
}

// AuthorizedPublicKeyByContent searches content as prefix (leak e-mail part)
// and returns public key found.
func AuthorizedPublicKeyByContent(ctx *macaron.Context) {
content := ctx.Query("content")

publicKey, err := models.SearchPublicKeyByContent(content)
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}
ctx.PlainText(http.StatusOK, []byte(publicKey.AuthorizedString()))
}