mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-10 15:32:55 +09:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b612ce42e | ||
|
|
1d8e56e6bb | ||
|
|
57ab65d922 | ||
|
|
3ac4a7fab8 | ||
|
|
253efbcb51 | ||
|
|
c8f061e15b | ||
|
|
7f7c451de4 | ||
|
|
b0b574f805 | ||
|
|
d269179523 | ||
|
|
6416f06508 | ||
|
|
1a8ab63dda | ||
|
|
477b4de0d1 | ||
|
|
849c85a2ec | ||
|
|
731275247d | ||
|
|
022634aa75 | ||
|
|
dfad569e40 | ||
|
|
c3b67ff2f6 | ||
|
|
5c30817b5f | ||
|
|
438848a2ca | ||
|
|
9d4aa78113 | ||
|
|
e5af93af20 | ||
|
|
3f802a2846 | ||
|
|
0190d3c243 | ||
|
|
4fe1a3050e | ||
|
|
29799537a7 | ||
|
|
d3a334d99a | ||
|
|
28d9305ea3 | ||
|
|
8a9f5b3b50 | ||
|
|
f28e17473c | ||
|
|
2c26521579 | ||
|
|
f635041c98 |
@@ -211,7 +211,7 @@ pipeline:
|
||||
branch: [ master ]
|
||||
|
||||
static:
|
||||
image: karalabe/xgo-latest:latest
|
||||
image: techknowlogick/xgo:latest
|
||||
pull: true
|
||||
environment:
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
|
||||
37
CHANGELOG.md
37
CHANGELOG.md
@@ -4,6 +4,43 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.7.2](https://github.com/go-gitea/gitea/releases/tag/v1.7.2) - 2019-02-14
|
||||
* BUGFIXES
|
||||
* Remove all CommitStatus when a repo is deleted (#5940) (#5941)
|
||||
* Fix notifications on pushing with deploy keys by setting hook environment variables (#5935) (#5944)
|
||||
* Silence console logger in gitea serv (#5887) (#5943)
|
||||
* Handle milestone webhook events for issues and PR (#5947) (#5955)
|
||||
* Show user who created the repository instead of the organization in action feed (#5948) (#5956)
|
||||
* Fix ssh deploy and user key constraints (#1357) (#5939) (#5966)
|
||||
* Fix bug when deleting a linked account will removed all (#5989) (#5990)
|
||||
* Fix empty ssh key importing in ldap (#5984) (#6009)
|
||||
* Fix metrics auth token detection (#6006) (#6017)
|
||||
* Create repository on organisation by default on its dashboard (#6026) (#6048)
|
||||
* Make sure labels are actually returned in API (#6053) (#6059)
|
||||
* Switch to more recent build of xgo (#6070) (#6072)
|
||||
* In basic auth check for tokens before call UserSignIn (#5725) (#6083)
|
||||
|
||||
## [1.7.1](https://github.com/go-gitea/gitea/releases/tag/v1.7.1) - 2019-01-31
|
||||
* SECURITY
|
||||
* Disable redirect for i18n (#5910) (#5916)
|
||||
* Only allow local login if password is non-empty (#5906) (#5908)
|
||||
* Fix go-get URL generation (#5905) (#5907)
|
||||
* BUGFIXES
|
||||
* Fix TLS errors when using acme/autocert for local connections (#5820) (#5826)
|
||||
* Request for public keys only if LDAP attribute is set (#5816) (#5819)
|
||||
* Fix delete correct temp directory (#5840) (#5839)
|
||||
* Fix an error while adding a dependency via UI (#5862) (#5876)
|
||||
* Fix null pointer in attempt to Sudo if not logged in (#5872) (#5884)
|
||||
* When creating new repository fsck option should be enabled (#5817) (#5885)
|
||||
* Prevent nil dereference in mailIssueCommentToParticipants (#5891) (#5895) (#5894)
|
||||
* Fix bug when read public repo lfs file (#5913) (#5912)
|
||||
* Respect value of REQUIRE_SIGNIN_VIEW (#5901) (#5915)
|
||||
* Fix compare button on upstream repo leading to 404 (#5877) (#5914)
|
||||
* DOCS
|
||||
* Added docs for the tree api (#5835)
|
||||
* MISC
|
||||
* Include Go toolchain to --version (#5832) (#5830)
|
||||
|
||||
## [1.7.0](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-22
|
||||
* SECURITY
|
||||
* Do not display the raw OpenID error in the UI (#5705) (#5712)
|
||||
|
||||
7
Gopkg.lock
generated
7
Gopkg.lock
generated
@@ -1005,12 +1005,12 @@
|
||||
version = "v1.31.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:01f4ac37c52bda6f7e1bd73680a99f88733c0408aaa159ecb1ba53a1ade9423c"
|
||||
digest = "1:7e1c00b9959544fa1ccca7cf0407a5b29ac6d5201059c4fac6f599cb99bfd24d"
|
||||
name = "gopkg.in/ldap.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "d0a5ced67b4dc310b9158d63a2c6f9c5ec13f105"
|
||||
version = "v2.4.1"
|
||||
revision = "bb7a9ca6e4fbc2129e3db588a34bc970ffe811a9"
|
||||
version = "v2.5.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cfe1730a152ff033ad7d9c115d22e36b19eec6d5928c06146b9119be45d39dc0"
|
||||
@@ -1173,6 +1173,7 @@
|
||||
"github.com/keybase/go-crypto/openpgp",
|
||||
"github.com/keybase/go-crypto/openpgp/armor",
|
||||
"github.com/keybase/go-crypto/openpgp/packet",
|
||||
"github.com/klauspost/compress/gzip",
|
||||
"github.com/lafriks/xormstore",
|
||||
"github.com/lib/pq",
|
||||
"github.com/lunny/dingtalk_webhook",
|
||||
|
||||
22
cmd/serv.go
22
cmd/serv.go
@@ -70,6 +70,7 @@ func checkLFSVersion() {
|
||||
}
|
||||
|
||||
func setup(logPath string) {
|
||||
log.DelLogger("console")
|
||||
setting.NewContext()
|
||||
checkLFSVersion()
|
||||
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
|
||||
@@ -233,23 +234,30 @@ func runServ(c *cli.Context) error {
|
||||
|
||||
// Check deploy key or user key.
|
||||
if key.Type == models.KeyTypeDeploy {
|
||||
if key.Mode < requestedMode {
|
||||
fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
|
||||
}
|
||||
|
||||
// Check if this deploy key belongs to current repository.
|
||||
has, err := private.HasDeployKey(key.ID, repo.ID)
|
||||
// Now we have to get the deploy key for this repo
|
||||
deployKey, err := private.GetDeployKey(key.ID, repo.ID)
|
||||
if err != nil {
|
||||
fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
||||
}
|
||||
if !has {
|
||||
|
||||
if deployKey == nil {
|
||||
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
if deployKey.Mode < requestedMode {
|
||||
fail("Key permission denied", "Cannot push with read-only deployment key: %d to repo_id: %d", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
// Update deploy key activity.
|
||||
if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
|
||||
fail("Internal error", "UpdateDeployKey: %v", err)
|
||||
}
|
||||
|
||||
// FIXME: Deploy keys aren't really the owner of the repo pushing changes
|
||||
// however we don't have good way of representing deploy keys in hook.go
|
||||
// so for now use the owner
|
||||
os.Setenv(models.EnvPusherName, username)
|
||||
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID))
|
||||
} else {
|
||||
user, err = private.GetUserByKeyID(key.ID)
|
||||
if err != nil {
|
||||
|
||||
152
integrations/api_helper_for_declarative_test.go
Normal file
152
integrations/api_helper_for_declarative_test.go
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type APITestContext struct {
|
||||
Reponame string
|
||||
Session *TestSession
|
||||
Token string
|
||||
Username string
|
||||
ExpectedCode int
|
||||
}
|
||||
|
||||
func NewAPITestContext(t *testing.T, username, reponame string) APITestContext {
|
||||
session := loginUser(t, username)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
return APITestContext{
|
||||
Session: session,
|
||||
Token: token,
|
||||
Username: username,
|
||||
Reponame: reponame,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx APITestContext) GitPath() string {
|
||||
return fmt.Sprintf("%s/%s.git", ctx.Username, ctx.Reponame)
|
||||
}
|
||||
|
||||
func doAPICreateRepository(ctx APITestContext, empty bool, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
createRepoOption := &api.CreateRepoOption{
|
||||
AutoInit: !empty,
|
||||
Description: "Temporary repo",
|
||||
Name: ctx.Reponame,
|
||||
Private: true,
|
||||
Gitignores: "",
|
||||
License: "WTFPL",
|
||||
Readme: "Default",
|
||||
}
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+ctx.Token, createRepoOption)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var repository api.Repository
|
||||
DecodeJSON(t, resp, &repository)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIGetRepository(ctx APITestContext, callback ...func(*testing.T, api.Repository)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repository api.Repository
|
||||
DecodeJSON(t, resp, &repository)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIDeleteRepository(ctx APITestContext) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "DELETE", urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateUserKey(ctx APITestContext, keyname, keyFile string, callback ...func(*testing.T, api.PublicKey)) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/user/keys?token=%s", ctx.Token)
|
||||
|
||||
dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
|
||||
assert.NoError(t, err)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateKeyOption{
|
||||
Title: keyname,
|
||||
Key: string(dataPubKey),
|
||||
})
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
var publicKey api.PublicKey
|
||||
DecodeJSON(t, resp, &publicKey)
|
||||
if len(callback) > 0 {
|
||||
callback[0](t, publicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAPIDeleteUserKey(ctx APITestContext, keyID int64) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/user/keys/%d?token=%s", keyID, ctx.Token)
|
||||
|
||||
req := NewRequest(t, "DELETE", urlStr)
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func doAPICreateDeployKey(ctx APITestContext, keyname, keyFile string, readOnly bool) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", ctx.Username, ctx.Reponame, ctx.Token)
|
||||
|
||||
dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
|
||||
assert.NoError(t, err)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, api.CreateKeyOption{
|
||||
Title: keyname,
|
||||
Key: string(dataPubKey),
|
||||
ReadOnly: readOnly,
|
||||
})
|
||||
|
||||
if ctx.ExpectedCode != 0 {
|
||||
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
|
||||
return
|
||||
}
|
||||
ctx.Session.MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
}
|
||||
127
integrations/git_helper_for_declarative_test.go
Normal file
127
integrations/git_helper_for_declarative_test.go
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func withKeyFile(t *testing.T, keyname string, callback func(string)) {
|
||||
keyFile := filepath.Join(setting.AppDataPath, keyname)
|
||||
err := exec.Command("ssh-keygen", "-f", keyFile, "-t", "rsa", "-N", "").Run()
|
||||
assert.NoError(t, err)
|
||||
|
||||
//Setup ssh wrapper
|
||||
os.Setenv("GIT_SSH_COMMAND",
|
||||
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
|
||||
filepath.Join(setting.AppWorkPath, keyFile))
|
||||
os.Setenv("GIT_SSH_VARIANT", "ssh")
|
||||
|
||||
callback(keyFile)
|
||||
|
||||
defer os.RemoveAll(keyFile)
|
||||
defer os.RemoveAll(keyFile + ".pub")
|
||||
}
|
||||
|
||||
func createSSHUrl(gitPath string, u *url.URL) *url.URL {
|
||||
u2 := *u
|
||||
u2.Scheme = "ssh"
|
||||
u2.User = url.User("git")
|
||||
u2.Host = fmt.Sprintf("%s:%d", setting.SSH.ListenHost, setting.SSH.ListenPort)
|
||||
u2.Path = gitPath
|
||||
return &u2
|
||||
}
|
||||
|
||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) {
|
||||
prepareTestEnv(t)
|
||||
s := http.Server{
|
||||
Handler: mac,
|
||||
}
|
||||
|
||||
u, err := url.Parse(setting.AppURL)
|
||||
assert.NoError(t, err)
|
||||
listener, err := net.Listen("tcp", u.Host)
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
s.Shutdown(ctx)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
go s.Serve(listener)
|
||||
//Started by config go ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
|
||||
|
||||
callback(t, u)
|
||||
}
|
||||
|
||||
func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
assert.NoError(t, git.Clone(u.String(), dstLocalPath, git.CloneRepoOptions{}))
|
||||
assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md")))
|
||||
}
|
||||
}
|
||||
|
||||
func doGitCloneFail(dstLocalPath string, u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
assert.Error(t, git.Clone(u.String(), dstLocalPath, git.CloneRepoOptions{}))
|
||||
assert.False(t, com.IsExist(filepath.Join(dstLocalPath, "README.md")))
|
||||
}
|
||||
}
|
||||
|
||||
func doGitInitTestRepository(dstPath string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// Init repository in dstPath
|
||||
assert.NoError(t, git.InitRepository(dstPath, false))
|
||||
assert.NoError(t, ioutil.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0644))
|
||||
assert.NoError(t, git.AddChanges(dstPath, true))
|
||||
signature := git.Signature{
|
||||
Email: "test@example.com",
|
||||
Name: "test",
|
||||
When: time.Now(),
|
||||
}
|
||||
assert.NoError(t, git.CommitChanges(dstPath, git.CommitChangesOptions{
|
||||
Committer: &signature,
|
||||
Author: &signature,
|
||||
Message: "Initial Commit",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, err := git.NewCommand("remote", "add", remoteName, u.String()).RunInDir(dstPath)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitPushTestRepository(dstPath, remoteName, branch string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, err := git.NewCommand("push", "-u", remoteName, branch).RunInDir(dstPath)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doGitPushTestRepositoryFail(dstPath, remoteName, branch string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, err := git.NewCommand("push", "-u", remoteName, branch).RunInDir(dstPath)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
@@ -5,25 +5,17 @@
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/git"
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -32,69 +24,32 @@ const (
|
||||
bigSize = 128 * 1024 * 1024 //128Mo
|
||||
)
|
||||
|
||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) {
|
||||
prepareTestEnv(t)
|
||||
s := http.Server{
|
||||
Handler: mac,
|
||||
}
|
||||
|
||||
u, err := url.Parse(setting.AppURL)
|
||||
assert.NoError(t, err)
|
||||
listener, err := net.Listen("tcp", u.Host)
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
s.Shutdown(ctx)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
go s.Serve(listener)
|
||||
//Started by config go ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
|
||||
|
||||
callback(t, u)
|
||||
}
|
||||
|
||||
func TestGit(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
u.Path = "user2/repo1.git"
|
||||
onGiteaRun(t, testGit)
|
||||
}
|
||||
|
||||
func testGit(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1")
|
||||
|
||||
u.Path = baseAPITestContext.GitPath()
|
||||
|
||||
t.Run("HTTP", func(t *testing.T) {
|
||||
dstPath, err := ioutil.TempDir("", "repo-tmp-17")
|
||||
httpContext := baseAPITestContext
|
||||
httpContext.Reponame = "repo-tmp-17"
|
||||
|
||||
dstPath, err := ioutil.TempDir("", httpContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstPath)
|
||||
t.Run("Standard", func(t *testing.T) {
|
||||
t.Run("CloneNoLogin", func(t *testing.T) {
|
||||
dstLocalPath, err := ioutil.TempDir("", "repo1")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstLocalPath)
|
||||
err = git.Clone(u.String(), dstLocalPath, git.CloneRepoOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md")))
|
||||
})
|
||||
ensureAnonymousClone(t, u)
|
||||
|
||||
t.Run("CreateRepo", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
|
||||
AutoInit: true,
|
||||
Description: "Temporary repo",
|
||||
Name: "repo-tmp-17",
|
||||
Private: false,
|
||||
Gitignores: "",
|
||||
License: "WTFPL",
|
||||
Readme: "Default",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
})
|
||||
t.Run("CreateRepo", doAPICreateRepository(httpContext, false))
|
||||
|
||||
u.Path = "user2/repo-tmp-17.git"
|
||||
u.User = url.UserPassword("user2", userPassword)
|
||||
t.Run("Clone", func(t *testing.T) {
|
||||
err = git.Clone(u.String(), dstPath, git.CloneRepoOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
|
||||
})
|
||||
u.Path = httpContext.GitPath()
|
||||
u.User = url.UserPassword(username, userPassword)
|
||||
|
||||
t.Run("Clone", doGitClone(dstPath, u))
|
||||
|
||||
t.Run("PushCommit", func(t *testing.T) {
|
||||
t.Run("Little", func(t *testing.T) {
|
||||
@@ -128,64 +83,27 @@ func TestGit(t *testing.T) {
|
||||
})
|
||||
})
|
||||
t.Run("SSH", func(t *testing.T) {
|
||||
sshContext := baseAPITestContext
|
||||
sshContext.Reponame = "repo-tmp-18"
|
||||
keyname := "my-testing-key"
|
||||
//Setup key the user ssh key
|
||||
withKeyFile(t, keyname, func(keyFile string) {
|
||||
t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile))
|
||||
|
||||
//Setup remote link
|
||||
u.Scheme = "ssh"
|
||||
u.User = url.User("git")
|
||||
u.Host = fmt.Sprintf("%s:%d", setting.SSH.ListenHost, setting.SSH.ListenPort)
|
||||
u.Path = "user2/repo-tmp-18.git"
|
||||
|
||||
//Setup key
|
||||
keyFile := filepath.Join(setting.AppDataPath, "my-testing-key")
|
||||
err := exec.Command("ssh-keygen", "-f", keyFile, "-t", "rsa", "-N", "").Run()
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(keyFile)
|
||||
defer os.RemoveAll(keyFile + ".pub")
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token)
|
||||
|
||||
dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
|
||||
assert.NoError(t, err)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"key": string(dataPubKey),
|
||||
"title": "test-key",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
//Setup ssh wrapper
|
||||
os.Setenv("GIT_SSH_COMMAND",
|
||||
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
|
||||
filepath.Join(setting.AppWorkPath, keyFile))
|
||||
os.Setenv("GIT_SSH_VARIANT", "ssh")
|
||||
sshURL := createSSHUrl(sshContext.GitPath(), u)
|
||||
|
||||
//Setup clone folder
|
||||
dstPath, err := ioutil.TempDir("", "repo-tmp-18")
|
||||
dstPath, err := ioutil.TempDir("", sshContext.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstPath)
|
||||
|
||||
t.Run("Standard", func(t *testing.T) {
|
||||
t.Run("CreateRepo", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
|
||||
AutoInit: true,
|
||||
Description: "Temporary repo",
|
||||
Name: "repo-tmp-18",
|
||||
Private: false,
|
||||
Gitignores: "",
|
||||
License: "WTFPL",
|
||||
Readme: "Default",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusCreated)
|
||||
})
|
||||
t.Run("CreateRepo", doAPICreateRepository(sshContext, false))
|
||||
|
||||
//TODO get url from api
|
||||
t.Run("Clone", func(t *testing.T) {
|
||||
_, err = git.NewCommand("clone").AddArguments(u.String(), dstPath).Run()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
|
||||
})
|
||||
t.Run("Clone", doGitClone(dstPath, sshURL))
|
||||
|
||||
//time.Sleep(5 * time.Minute)
|
||||
t.Run("PushCommit", func(t *testing.T) {
|
||||
t.Run("Little", func(t *testing.T) {
|
||||
@@ -217,10 +135,20 @@ func TestGit(t *testing.T) {
|
||||
lockTest(t, u.String(), dstPath)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func ensureAnonymousClone(t *testing.T, u *url.URL) {
|
||||
dstLocalPath, err := ioutil.TempDir("", "repo1")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstLocalPath)
|
||||
t.Run("CloneAnonymous", doGitClone(dstLocalPath, u))
|
||||
|
||||
}
|
||||
|
||||
func lockTest(t *testing.T, remote, repoPath string) {
|
||||
_, err := git.NewCommand("remote").AddArguments("set-url", "origin", remote).RunInDir(repoPath) //TODO add test ssh git-lfs-creds
|
||||
assert.NoError(t, err)
|
||||
|
||||
217
integrations/ssh_key_test.go
Normal file
217
integrations/ssh_key_test.go
Normal file
@@ -0,0 +1,217 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/git"
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func doCheckRepositoryEmptyStatus(ctx APITestContext, isEmpty bool) func(*testing.T) {
|
||||
return doAPIGetRepository(ctx, func(t *testing.T, repository api.Repository) {
|
||||
assert.Equal(t, isEmpty, repository.Empty)
|
||||
})
|
||||
}
|
||||
|
||||
func doAddChangesToCheckout(dstPath, filename string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
assert.NoError(t, ioutil.WriteFile(filepath.Join(dstPath, filename), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s at time: %v", dstPath, time.Now())), 0644))
|
||||
assert.NoError(t, git.AddChanges(dstPath, true))
|
||||
signature := git.Signature{
|
||||
Email: "test@example.com",
|
||||
Name: "test",
|
||||
When: time.Now(),
|
||||
}
|
||||
assert.NoError(t, git.CommitChanges(dstPath, git.CommitChangesOptions{
|
||||
Committer: &signature,
|
||||
Author: &signature,
|
||||
Message: "Initial Commit",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushDeployKeyOnEmptyRepo(t *testing.T) {
|
||||
onGiteaRun(t, testPushDeployKeyOnEmptyRepo)
|
||||
}
|
||||
|
||||
func testPushDeployKeyOnEmptyRepo(t *testing.T, u *url.URL) {
|
||||
// OK login
|
||||
ctx := NewAPITestContext(t, "user2", "deploy-key-empty-repo-1")
|
||||
keyname := fmt.Sprintf("%s-push", ctx.Reponame)
|
||||
u.Path = ctx.GitPath()
|
||||
|
||||
t.Run("CreateEmptyRepository", doAPICreateRepository(ctx, true))
|
||||
|
||||
t.Run("CheckIsEmpty", doCheckRepositoryEmptyStatus(ctx, true))
|
||||
|
||||
withKeyFile(t, keyname, func(keyFile string) {
|
||||
t.Run("CreatePushDeployKey", doAPICreateDeployKey(ctx, keyname, keyFile, false))
|
||||
|
||||
// Setup the testing repository
|
||||
dstPath, err := ioutil.TempDir("", "repo-tmp-deploy-key-empty-repo-1")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstPath)
|
||||
|
||||
t.Run("InitTestRepository", doGitInitTestRepository(dstPath))
|
||||
|
||||
//Setup remote link
|
||||
sshURL := createSSHUrl(ctx.GitPath(), u)
|
||||
|
||||
t.Run("AddRemote", doGitAddRemote(dstPath, "origin", sshURL))
|
||||
|
||||
t.Run("SSHPushTestRepository", doGitPushTestRepository(dstPath, "origin", "master"))
|
||||
|
||||
t.Run("CheckIsNotEmpty", doCheckRepositoryEmptyStatus(ctx, false))
|
||||
|
||||
t.Run("DeleteRepository", doAPIDeleteRepository(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
func TestKeyOnlyOneType(t *testing.T) {
|
||||
onGiteaRun(t, testKeyOnlyOneType)
|
||||
}
|
||||
|
||||
func testKeyOnlyOneType(t *testing.T, u *url.URL) {
|
||||
// Once a key is a user key we cannot use it as a deploy key
|
||||
// If we delete it from the user we should be able to use it as a deploy key
|
||||
reponame := "ssh-key-test-repo"
|
||||
username := "user2"
|
||||
u.Path = fmt.Sprintf("%s/%s.git", username, reponame)
|
||||
keyname := fmt.Sprintf("%s-push", reponame)
|
||||
|
||||
// OK login
|
||||
ctx := NewAPITestContext(t, username, reponame)
|
||||
|
||||
otherCtx := ctx
|
||||
otherCtx.Reponame = "ssh-key-test-repo-2"
|
||||
|
||||
failCtx := ctx
|
||||
failCtx.ExpectedCode = http.StatusUnprocessableEntity
|
||||
|
||||
t.Run("CreateRepository", doAPICreateRepository(ctx, false))
|
||||
t.Run("CreateOtherRepository", doAPICreateRepository(otherCtx, false))
|
||||
|
||||
withKeyFile(t, keyname, func(keyFile string) {
|
||||
var userKeyPublicKeyID int64
|
||||
t.Run("KeyCanOnlyBeUser", func(t *testing.T) {
|
||||
dstPath, err := ioutil.TempDir("", ctx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstPath)
|
||||
|
||||
sshURL := createSSHUrl(ctx.GitPath(), u)
|
||||
|
||||
t.Run("FailToClone", doGitCloneFail(dstPath, sshURL))
|
||||
|
||||
t.Run("CreateUserKey", doAPICreateUserKey(ctx, keyname, keyFile, func(t *testing.T, publicKey api.PublicKey) {
|
||||
userKeyPublicKeyID = publicKey.ID
|
||||
}))
|
||||
|
||||
t.Run("FailToAddReadOnlyDeployKey", doAPICreateDeployKey(failCtx, keyname, keyFile, true))
|
||||
|
||||
t.Run("FailToAddDeployKey", doAPICreateDeployKey(failCtx, keyname, keyFile, false))
|
||||
|
||||
t.Run("Clone", doGitClone(dstPath, sshURL))
|
||||
|
||||
t.Run("AddChanges", doAddChangesToCheckout(dstPath, "CHANGES1.md"))
|
||||
|
||||
t.Run("Push", doGitPushTestRepository(dstPath, "origin", "master"))
|
||||
|
||||
t.Run("DeleteUserKey", doAPIDeleteUserKey(ctx, userKeyPublicKeyID))
|
||||
})
|
||||
|
||||
t.Run("KeyCanBeAnyDeployButNotUserAswell", func(t *testing.T) {
|
||||
dstPath, err := ioutil.TempDir("", ctx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstPath)
|
||||
|
||||
sshURL := createSSHUrl(ctx.GitPath(), u)
|
||||
|
||||
t.Run("FailToClone", doGitCloneFail(dstPath, sshURL))
|
||||
|
||||
// Should now be able to add...
|
||||
t.Run("AddReadOnlyDeployKey", doAPICreateDeployKey(ctx, keyname, keyFile, true))
|
||||
|
||||
t.Run("Clone", doGitClone(dstPath, sshURL))
|
||||
|
||||
t.Run("AddChanges", doAddChangesToCheckout(dstPath, "CHANGES2.md"))
|
||||
|
||||
t.Run("FailToPush", doGitPushTestRepositoryFail(dstPath, "origin", "master"))
|
||||
|
||||
otherSSHURL := createSSHUrl(otherCtx.GitPath(), u)
|
||||
dstOtherPath, err := ioutil.TempDir("", otherCtx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstOtherPath)
|
||||
|
||||
t.Run("AddWriterDeployKeyToOther", doAPICreateDeployKey(otherCtx, keyname, keyFile, false))
|
||||
|
||||
t.Run("CloneOther", doGitClone(dstOtherPath, otherSSHURL))
|
||||
|
||||
t.Run("AddChangesToOther", doAddChangesToCheckout(dstOtherPath, "CHANGES3.md"))
|
||||
|
||||
t.Run("PushToOther", doGitPushTestRepository(dstOtherPath, "origin", "master"))
|
||||
|
||||
t.Run("FailToCreateUserKey", doAPICreateUserKey(failCtx, keyname, keyFile))
|
||||
})
|
||||
|
||||
t.Run("DeleteRepositoryShouldReleaseKey", func(t *testing.T) {
|
||||
otherSSHURL := createSSHUrl(otherCtx.GitPath(), u)
|
||||
dstOtherPath, err := ioutil.TempDir("", otherCtx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstOtherPath)
|
||||
|
||||
t.Run("DeleteRepository", doAPIDeleteRepository(ctx))
|
||||
|
||||
t.Run("FailToCreateUserKeyAsStillDeploy", doAPICreateUserKey(failCtx, keyname, keyFile))
|
||||
|
||||
t.Run("MakeSureCloneOtherStillWorks", doGitClone(dstOtherPath, otherSSHURL))
|
||||
|
||||
t.Run("AddChangesToOther", doAddChangesToCheckout(dstOtherPath, "CHANGES3.md"))
|
||||
|
||||
t.Run("PushToOther", doGitPushTestRepository(dstOtherPath, "origin", "master"))
|
||||
|
||||
t.Run("DeleteOtherRepository", doAPIDeleteRepository(otherCtx))
|
||||
|
||||
t.Run("RecreateRepository", doAPICreateRepository(ctx, false))
|
||||
|
||||
t.Run("CreateUserKey", doAPICreateUserKey(ctx, keyname, keyFile, func(t *testing.T, publicKey api.PublicKey) {
|
||||
userKeyPublicKeyID = publicKey.ID
|
||||
}))
|
||||
|
||||
dstPath, err := ioutil.TempDir("", ctx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstPath)
|
||||
|
||||
sshURL := createSSHUrl(ctx.GitPath(), u)
|
||||
|
||||
t.Run("Clone", doGitClone(dstPath, sshURL))
|
||||
|
||||
t.Run("AddChanges", doAddChangesToCheckout(dstPath, "CHANGES1.md"))
|
||||
|
||||
t.Run("Push", doGitPushTestRepository(dstPath, "origin", "master"))
|
||||
})
|
||||
|
||||
t.Run("DeleteUserKeyShouldRemoveAbilityToClone", func(t *testing.T) {
|
||||
dstPath, err := ioutil.TempDir("", ctx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dstPath)
|
||||
|
||||
sshURL := createSSHUrl(ctx.GitPath(), u)
|
||||
|
||||
t.Run("DeleteUserKey", doAPIDeleteUserKey(ctx, userKeyPublicKeyID))
|
||||
|
||||
t.Run("FailToClone", doGitCloneFail(dstPath, sshURL))
|
||||
})
|
||||
})
|
||||
}
|
||||
5
main.go
5
main.go
@@ -8,6 +8,7 @@ package main // import "code.gitea.io/gitea"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/cmd"
|
||||
@@ -61,8 +62,8 @@ arguments - which can alternatively be run by running the subcommand web.`
|
||||
|
||||
func formatBuiltWith(Tags string) string {
|
||||
if len(Tags) == 0 {
|
||||
return ""
|
||||
return " built with " + runtime.Version()
|
||||
}
|
||||
|
||||
return " built with: " + strings.Replace(Tags, " ", ", ", -1)
|
||||
return " built with " + runtime.Version() + " : " + strings.Replace(Tags, " ", ", ", -1)
|
||||
}
|
||||
|
||||
@@ -748,6 +748,9 @@ func createIssueDependencyComment(e *xorm.Session, doer *User, issue *Issue, dep
|
||||
if !add {
|
||||
cType = CommentTypeRemoveDependency
|
||||
}
|
||||
if err = issue.loadRepo(e); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Make two comments, one in each issue
|
||||
_, err = createComment(e, &CreateCommentOptions{
|
||||
|
||||
@@ -19,11 +19,9 @@ func TestCreateIssueDependency(t *testing.T) {
|
||||
|
||||
issue1, err := GetIssueByID(1)
|
||||
assert.NoError(t, err)
|
||||
issue1.LoadAttributes()
|
||||
|
||||
issue2, err := GetIssueByID(2)
|
||||
assert.NoError(t, err)
|
||||
issue2.LoadAttributes()
|
||||
|
||||
// Create a dependency and check if it was successful
|
||||
err = CreateIssueDependency(user1, issue1, issue2)
|
||||
|
||||
@@ -39,11 +39,11 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
|
||||
|
||||
// In case the issue poster is not watching the repository and is active,
|
||||
// even if we have duplicated in watchers, can be safely filtered out.
|
||||
poster, err := getUserByID(e, issue.PosterID)
|
||||
err = issue.loadPoster(e)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
|
||||
}
|
||||
if issue.PosterID != doer.ID && poster.IsActive && !poster.ProhibitLogin {
|
||||
if issue.PosterID != doer.ID && issue.Poster.IsActive && !issue.Poster.ProhibitLogin {
|
||||
participants = append(participants, issue.Poster)
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
|
||||
names = append(names, participants[i].Name)
|
||||
}
|
||||
|
||||
if err := issue.loadRepo(e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, to := range tos {
|
||||
SendIssueCommentMail(issue, doer, content, comment, []string{to})
|
||||
}
|
||||
|
||||
@@ -644,7 +644,7 @@ func UserSignIn(username, password string) (*User, error) {
|
||||
if hasUser {
|
||||
switch user.LoginType {
|
||||
case LoginNoType, LoginPlain, LoginOAuth2:
|
||||
if user.ValidatePassword(password) {
|
||||
if user.IsPasswordSet() && user.ValidatePassword(password) {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
||||
return fmt.Errorf("Failed to create dir %s: %v", tmpBasePath, err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(path.Dir(tmpBasePath))
|
||||
defer os.RemoveAll(tmpBasePath)
|
||||
|
||||
var stderr string
|
||||
if _, stderr, err = process.GetManager().ExecTimeout(5*time.Minute,
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -34,8 +35,8 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/builder"
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/mcuadros/go-version"
|
||||
"gopkg.in/ini.v1"
|
||||
version "github.com/mcuadros/go-version"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
var repoWorkingPool = sync.NewExclusivePool()
|
||||
@@ -824,7 +825,7 @@ type CloneLink struct {
|
||||
|
||||
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
|
||||
func ComposeHTTPSCloneURL(owner, repo string) string {
|
||||
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, owner, repo)
|
||||
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.QueryEscape(owner), url.QueryEscape(repo))
|
||||
}
|
||||
|
||||
func (repo *Repository) cloneLink(e Engine, isWiki bool) *CloneLink {
|
||||
@@ -1345,14 +1346,14 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
|
||||
|
||||
if err = watchRepo(e, doer.ID, repo.ID, true); err != nil {
|
||||
return fmt.Errorf("watchRepo: %v", err)
|
||||
} else if err = newRepoAction(e, u, repo); err != nil {
|
||||
} else if err = newRepoAction(e, doer, repo); err != nil {
|
||||
return fmt.Errorf("newRepoAction: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateRepository creates a repository for the user/organization u.
|
||||
// CreateRepository creates a repository for the user/organization.
|
||||
func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err error) {
|
||||
if !doer.IsAdmin && !u.CanCreateRepo() {
|
||||
return nil, ErrReachLimitOfRepo{u.MaxRepoCreation}
|
||||
@@ -1365,6 +1366,7 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
|
||||
LowerName: strings.ToLower(opts.Name),
|
||||
Description: opts.Description,
|
||||
IsPrivate: opts.IsPrivate,
|
||||
IsFsckEnabled: true,
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
@@ -1741,6 +1743,17 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||
return ErrRepoNotExist{repoID, uid, "", ""}
|
||||
}
|
||||
|
||||
// Delete Deploy Keys
|
||||
deployKeys, err := listDeployKeys(sess, repo.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listDeployKeys: %v", err)
|
||||
}
|
||||
for _, dKey := range deployKeys {
|
||||
if err := deleteDeployKey(sess, doer, dKey.ID); err != nil {
|
||||
return fmt.Errorf("deleteDeployKeys: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if cnt, err := sess.ID(repoID).Delete(&Repository{}); err != nil {
|
||||
return err
|
||||
} else if cnt != 1 {
|
||||
@@ -1772,6 +1785,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||
&Webhook{RepoID: repoID},
|
||||
&HookTask{RepoID: repoID},
|
||||
&Notification{RepoID: repoID},
|
||||
&CommitStatus{RepoID: repoID},
|
||||
); err != nil {
|
||||
return fmt.Errorf("deleteBeans: %v", err)
|
||||
}
|
||||
@@ -1882,6 +1896,12 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||
}
|
||||
|
||||
if err = sess.Commit(); err != nil {
|
||||
if len(deployKeys) > 0 {
|
||||
// We need to rewrite the public keys because the commit failed
|
||||
if err2 := RewriteAllPublicKeys(); err2 != nil {
|
||||
return fmt.Errorf("Commit: %v SSH Keys: %v", err, err2)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Commit: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ type PublicKey struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||
Name string `xorm:"NOT NULL"`
|
||||
Fingerprint string `xorm:"NOT NULL"`
|
||||
Fingerprint string `xorm:"INDEX NOT NULL"`
|
||||
Content string `xorm:"TEXT NOT NULL"`
|
||||
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
||||
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
||||
@@ -350,7 +350,6 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
|
||||
func checkKeyFingerprint(e Engine, fingerprint string) error {
|
||||
has, err := e.Get(&PublicKey{
|
||||
Fingerprint: fingerprint,
|
||||
Type: KeyTypeUser,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -401,12 +400,18 @@ func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*Pu
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkKeyFingerprint(x, fingerprint); err != nil {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err = sess.Begin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkKeyFingerprint(sess, fingerprint); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Key name of same user cannot be duplicated.
|
||||
has, err := x.
|
||||
has, err := sess.
|
||||
Where("owner_id = ? AND name = ?", ownerID, name).
|
||||
Get(new(PublicKey))
|
||||
if err != nil {
|
||||
@@ -415,12 +420,6 @@ func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*Pu
|
||||
return nil, ErrKeyNameAlreadyUsed{ownerID, name}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err = sess.Begin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := &PublicKey{
|
||||
OwnerID: ownerID,
|
||||
Name: name,
|
||||
@@ -519,7 +518,7 @@ func UpdatePublicKeyUpdated(id int64) error {
|
||||
}
|
||||
|
||||
// deletePublicKeys does the actual key deletion but does not update authorized_keys file.
|
||||
func deletePublicKeys(e *xorm.Session, keyIDs ...int64) error {
|
||||
func deletePublicKeys(e Engine, keyIDs ...int64) error {
|
||||
if len(keyIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -728,24 +727,28 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey
|
||||
accessMode = AccessModeWrite
|
||||
}
|
||||
|
||||
pkey := &PublicKey{
|
||||
Fingerprint: fingerprint,
|
||||
Mode: accessMode,
|
||||
Type: KeyTypeDeploy,
|
||||
}
|
||||
has, err := x.Get(pkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err = sess.Begin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkey := &PublicKey{
|
||||
Fingerprint: fingerprint,
|
||||
}
|
||||
has, err := sess.Get(pkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if has {
|
||||
if pkey.Type != KeyTypeDeploy {
|
||||
return nil, ErrKeyAlreadyExist{0, fingerprint, ""}
|
||||
}
|
||||
} else {
|
||||
// First time use this deploy key.
|
||||
if !has {
|
||||
pkey.Mode = accessMode
|
||||
pkey.Type = KeyTypeDeploy
|
||||
pkey.Content = content
|
||||
pkey.Name = name
|
||||
if err = addKey(sess, pkey); err != nil {
|
||||
@@ -763,8 +766,12 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey
|
||||
|
||||
// GetDeployKeyByID returns deploy key by given ID.
|
||||
func GetDeployKeyByID(id int64) (*DeployKey, error) {
|
||||
return getDeployKeyByID(x, id)
|
||||
}
|
||||
|
||||
func getDeployKeyByID(e Engine, id int64) (*DeployKey, error) {
|
||||
key := new(DeployKey)
|
||||
has, err := x.ID(id).Get(key)
|
||||
has, err := e.ID(id).Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@@ -775,11 +782,15 @@ func GetDeployKeyByID(id int64) (*DeployKey, error) {
|
||||
|
||||
// GetDeployKeyByRepo returns deploy key by given public key ID and repository ID.
|
||||
func GetDeployKeyByRepo(keyID, repoID int64) (*DeployKey, error) {
|
||||
return getDeployKeyByRepo(x, keyID, repoID)
|
||||
}
|
||||
|
||||
func getDeployKeyByRepo(e Engine, keyID, repoID int64) (*DeployKey, error) {
|
||||
key := &DeployKey{
|
||||
KeyID: keyID,
|
||||
RepoID: repoID,
|
||||
}
|
||||
has, err := x.Get(key)
|
||||
has, err := e.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@@ -802,7 +813,19 @@ func UpdateDeployKey(key *DeployKey) error {
|
||||
|
||||
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
|
||||
func DeleteDeployKey(doer *User, id int64) error {
|
||||
key, err := GetDeployKeyByID(id)
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deleteDeployKey(sess, doer, id); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func deleteDeployKey(sess Engine, doer *User, id int64) error {
|
||||
key, err := getDeployKeyByID(sess, id)
|
||||
if err != nil {
|
||||
if IsErrDeployKeyNotExist(err) {
|
||||
return nil
|
||||
@@ -812,11 +835,11 @@ func DeleteDeployKey(doer *User, id int64) error {
|
||||
|
||||
// Check if user has access to delete this key.
|
||||
if !doer.IsAdmin {
|
||||
repo, err := GetRepositoryByID(key.RepoID)
|
||||
repo, err := getRepositoryByID(sess, key.RepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByID: %v", err)
|
||||
}
|
||||
has, err := IsUserRepoAdmin(repo, doer)
|
||||
has, err := isUserRepoAdmin(sess, repo, doer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserRepoPermission: %v", err)
|
||||
} else if !has {
|
||||
@@ -824,12 +847,6 @@ func DeleteDeployKey(doer *User, id int64) error {
|
||||
}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.ID(key.ID).Delete(new(DeployKey)); err != nil {
|
||||
return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err)
|
||||
}
|
||||
@@ -851,13 +868,17 @@ func DeleteDeployKey(doer *User, id int64) error {
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListDeployKeys returns all deploy keys by given repository ID.
|
||||
func ListDeployKeys(repoID int64) ([]*DeployKey, error) {
|
||||
return listDeployKeys(x, repoID)
|
||||
}
|
||||
|
||||
func listDeployKeys(e Engine, repoID int64) ([]*DeployKey, error) {
|
||||
keys := make([]*DeployKey, 0, 5)
|
||||
return keys, x.
|
||||
return keys, e.
|
||||
Where("repo_id = ?", repoID).
|
||||
Find(&keys)
|
||||
}
|
||||
|
||||
@@ -1461,11 +1461,14 @@ func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []str
|
||||
// Get Public Keys from LDAP and skip duplicate keys
|
||||
var ldapKeys []string
|
||||
for _, v := range SSHPublicKeys {
|
||||
ldapKey := strings.Join(strings.Split(v, " ")[:2], " ")
|
||||
sshKeySplit := strings.Split(v, " ")
|
||||
if len(sshKeySplit) > 1 {
|
||||
ldapKey := strings.Join(sshKeySplit[:2], " ")
|
||||
if !util.ExistsInSlice(ldapKey, ldapKeys) {
|
||||
ldapKeys = append(ldapKeys, ldapKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if Public Key sync is needed
|
||||
if util.IsEqualSlice(giteaKeys, ldapKeys) {
|
||||
|
||||
@@ -160,6 +160,10 @@ func getSlackIssuesPayload(p *api.IssuePayload, slack *SlackMeta) (*SlackPayload
|
||||
text = fmt.Sprintf("[%s] Issue labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HookIssueSynchronized:
|
||||
text = fmt.Sprintf("[%s] Issue synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HookIssueMilestoned:
|
||||
text = fmt.Sprintf("[%s] Issue milestoned: #%s %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HookIssueDemilestoned:
|
||||
text = fmt.Sprintf("[%s] Issue milestone cleared: #%s %s", p.Repository.FullName, titleLink, senderLink)
|
||||
}
|
||||
|
||||
return &SlackPayload{
|
||||
@@ -312,6 +316,10 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
|
||||
text = fmt.Sprintf("[%s] Pull request labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HookIssueSynchronized:
|
||||
text = fmt.Sprintf("[%s] Pull request synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HookIssueMilestoned:
|
||||
text = fmt.Sprintf("[%s] Pull request milestoned: #%s %s", p.Repository.FullName, titleLink, senderLink)
|
||||
case api.HookIssueDemilestoned:
|
||||
text = fmt.Sprintf("[%s] Pull request milestone cleared: #%s %s", p.Repository.FullName, titleLink, senderLink)
|
||||
}
|
||||
|
||||
return &SlackPayload{
|
||||
|
||||
@@ -135,15 +135,56 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
if len(baHead) > 0 {
|
||||
auths := strings.Fields(baHead)
|
||||
if len(auths) == 2 && auths[0] == "Basic" {
|
||||
var u *models.User
|
||||
|
||||
uname, passwd, _ := base.BasicAuthDecode(auths[1])
|
||||
|
||||
u, err := models.UserSignIn(uname, passwd)
|
||||
// Check if username or password is a token
|
||||
isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic"
|
||||
// Assume username is token
|
||||
authToken := uname
|
||||
if !isUsernameToken {
|
||||
// Assume password is token
|
||||
authToken = passwd
|
||||
}
|
||||
token, err := models.GetAccessTokenBySHA(authToken)
|
||||
if err == nil {
|
||||
if isUsernameToken {
|
||||
u, err = models.GetUserByID(token.UID)
|
||||
if err != nil {
|
||||
log.Error(4, "GetUserByID: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
} else {
|
||||
u, err = models.GetUserByName(uname)
|
||||
if err != nil {
|
||||
log.Error(4, "GetUserByID: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
if u.ID != token.UID {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
token.UpdatedUnix = util.TimeStampNow()
|
||||
if err = models.UpdateAccessToken(token); err != nil {
|
||||
log.Error(4, "UpdateAccessToken: %v", err)
|
||||
}
|
||||
} else {
|
||||
if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) {
|
||||
log.Error(4, "GetAccessTokenBySha: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if u == nil {
|
||||
u, err = models.UserSignIn(uname, passwd)
|
||||
if err != nil {
|
||||
if !models.IsErrUserNotExist(err) {
|
||||
log.Error(4, "UserSignIn: %v", err)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["IsApiToken"] = true
|
||||
return u, true
|
||||
}
|
||||
|
||||
@@ -247,11 +247,17 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
|
||||
return nil
|
||||
}
|
||||
|
||||
var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
|
||||
|
||||
attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
|
||||
if isAttributeSSHPublicKeySet {
|
||||
attribs = append(attribs, ls.AttributeSSHPublicKey)
|
||||
}
|
||||
|
||||
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, userDN)
|
||||
search := ldap.NewSearchRequest(
|
||||
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
||||
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey},
|
||||
nil)
|
||||
attribs, nil)
|
||||
|
||||
sr, err := l.Search(search)
|
||||
if err != nil {
|
||||
@@ -267,11 +273,15 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
|
||||
return nil
|
||||
}
|
||||
|
||||
var sshPublicKey []string
|
||||
|
||||
username := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
|
||||
firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
|
||||
surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
|
||||
mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
|
||||
sshPublicKey := sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
|
||||
if isAttributeSSHPublicKeySet {
|
||||
sshPublicKey = sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
|
||||
}
|
||||
isAdmin := checkAdmin(l, ls, userDN)
|
||||
|
||||
if !directBind && ls.AttributesInBind {
|
||||
@@ -320,11 +330,17 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
||||
|
||||
userFilter := fmt.Sprintf(ls.Filter, "*")
|
||||
|
||||
var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
|
||||
|
||||
attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
|
||||
if isAttributeSSHPublicKeySet {
|
||||
attribs = append(attribs, ls.AttributeSSHPublicKey)
|
||||
}
|
||||
|
||||
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, ls.UserBase)
|
||||
search := ldap.NewSearchRequest(
|
||||
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
||||
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey},
|
||||
nil)
|
||||
attribs, nil)
|
||||
|
||||
var sr *ldap.SearchResult
|
||||
if ls.UsePagedSearch() {
|
||||
@@ -345,9 +361,11 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
||||
Name: v.GetAttributeValue(ls.AttributeName),
|
||||
Surname: v.GetAttributeValue(ls.AttributeSurname),
|
||||
Mail: v.GetAttributeValue(ls.AttributeMail),
|
||||
SSHPublicKey: v.GetAttributeValues(ls.AttributeSSHPublicKey),
|
||||
IsAdmin: checkAdmin(l, ls, v.DN),
|
||||
}
|
||||
if isAttributeSSHPublicKeySet {
|
||||
result[i].SSHPublicKey = v.GetAttributeValues(ls.AttributeSSHPublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
@@ -209,7 +209,7 @@ func Contexter() macaron.Handler {
|
||||
if err == nil && len(repo.DefaultBranch) > 0 {
|
||||
branchName = repo.DefaultBranch
|
||||
}
|
||||
prefix := setting.AppURL + path.Join(ownerName, repoName, "src", "branch", branchName)
|
||||
prefix := setting.AppURL + path.Join(url.QueryEscape(ownerName), url.QueryEscape(repoName), "src", "branch", branchName)
|
||||
c.Header().Set("Content-Type", "text/html")
|
||||
c.WriteHeader(http.StatusOK)
|
||||
c.Write([]byte(com.Expand(`<!doctype html>
|
||||
|
||||
@@ -8,6 +8,7 @@ package context
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@@ -162,7 +163,7 @@ func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
|
||||
|
||||
// ComposeGoGetImport returns go-get-import meta content.
|
||||
func ComposeGoGetImport(owner, repo string) string {
|
||||
return path.Join(setting.Domain, setting.AppSubURL, owner, repo)
|
||||
return path.Join(setting.Domain, setting.AppSubURL, url.QueryEscape(owner), url.QueryEscape(repo))
|
||||
}
|
||||
|
||||
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
|
||||
|
||||
@@ -497,12 +497,15 @@ func authenticate(ctx *context.Context, repository *models.Repository, authoriza
|
||||
accessMode = models.AccessModeWrite
|
||||
}
|
||||
|
||||
// ctx.IsSigned is unnecessary here, this will be checked in perm.CanAccess
|
||||
perm, err := models.GetUserRepoPermission(repository, ctx.User)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if ctx.IsSigned {
|
||||
return perm.CanAccess(accessMode, models.UnitTypeCode)
|
||||
|
||||
canRead := perm.CanAccess(accessMode, models.UnitTypeCode)
|
||||
if canRead {
|
||||
return true
|
||||
}
|
||||
|
||||
user, repo, opStr, err := parseToken(authorization)
|
||||
@@ -582,7 +585,7 @@ func parseToken(authorization string) (*models.User, *models.Repository, string,
|
||||
if err != nil {
|
||||
return nil, nil, "basic", err
|
||||
}
|
||||
if !u.ValidatePassword(password) {
|
||||
if !u.IsPasswordSet() || !u.ValidatePassword(password) {
|
||||
return nil, nil, "basic", fmt.Errorf("Basic auth failed")
|
||||
}
|
||||
return u, nil, "basic", nil
|
||||
|
||||
@@ -39,6 +39,7 @@ func decodeJSONError(resp *http.Response) *Response {
|
||||
func newInternalRequest(url, method string) *httplib.Request {
|
||||
req := newRequest(url, method).SetTLSClientConfig(&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: setting.Domain,
|
||||
})
|
||||
if setting.Protocol == setting.UnixSocket {
|
||||
req.SetTransport(&http.Transport{
|
||||
|
||||
@@ -32,6 +32,31 @@ func UpdateDeployKeyUpdated(keyID int64, repoID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDeployKey check if repo has deploy key
|
||||
func GetDeployKey(keyID, repoID int64) (*models.DeployKey, error) {
|
||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/keys/%d", repoID, keyID)
|
||||
log.GitLogger.Trace("GetDeployKey: %s", reqURL)
|
||||
|
||||
resp, err := newInternalRequest(reqURL, "GET").Response()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case 404:
|
||||
return nil, nil
|
||||
case 200:
|
||||
var dKey models.DeployKey
|
||||
if err := json.NewDecoder(resp.Body).Decode(&dKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dKey, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Failed to get deploy key: %s", decodeJSONError(resp).Err)
|
||||
}
|
||||
}
|
||||
|
||||
// HasDeployKey check if repo has deploy key
|
||||
func HasDeployKey(keyID, repoID int64) (bool, error) {
|
||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/has-keys/%d", repoID, keyID)
|
||||
|
||||
@@ -413,7 +413,7 @@ ssh_helper = <strong>Need help?</strong> Have a look at GitHub's guide to <a hre
|
||||
gpg_helper = <strong>Need help?</strong> Have a look at GitHub's guide <a href="%s">about GPG</a>.
|
||||
add_new_key = Add SSH Key
|
||||
add_new_gpg_key = Add GPG Key
|
||||
ssh_key_been_used = This SSH key is already added to your account.
|
||||
ssh_key_been_used = This SSH key has already been added to the server.
|
||||
ssh_key_name_used = An SSH key with same name is already added to your account.
|
||||
gpg_key_id_used = A public GPG key with same ID already exists.
|
||||
gpg_no_key_email_found = This GPG key is not usable with any email address associated with your account.
|
||||
|
||||
@@ -85,7 +85,7 @@ func sudo() macaron.Handler {
|
||||
}
|
||||
|
||||
if len(sudo) > 0 {
|
||||
if ctx.User.IsAdmin {
|
||||
if ctx.IsSigned && ctx.User.IsAdmin {
|
||||
user, err := models.GetUserByName(sudo)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
|
||||
@@ -51,6 +51,11 @@ func ListIssueLabels(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := issue.LoadAttributes(); err != nil {
|
||||
ctx.Error(500, "LoadAttributes", err)
|
||||
return
|
||||
}
|
||||
|
||||
apiLabels := make([]*api.Label, len(issue.Labels))
|
||||
for i := range issue.Labels {
|
||||
apiLabels[i] = issue.Labels[i].APIFormat()
|
||||
|
||||
@@ -159,6 +159,8 @@ func HandleCheckKeyStringError(ctx *context.APIContext, err error) {
|
||||
// HandleAddKeyError handle add key error
|
||||
func HandleAddKeyError(ctx *context.APIContext, err error) {
|
||||
switch {
|
||||
case models.IsErrDeployKeyAlreadyExist(err):
|
||||
ctx.Error(422, "", "This key has already been added to this repository")
|
||||
case models.IsErrKeyAlreadyExist(err):
|
||||
ctx.Error(422, "", "Key content has been used as non-deploy key")
|
||||
case models.IsErrKeyNameAlreadyUsed(err):
|
||||
|
||||
@@ -16,6 +16,30 @@ import (
|
||||
|
||||
// GetTree get the tree of a repository.
|
||||
func GetTree(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/git/trees/{sha} repository GetTree
|
||||
// ---
|
||||
// summary: Gets the tree of a repository.
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: sha
|
||||
// in: path
|
||||
// description: sha of the commit
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/GitTreeResponse"
|
||||
sha := ctx.Params("sha")
|
||||
if len(sha) == 0 {
|
||||
ctx.Error(400, "sha not provided", nil)
|
||||
|
||||
@@ -133,3 +133,10 @@ type swaggerResponseAttachment struct {
|
||||
//in: body
|
||||
Body api.Attachment `json:"body"`
|
||||
}
|
||||
|
||||
// GitTreeResponse
|
||||
// swagger:response GitTreeResponse
|
||||
type swaggerGitTreeResponse struct {
|
||||
//in: body
|
||||
Body api.GitTreeResponse `json:"body"`
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ func Metrics(ctx *context.Context) {
|
||||
promhttp.Handler().ServeHTTP(ctx.Resp, ctx.Req.Request)
|
||||
return
|
||||
}
|
||||
header := ctx.Header().Get("Authorization")
|
||||
header := ctx.Req.Header.Get("Authorization")
|
||||
if header == "" {
|
||||
ctx.Error(401)
|
||||
return
|
||||
|
||||
@@ -82,6 +82,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Post("/repositories/:repoid/keys/:keyid/update", UpdateDeployKey)
|
||||
m.Get("/repositories/:repoid/user/:userid/checkunituser", CheckUnitUser)
|
||||
m.Get("/repositories/:repoid/has-keys/:keyid", HasDeployKey)
|
||||
m.Get("/repositories/:repoid/keys/:keyid", GetDeployKey)
|
||||
m.Get("/repositories/:repoid/wiki/init", InitWiki)
|
||||
m.Post("/push/update", PushUpdate)
|
||||
m.Get("/protectedbranch/:pbid/:userid", CanUserPush)
|
||||
|
||||
@@ -72,6 +72,24 @@ func GetUserByKeyID(ctx *macaron.Context) {
|
||||
ctx.JSON(200, user)
|
||||
}
|
||||
|
||||
//GetDeployKey chainload to models.GetDeployKey
|
||||
func GetDeployKey(ctx *macaron.Context) {
|
||||
repoID := ctx.ParamsInt64(":repoid")
|
||||
keyID := ctx.ParamsInt64(":keyid")
|
||||
dKey, err := models.GetDeployKeyByRepo(keyID, repoID)
|
||||
if err != nil {
|
||||
if models.IsErrDeployKeyNotExist(err) {
|
||||
ctx.JSON(404, []byte("not found"))
|
||||
return
|
||||
}
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"err": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.JSON(200, dKey)
|
||||
}
|
||||
|
||||
//HasDeployKey chainload to models.HasDeployKey
|
||||
func HasDeployKey(ctx *macaron.Context) {
|
||||
repoID := ctx.ParamsInt64(":repoid")
|
||||
|
||||
@@ -113,24 +113,24 @@ func HTTP(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
authUser, err = models.UserSignIn(authUsername, authPasswd)
|
||||
if err != nil {
|
||||
if !models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("UserSignIn error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if authUser == nil {
|
||||
// Check if username or password is a token
|
||||
isUsernameToken := len(authPasswd) == 0 || authPasswd == "x-oauth-basic"
|
||||
|
||||
// Assume username is token
|
||||
authToken := authUsername
|
||||
|
||||
if !isUsernameToken {
|
||||
// Assume password is token
|
||||
authToken = authPasswd
|
||||
|
||||
}
|
||||
// Assume password is a token.
|
||||
token, err := models.GetAccessTokenBySHA(authToken)
|
||||
if err == nil {
|
||||
if isUsernameToken {
|
||||
authUser, err = models.GetUserByID(token.UID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetUserByID", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
authUser, err = models.GetUserByName(authUsername)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
@@ -140,37 +140,37 @@ func HTTP(ctx *context.Context) {
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Assume password is a token.
|
||||
token, err := models.GetAccessTokenBySHA(authToken)
|
||||
if err != nil {
|
||||
if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) {
|
||||
ctx.HandleText(http.StatusUnauthorized, "invalid credentials")
|
||||
} else {
|
||||
ctx.ServerError("GetAccessTokenBySha", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if isUsernameToken {
|
||||
authUser, err = models.GetUserByID(token.UID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetUserByID", err)
|
||||
return
|
||||
}
|
||||
} else if authUser.ID != token.UID {
|
||||
if authUser.ID != token.UID {
|
||||
ctx.HandleText(http.StatusUnauthorized, "invalid credentials")
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
token.UpdatedUnix = util.TimeStampNow()
|
||||
if err = models.UpdateAccessToken(token); err != nil {
|
||||
ctx.ServerError("UpdateAccessToken", err)
|
||||
}
|
||||
} else {
|
||||
_, err = models.GetTwoFactorByUID(authUser.ID)
|
||||
if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) {
|
||||
log.Error(4, "GetAccessTokenBySha: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if authUser == nil {
|
||||
// Check username and password
|
||||
authUser, err = models.UserSignIn(authUsername, authPasswd)
|
||||
if err != nil {
|
||||
if !models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("UserSignIn error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if authUser == nil {
|
||||
ctx.HandleText(http.StatusUnauthorized, "invalid credentials")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = models.GetTwoFactorByUID(authUser.ID)
|
||||
if err == nil {
|
||||
// TODO: This response should be changed to "invalid credentials" for security reasons once the expectation behind it (creating an app token to authenticate) is properly documented
|
||||
ctx.HandleText(http.StatusUnauthorized, "Users with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password. Please create and use a personal access token on the user settings page")
|
||||
|
||||
@@ -581,6 +581,9 @@ func DeployKeysPost(ctx *context.Context, form auth.AddKeyForm) {
|
||||
case models.IsErrDeployKeyAlreadyExist(err):
|
||||
ctx.Data["Err_Content"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form)
|
||||
case models.IsErrKeyAlreadyExist(err):
|
||||
ctx.Data["Err_Content"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplDeployKeys, &form)
|
||||
case models.IsErrKeyNameAlreadyUsed(err):
|
||||
ctx.Data["Err_Title"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
|
||||
|
||||
@@ -106,7 +106,7 @@ func NewMacaron() *macaron.Macaron {
|
||||
Langs: setting.Langs,
|
||||
Names: setting.Names,
|
||||
DefaultLang: "en-US",
|
||||
Redirect: true,
|
||||
Redirect: false,
|
||||
}))
|
||||
m.Use(cache.Cacher(cache.Options{
|
||||
Adapter: setting.CacheService.Adapter,
|
||||
@@ -643,7 +643,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
}
|
||||
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
||||
})
|
||||
}, context.RepoAssignment(), context.UnitTypes(), reqRepoReleaseReader)
|
||||
}, ignSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoReleaseReader)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Post("/topics", repo.TopicsPost)
|
||||
|
||||
@@ -34,11 +34,16 @@ func Security(ctx *context.Context) {
|
||||
|
||||
// DeleteAccountLink delete a single account link
|
||||
func DeleteAccountLink(ctx *context.Context) {
|
||||
if _, err := models.RemoveAccountLink(ctx.User, ctx.QueryInt64("loginSourceID")); err != nil {
|
||||
id := ctx.QueryInt64("id")
|
||||
if id <= 0 {
|
||||
ctx.Flash.Error("Account link id is not given")
|
||||
} else {
|
||||
if _, err := models.RemoveAccountLink(ctx.User, id); err != nil {
|
||||
ctx.Flash.Error("RemoveAccountLink: " + err.Error())
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("settings.remove_account_link_success"))
|
||||
}
|
||||
}
|
||||
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"redirect": setting.AppSubURL + "/user/settings/security",
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="ui stackable secondary menu mobile--margin-between-items mobile--no-negative-margins">
|
||||
{{if and .PullRequestCtx.Allowed .IsViewBranch}}
|
||||
<div class="fitted item">
|
||||
<a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{.Repository.Owner.Name}}:{{.BranchName | EscapePound}}">
|
||||
<a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{ if .Repository.IsFork }}{{.Repository.Owner.Name}}{{ else }}{{ .SignedUserName }}{{ end }}:{{.BranchName | EscapePound}}">
|
||||
<button class="ui green tiny compact button"><i class="octicon octicon-git-compare"></i></button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1663,6 +1663,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/git/trees/{sha}": {
|
||||
"get": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"repository"
|
||||
],
|
||||
"summary": "Gets the tree of a repository.",
|
||||
"operationId": "GetTree",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "owner of the repo",
|
||||
"name": "owner",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "name of the repo",
|
||||
"name": "repo",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "sha of the commit",
|
||||
"name": "sha",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/GitTreeResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks": {
|
||||
"get": {
|
||||
"produces": [
|
||||
@@ -7040,6 +7080,38 @@
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||
},
|
||||
"GitEntry": {
|
||||
"description": "GitEntry represents a git tree",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"x-go-name": "Mode"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"x-go-name": "Path"
|
||||
},
|
||||
"sha": {
|
||||
"type": "string",
|
||||
"x-go-name": "SHA"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "Size"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"x-go-name": "Type"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"x-go-name": "URL"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||
},
|
||||
"GitObject": {
|
||||
"type": "object",
|
||||
"title": "GitObject represents a Git object.",
|
||||
@@ -7059,6 +7131,32 @@
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||
},
|
||||
"GitTreeResponse": {
|
||||
"description": "GitTreeResponse returns a git tree",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sha": {
|
||||
"type": "string",
|
||||
"x-go-name": "SHA"
|
||||
},
|
||||
"tree": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/GitEntry"
|
||||
},
|
||||
"x-go-name": "Entries"
|
||||
},
|
||||
"truncated": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "Truncated"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"x-go-name": "URL"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||
},
|
||||
"Issue": {
|
||||
"description": "Issue represents an issue in a repository",
|
||||
"type": "object",
|
||||
@@ -8200,6 +8298,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"GitTreeResponse": {
|
||||
"description": "GitTreeResponse",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/GitTreeResponse"
|
||||
}
|
||||
},
|
||||
"Hook": {
|
||||
"description": "Hook",
|
||||
"schema": {
|
||||
|
||||
@@ -44,12 +44,14 @@
|
||||
<div v-show="tab === 'repos'" class="ui tab active list dashboard-repos">
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "home.my_repos"}} <span class="ui grey label">${reposTotalCount}</span>
|
||||
{{if or (not .ContextUser.IsOrganization) .IsOrganizationOwner}}
|
||||
<div class="ui right">
|
||||
<a class="poping up" :href="suburl + '/repo/create'" data-content="{{.i18n.Tr "new_repo"}}" data-variation="tiny inverted" data-position="left center">
|
||||
<a class="poping up" :href="suburl + '/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}'" data-content="{{.i18n.Tr "new_repo"}}" data-variation="tiny inverted" data-position="left center">
|
||||
<i class="plus icon"></i>
|
||||
<span class="sr-only">{{.i18n.Tr "new_repo"}}</span>
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</h4>
|
||||
<div class="ui attached secondary segment repos-search">
|
||||
<div class="ui fluid icon input" :class="{loading: isLoading}">
|
||||
|
||||
43
vendor/gopkg.in/ldap.v2/LICENSE
generated
vendored
43
vendor/gopkg.in/ldap.v2/LICENSE
generated
vendored
@@ -1,27 +1,22 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
The MIT License (MIT)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)
|
||||
Portions copyright (c) 2015-2016 go-ldap Authors
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
13
vendor/gopkg.in/ldap.v2/atomic_value.go
generated
vendored
Normal file
13
vendor/gopkg.in/ldap.v2/atomic_value.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// +build go1.4
|
||||
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// For compilers that support it, we just use the underlying sync/atomic.Value
|
||||
// type.
|
||||
type atomicValue struct {
|
||||
atomic.Value
|
||||
}
|
||||
28
vendor/gopkg.in/ldap.v2/atomic_value_go13.go
generated
vendored
Normal file
28
vendor/gopkg.in/ldap.v2/atomic_value_go13.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// +build !go1.4
|
||||
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// This is a helper type that emulates the use of the "sync/atomic.Value"
|
||||
// struct that's available in Go 1.4 and up.
|
||||
type atomicValue struct {
|
||||
value interface{}
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func (av *atomicValue) Store(val interface{}) {
|
||||
av.lock.Lock()
|
||||
av.value = val
|
||||
av.lock.Unlock()
|
||||
}
|
||||
|
||||
func (av *atomicValue) Load() interface{} {
|
||||
av.lock.RLock()
|
||||
ret := av.value
|
||||
av.lock.RUnlock()
|
||||
|
||||
return ret
|
||||
}
|
||||
69
vendor/gopkg.in/ldap.v2/conn.go
generated
vendored
69
vendor/gopkg.in/ldap.v2/conn.go
generated
vendored
@@ -11,6 +11,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
@@ -82,20 +83,18 @@ const (
|
||||
type Conn struct {
|
||||
conn net.Conn
|
||||
isTLS bool
|
||||
isClosing bool
|
||||
closeErr error
|
||||
closing uint32
|
||||
closeErr atomicValue
|
||||
isStartingTLS bool
|
||||
Debug debugging
|
||||
chanConfirm chan bool
|
||||
chanConfirm chan struct{}
|
||||
messageContexts map[int64]*messageContext
|
||||
chanMessage chan *messagePacket
|
||||
chanMessageID chan int64
|
||||
wgSender sync.WaitGroup
|
||||
wgClose sync.WaitGroup
|
||||
once sync.Once
|
||||
outstandingRequests uint
|
||||
messageMutex sync.Mutex
|
||||
requestTimeout time.Duration
|
||||
requestTimeout int64
|
||||
}
|
||||
|
||||
var _ Client = &Conn{}
|
||||
@@ -142,7 +141,7 @@ func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
|
||||
func NewConn(conn net.Conn, isTLS bool) *Conn {
|
||||
return &Conn{
|
||||
conn: conn,
|
||||
chanConfirm: make(chan bool),
|
||||
chanConfirm: make(chan struct{}),
|
||||
chanMessageID: make(chan int64),
|
||||
chanMessage: make(chan *messagePacket, 10),
|
||||
messageContexts: map[int64]*messageContext{},
|
||||
@@ -158,12 +157,22 @@ func (l *Conn) Start() {
|
||||
l.wgClose.Add(1)
|
||||
}
|
||||
|
||||
// isClosing returns whether or not we're currently closing.
|
||||
func (l *Conn) isClosing() bool {
|
||||
return atomic.LoadUint32(&l.closing) == 1
|
||||
}
|
||||
|
||||
// setClosing sets the closing value to true
|
||||
func (l *Conn) setClosing() bool {
|
||||
return atomic.CompareAndSwapUint32(&l.closing, 0, 1)
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
func (l *Conn) Close() {
|
||||
l.once.Do(func() {
|
||||
l.isClosing = true
|
||||
l.wgSender.Wait()
|
||||
l.messageMutex.Lock()
|
||||
defer l.messageMutex.Unlock()
|
||||
|
||||
if l.setClosing() {
|
||||
l.Debug.Printf("Sending quit message and waiting for confirmation")
|
||||
l.chanMessage <- &messagePacket{Op: MessageQuit}
|
||||
<-l.chanConfirm
|
||||
@@ -171,28 +180,26 @@ func (l *Conn) Close() {
|
||||
|
||||
l.Debug.Printf("Closing network connection")
|
||||
if err := l.conn.Close(); err != nil {
|
||||
log.Print(err)
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
l.wgClose.Done()
|
||||
})
|
||||
}
|
||||
l.wgClose.Wait()
|
||||
}
|
||||
|
||||
// SetTimeout sets the time after a request is sent that a MessageTimeout triggers
|
||||
func (l *Conn) SetTimeout(timeout time.Duration) {
|
||||
if timeout > 0 {
|
||||
l.requestTimeout = timeout
|
||||
atomic.StoreInt64(&l.requestTimeout, int64(timeout))
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the next available messageID
|
||||
func (l *Conn) nextMessageID() int64 {
|
||||
if l.chanMessageID != nil {
|
||||
if messageID, ok := <-l.chanMessageID; ok {
|
||||
return messageID
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -258,7 +265,7 @@ func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) {
|
||||
}
|
||||
|
||||
func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) {
|
||||
if l.isClosing {
|
||||
if l.isClosing() {
|
||||
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
|
||||
}
|
||||
l.messageMutex.Lock()
|
||||
@@ -297,7 +304,7 @@ func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags)
|
||||
func (l *Conn) finishMessage(msgCtx *messageContext) {
|
||||
close(msgCtx.done)
|
||||
|
||||
if l.isClosing {
|
||||
if l.isClosing() {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -316,12 +323,12 @@ func (l *Conn) finishMessage(msgCtx *messageContext) {
|
||||
}
|
||||
|
||||
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
|
||||
if l.isClosing {
|
||||
l.messageMutex.Lock()
|
||||
defer l.messageMutex.Unlock()
|
||||
if l.isClosing() {
|
||||
return false
|
||||
}
|
||||
l.wgSender.Add(1)
|
||||
l.chanMessage <- message
|
||||
l.wgSender.Done()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -333,15 +340,14 @@ func (l *Conn) processMessages() {
|
||||
for messageID, msgCtx := range l.messageContexts {
|
||||
// If we are closing due to an error, inform anyone who
|
||||
// is waiting about the error.
|
||||
if l.isClosing && l.closeErr != nil {
|
||||
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr})
|
||||
if l.isClosing() && l.closeErr.Load() != nil {
|
||||
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
|
||||
}
|
||||
l.Debug.Printf("Closing channel for MessageID %d", messageID)
|
||||
close(msgCtx.responses)
|
||||
delete(l.messageContexts, messageID)
|
||||
}
|
||||
close(l.chanMessageID)
|
||||
l.chanConfirm <- true
|
||||
close(l.chanConfirm)
|
||||
}()
|
||||
|
||||
@@ -350,11 +356,7 @@ func (l *Conn) processMessages() {
|
||||
select {
|
||||
case l.chanMessageID <- messageID:
|
||||
messageID++
|
||||
case message, ok := <-l.chanMessage:
|
||||
if !ok {
|
||||
l.Debug.Printf("Shutting down - message channel is closed")
|
||||
return
|
||||
}
|
||||
case message := <-l.chanMessage:
|
||||
switch message.Op {
|
||||
case MessageQuit:
|
||||
l.Debug.Printf("Shutting down - quit message received")
|
||||
@@ -377,14 +379,15 @@ func (l *Conn) processMessages() {
|
||||
l.messageContexts[message.MessageID] = message.Context
|
||||
|
||||
// Add timeout if defined
|
||||
if l.requestTimeout > 0 {
|
||||
requestTimeout := time.Duration(atomic.LoadInt64(&l.requestTimeout))
|
||||
if requestTimeout > 0 {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Printf("ldap: recovered panic in RequestTimeout: %v", err)
|
||||
}
|
||||
}()
|
||||
time.Sleep(l.requestTimeout)
|
||||
time.Sleep(requestTimeout)
|
||||
timeoutMessage := &messagePacket{
|
||||
Op: MessageTimeout,
|
||||
MessageID: message.MessageID,
|
||||
@@ -397,7 +400,7 @@ func (l *Conn) processMessages() {
|
||||
if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
|
||||
msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
|
||||
} else {
|
||||
log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing)
|
||||
log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing())
|
||||
ber.PrintPacket(message.Packet)
|
||||
}
|
||||
case MessageTimeout:
|
||||
@@ -439,8 +442,8 @@ func (l *Conn) reader() {
|
||||
packet, err := ber.ReadPacket(l.conn)
|
||||
if err != nil {
|
||||
// A read error is expected here if we are closing the connection...
|
||||
if !l.isClosing {
|
||||
l.closeErr = fmt.Errorf("unable to read LDAP response packet: %s", err)
|
||||
if !l.isClosing() {
|
||||
l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err))
|
||||
l.Debug.Printf("reader error: %s", err.Error())
|
||||
}
|
||||
return
|
||||
|
||||
12
vendor/gopkg.in/ldap.v2/control.go
generated
vendored
12
vendor/gopkg.in/ldap.v2/control.go
generated
vendored
@@ -334,18 +334,18 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
for _, child := range sequence.Children {
|
||||
if child.Tag == 0 {
|
||||
//Warning
|
||||
child := child.Children[0]
|
||||
packet := ber.DecodePacket(child.Data.Bytes())
|
||||
warningPacket := child.Children[0]
|
||||
packet := ber.DecodePacket(warningPacket.Data.Bytes())
|
||||
val, ok := packet.Value.(int64)
|
||||
if ok {
|
||||
if child.Tag == 0 {
|
||||
if warningPacket.Tag == 0 {
|
||||
//timeBeforeExpiration
|
||||
c.Expire = val
|
||||
child.Value = c.Expire
|
||||
} else if child.Tag == 1 {
|
||||
warningPacket.Value = c.Expire
|
||||
} else if warningPacket.Tag == 1 {
|
||||
//graceAuthNsRemaining
|
||||
c.Grace = val
|
||||
child.Value = c.Grace
|
||||
warningPacket.Value = c.Grace
|
||||
}
|
||||
}
|
||||
} else if child.Tag == 1 {
|
||||
|
||||
2
vendor/gopkg.in/ldap.v2/debug.go
generated
vendored
2
vendor/gopkg.in/ldap.v2/debug.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
)
|
||||
|
||||
// debbuging type
|
||||
// debugging type
|
||||
// - has a Printf method to write the debug output
|
||||
type debugging bool
|
||||
|
||||
|
||||
103
vendor/gopkg.in/ldap.v2/dn.go
generated
vendored
103
vendor/gopkg.in/ldap.v2/dn.go
generated
vendored
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// File contains DN parsing functionallity
|
||||
// File contains DN parsing functionality
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc4514
|
||||
//
|
||||
@@ -52,7 +52,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
ber "gopkg.in/asn1-ber.v1"
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
)
|
||||
|
||||
// AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514
|
||||
@@ -83,9 +83,19 @@ func ParseDN(str string) (*DN, error) {
|
||||
attribute := new(AttributeTypeAndValue)
|
||||
escaping := false
|
||||
|
||||
unescapedTrailingSpaces := 0
|
||||
stringFromBuffer := func() string {
|
||||
s := buffer.String()
|
||||
s = s[0 : len(s)-unescapedTrailingSpaces]
|
||||
buffer.Reset()
|
||||
unescapedTrailingSpaces = 0
|
||||
return s
|
||||
}
|
||||
|
||||
for i := 0; i < len(str); i++ {
|
||||
char := str[i]
|
||||
if escaping {
|
||||
unescapedTrailingSpaces = 0
|
||||
escaping = false
|
||||
switch char {
|
||||
case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\':
|
||||
@@ -107,10 +117,10 @@ func ParseDN(str string) (*DN, error) {
|
||||
buffer.WriteByte(dst[0])
|
||||
i++
|
||||
} else if char == '\\' {
|
||||
unescapedTrailingSpaces = 0
|
||||
escaping = true
|
||||
} else if char == '=' {
|
||||
attribute.Type = buffer.String()
|
||||
buffer.Reset()
|
||||
attribute.Type = stringFromBuffer()
|
||||
// Special case: If the first character in the value is # the
|
||||
// following data is BER encoded so we can just fast forward
|
||||
// and decode.
|
||||
@@ -133,7 +143,10 @@ func ParseDN(str string) (*DN, error) {
|
||||
}
|
||||
} else if char == ',' || char == '+' {
|
||||
// We're done with this RDN or value, push it
|
||||
attribute.Value = buffer.String()
|
||||
if len(attribute.Type) == 0 {
|
||||
return nil, errors.New("incomplete type, value pair")
|
||||
}
|
||||
attribute.Value = stringFromBuffer()
|
||||
rdn.Attributes = append(rdn.Attributes, attribute)
|
||||
attribute = new(AttributeTypeAndValue)
|
||||
if char == ',' {
|
||||
@@ -141,8 +154,17 @@ func ParseDN(str string) (*DN, error) {
|
||||
rdn = new(RelativeDN)
|
||||
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
||||
}
|
||||
buffer.Reset()
|
||||
} else if char == ' ' && buffer.Len() == 0 {
|
||||
// ignore unescaped leading spaces
|
||||
continue
|
||||
} else {
|
||||
if char == ' ' {
|
||||
// Track unescaped spaces in case they are trailing and we need to remove them
|
||||
unescapedTrailingSpaces++
|
||||
} else {
|
||||
// Reset if we see a non-space char
|
||||
unescapedTrailingSpaces = 0
|
||||
}
|
||||
buffer.WriteByte(char)
|
||||
}
|
||||
}
|
||||
@@ -150,9 +172,76 @@ func ParseDN(str string) (*DN, error) {
|
||||
if len(attribute.Type) == 0 {
|
||||
return nil, errors.New("DN ended with incomplete type, value pair")
|
||||
}
|
||||
attribute.Value = buffer.String()
|
||||
attribute.Value = stringFromBuffer()
|
||||
rdn.Attributes = append(rdn.Attributes, attribute)
|
||||
dn.RDNs = append(dn.RDNs, rdn)
|
||||
}
|
||||
return dn, nil
|
||||
}
|
||||
|
||||
// Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
|
||||
// Returns true if they have the same number of relative distinguished names
|
||||
// and corresponding relative distinguished names (by position) are the same.
|
||||
func (d *DN) Equal(other *DN) bool {
|
||||
if len(d.RDNs) != len(other.RDNs) {
|
||||
return false
|
||||
}
|
||||
for i := range d.RDNs {
|
||||
if !d.RDNs[i].Equal(other.RDNs[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AncestorOf returns true if the other DN consists of at least one RDN followed by all the RDNs of the current DN.
|
||||
// "ou=widgets,o=acme.com" is an ancestor of "ou=sprockets,ou=widgets,o=acme.com"
|
||||
// "ou=widgets,o=acme.com" is not an ancestor of "ou=sprockets,ou=widgets,o=foo.com"
|
||||
// "ou=widgets,o=acme.com" is not an ancestor of "ou=widgets,o=acme.com"
|
||||
func (d *DN) AncestorOf(other *DN) bool {
|
||||
if len(d.RDNs) >= len(other.RDNs) {
|
||||
return false
|
||||
}
|
||||
// Take the last `len(d.RDNs)` RDNs from the other DN to compare against
|
||||
otherRDNs := other.RDNs[len(other.RDNs)-len(d.RDNs):]
|
||||
for i := range d.RDNs {
|
||||
if !d.RDNs[i].Equal(otherRDNs[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
|
||||
// Relative distinguished names are the same if and only if they have the same number of AttributeTypeAndValues
|
||||
// and each attribute of the first RDN is the same as the attribute of the second RDN with the same attribute type.
|
||||
// The order of attributes is not significant.
|
||||
// Case of attribute types is not significant.
|
||||
func (r *RelativeDN) Equal(other *RelativeDN) bool {
|
||||
if len(r.Attributes) != len(other.Attributes) {
|
||||
return false
|
||||
}
|
||||
return r.hasAllAttributes(other.Attributes) && other.hasAllAttributes(r.Attributes)
|
||||
}
|
||||
|
||||
func (r *RelativeDN) hasAllAttributes(attrs []*AttributeTypeAndValue) bool {
|
||||
for _, attr := range attrs {
|
||||
found := false
|
||||
for _, myattr := range r.Attributes {
|
||||
if myattr.Equal(attr) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if the AttributeTypeAndValue is equivalent to the specified AttributeTypeAndValue
|
||||
// Case of the attribute type is not significant
|
||||
func (a *AttributeTypeAndValue) Equal(other *AttributeTypeAndValue) bool {
|
||||
return strings.EqualFold(a.Type, other.Type) && a.Value == other.Value
|
||||
}
|
||||
|
||||
7
vendor/gopkg.in/ldap.v2/error.go
generated
vendored
7
vendor/gopkg.in/ldap.v2/error.go
generated
vendored
@@ -97,6 +97,13 @@ var LDAPResultCodeMap = map[uint8]string{
|
||||
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
|
||||
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
|
||||
LDAPResultOther: "Other",
|
||||
|
||||
ErrorNetwork: "Network Error",
|
||||
ErrorFilterCompile: "Filter Compile Error",
|
||||
ErrorFilterDecompile: "Filter Decompile Error",
|
||||
ErrorDebugging: "Debugging Error",
|
||||
ErrorUnexpectedMessage: "Unexpected Message",
|
||||
ErrorUnexpectedResponse: "Unexpected Response",
|
||||
}
|
||||
|
||||
func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
|
||||
|
||||
5
vendor/gopkg.in/ldap.v2/filter.go
generated
vendored
5
vendor/gopkg.in/ldap.v2/filter.go
generated
vendored
@@ -82,7 +82,10 @@ func CompileFilter(filter string) (*ber.Packet, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pos != len(filter) {
|
||||
switch {
|
||||
case pos > len(filter):
|
||||
return nil, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
|
||||
case pos < len(filter):
|
||||
return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
|
||||
}
|
||||
return packet, nil
|
||||
|
||||
61
vendor/gopkg.in/ldap.v2/ldap.go
generated
vendored
61
vendor/gopkg.in/ldap.v2/ldap.go
generated
vendored
@@ -9,7 +9,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
ber "gopkg.in/asn1-ber.v1"
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
)
|
||||
|
||||
// LDAP Application Codes
|
||||
@@ -153,16 +153,47 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
|
||||
func addControlDescriptions(packet *ber.Packet) {
|
||||
packet.Description = "Controls"
|
||||
for _, child := range packet.Children {
|
||||
var value *ber.Packet
|
||||
controlType := ""
|
||||
child.Description = "Control"
|
||||
child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")"
|
||||
value := child.Children[1]
|
||||
if len(child.Children) == 3 {
|
||||
child.Children[1].Description = "Criticality"
|
||||
value = child.Children[2]
|
||||
}
|
||||
value.Description = "Control Value"
|
||||
switch len(child.Children) {
|
||||
case 0:
|
||||
// at least one child is required for control type
|
||||
continue
|
||||
|
||||
switch child.Children[0].Value.(string) {
|
||||
case 1:
|
||||
// just type, no criticality or value
|
||||
controlType = child.Children[0].Value.(string)
|
||||
child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")"
|
||||
|
||||
case 2:
|
||||
controlType = child.Children[0].Value.(string)
|
||||
child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")"
|
||||
// Children[1] could be criticality or value (both are optional)
|
||||
// duck-type on whether this is a boolean
|
||||
if _, ok := child.Children[1].Value.(bool); ok {
|
||||
child.Children[1].Description = "Criticality"
|
||||
} else {
|
||||
child.Children[1].Description = "Control Value"
|
||||
value = child.Children[1]
|
||||
}
|
||||
|
||||
case 3:
|
||||
// criticality and value present
|
||||
controlType = child.Children[0].Value.(string)
|
||||
child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")"
|
||||
child.Children[1].Description = "Criticality"
|
||||
child.Children[2].Description = "Control Value"
|
||||
value = child.Children[2]
|
||||
|
||||
default:
|
||||
// more than 3 children is invalid
|
||||
continue
|
||||
}
|
||||
if value == nil {
|
||||
continue
|
||||
}
|
||||
switch controlType {
|
||||
case ControlTypePaging:
|
||||
value.Description += " (Paging)"
|
||||
if value.Value != nil {
|
||||
@@ -188,18 +219,18 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
for _, child := range sequence.Children {
|
||||
if child.Tag == 0 {
|
||||
//Warning
|
||||
child := child.Children[0]
|
||||
packet := ber.DecodePacket(child.Data.Bytes())
|
||||
warningPacket := child.Children[0]
|
||||
packet := ber.DecodePacket(warningPacket.Data.Bytes())
|
||||
val, ok := packet.Value.(int64)
|
||||
if ok {
|
||||
if child.Tag == 0 {
|
||||
if warningPacket.Tag == 0 {
|
||||
//timeBeforeExpiration
|
||||
value.Description += " (TimeBeforeExpiration)"
|
||||
child.Value = val
|
||||
} else if child.Tag == 1 {
|
||||
warningPacket.Value = val
|
||||
} else if warningPacket.Tag == 1 {
|
||||
//graceAuthNsRemaining
|
||||
value.Description += " (GraceAuthNsRemaining)"
|
||||
child.Value = val
|
||||
warningPacket.Value = val
|
||||
}
|
||||
}
|
||||
} else if child.Tag == 1 {
|
||||
|
||||
8
vendor/gopkg.in/ldap.v2/passwdmodify.go
generated
vendored
8
vendor/gopkg.in/ldap.v2/passwdmodify.go
generated
vendored
@@ -135,10 +135,10 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa
|
||||
extendedResponse := packet.Children[1]
|
||||
for _, child := range extendedResponse.Children {
|
||||
if child.Tag == 11 {
|
||||
passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes())
|
||||
if len(passwordModifyReponseValue.Children) == 1 {
|
||||
if passwordModifyReponseValue.Children[0].Tag == 0 {
|
||||
result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes())
|
||||
passwordModifyResponseValue := ber.DecodePacket(child.Data.Bytes())
|
||||
if len(passwordModifyResponseValue.Children) == 1 {
|
||||
if passwordModifyResponseValue.Children[0].Tag == 0 {
|
||||
result.GeneratedPassword = ber.DecodeString(passwordModifyResponseValue.Children[0].Data.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user