mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			27 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8ab107c2dd | ||
| 
						 | 
					cbfc7f52b9 | ||
| 
						 | 
					d602ba564f | ||
| 
						 | 
					55063f2524 | ||
| 
						 | 
					585dd13cce | ||
| 
						 | 
					12d883412f | ||
| 
						 | 
					597a30b727 | ||
| 
						 | 
					b5ae8945e5 | ||
| 
						 | 
					5cca840bb8 | ||
| 
						 | 
					f4c7e87fc9 | ||
| 
						 | 
					fe99c9901d | ||
| 
						 | 
					2e1540e827 | ||
| 
						 | 
					3b612ce42e | ||
| 
						 | 
					1d8e56e6bb | ||
| 
						 | 
					57ab65d922 | ||
| 
						 | 
					3ac4a7fab8 | ||
| 
						 | 
					253efbcb51 | ||
| 
						 | 
					c8f061e15b | ||
| 
						 | 
					7f7c451de4 | ||
| 
						 | 
					b0b574f805 | ||
| 
						 | 
					d269179523 | ||
| 
						 | 
					6416f06508 | ||
| 
						 | 
					1a8ab63dda | ||
| 
						 | 
					477b4de0d1 | ||
| 
						 | 
					849c85a2ec | ||
| 
						 | 
					731275247d | ||
| 
						 | 
					022634aa75 | 
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,6 +4,36 @@ 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.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197)
 | 
			
		||||
  * Load Issue attributes for API /repos/{owner}/{repo}/issues/{index} (#6122) (#6185)
 | 
			
		||||
  * Fix bug whereby user could change private repository to public when force private enabled. (#6156) (#6165)
 | 
			
		||||
  * Fix bug when update owner team then visit team's repo return 404 (#6119) (#6166)
 | 
			
		||||
  * Fix heatmap and repository menu display in Internet Explorer 9+ (#6117) (#6137)
 | 
			
		||||
  * Fix prohibit login check on authorization (#6106) (#6115)
 | 
			
		||||
  * Fix LDAP protocol error regression by moving to ldap.v3 (#6105) (#6107)
 | 
			
		||||
  * Fix deadlock in webhook PullRequest (#6102) (#6104)
 | 
			
		||||
  * Fix redirect loop when password change is required and Gitea is installed as a suburl (#5965) (#6101)
 | 
			
		||||
  * Fix compare button regression (#5929) (#6098)
 | 
			
		||||
  * Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) (#6097)
 | 
			
		||||
 | 
			
		||||
## [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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							@@ -1005,12 +1005,12 @@
 | 
			
		||||
  version = "v1.31.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:7e1c00b9959544fa1ccca7cf0407a5b29ac6d5201059c4fac6f599cb99bfd24d"
 | 
			
		||||
  name = "gopkg.in/ldap.v2"
 | 
			
		||||
  digest = "1:8a502dedecf5b6d56e36f0d0e6196392baf616634af2c23108b6e8bb89ec57fc"
 | 
			
		||||
  name = "gopkg.in/ldap.v3"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "NUT"
 | 
			
		||||
  revision = "bb7a9ca6e4fbc2129e3db588a34bc970ffe811a9"
 | 
			
		||||
  version = "v2.5.1"
 | 
			
		||||
  revision = "214f299a0ecb2a6c6f6d2b0f13977032b207dc58"
 | 
			
		||||
  version = "v3.0.1"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  digest = "1:cfe1730a152ff033ad7d9c115d22e36b19eec6d5928c06146b9119be45d39dc0"
 | 
			
		||||
@@ -1215,7 +1215,7 @@
 | 
			
		||||
    "gopkg.in/editorconfig/editorconfig-core-go.v1",
 | 
			
		||||
    "gopkg.in/gomail.v2",
 | 
			
		||||
    "gopkg.in/ini.v1",
 | 
			
		||||
    "gopkg.in/ldap.v2",
 | 
			
		||||
    "gopkg.in/ldap.v3",
 | 
			
		||||
    "gopkg.in/macaron.v1",
 | 
			
		||||
    "gopkg.in/testfixtures.v2",
 | 
			
		||||
    "strk.kbt.io/projects/go/libravatar",
 | 
			
		||||
 
 | 
			
		||||
@@ -97,8 +97,8 @@ ignored = ["google.golang.org/appengine*"]
 | 
			
		||||
  version = "1.31.1"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "gopkg.in/ldap.v2"
 | 
			
		||||
  version = "2.4.1"
 | 
			
		||||
  name = "gopkg.in/ldap.v3"
 | 
			
		||||
  version = "3.0.1"
 | 
			
		||||
 | 
			
		||||
[[constraint]]
 | 
			
		||||
  name = "gopkg.in/macaron.v1"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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)
 | 
			
		||||
 
 | 
			
		||||
@@ -112,7 +112,7 @@ func TestCreateReleasePaging(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", i18n.Tr("en", "repo.release.draft"), 10)
 | 
			
		||||
 | 
			
		||||
	// Check that user3 does not see draft and still see 10 latest releases
 | 
			
		||||
	session2 := loginUser(t, "user3")
 | 
			
		||||
	// Check that user4 does not see draft and still see 10 latest releases
 | 
			
		||||
	session2 := loginUser(t, "user4")
 | 
			
		||||
	checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", i18n.Tr("en", "repo.release.stable"), 10)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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))
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -90,6 +90,38 @@ func (err ErrUserNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrUserProhibitLogin represents a "ErrUserProhibitLogin" kind of error.
 | 
			
		||||
type ErrUserProhibitLogin struct {
 | 
			
		||||
	UID  int64
 | 
			
		||||
	Name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrUserProhibitLogin checks if an error is a ErrUserProhibitLogin
 | 
			
		||||
func IsErrUserProhibitLogin(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrUserProhibitLogin)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrUserProhibitLogin) Error() string {
 | 
			
		||||
	return fmt.Sprintf("user is not allowed login [uid: %d, name: %s]", err.UID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrUserInactive represents a "ErrUserInactive" kind of error.
 | 
			
		||||
type ErrUserInactive struct {
 | 
			
		||||
	UID  int64
 | 
			
		||||
	Name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrUserInactive checks if an error is a ErrUserInactive
 | 
			
		||||
func IsErrUserInactive(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrUserInactive)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrUserInactive) Error() string {
 | 
			
		||||
	return fmt.Sprintf("user is inactive [uid: %d, name: %s]", err.UID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrEmailAlreadyUsed represents a "EmailAlreadyUsed" kind of error.
 | 
			
		||||
type ErrEmailAlreadyUsed struct {
 | 
			
		||||
	Email string
 | 
			
		||||
 
 | 
			
		||||
@@ -600,16 +600,29 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
 | 
			
		||||
		return nil, ErrLoginSourceNotActived
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	switch source.Type {
 | 
			
		||||
	case LoginLDAP, LoginDLDAP:
 | 
			
		||||
		return LoginViaLDAP(user, login, password, source, autoRegister)
 | 
			
		||||
		user, err = LoginViaLDAP(user, login, password, source, autoRegister)
 | 
			
		||||
	case LoginSMTP:
 | 
			
		||||
		return LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
 | 
			
		||||
		user, err = LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
 | 
			
		||||
	case LoginPAM:
 | 
			
		||||
		return LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig), autoRegister)
 | 
			
		||||
		user, err = LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig), autoRegister)
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, ErrUnsupportedLoginType
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, ErrUnsupportedLoginType
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !user.IsActive {
 | 
			
		||||
		return nil, ErrUserInactive{user.ID, user.Name}
 | 
			
		||||
	} else if user.ProhibitLogin {
 | 
			
		||||
		return nil, ErrUserProhibitLogin{user.ID, user.Name}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return user, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UserSignIn validates user name and password.
 | 
			
		||||
@@ -645,6 +658,12 @@ func UserSignIn(username, password string) (*User, error) {
 | 
			
		||||
		switch user.LoginType {
 | 
			
		||||
		case LoginNoType, LoginPlain, LoginOAuth2:
 | 
			
		||||
			if user.IsPasswordSet() && user.ValidatePassword(password) {
 | 
			
		||||
				if !user.IsActive {
 | 
			
		||||
					return nil, ErrUserInactive{user.ID, user.Name}
 | 
			
		||||
				} else if user.ProhibitLogin {
 | 
			
		||||
					return nil, ErrUserProhibitLogin{user.ID, user.Name}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return user, nil
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,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()
 | 
			
		||||
@@ -1346,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}
 | 
			
		||||
@@ -1743,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 {
 | 
			
		||||
@@ -1774,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)
 | 
			
		||||
	}
 | 
			
		||||
@@ -1884,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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -151,6 +151,15 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if user in an owner team
 | 
			
		||||
	for _, team := range teams {
 | 
			
		||||
		if team.Authorize >= AccessModeOwner {
 | 
			
		||||
			perm.AccessMode = AccessModeOwner
 | 
			
		||||
			perm.UnitsMode = nil
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, u := range repo.Units {
 | 
			
		||||
		var found bool
 | 
			
		||||
		for _, team := range teams {
 | 
			
		||||
 
 | 
			
		||||
@@ -219,6 +219,17 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// update team information and then check permission
 | 
			
		||||
	team := AssertExistsAndLoadBean(t, &Team{ID: 5}).(*Team)
 | 
			
		||||
	err = UpdateTeamUnits(team, nil)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	perm, err = GetUserRepoPermission(repo, owner)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// org member team tester
 | 
			
		||||
	tester := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 | 
			
		||||
	perm, err = GetUserRepoPermission(repo, tester)
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -230,12 +230,13 @@ func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload,
 | 
			
		||||
		title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title)
 | 
			
		||||
		text = p.PullRequest.Body
 | 
			
		||||
	case api.HookIssueAssigned:
 | 
			
		||||
		list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return &DingtalkPayload{}, err
 | 
			
		||||
		list := make([]string, len(p.PullRequest.Assignees))
 | 
			
		||||
		for i, user := range p.PullRequest.Assignees {
 | 
			
		||||
			list[i] = user.UserName
 | 
			
		||||
		}
 | 
			
		||||
		title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName,
 | 
			
		||||
			list, p.Index, p.PullRequest.Title)
 | 
			
		||||
			strings.Join(list, ", "),
 | 
			
		||||
			p.Index, p.PullRequest.Title)
 | 
			
		||||
		text = p.PullRequest.Body
 | 
			
		||||
	case api.HookIssueUnassigned:
 | 
			
		||||
		title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title)
 | 
			
		||||
 
 | 
			
		||||
@@ -347,12 +347,13 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta)
 | 
			
		||||
		text = p.PullRequest.Body
 | 
			
		||||
		color = warnColor
 | 
			
		||||
	case api.HookIssueAssigned:
 | 
			
		||||
		list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return &DiscordPayload{}, err
 | 
			
		||||
		list := make([]string, len(p.PullRequest.Assignees))
 | 
			
		||||
		for i, user := range p.PullRequest.Assignees {
 | 
			
		||||
			list[i] = user.UserName
 | 
			
		||||
		}
 | 
			
		||||
		title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName,
 | 
			
		||||
			list, p.Index, p.PullRequest.Title)
 | 
			
		||||
		title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d by %s", p.Repository.FullName,
 | 
			
		||||
			strings.Join(list, ", "),
 | 
			
		||||
			p.Index, p.PullRequest.Title)
 | 
			
		||||
		text = p.PullRequest.Body
 | 
			
		||||
		color = successColor
 | 
			
		||||
	case api.HookIssueUnassigned:
 | 
			
		||||
 
 | 
			
		||||
@@ -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{
 | 
			
		||||
@@ -297,12 +301,12 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
 | 
			
		||||
		text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink)
 | 
			
		||||
		attachmentText = SlackTextFormatter(p.PullRequest.Body)
 | 
			
		||||
	case api.HookIssueAssigned:
 | 
			
		||||
		list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return &SlackPayload{}, err
 | 
			
		||||
		list := make([]string, len(p.PullRequest.Assignees))
 | 
			
		||||
		for i, user := range p.PullRequest.Assignees {
 | 
			
		||||
			list[i] = SlackLinkFormatter(setting.AppURL+user.UserName, user.UserName)
 | 
			
		||||
		}
 | 
			
		||||
		text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName,
 | 
			
		||||
			SlackLinkFormatter(setting.AppURL+list, list),
 | 
			
		||||
			strings.Join(list, ", "),
 | 
			
		||||
			titleLink, senderLink)
 | 
			
		||||
	case api.HookIssueUnassigned:
 | 
			
		||||
		text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink)
 | 
			
		||||
@@ -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
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,9 +11,9 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/ldap.v2"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
 | 
			
		||||
	ldap "gopkg.in/ldap.v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SecurityProtocol protocol type
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"net/url"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/auth"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"github.com/go-macaron/csrf"
 | 
			
		||||
	macaron "gopkg.in/macaron.v1"
 | 
			
		||||
@@ -32,8 +33,12 @@ func Toggle(options *ToggleOptions) macaron.Handler {
 | 
			
		||||
 | 
			
		||||
		// Check prohibit login users.
 | 
			
		||||
		if ctx.IsSigned {
 | 
			
		||||
 | 
			
		||||
			if ctx.User.ProhibitLogin {
 | 
			
		||||
			if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
 | 
			
		||||
				ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
 | 
			
		||||
				ctx.HTML(200, "user/auth/activate")
 | 
			
		||||
				return
 | 
			
		||||
			} else if !ctx.User.IsActive || ctx.User.ProhibitLogin {
 | 
			
		||||
				log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr())
 | 
			
		||||
				ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
 | 
			
		||||
				ctx.HTML(200, "user/auth/prohibit_login")
 | 
			
		||||
				return
 | 
			
		||||
@@ -42,7 +47,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
 | 
			
		||||
			// prevent infinite redirection
 | 
			
		||||
			// also make sure that the form cannot be accessed by
 | 
			
		||||
			// users who don't need this
 | 
			
		||||
			if ctx.Req.URL.Path == setting.AppSubURL+"/user/settings/change_password" {
 | 
			
		||||
			if ctx.Req.URL.Path == "/user/settings/change_password" {
 | 
			
		||||
				if !ctx.User.MustChangePassword {
 | 
			
		||||
					ctx.Redirect(setting.AppSubURL + "/")
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
package markup
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/markup"
 | 
			
		||||
	"code.gitea.io/gitea/modules/markup/markdown"
 | 
			
		||||
 | 
			
		||||
@@ -31,7 +32,13 @@ func (Parser) Extensions() []string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Render renders orgmode rawbytes to HTML
 | 
			
		||||
func Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte {
 | 
			
		||||
func Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) (result []byte) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := recover(); err != nil {
 | 
			
		||||
			log.Error(4, "Panic in orgmode.Render: %v Just returning the rawBytes", err)
 | 
			
		||||
			result = rawBytes
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	htmlFlags := blackfriday.HTML_USE_XHTML
 | 
			
		||||
	htmlFlags |= blackfriday.HTML_SKIP_STYLE
 | 
			
		||||
	htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
 | 
			
		||||
@@ -40,9 +47,8 @@ func Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki b
 | 
			
		||||
		URLPrefix: urlPrefix,
 | 
			
		||||
		IsWiki:    isWiki,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := goorgeous.Org(rawBytes, renderer)
 | 
			
		||||
	return result
 | 
			
		||||
	result = goorgeous.Org(rawBytes, renderer)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderString reners orgmode string to HTML string
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,115 @@ function htmlEncode(text) {
 | 
			
		||||
var csrf;
 | 
			
		||||
var suburl;
 | 
			
		||||
 | 
			
		||||
// Polyfill for IE9+ support (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
 | 
			
		||||
if (!Array.from) {
 | 
			
		||||
    Array.from = (function () {
 | 
			
		||||
        var toStr = Object.prototype.toString;
 | 
			
		||||
        var isCallable = function (fn) {
 | 
			
		||||
            return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
 | 
			
		||||
        };
 | 
			
		||||
        var toInteger = function (value) {
 | 
			
		||||
            var number = Number(value);
 | 
			
		||||
            if (isNaN(number)) { return 0; }
 | 
			
		||||
            if (number === 0 || !isFinite(number)) { return number; }
 | 
			
		||||
            return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
 | 
			
		||||
        };
 | 
			
		||||
        var maxSafeInteger = Math.pow(2, 53) - 1;
 | 
			
		||||
        var toLength = function (value) {
 | 
			
		||||
            var len = toInteger(value);
 | 
			
		||||
            return Math.min(Math.max(len, 0), maxSafeInteger);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // The length property of the from method is 1.
 | 
			
		||||
        return function from(arrayLike/*, mapFn, thisArg */) {
 | 
			
		||||
            // 1. Let C be the this value.
 | 
			
		||||
            var C = this;
 | 
			
		||||
 | 
			
		||||
            // 2. Let items be ToObject(arrayLike).
 | 
			
		||||
            var items = Object(arrayLike);
 | 
			
		||||
 | 
			
		||||
            // 3. ReturnIfAbrupt(items).
 | 
			
		||||
            if (arrayLike == null) {
 | 
			
		||||
                throw new TypeError("Array.from requires an array-like object - not null or undefined");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 4. If mapfn is undefined, then let mapping be false.
 | 
			
		||||
            var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
 | 
			
		||||
            var T;
 | 
			
		||||
            if (typeof mapFn !== 'undefined') {
 | 
			
		||||
                // 5. else
 | 
			
		||||
                // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
 | 
			
		||||
                if (!isCallable(mapFn)) {
 | 
			
		||||
                    throw new TypeError('Array.from: when provided, the second argument must be a function');
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
 | 
			
		||||
                if (arguments.length > 2) {
 | 
			
		||||
                    T = arguments[2];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 10. Let lenValue be Get(items, "length").
 | 
			
		||||
            // 11. Let len be ToLength(lenValue).
 | 
			
		||||
            var len = toLength(items.length);
 | 
			
		||||
 | 
			
		||||
            // 13. If IsConstructor(C) is true, then
 | 
			
		||||
            // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
 | 
			
		||||
            // 14. a. Else, Let A be ArrayCreate(len).
 | 
			
		||||
            var A = isCallable(C) ? Object(new C(len)) : new Array(len);
 | 
			
		||||
 | 
			
		||||
            // 16. Let k be 0.
 | 
			
		||||
            var k = 0;
 | 
			
		||||
            // 17. Repeat, while k < len… (also steps a - h)
 | 
			
		||||
            var kValue;
 | 
			
		||||
            while (k < len) {
 | 
			
		||||
                kValue = items[k];
 | 
			
		||||
                if (mapFn) {
 | 
			
		||||
                    A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
 | 
			
		||||
                } else {
 | 
			
		||||
                    A[k] = kValue;
 | 
			
		||||
                }
 | 
			
		||||
                k += 1;
 | 
			
		||||
            }
 | 
			
		||||
            // 18. Let putStatus be Put(A, "length", len, true).
 | 
			
		||||
            A.length = len;
 | 
			
		||||
            // 20. Return A.
 | 
			
		||||
            return A;
 | 
			
		||||
        };
 | 
			
		||||
    }());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
 | 
			
		||||
if (typeof Object.assign != 'function') {
 | 
			
		||||
    // Must be writable: true, enumerable: false, configurable: true
 | 
			
		||||
    Object.defineProperty(Object, "assign", {
 | 
			
		||||
        value: function assign(target, varArgs) { // .length of function is 2
 | 
			
		||||
            'use strict';
 | 
			
		||||
            if (target == null) { // TypeError if undefined or null
 | 
			
		||||
                throw new TypeError('Cannot convert undefined or null to object');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var to = Object(target);
 | 
			
		||||
 | 
			
		||||
            for (var index = 1; index < arguments.length; index++) {
 | 
			
		||||
                var nextSource = arguments[index];
 | 
			
		||||
 | 
			
		||||
                if (nextSource != null) { // Skip over if undefined or null
 | 
			
		||||
                    for (var nextKey in nextSource) {
 | 
			
		||||
                        // Avoid bugs when hasOwnProperty is shadowed
 | 
			
		||||
                        if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
 | 
			
		||||
                            to[nextKey] = nextSource[nextKey];
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return to;
 | 
			
		||||
        },
 | 
			
		||||
        writable: true,
 | 
			
		||||
        configurable: true
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function initCommentPreviewTab($form) {
 | 
			
		||||
    var $tabMenu = $form.find('.tabular.menu');
 | 
			
		||||
    $tabMenu.find('.item').tab();
 | 
			
		||||
@@ -2348,7 +2457,6 @@ function initHeatmap(appElementId, heatmapUser, locale) {
 | 
			
		||||
                this.getColor(4),
 | 
			
		||||
                this.getColor(5)
 | 
			
		||||
            ];
 | 
			
		||||
            console.log(this.colorRange);
 | 
			
		||||
            this.endDate = new Date();
 | 
			
		||||
            this.loadHeatmap(this.user);
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							@@ -48,7 +48,7 @@
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td><a href="./plugins/vue/vue.min.js">vue.min.js</a></td>
 | 
			
		||||
          <td><a href="https://github.com/vuejs/vue/blob/dev/LICENSE">Expat</a></td>
 | 
			
		||||
          <td><a href="https://github.com/vuejs/vue/archive/v2.1.10.tar.gz">vue.js-v2.1.10.tar.gz</a></td>
 | 
			
		||||
          <td><a href="https://github.com/vuejs/vue/archive/v2.6.6.tar.gz">vue.js-v2.6.6.tar.gz</a></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td><a href="./plugins/emojify/emojify.min.js">emojify.min.js</a></td>
 | 
			
		||||
@@ -136,7 +136,7 @@
 | 
			
		||||
          <td><a href="https://github.com/swagger-api/swagger-ui/archive/v3.0.4.tar.gz">swagger-ui-v3.0.4.tar.gz</a></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td><a href="./plugins/vue-calendar-heatmap">vue-calendar-heatmap</a></td>
 | 
			
		||||
          <td><a href="./plugins/vue-calendar-heatmap/">vue-calendar-heatmap</a></td>
 | 
			
		||||
          <td><a href="https://github.com/WildCodeSchool/vue-calendar-heatmap/blob/master/README.md">MIT</a></td>
 | 
			
		||||
          <td><a href="https://github.com/WildCodeSchool/vue-calendar-heatmap/archive/master.zip">7f48b20.zip</a></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
@@ -145,6 +145,11 @@
 | 
			
		||||
          <td><a href="https://github.com/moment/moment/blob/develop/LICENSE">MIT</a></td>
 | 
			
		||||
          <td><a href="https://github.com/moment/moment/archive/2.22.2.tar.gz">0.4.1.tar.gz</a></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td><a href="./plugins/es6-promise/">es6-promise</a></td>
 | 
			
		||||
          <td><a href="https://github.com/stefanpenner/es6-promise/blob/master/LICENSE">MIT</a></td>
 | 
			
		||||
          <td><a href="https://github.com/stefanpenner/es6-promise/archive/v4.2.6.tar.gz">4.2.6.tar.gz</a></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
  </body>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								public/vendor/plugins/es6-promise/es6-promise.auto.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/vendor/plugins/es6-promise/es6-promise.auto.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										8
									
								
								public/vendor/plugins/vue/vue.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								public/vendor/plugins/vue/vue.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -129,7 +129,7 @@ func GetIssue(ctx *context.APIContext) {
 | 
			
		||||
	// responses:
 | 
			
		||||
	//   "200":
 | 
			
		||||
	//     "$ref": "#/responses/Issue"
 | 
			
		||||
	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
 | 
			
		||||
	issue, err := models.GetIssueWithAttrsByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if models.IsErrIssueNotExist(err) {
 | 
			
		||||
			ctx.Status(404)
 | 
			
		||||
 
 | 
			
		||||
@@ -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):
 | 
			
		||||
 
 | 
			
		||||
@@ -668,8 +668,8 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
 | 
			
		||||
		ctx.ServerError("GetUserRepoPermission", err)
 | 
			
		||||
		return nil, nil, nil, nil, "", ""
 | 
			
		||||
	}
 | 
			
		||||
	if !perm.CanWrite(models.UnitTypeCode) {
 | 
			
		||||
		log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
 | 
			
		||||
	if !perm.CanReadIssuesOrPulls(true) {
 | 
			
		||||
		log.Trace("ParseCompareInfo[%d]: cannot create/read pull requests", baseRepo.ID)
 | 
			
		||||
		ctx.Status(404)
 | 
			
		||||
		return nil, nil, nil, nil, "", ""
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -400,6 +400,11 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
 | 
			
		||||
		RemoteAddr:  remoteAddr,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if models.IsErrRepoAlreadyExist(err) {
 | 
			
		||||
			ctx.Error(409, "", "The repository with the same name already exists.")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = util.URLSanitizedError(err, remoteAddr)
 | 
			
		||||
		if repo != nil {
 | 
			
		||||
			if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/base"
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/search"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
@@ -38,6 +39,10 @@ func Home(ctx *context.Context) {
 | 
			
		||||
		if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
 | 
			
		||||
			ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
 | 
			
		||||
			ctx.HTML(200, user.TplActivate)
 | 
			
		||||
		} else if !ctx.User.IsActive || ctx.User.ProhibitLogin {
 | 
			
		||||
			log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr())
 | 
			
		||||
			ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
 | 
			
		||||
			ctx.HTML(200, "user/auth/prohibit_login")
 | 
			
		||||
		} else {
 | 
			
		||||
			user.Dashboard(ctx)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -288,8 +288,6 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		models.UpdateTeamUnits(t, units)
 | 
			
		||||
	} else {
 | 
			
		||||
		models.UpdateTeamUnits(t, nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
 
 | 
			
		||||
@@ -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")
 | 
			
		||||
 
 | 
			
		||||
@@ -684,8 +684,8 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
 | 
			
		||||
		ctx.ServerError("GetUserRepoPermission", err)
 | 
			
		||||
		return nil, nil, nil, nil, "", ""
 | 
			
		||||
	}
 | 
			
		||||
	if !perm.CanWrite(models.UnitTypeCode) {
 | 
			
		||||
		log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
 | 
			
		||||
	if !perm.CanReadIssuesOrPulls(true) {
 | 
			
		||||
		log.Trace("ParseCompareInfo[%d]: cannot create/read pull requests", baseRepo.ID)
 | 
			
		||||
		ctx.NotFound("ParseCompareInfo", nil)
 | 
			
		||||
		return nil, nil, nil, nil, "", ""
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -256,6 +256,11 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if models.IsErrRepoAlreadyExist(err) {
 | 
			
		||||
		ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplMigrate, &form)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// remoteAddr may contain credentials, so we sanitize it
 | 
			
		||||
	err = util.URLSanitizedError(err, remoteAddr)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -36,6 +37,7 @@ const (
 | 
			
		||||
func Settings(ctx *context.Context) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("repo.settings")
 | 
			
		||||
	ctx.Data["PageIsSettingsOptions"] = true
 | 
			
		||||
	ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate
 | 
			
		||||
	ctx.HTML(200, tplSettingsOptions)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -94,6 +96,12 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		visibilityChanged := repo.IsPrivate != form.Private
 | 
			
		||||
		// when ForcePrivate enabled, you could change public repo to private, but could not change private to public
 | 
			
		||||
		if visibilityChanged && setting.Repository.ForcePrivate && !form.Private {
 | 
			
		||||
			ctx.ServerError("Force Private enabled", errors.New("cannot change private repository to public"))
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		repo.IsPrivate = form.Private
 | 
			
		||||
		if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
 | 
			
		||||
			ctx.ServerError("UpdateRepository", err)
 | 
			
		||||
@@ -581,6 +589,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)
 | 
			
		||||
 
 | 
			
		||||
@@ -161,6 +161,19 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) {
 | 
			
		||||
		} else if models.IsErrEmailAlreadyUsed(err) {
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
 | 
			
		||||
			log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
 | 
			
		||||
		} else if models.IsErrUserProhibitLogin(err) {
 | 
			
		||||
			log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
 | 
			
		||||
			ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
 | 
			
		||||
			ctx.HTML(200, "user/auth/prohibit_login")
 | 
			
		||||
		} else if models.IsErrUserInactive(err) {
 | 
			
		||||
			if setting.Service.RegisterEmailConfirm {
 | 
			
		||||
				ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
 | 
			
		||||
				ctx.HTML(200, TplActivate)
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
 | 
			
		||||
				ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
 | 
			
		||||
				ctx.HTML(200, "user/auth/prohibit_login")
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.ServerError("UserSignIn", err)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -112,6 +112,7 @@
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}"></script>
 | 
			
		||||
{{if .EnableHeatmap}}
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/es6-promise/es6-promise.auto.min.js" charset="utf-8"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script>
 | 
			
		||||
	<script type="text/javascript">
 | 
			
		||||
 
 | 
			
		||||
@@ -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}}...{{ if .Repository.IsFork }}{{.Repository.Owner.Name}}{{ else }}{{ .SignedUserName }}{{ end }}:{{.BranchName | EscapePound}}">
 | 
			
		||||
					<a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{if ne .Repository.Owner.Name .BaseRepo.Owner.Name}}{{.Repository.Owner.Name}}:{{end}}{{.BranchName | EscapePound}}">
 | 
			
		||||
					<button class="ui green tiny compact button"><i class="octicon octicon-git-compare"></i></button>
 | 
			
		||||
					</a>
 | 
			
		||||
				</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
					<div class="inline field">
 | 
			
		||||
						<label>{{.i18n.Tr "repo.visibility"}}</label>
 | 
			
		||||
						<div class="ui checkbox">
 | 
			
		||||
							<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
 | 
			
		||||
							<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} readonly{{end}}>
 | 
			
		||||
							<label>{{.i18n.Tr "repo.visibility_helper" | Safe}} {{if .Repository.NumForks}}<span class="text red">{{.i18n.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -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}">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/gopkg.in/ldap.v2/atomic_value.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/gopkg.in/ldap.v2/atomic_value.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,13 +0,0 @@
 | 
			
		||||
// +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
									
									
								
							
							
						
						
									
										28
									
								
								vendor/gopkg.in/ldap.v2/atomic_value_go13.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,28 +0,0 @@
 | 
			
		||||
// +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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										155
									
								
								vendor/gopkg.in/ldap.v2/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										155
									
								
								vendor/gopkg.in/ldap.v2/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,155 +0,0 @@
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/asn1-ber.v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// LDAP Result Codes
 | 
			
		||||
const (
 | 
			
		||||
	LDAPResultSuccess                      = 0
 | 
			
		||||
	LDAPResultOperationsError              = 1
 | 
			
		||||
	LDAPResultProtocolError                = 2
 | 
			
		||||
	LDAPResultTimeLimitExceeded            = 3
 | 
			
		||||
	LDAPResultSizeLimitExceeded            = 4
 | 
			
		||||
	LDAPResultCompareFalse                 = 5
 | 
			
		||||
	LDAPResultCompareTrue                  = 6
 | 
			
		||||
	LDAPResultAuthMethodNotSupported       = 7
 | 
			
		||||
	LDAPResultStrongAuthRequired           = 8
 | 
			
		||||
	LDAPResultReferral                     = 10
 | 
			
		||||
	LDAPResultAdminLimitExceeded           = 11
 | 
			
		||||
	LDAPResultUnavailableCriticalExtension = 12
 | 
			
		||||
	LDAPResultConfidentialityRequired      = 13
 | 
			
		||||
	LDAPResultSaslBindInProgress           = 14
 | 
			
		||||
	LDAPResultNoSuchAttribute              = 16
 | 
			
		||||
	LDAPResultUndefinedAttributeType       = 17
 | 
			
		||||
	LDAPResultInappropriateMatching        = 18
 | 
			
		||||
	LDAPResultConstraintViolation          = 19
 | 
			
		||||
	LDAPResultAttributeOrValueExists       = 20
 | 
			
		||||
	LDAPResultInvalidAttributeSyntax       = 21
 | 
			
		||||
	LDAPResultNoSuchObject                 = 32
 | 
			
		||||
	LDAPResultAliasProblem                 = 33
 | 
			
		||||
	LDAPResultInvalidDNSyntax              = 34
 | 
			
		||||
	LDAPResultAliasDereferencingProblem    = 36
 | 
			
		||||
	LDAPResultInappropriateAuthentication  = 48
 | 
			
		||||
	LDAPResultInvalidCredentials           = 49
 | 
			
		||||
	LDAPResultInsufficientAccessRights     = 50
 | 
			
		||||
	LDAPResultBusy                         = 51
 | 
			
		||||
	LDAPResultUnavailable                  = 52
 | 
			
		||||
	LDAPResultUnwillingToPerform           = 53
 | 
			
		||||
	LDAPResultLoopDetect                   = 54
 | 
			
		||||
	LDAPResultNamingViolation              = 64
 | 
			
		||||
	LDAPResultObjectClassViolation         = 65
 | 
			
		||||
	LDAPResultNotAllowedOnNonLeaf          = 66
 | 
			
		||||
	LDAPResultNotAllowedOnRDN              = 67
 | 
			
		||||
	LDAPResultEntryAlreadyExists           = 68
 | 
			
		||||
	LDAPResultObjectClassModsProhibited    = 69
 | 
			
		||||
	LDAPResultAffectsMultipleDSAs          = 71
 | 
			
		||||
	LDAPResultOther                        = 80
 | 
			
		||||
 | 
			
		||||
	ErrorNetwork            = 200
 | 
			
		||||
	ErrorFilterCompile      = 201
 | 
			
		||||
	ErrorFilterDecompile    = 202
 | 
			
		||||
	ErrorDebugging          = 203
 | 
			
		||||
	ErrorUnexpectedMessage  = 204
 | 
			
		||||
	ErrorUnexpectedResponse = 205
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// LDAPResultCodeMap contains string descriptions for LDAP error codes
 | 
			
		||||
var LDAPResultCodeMap = map[uint8]string{
 | 
			
		||||
	LDAPResultSuccess:                      "Success",
 | 
			
		||||
	LDAPResultOperationsError:              "Operations Error",
 | 
			
		||||
	LDAPResultProtocolError:                "Protocol Error",
 | 
			
		||||
	LDAPResultTimeLimitExceeded:            "Time Limit Exceeded",
 | 
			
		||||
	LDAPResultSizeLimitExceeded:            "Size Limit Exceeded",
 | 
			
		||||
	LDAPResultCompareFalse:                 "Compare False",
 | 
			
		||||
	LDAPResultCompareTrue:                  "Compare True",
 | 
			
		||||
	LDAPResultAuthMethodNotSupported:       "Auth Method Not Supported",
 | 
			
		||||
	LDAPResultStrongAuthRequired:           "Strong Auth Required",
 | 
			
		||||
	LDAPResultReferral:                     "Referral",
 | 
			
		||||
	LDAPResultAdminLimitExceeded:           "Admin Limit Exceeded",
 | 
			
		||||
	LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
 | 
			
		||||
	LDAPResultConfidentialityRequired:      "Confidentiality Required",
 | 
			
		||||
	LDAPResultSaslBindInProgress:           "Sasl Bind In Progress",
 | 
			
		||||
	LDAPResultNoSuchAttribute:              "No Such Attribute",
 | 
			
		||||
	LDAPResultUndefinedAttributeType:       "Undefined Attribute Type",
 | 
			
		||||
	LDAPResultInappropriateMatching:        "Inappropriate Matching",
 | 
			
		||||
	LDAPResultConstraintViolation:          "Constraint Violation",
 | 
			
		||||
	LDAPResultAttributeOrValueExists:       "Attribute Or Value Exists",
 | 
			
		||||
	LDAPResultInvalidAttributeSyntax:       "Invalid Attribute Syntax",
 | 
			
		||||
	LDAPResultNoSuchObject:                 "No Such Object",
 | 
			
		||||
	LDAPResultAliasProblem:                 "Alias Problem",
 | 
			
		||||
	LDAPResultInvalidDNSyntax:              "Invalid DN Syntax",
 | 
			
		||||
	LDAPResultAliasDereferencingProblem:    "Alias Dereferencing Problem",
 | 
			
		||||
	LDAPResultInappropriateAuthentication:  "Inappropriate Authentication",
 | 
			
		||||
	LDAPResultInvalidCredentials:           "Invalid Credentials",
 | 
			
		||||
	LDAPResultInsufficientAccessRights:     "Insufficient Access Rights",
 | 
			
		||||
	LDAPResultBusy:                         "Busy",
 | 
			
		||||
	LDAPResultUnavailable:                  "Unavailable",
 | 
			
		||||
	LDAPResultUnwillingToPerform:           "Unwilling To Perform",
 | 
			
		||||
	LDAPResultLoopDetect:                   "Loop Detect",
 | 
			
		||||
	LDAPResultNamingViolation:              "Naming Violation",
 | 
			
		||||
	LDAPResultObjectClassViolation:         "Object Class Violation",
 | 
			
		||||
	LDAPResultNotAllowedOnNonLeaf:          "Not Allowed On Non Leaf",
 | 
			
		||||
	LDAPResultNotAllowedOnRDN:              "Not Allowed On RDN",
 | 
			
		||||
	LDAPResultEntryAlreadyExists:           "Entry Already Exists",
 | 
			
		||||
	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) {
 | 
			
		||||
	if packet == nil {
 | 
			
		||||
		return ErrorUnexpectedResponse, "Empty packet"
 | 
			
		||||
	} else if len(packet.Children) >= 2 {
 | 
			
		||||
		response := packet.Children[1]
 | 
			
		||||
		if response == nil {
 | 
			
		||||
			return ErrorUnexpectedResponse, "Empty response in packet"
 | 
			
		||||
		}
 | 
			
		||||
		if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
 | 
			
		||||
			// Children[1].Children[2] is the diagnosticMessage which is guaranteed to exist as seen here: https://tools.ietf.org/html/rfc4511#section-4.1.9
 | 
			
		||||
			return uint8(response.Children[0].Value.(int64)), response.Children[2].Value.(string)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ErrorNetwork, "Invalid packet format"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error holds LDAP error information
 | 
			
		||||
type Error struct {
 | 
			
		||||
	// Err is the underlying error
 | 
			
		||||
	Err error
 | 
			
		||||
	// ResultCode is the LDAP error code
 | 
			
		||||
	ResultCode uint8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Error) Error() string {
 | 
			
		||||
	return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewError creates an LDAP error with the given code and underlying error
 | 
			
		||||
func NewError(resultCode uint8, err error) error {
 | 
			
		||||
	return &Error{ResultCode: resultCode, Err: err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
 | 
			
		||||
func IsErrorWithCode(err error, desiredResultCode uint8) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serverError, ok := err.(*Error)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return serverError.ResultCode == desiredResultCode
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								vendor/gopkg.in/ldap.v2/LICENSE → vendor/gopkg.in/ldap.v3/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								vendor/gopkg.in/ldap.v2/LICENSE → vendor/gopkg.in/ldap.v3/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
									
										14
									
								
								vendor/gopkg.in/ldap.v2/add.go → vendor/gopkg.in/ldap.v3/add.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/gopkg.in/ldap.v2/add.go → vendor/gopkg.in/ldap.v3/add.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -41,6 +41,8 @@ type AddRequest struct {
 | 
			
		||||
	DN string
 | 
			
		||||
	// Attributes list the attributes of the new entry
 | 
			
		||||
	Attributes []Attribute
 | 
			
		||||
	// Controls hold optional controls to send with the request
 | 
			
		||||
	Controls []Control
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a AddRequest) encode() *ber.Packet {
 | 
			
		||||
@@ -60,9 +62,10 @@ func (a *AddRequest) Attribute(attrType string, attrVals []string) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewAddRequest returns an AddRequest for the given DN, with no attributes
 | 
			
		||||
func NewAddRequest(dn string) *AddRequest {
 | 
			
		||||
func NewAddRequest(dn string, controls []Control) *AddRequest {
 | 
			
		||||
	return &AddRequest{
 | 
			
		||||
		DN:       dn,
 | 
			
		||||
		Controls: controls,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -72,6 +75,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 | 
			
		||||
	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 | 
			
		||||
	packet.AppendChild(addRequest.encode())
 | 
			
		||||
	if len(addRequest.Controls) > 0 {
 | 
			
		||||
		packet.AppendChild(encodeControls(addRequest.Controls))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.Debug.PrintPacket(packet)
 | 
			
		||||
 | 
			
		||||
@@ -100,9 +106,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if packet.Children[1].Tag == ApplicationAddResponse {
 | 
			
		||||
		resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
		if resultCode != 0 {
 | 
			
		||||
			return NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
		err := GetLDAPError(packet)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
 | 
			
		||||
							
								
								
									
										94
									
								
								vendor/gopkg.in/ldap.v2/bind.go → vendor/gopkg.in/ldap.v3/bind.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										94
									
								
								vendor/gopkg.in/ldap.v2/bind.go → vendor/gopkg.in/ldap.v3/bind.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,11 +1,8 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/asn1-ber.v1"
 | 
			
		||||
)
 | 
			
		||||
@@ -18,6 +15,9 @@ type SimpleBindRequest struct {
 | 
			
		||||
	Password string
 | 
			
		||||
	// Controls are optional controls to send with the bind request
 | 
			
		||||
	Controls []Control
 | 
			
		||||
	// AllowEmptyPassword sets whether the client allows binding with an empty password
 | 
			
		||||
	// (normally used for unauthenticated bind).
 | 
			
		||||
	AllowEmptyPassword bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SimpleBindResult contains the response from the server
 | 
			
		||||
@@ -31,6 +31,7 @@ func NewSimpleBindRequest(username string, password string, controls []Control)
 | 
			
		||||
		Username:           username,
 | 
			
		||||
		Password:           password,
 | 
			
		||||
		Controls:           controls,
 | 
			
		||||
		AllowEmptyPassword: false,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -40,17 +41,22 @@ func (bindRequest *SimpleBindRequest) encode() *ber.Packet {
 | 
			
		||||
	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name"))
 | 
			
		||||
	request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
 | 
			
		||||
 | 
			
		||||
	request.AppendChild(encodeControls(bindRequest.Controls))
 | 
			
		||||
 | 
			
		||||
	return request
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SimpleBind performs the simple bind operation defined in the given request
 | 
			
		||||
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
 | 
			
		||||
	if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword {
 | 
			
		||||
		return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 | 
			
		||||
	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 | 
			
		||||
	encodedBindRequest := simpleBindRequest.encode()
 | 
			
		||||
	packet.AppendChild(encodedBindRequest)
 | 
			
		||||
	if len(simpleBindRequest.Controls) > 0 {
 | 
			
		||||
		packet.AppendChild(encodeControls(simpleBindRequest.Controls))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if l.Debug {
 | 
			
		||||
		ber.PrintPacket(packet)
 | 
			
		||||
@@ -73,7 +79,7 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if l.Debug {
 | 
			
		||||
		if err := addLDAPDescriptions(packet); err != nil {
 | 
			
		||||
		if err = addLDAPDescriptions(packet); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		ber.PrintPacket(packet)
 | 
			
		||||
@@ -85,59 +91,45 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
 | 
			
		||||
 | 
			
		||||
	if len(packet.Children) == 3 {
 | 
			
		||||
		for _, child := range packet.Children[2].Children {
 | 
			
		||||
			result.Controls = append(result.Controls, DecodeControl(child))
 | 
			
		||||
			decodedChild, decodeErr := DecodeControl(child)
 | 
			
		||||
			if decodeErr != nil {
 | 
			
		||||
				return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
 | 
			
		||||
			}
 | 
			
		||||
			result.Controls = append(result.Controls, decodedChild)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
	if resultCode != 0 {
 | 
			
		||||
		return result, NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
	err = GetLDAPError(packet)
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Bind performs a bind with the given username and password
 | 
			
		||||
// Bind performs a bind with the given username and password.
 | 
			
		||||
//
 | 
			
		||||
// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method
 | 
			
		||||
// for that.
 | 
			
		||||
func (l *Conn) Bind(username, password string) error {
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 | 
			
		||||
	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 | 
			
		||||
	bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
 | 
			
		||||
	bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
 | 
			
		||||
	bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name"))
 | 
			
		||||
	bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password"))
 | 
			
		||||
	packet.AppendChild(bindRequest)
 | 
			
		||||
 | 
			
		||||
	if l.Debug {
 | 
			
		||||
		ber.PrintPacket(packet)
 | 
			
		||||
	req := &SimpleBindRequest{
 | 
			
		||||
		Username:           username,
 | 
			
		||||
		Password:           password,
 | 
			
		||||
		AllowEmptyPassword: false,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msgCtx, err := l.sendMessage(packet)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer l.finishMessage(msgCtx)
 | 
			
		||||
 | 
			
		||||
	packetResponse, ok := <-msgCtx.responses
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
 | 
			
		||||
	}
 | 
			
		||||
	packet, err = packetResponse.ReadPacket()
 | 
			
		||||
	l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	_, err := l.SimpleBind(req)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	if l.Debug {
 | 
			
		||||
		if err := addLDAPDescriptions(packet); err != nil {
 | 
			
		||||
// UnauthenticatedBind performs an unauthenticated bind.
 | 
			
		||||
//
 | 
			
		||||
// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
 | 
			
		||||
// authenticated or otherwise validated by the LDAP server.
 | 
			
		||||
//
 | 
			
		||||
// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
 | 
			
		||||
// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
 | 
			
		||||
func (l *Conn) UnauthenticatedBind(username string) error {
 | 
			
		||||
	req := &SimpleBindRequest{
 | 
			
		||||
		Username:           username,
 | 
			
		||||
		Password:           "",
 | 
			
		||||
		AllowEmptyPassword: true,
 | 
			
		||||
	}
 | 
			
		||||
	_, err := l.SimpleBind(req)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
		ber.PrintPacket(packet)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
	if resultCode != 0 {
 | 
			
		||||
		return NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/gopkg.in/ldap.v2/client.go → vendor/gopkg.in/ldap.v3/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/gopkg.in/ldap.v2/client.go → vendor/gopkg.in/ldap.v3/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -18,6 +18,7 @@ type Client interface {
 | 
			
		||||
	Add(addRequest *AddRequest) error
 | 
			
		||||
	Del(delRequest *DelRequest) error
 | 
			
		||||
	Modify(modifyRequest *ModifyRequest) error
 | 
			
		||||
	ModifyDN(modifyDNRequest *ModifyDNRequest) error
 | 
			
		||||
 | 
			
		||||
	Compare(dn, attribute, value string) (bool, error)
 | 
			
		||||
	PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/gopkg.in/ldap.v2/compare.go → vendor/gopkg.in/ldap.v3/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/gopkg.in/ldap.v2/compare.go → vendor/gopkg.in/ldap.v3/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,3 @@
 | 
			
		||||
// Copyright 2014 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
//
 | 
			
		||||
// File contains Compare functionality
 | 
			
		||||
//
 | 
			
		||||
// https://tools.ietf.org/html/rfc4511
 | 
			
		||||
@@ -41,7 +37,7 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
 | 
			
		||||
 | 
			
		||||
	ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion")
 | 
			
		||||
	ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "AttributeDesc"))
 | 
			
		||||
	ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagOctetString, value, "AssertionValue"))
 | 
			
		||||
	ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "AssertionValue"))
 | 
			
		||||
	request.AppendChild(ava)
 | 
			
		||||
	packet.AppendChild(request)
 | 
			
		||||
 | 
			
		||||
@@ -72,14 +68,16 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if packet.Children[1].Tag == ApplicationCompareResponse {
 | 
			
		||||
		resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
		if resultCode == LDAPResultCompareTrue {
 | 
			
		||||
		err := GetLDAPError(packet)
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case IsErrorWithCode(err, LDAPResultCompareTrue):
 | 
			
		||||
			return true, nil
 | 
			
		||||
		} else if resultCode == LDAPResultCompareFalse {
 | 
			
		||||
		case IsErrorWithCode(err, LDAPResultCompareFalse):
 | 
			
		||||
			return false, nil
 | 
			
		||||
		} else {
 | 
			
		||||
			return false, NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
		default:
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag)
 | 
			
		||||
	return false, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								vendor/gopkg.in/ldap.v2/conn.go → vendor/gopkg.in/ldap.v3/conn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								vendor/gopkg.in/ldap.v2/conn.go → vendor/gopkg.in/ldap.v3/conn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,3 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@@ -10,6 +6,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"time"
 | 
			
		||||
@@ -30,6 +27,13 @@ const (
 | 
			
		||||
	MessageTimeout = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// DefaultLdapPort default ldap port for pure TCP connection
 | 
			
		||||
	DefaultLdapPort = "389"
 | 
			
		||||
	// DefaultLdapsPort default ldap port for SSL connection
 | 
			
		||||
	DefaultLdapsPort = "636"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PacketResponse contains the packet or error encountered reading a response
 | 
			
		||||
type PacketResponse struct {
 | 
			
		||||
	// Packet is the packet read from the server
 | 
			
		||||
@@ -81,10 +85,13 @@ const (
 | 
			
		||||
 | 
			
		||||
// Conn represents an LDAP Connection
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	// requestTimeout is loaded atomically
 | 
			
		||||
	// so we need to ensure 64-bit alignment on 32-bit platforms.
 | 
			
		||||
	requestTimeout      int64
 | 
			
		||||
	conn                net.Conn
 | 
			
		||||
	isTLS               bool
 | 
			
		||||
	closing             uint32
 | 
			
		||||
	closeErr            atomicValue
 | 
			
		||||
	closeErr            atomic.Value
 | 
			
		||||
	isStartingTLS       bool
 | 
			
		||||
	Debug               debugging
 | 
			
		||||
	chanConfirm         chan struct{}
 | 
			
		||||
@@ -94,7 +101,6 @@ type Conn struct {
 | 
			
		||||
	wgClose             sync.WaitGroup
 | 
			
		||||
	outstandingRequests uint
 | 
			
		||||
	messageMutex        sync.Mutex
 | 
			
		||||
	requestTimeout      int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Client = &Conn{}
 | 
			
		||||
@@ -121,22 +127,51 @@ func Dial(network, addr string) (*Conn, error) {
 | 
			
		||||
// DialTLS connects to the given address on the given network using tls.Dial
 | 
			
		||||
// and then returns a new Conn for the connection.
 | 
			
		||||
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
 | 
			
		||||
	dc, err := net.DialTimeout(network, addr, DefaultTimeout)
 | 
			
		||||
	c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, NewError(ErrorNetwork, err)
 | 
			
		||||
	}
 | 
			
		||||
	c := tls.Client(dc, config)
 | 
			
		||||
	err = c.Handshake()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Handshake error, close the established connection before we return an error
 | 
			
		||||
		dc.Close()
 | 
			
		||||
		return nil, NewError(ErrorNetwork, err)
 | 
			
		||||
	}
 | 
			
		||||
	conn := NewConn(c, true)
 | 
			
		||||
	conn.Start()
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialURL connects to the given ldap URL vie TCP using tls.Dial or net.Dial if ldaps://
 | 
			
		||||
// or ldap:// specified as protocol. On success a new Conn for the connection
 | 
			
		||||
// is returned.
 | 
			
		||||
func DialURL(addr string) (*Conn, error) {
 | 
			
		||||
 | 
			
		||||
	lurl, err := url.Parse(addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, NewError(ErrorNetwork, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	host, port, err := net.SplitHostPort(lurl.Host)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// we asume that error is due to missing port
 | 
			
		||||
		host = lurl.Host
 | 
			
		||||
		port = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch lurl.Scheme {
 | 
			
		||||
	case "ldap":
 | 
			
		||||
		if port == "" {
 | 
			
		||||
			port = DefaultLdapPort
 | 
			
		||||
		}
 | 
			
		||||
		return Dial("tcp", net.JoinHostPort(host, port))
 | 
			
		||||
	case "ldaps":
 | 
			
		||||
		if port == "" {
 | 
			
		||||
			port = DefaultLdapsPort
 | 
			
		||||
		}
 | 
			
		||||
		tlsConf := &tls.Config{
 | 
			
		||||
			ServerName: host,
 | 
			
		||||
		}
 | 
			
		||||
		return DialTLS("tcp", net.JoinHostPort(host, port), tlsConf)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, NewError(ErrorNetwork, fmt.Errorf("Unknown scheme '%s'", lurl.Scheme))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewConn returns a new Conn using conn for network I/O.
 | 
			
		||||
func NewConn(conn net.Conn, isTLS bool) *Conn {
 | 
			
		||||
	return &Conn{
 | 
			
		||||
@@ -157,8 +192,8 @@ func (l *Conn) Start() {
 | 
			
		||||
	l.wgClose.Add(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isClosing returns whether or not we're currently closing.
 | 
			
		||||
func (l *Conn) isClosing() bool {
 | 
			
		||||
// IsClosing returns whether or not we're currently closing.
 | 
			
		||||
func (l *Conn) IsClosing() bool {
 | 
			
		||||
	return atomic.LoadUint32(&l.closing) == 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -242,30 +277,41 @@ func (l *Conn) StartTLS(config *tls.Config) error {
 | 
			
		||||
		ber.PrintPacket(packet)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if resultCode, message := getLDAPResultCode(packet); resultCode == LDAPResultSuccess {
 | 
			
		||||
	if err := GetLDAPError(packet); err == nil {
 | 
			
		||||
		conn := tls.Client(l.conn, config)
 | 
			
		||||
 | 
			
		||||
		if err := conn.Handshake(); err != nil {
 | 
			
		||||
		if connErr := conn.Handshake(); connErr != nil {
 | 
			
		||||
			l.Close()
 | 
			
		||||
			return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", err))
 | 
			
		||||
			return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", connErr))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		l.isTLS = true
 | 
			
		||||
		l.conn = conn
 | 
			
		||||
	} else {
 | 
			
		||||
		return NewError(resultCode, fmt.Errorf("ldap: cannot StartTLS (%s)", message))
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	go l.reader()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TLSConnectionState returns the client's TLS connection state.
 | 
			
		||||
// The return values are their zero values if StartTLS did
 | 
			
		||||
// not succeed.
 | 
			
		||||
func (l *Conn) TLSConnectionState() (state tls.ConnectionState, ok bool) {
 | 
			
		||||
	tc, ok := l.conn.(*tls.Conn)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return tc.ConnectionState(), true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) {
 | 
			
		||||
	return l.sendMessageWithFlags(packet, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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()
 | 
			
		||||
@@ -304,7 +350,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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -325,7 +371,7 @@ func (l *Conn) finishMessage(msgCtx *messageContext) {
 | 
			
		||||
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
 | 
			
		||||
	l.messageMutex.Lock()
 | 
			
		||||
	defer l.messageMutex.Unlock()
 | 
			
		||||
	if l.isClosing() {
 | 
			
		||||
	if l.IsClosing() {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	l.chanMessage <- message
 | 
			
		||||
@@ -340,7 +386,7 @@ 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.Load() != nil {
 | 
			
		||||
			if l.IsClosing() && l.closeErr.Load() != nil {
 | 
			
		||||
				msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
 | 
			
		||||
			}
 | 
			
		||||
			l.Debug.Printf("Closing channel for MessageID %d", messageID)
 | 
			
		||||
@@ -400,7 +446,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:
 | 
			
		||||
@@ -442,7 +488,7 @@ 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() {
 | 
			
		||||
			if !l.IsClosing() {
 | 
			
		||||
				l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err))
 | 
			
		||||
				l.Debug.Printf("reader error: %s", err.Error())
 | 
			
		||||
			}
 | 
			
		||||
							
								
								
									
										113
									
								
								vendor/gopkg.in/ldap.v2/control.go → vendor/gopkg.in/ldap.v3/control.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										113
									
								
								vendor/gopkg.in/ldap.v2/control.go → vendor/gopkg.in/ldap.v3/control.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,3 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@@ -22,6 +18,11 @@ const (
 | 
			
		||||
	ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
 | 
			
		||||
	// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
 | 
			
		||||
	ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
 | 
			
		||||
 | 
			
		||||
	// ControlTypeMicrosoftNotification - https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
 | 
			
		||||
	ControlTypeMicrosoftNotification = "1.2.840.113556.1.4.528"
 | 
			
		||||
	// ControlTypeMicrosoftShowDeleted - https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
 | 
			
		||||
	ControlTypeMicrosoftShowDeleted = "1.2.840.113556.1.4.417"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ControlTypeMap maps controls to text descriptions
 | 
			
		||||
@@ -29,6 +30,8 @@ var ControlTypeMap = map[string]string{
 | 
			
		||||
	ControlTypePaging:                "Paging",
 | 
			
		||||
	ControlTypeBeheraPasswordPolicy:  "Password Policy - Behera Draft",
 | 
			
		||||
	ControlTypeManageDsaIT:           "Manage DSA IT",
 | 
			
		||||
	ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
 | 
			
		||||
	ControlTypeMicrosoftShowDeleted:  "Show Deleted Objects - Microsoft",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Control defines an interface controls provide to encode and describe themselves
 | 
			
		||||
@@ -242,6 +245,64 @@ func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
 | 
			
		||||
	return &ControlManageDsaIT{Criticality: Criticality}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ControlMicrosoftNotification implements the control described in https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
 | 
			
		||||
type ControlMicrosoftNotification struct{}
 | 
			
		||||
 | 
			
		||||
// GetControlType returns the OID
 | 
			
		||||
func (c *ControlMicrosoftNotification) GetControlType() string {
 | 
			
		||||
	return ControlTypeMicrosoftNotification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encode returns the ber packet representation
 | 
			
		||||
func (c *ControlMicrosoftNotification) Encode() *ber.Packet {
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
 | 
			
		||||
	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftNotification, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftNotification]+")"))
 | 
			
		||||
 | 
			
		||||
	return packet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String returns a human-readable description
 | 
			
		||||
func (c *ControlMicrosoftNotification) String() string {
 | 
			
		||||
	return fmt.Sprintf(
 | 
			
		||||
		"Control Type: %s (%q)",
 | 
			
		||||
		ControlTypeMap[ControlTypeMicrosoftNotification],
 | 
			
		||||
		ControlTypeMicrosoftNotification)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewControlMicrosoftNotification returns a ControlMicrosoftNotification control
 | 
			
		||||
func NewControlMicrosoftNotification() *ControlMicrosoftNotification {
 | 
			
		||||
	return &ControlMicrosoftNotification{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ControlMicrosoftShowDeleted implements the control described in https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
 | 
			
		||||
type ControlMicrosoftShowDeleted struct{}
 | 
			
		||||
 | 
			
		||||
// GetControlType returns the OID
 | 
			
		||||
func (c *ControlMicrosoftShowDeleted) GetControlType() string {
 | 
			
		||||
	return ControlTypeMicrosoftShowDeleted
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encode returns the ber packet representation
 | 
			
		||||
func (c *ControlMicrosoftShowDeleted) Encode() *ber.Packet {
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
 | 
			
		||||
	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftShowDeleted, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftShowDeleted]+")"))
 | 
			
		||||
 | 
			
		||||
	return packet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String returns a human-readable description
 | 
			
		||||
func (c *ControlMicrosoftShowDeleted) String() string {
 | 
			
		||||
	return fmt.Sprintf(
 | 
			
		||||
		"Control Type: %s (%q)",
 | 
			
		||||
		ControlTypeMap[ControlTypeMicrosoftShowDeleted],
 | 
			
		||||
		ControlTypeMicrosoftShowDeleted)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewControlMicrosoftShowDeleted returns a ControlMicrosoftShowDeleted control
 | 
			
		||||
func NewControlMicrosoftShowDeleted() *ControlMicrosoftShowDeleted {
 | 
			
		||||
	return &ControlMicrosoftShowDeleted{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindControl returns the first control of the given type in the list, or nil
 | 
			
		||||
func FindControl(controls []Control, controlType string) Control {
 | 
			
		||||
	for _, c := range controls {
 | 
			
		||||
@@ -253,7 +314,7 @@ func FindControl(controls []Control, controlType string) Control {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
 | 
			
		||||
func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
func DecodeControl(packet *ber.Packet) (Control, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		ControlType = ""
 | 
			
		||||
		Criticality = false
 | 
			
		||||
@@ -263,7 +324,7 @@ func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
	switch len(packet.Children) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		// at least one child is required for control type
 | 
			
		||||
		return nil
 | 
			
		||||
		return nil, fmt.Errorf("at least one child is required for control type")
 | 
			
		||||
 | 
			
		||||
	case 1:
 | 
			
		||||
		// just type, no criticality or value
 | 
			
		||||
@@ -296,17 +357,20 @@ func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		// more than 3 children is invalid
 | 
			
		||||
		return nil
 | 
			
		||||
		return nil, fmt.Errorf("more than 3 children is invalid for controls")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch ControlType {
 | 
			
		||||
	case ControlTypeManageDsaIT:
 | 
			
		||||
		return NewControlManageDsaIT(Criticality)
 | 
			
		||||
		return NewControlManageDsaIT(Criticality), nil
 | 
			
		||||
	case ControlTypePaging:
 | 
			
		||||
		value.Description += " (Paging)"
 | 
			
		||||
		c := new(ControlPaging)
 | 
			
		||||
		if value.Value != nil {
 | 
			
		||||
			valueChildren := ber.DecodePacket(value.Data.Bytes())
 | 
			
		||||
			valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
			}
 | 
			
		||||
			value.Data.Truncate(0)
 | 
			
		||||
			value.Value = nil
 | 
			
		||||
			value.AppendChild(valueChildren)
 | 
			
		||||
@@ -318,12 +382,15 @@ func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
		c.PagingSize = uint32(value.Children[0].Value.(int64))
 | 
			
		||||
		c.Cookie = value.Children[1].Data.Bytes()
 | 
			
		||||
		value.Children[1].Value = c.Cookie
 | 
			
		||||
		return c
 | 
			
		||||
		return c, nil
 | 
			
		||||
	case ControlTypeBeheraPasswordPolicy:
 | 
			
		||||
		value.Description += " (Password Policy - Behera)"
 | 
			
		||||
		c := NewControlBeheraPasswordPolicy()
 | 
			
		||||
		if value.Value != nil {
 | 
			
		||||
			valueChildren := ber.DecodePacket(value.Data.Bytes())
 | 
			
		||||
			valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
			}
 | 
			
		||||
			value.Data.Truncate(0)
 | 
			
		||||
			value.Value = nil
 | 
			
		||||
			value.AppendChild(valueChildren)
 | 
			
		||||
@@ -335,7 +402,10 @@ func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
			if child.Tag == 0 {
 | 
			
		||||
				//Warning
 | 
			
		||||
				warningPacket := child.Children[0]
 | 
			
		||||
				packet := ber.DecodePacket(warningPacket.Data.Bytes())
 | 
			
		||||
				packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
				val, ok := packet.Value.(int64)
 | 
			
		||||
				if ok {
 | 
			
		||||
					if warningPacket.Tag == 0 {
 | 
			
		||||
@@ -350,7 +420,10 @@ func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
				}
 | 
			
		||||
			} else if child.Tag == 1 {
 | 
			
		||||
				// Error
 | 
			
		||||
				packet := ber.DecodePacket(child.Data.Bytes())
 | 
			
		||||
				packet, err := ber.DecodePacketErr(child.Data.Bytes())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
				val, ok := packet.Value.(int8)
 | 
			
		||||
				if !ok {
 | 
			
		||||
					// what to do?
 | 
			
		||||
@@ -361,22 +434,26 @@ func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
				c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return c
 | 
			
		||||
		return c, nil
 | 
			
		||||
	case ControlTypeVChuPasswordMustChange:
 | 
			
		||||
		c := &ControlVChuPasswordMustChange{MustChange: true}
 | 
			
		||||
		return c
 | 
			
		||||
		return c, nil
 | 
			
		||||
	case ControlTypeVChuPasswordWarning:
 | 
			
		||||
		c := &ControlVChuPasswordWarning{Expire: -1}
 | 
			
		||||
		expireStr := ber.DecodeString(value.Data.Bytes())
 | 
			
		||||
 | 
			
		||||
		expire, err := strconv.ParseInt(expireStr, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil
 | 
			
		||||
			return nil, fmt.Errorf("failed to parse value as int: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
		c.Expire = expire
 | 
			
		||||
		value.Value = c.Expire
 | 
			
		||||
 | 
			
		||||
		return c
 | 
			
		||||
		return c, nil
 | 
			
		||||
	case ControlTypeMicrosoftNotification:
 | 
			
		||||
		return NewControlMicrosoftNotification(), nil
 | 
			
		||||
	case ControlTypeMicrosoftShowDeleted:
 | 
			
		||||
		return NewControlMicrosoftShowDeleted(), nil
 | 
			
		||||
	default:
 | 
			
		||||
		c := new(ControlString)
 | 
			
		||||
		c.ControlType = ControlType
 | 
			
		||||
@@ -384,7 +461,7 @@ func DecodeControl(packet *ber.Packet) Control {
 | 
			
		||||
		if value != nil {
 | 
			
		||||
			c.ControlValue = value.Value.(string)
 | 
			
		||||
		}
 | 
			
		||||
		return c
 | 
			
		||||
		return c, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										0
									
								
								vendor/gopkg.in/ldap.v2/debug.go → vendor/gopkg.in/ldap.v3/debug.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								vendor/gopkg.in/ldap.v2/debug.go → vendor/gopkg.in/ldap.v3/debug.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
									
										8
									
								
								vendor/gopkg.in/ldap.v2/del.go → vendor/gopkg.in/ldap.v3/del.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/gopkg.in/ldap.v2/del.go → vendor/gopkg.in/ldap.v3/del.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -40,7 +40,7 @@ func (l *Conn) Del(delRequest *DelRequest) error {
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 | 
			
		||||
	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 | 
			
		||||
	packet.AppendChild(delRequest.encode())
 | 
			
		||||
	if delRequest.Controls != nil {
 | 
			
		||||
	if len(delRequest.Controls) > 0 {
 | 
			
		||||
		packet.AppendChild(encodeControls(delRequest.Controls))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -71,9 +71,9 @@ func (l *Conn) Del(delRequest *DelRequest) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if packet.Children[1].Tag == ApplicationDelResponse {
 | 
			
		||||
		resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
		if resultCode != 0 {
 | 
			
		||||
			return NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
		err := GetLDAPError(packet)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
 | 
			
		||||
							
								
								
									
										30
									
								
								vendor/gopkg.in/ldap.v2/dn.go → vendor/gopkg.in/ldap.v3/dn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/gopkg.in/ldap.v2/dn.go → vendor/gopkg.in/ldap.v3/dn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,3 @@
 | 
			
		||||
// Copyright 2015 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
//
 | 
			
		||||
// File contains DN parsing functionality
 | 
			
		||||
//
 | 
			
		||||
// https://tools.ietf.org/html/rfc4514
 | 
			
		||||
@@ -94,7 +90,8 @@ func ParseDN(str string) (*DN, error) {
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < len(str); i++ {
 | 
			
		||||
		char := str[i]
 | 
			
		||||
		if escaping {
 | 
			
		||||
		switch {
 | 
			
		||||
		case escaping:
 | 
			
		||||
			unescapedTrailingSpaces = 0
 | 
			
		||||
			escaping = false
 | 
			
		||||
			switch char {
 | 
			
		||||
@@ -104,22 +101,22 @@ func ParseDN(str string) (*DN, error) {
 | 
			
		||||
			}
 | 
			
		||||
			// Not a special character, assume hex encoded octet
 | 
			
		||||
			if len(str) == i+1 {
 | 
			
		||||
				return nil, errors.New("Got corrupted escaped character")
 | 
			
		||||
				return nil, errors.New("got corrupted escaped character")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			dst := []byte{0}
 | 
			
		||||
			n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("Failed to decode escaped character: %s", err)
 | 
			
		||||
				return nil, fmt.Errorf("failed to decode escaped character: %s", err)
 | 
			
		||||
			} else if n != 1 {
 | 
			
		||||
				return nil, fmt.Errorf("Expected 1 byte when un-escaping, got %d", n)
 | 
			
		||||
				return nil, fmt.Errorf("expected 1 byte when un-escaping, got %d", n)
 | 
			
		||||
			}
 | 
			
		||||
			buffer.WriteByte(dst[0])
 | 
			
		||||
			i++
 | 
			
		||||
		} else if char == '\\' {
 | 
			
		||||
		case char == '\\':
 | 
			
		||||
			unescapedTrailingSpaces = 0
 | 
			
		||||
			escaping = true
 | 
			
		||||
		} else if char == '=' {
 | 
			
		||||
		case char == '=':
 | 
			
		||||
			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
 | 
			
		||||
@@ -135,13 +132,16 @@ func ParseDN(str string) (*DN, error) {
 | 
			
		||||
				}
 | 
			
		||||
				rawBER, err := enchex.DecodeString(data)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, fmt.Errorf("Failed to decode BER encoding: %s", err)
 | 
			
		||||
					return nil, fmt.Errorf("failed to decode BER encoding: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
				packet, err := ber.DecodePacketErr(rawBER)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, fmt.Errorf("failed to decode BER packet: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
				packet := ber.DecodePacket(rawBER)
 | 
			
		||||
				buffer.WriteString(packet.Data.String())
 | 
			
		||||
				i += len(data) - 1
 | 
			
		||||
			}
 | 
			
		||||
		} else if char == ',' || char == '+' {
 | 
			
		||||
		case char == ',' || char == '+':
 | 
			
		||||
			// We're done with this RDN or value, push it
 | 
			
		||||
			if len(attribute.Type) == 0 {
 | 
			
		||||
				return nil, errors.New("incomplete type, value pair")
 | 
			
		||||
@@ -154,10 +154,10 @@ func ParseDN(str string) (*DN, error) {
 | 
			
		||||
				rdn = new(RelativeDN)
 | 
			
		||||
				rdn.Attributes = make([]*AttributeTypeAndValue, 0)
 | 
			
		||||
			}
 | 
			
		||||
		} else if char == ' ' && buffer.Len() == 0 {
 | 
			
		||||
		case char == ' ' && buffer.Len() == 0:
 | 
			
		||||
			// ignore unescaped leading spaces
 | 
			
		||||
			continue
 | 
			
		||||
		} else {
 | 
			
		||||
		default:
 | 
			
		||||
			if char == ' ' {
 | 
			
		||||
				// Track unescaped spaces in case they are trailing and we need to remove them
 | 
			
		||||
				unescapedTrailingSpaces++
 | 
			
		||||
							
								
								
									
										0
									
								
								vendor/gopkg.in/ldap.v2/doc.go → vendor/gopkg.in/ldap.v3/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								vendor/gopkg.in/ldap.v2/doc.go → vendor/gopkg.in/ldap.v3/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
									
										234
									
								
								vendor/gopkg.in/ldap.v3/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								vendor/gopkg.in/ldap.v3/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,234 @@
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/asn1-ber.v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// LDAP Result Codes
 | 
			
		||||
const (
 | 
			
		||||
	LDAPResultSuccess                            = 0
 | 
			
		||||
	LDAPResultOperationsError                    = 1
 | 
			
		||||
	LDAPResultProtocolError                      = 2
 | 
			
		||||
	LDAPResultTimeLimitExceeded                  = 3
 | 
			
		||||
	LDAPResultSizeLimitExceeded                  = 4
 | 
			
		||||
	LDAPResultCompareFalse                       = 5
 | 
			
		||||
	LDAPResultCompareTrue                        = 6
 | 
			
		||||
	LDAPResultAuthMethodNotSupported             = 7
 | 
			
		||||
	LDAPResultStrongAuthRequired                 = 8
 | 
			
		||||
	LDAPResultReferral                           = 10
 | 
			
		||||
	LDAPResultAdminLimitExceeded                 = 11
 | 
			
		||||
	LDAPResultUnavailableCriticalExtension       = 12
 | 
			
		||||
	LDAPResultConfidentialityRequired            = 13
 | 
			
		||||
	LDAPResultSaslBindInProgress                 = 14
 | 
			
		||||
	LDAPResultNoSuchAttribute                    = 16
 | 
			
		||||
	LDAPResultUndefinedAttributeType             = 17
 | 
			
		||||
	LDAPResultInappropriateMatching              = 18
 | 
			
		||||
	LDAPResultConstraintViolation                = 19
 | 
			
		||||
	LDAPResultAttributeOrValueExists             = 20
 | 
			
		||||
	LDAPResultInvalidAttributeSyntax             = 21
 | 
			
		||||
	LDAPResultNoSuchObject                       = 32
 | 
			
		||||
	LDAPResultAliasProblem                       = 33
 | 
			
		||||
	LDAPResultInvalidDNSyntax                    = 34
 | 
			
		||||
	LDAPResultIsLeaf                             = 35
 | 
			
		||||
	LDAPResultAliasDereferencingProblem          = 36
 | 
			
		||||
	LDAPResultInappropriateAuthentication        = 48
 | 
			
		||||
	LDAPResultInvalidCredentials                 = 49
 | 
			
		||||
	LDAPResultInsufficientAccessRights           = 50
 | 
			
		||||
	LDAPResultBusy                               = 51
 | 
			
		||||
	LDAPResultUnavailable                        = 52
 | 
			
		||||
	LDAPResultUnwillingToPerform                 = 53
 | 
			
		||||
	LDAPResultLoopDetect                         = 54
 | 
			
		||||
	LDAPResultSortControlMissing                 = 60
 | 
			
		||||
	LDAPResultOffsetRangeError                   = 61
 | 
			
		||||
	LDAPResultNamingViolation                    = 64
 | 
			
		||||
	LDAPResultObjectClassViolation               = 65
 | 
			
		||||
	LDAPResultNotAllowedOnNonLeaf                = 66
 | 
			
		||||
	LDAPResultNotAllowedOnRDN                    = 67
 | 
			
		||||
	LDAPResultEntryAlreadyExists                 = 68
 | 
			
		||||
	LDAPResultObjectClassModsProhibited          = 69
 | 
			
		||||
	LDAPResultResultsTooLarge                    = 70
 | 
			
		||||
	LDAPResultAffectsMultipleDSAs                = 71
 | 
			
		||||
	LDAPResultVirtualListViewErrorOrControlError = 76
 | 
			
		||||
	LDAPResultOther                              = 80
 | 
			
		||||
	LDAPResultServerDown                         = 81
 | 
			
		||||
	LDAPResultLocalError                         = 82
 | 
			
		||||
	LDAPResultEncodingError                      = 83
 | 
			
		||||
	LDAPResultDecodingError                      = 84
 | 
			
		||||
	LDAPResultTimeout                            = 85
 | 
			
		||||
	LDAPResultAuthUnknown                        = 86
 | 
			
		||||
	LDAPResultFilterError                        = 87
 | 
			
		||||
	LDAPResultUserCanceled                       = 88
 | 
			
		||||
	LDAPResultParamError                         = 89
 | 
			
		||||
	LDAPResultNoMemory                           = 90
 | 
			
		||||
	LDAPResultConnectError                       = 91
 | 
			
		||||
	LDAPResultNotSupported                       = 92
 | 
			
		||||
	LDAPResultControlNotFound                    = 93
 | 
			
		||||
	LDAPResultNoResultsReturned                  = 94
 | 
			
		||||
	LDAPResultMoreResultsToReturn                = 95
 | 
			
		||||
	LDAPResultClientLoop                         = 96
 | 
			
		||||
	LDAPResultReferralLimitExceeded              = 97
 | 
			
		||||
	LDAPResultInvalidResponse                    = 100
 | 
			
		||||
	LDAPResultAmbiguousResponse                  = 101
 | 
			
		||||
	LDAPResultTLSNotSupported                    = 112
 | 
			
		||||
	LDAPResultIntermediateResponse               = 113
 | 
			
		||||
	LDAPResultUnknownType                        = 114
 | 
			
		||||
	LDAPResultCanceled                           = 118
 | 
			
		||||
	LDAPResultNoSuchOperation                    = 119
 | 
			
		||||
	LDAPResultTooLate                            = 120
 | 
			
		||||
	LDAPResultCannotCancel                       = 121
 | 
			
		||||
	LDAPResultAssertionFailed                    = 122
 | 
			
		||||
	LDAPResultAuthorizationDenied                = 123
 | 
			
		||||
	LDAPResultSyncRefreshRequired                = 4096
 | 
			
		||||
 | 
			
		||||
	ErrorNetwork            = 200
 | 
			
		||||
	ErrorFilterCompile      = 201
 | 
			
		||||
	ErrorFilterDecompile    = 202
 | 
			
		||||
	ErrorDebugging          = 203
 | 
			
		||||
	ErrorUnexpectedMessage  = 204
 | 
			
		||||
	ErrorUnexpectedResponse = 205
 | 
			
		||||
	ErrorEmptyPassword      = 206
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// LDAPResultCodeMap contains string descriptions for LDAP error codes
 | 
			
		||||
var LDAPResultCodeMap = map[uint16]string{
 | 
			
		||||
	LDAPResultSuccess:                            "Success",
 | 
			
		||||
	LDAPResultOperationsError:                    "Operations Error",
 | 
			
		||||
	LDAPResultProtocolError:                      "Protocol Error",
 | 
			
		||||
	LDAPResultTimeLimitExceeded:                  "Time Limit Exceeded",
 | 
			
		||||
	LDAPResultSizeLimitExceeded:                  "Size Limit Exceeded",
 | 
			
		||||
	LDAPResultCompareFalse:                       "Compare False",
 | 
			
		||||
	LDAPResultCompareTrue:                        "Compare True",
 | 
			
		||||
	LDAPResultAuthMethodNotSupported:             "Auth Method Not Supported",
 | 
			
		||||
	LDAPResultStrongAuthRequired:                 "Strong Auth Required",
 | 
			
		||||
	LDAPResultReferral:                           "Referral",
 | 
			
		||||
	LDAPResultAdminLimitExceeded:                 "Admin Limit Exceeded",
 | 
			
		||||
	LDAPResultUnavailableCriticalExtension:       "Unavailable Critical Extension",
 | 
			
		||||
	LDAPResultConfidentialityRequired:            "Confidentiality Required",
 | 
			
		||||
	LDAPResultSaslBindInProgress:                 "Sasl Bind In Progress",
 | 
			
		||||
	LDAPResultNoSuchAttribute:                    "No Such Attribute",
 | 
			
		||||
	LDAPResultUndefinedAttributeType:             "Undefined Attribute Type",
 | 
			
		||||
	LDAPResultInappropriateMatching:              "Inappropriate Matching",
 | 
			
		||||
	LDAPResultConstraintViolation:                "Constraint Violation",
 | 
			
		||||
	LDAPResultAttributeOrValueExists:             "Attribute Or Value Exists",
 | 
			
		||||
	LDAPResultInvalidAttributeSyntax:             "Invalid Attribute Syntax",
 | 
			
		||||
	LDAPResultNoSuchObject:                       "No Such Object",
 | 
			
		||||
	LDAPResultAliasProblem:                       "Alias Problem",
 | 
			
		||||
	LDAPResultInvalidDNSyntax:                    "Invalid DN Syntax",
 | 
			
		||||
	LDAPResultIsLeaf:                             "Is Leaf",
 | 
			
		||||
	LDAPResultAliasDereferencingProblem:          "Alias Dereferencing Problem",
 | 
			
		||||
	LDAPResultInappropriateAuthentication:        "Inappropriate Authentication",
 | 
			
		||||
	LDAPResultInvalidCredentials:                 "Invalid Credentials",
 | 
			
		||||
	LDAPResultInsufficientAccessRights:           "Insufficient Access Rights",
 | 
			
		||||
	LDAPResultBusy:                               "Busy",
 | 
			
		||||
	LDAPResultUnavailable:                        "Unavailable",
 | 
			
		||||
	LDAPResultUnwillingToPerform:                 "Unwilling To Perform",
 | 
			
		||||
	LDAPResultLoopDetect:                         "Loop Detect",
 | 
			
		||||
	LDAPResultSortControlMissing:                 "Sort Control Missing",
 | 
			
		||||
	LDAPResultOffsetRangeError:                   "Result Offset Range Error",
 | 
			
		||||
	LDAPResultNamingViolation:                    "Naming Violation",
 | 
			
		||||
	LDAPResultObjectClassViolation:               "Object Class Violation",
 | 
			
		||||
	LDAPResultResultsTooLarge:                    "Results Too Large",
 | 
			
		||||
	LDAPResultNotAllowedOnNonLeaf:                "Not Allowed On Non Leaf",
 | 
			
		||||
	LDAPResultNotAllowedOnRDN:                    "Not Allowed On RDN",
 | 
			
		||||
	LDAPResultEntryAlreadyExists:                 "Entry Already Exists",
 | 
			
		||||
	LDAPResultObjectClassModsProhibited:          "Object Class Mods Prohibited",
 | 
			
		||||
	LDAPResultAffectsMultipleDSAs:                "Affects Multiple DSAs",
 | 
			
		||||
	LDAPResultVirtualListViewErrorOrControlError: "Failed because of a problem related to the virtual list view",
 | 
			
		||||
	LDAPResultOther:                              "Other",
 | 
			
		||||
	LDAPResultServerDown:                         "Cannot establish a connection",
 | 
			
		||||
	LDAPResultLocalError:                         "An error occurred",
 | 
			
		||||
	LDAPResultEncodingError:                      "LDAP encountered an error while encoding",
 | 
			
		||||
	LDAPResultDecodingError:                      "LDAP encountered an error while decoding",
 | 
			
		||||
	LDAPResultTimeout:                            "LDAP timeout while waiting for a response from the server",
 | 
			
		||||
	LDAPResultAuthUnknown:                        "The auth method requested in a bind request is unknown",
 | 
			
		||||
	LDAPResultFilterError:                        "An error occurred while encoding the given search filter",
 | 
			
		||||
	LDAPResultUserCanceled:                       "The user canceled the operation",
 | 
			
		||||
	LDAPResultParamError:                         "An invalid parameter was specified",
 | 
			
		||||
	LDAPResultNoMemory:                           "Out of memory error",
 | 
			
		||||
	LDAPResultConnectError:                       "A connection to the server could not be established",
 | 
			
		||||
	LDAPResultNotSupported:                       "An attempt has been made to use a feature not supported LDAP",
 | 
			
		||||
	LDAPResultControlNotFound:                    "The controls required to perform the requested operation were not found",
 | 
			
		||||
	LDAPResultNoResultsReturned:                  "No results were returned from the server",
 | 
			
		||||
	LDAPResultMoreResultsToReturn:                "There are more results in the chain of results",
 | 
			
		||||
	LDAPResultClientLoop:                         "A loop has been detected. For example when following referrals",
 | 
			
		||||
	LDAPResultReferralLimitExceeded:              "The referral hop limit has been exceeded",
 | 
			
		||||
	LDAPResultCanceled:                           "Operation was canceled",
 | 
			
		||||
	LDAPResultNoSuchOperation:                    "Server has no knowledge of the operation requested for cancellation",
 | 
			
		||||
	LDAPResultTooLate:                            "Too late to cancel the outstanding operation",
 | 
			
		||||
	LDAPResultCannotCancel:                       "The identified operation does not support cancellation or the cancel operation cannot be performed",
 | 
			
		||||
	LDAPResultAssertionFailed:                    "An assertion control given in the LDAP operation evaluated to false causing the operation to not be performed",
 | 
			
		||||
	LDAPResultSyncRefreshRequired:                "Refresh Required",
 | 
			
		||||
	LDAPResultInvalidResponse:                    "Invalid Response",
 | 
			
		||||
	LDAPResultAmbiguousResponse:                  "Ambiguous Response",
 | 
			
		||||
	LDAPResultTLSNotSupported:                    "Tls Not Supported",
 | 
			
		||||
	LDAPResultIntermediateResponse:               "Intermediate Response",
 | 
			
		||||
	LDAPResultUnknownType:                        "Unknown Type",
 | 
			
		||||
	LDAPResultAuthorizationDenied:                "Authorization Denied",
 | 
			
		||||
 | 
			
		||||
	ErrorNetwork:            "Network Error",
 | 
			
		||||
	ErrorFilterCompile:      "Filter Compile Error",
 | 
			
		||||
	ErrorFilterDecompile:    "Filter Decompile Error",
 | 
			
		||||
	ErrorDebugging:          "Debugging Error",
 | 
			
		||||
	ErrorUnexpectedMessage:  "Unexpected Message",
 | 
			
		||||
	ErrorUnexpectedResponse: "Unexpected Response",
 | 
			
		||||
	ErrorEmptyPassword:      "Empty password not allowed by the client",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error holds LDAP error information
 | 
			
		||||
type Error struct {
 | 
			
		||||
	// Err is the underlying error
 | 
			
		||||
	Err error
 | 
			
		||||
	// ResultCode is the LDAP error code
 | 
			
		||||
	ResultCode uint16
 | 
			
		||||
	// MatchedDN is the matchedDN returned if any
 | 
			
		||||
	MatchedDN string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Error) Error() string {
 | 
			
		||||
	return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLDAPError creates an Error out of a BER packet representing a LDAPResult
 | 
			
		||||
// The return is an error object. It can be casted to a Error structure.
 | 
			
		||||
// This function returns nil if resultCode in the LDAPResult sequence is success(0).
 | 
			
		||||
func GetLDAPError(packet *ber.Packet) error {
 | 
			
		||||
	if packet == nil {
 | 
			
		||||
		return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty packet")}
 | 
			
		||||
	} else if len(packet.Children) >= 2 {
 | 
			
		||||
		response := packet.Children[1]
 | 
			
		||||
		if response == nil {
 | 
			
		||||
			return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet")}
 | 
			
		||||
		}
 | 
			
		||||
		if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
 | 
			
		||||
			resultCode := uint16(response.Children[0].Value.(int64))
 | 
			
		||||
			if resultCode == 0 { // No error
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			return &Error{ResultCode: resultCode, MatchedDN: response.Children[1].Value.(string),
 | 
			
		||||
				Err: fmt.Errorf(response.Children[2].Value.(string))}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid packet format")}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewError creates an LDAP error with the given code and underlying error
 | 
			
		||||
func NewError(resultCode uint16, err error) error {
 | 
			
		||||
	return &Error{ResultCode: resultCode, Err: err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
 | 
			
		||||
func IsErrorWithCode(err error, desiredResultCode uint16) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serverError, ok := err.(*Error)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return serverError.ResultCode == desiredResultCode
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/gopkg.in/ldap.v2/filter.go → vendor/gopkg.in/ldap.v3/filter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/gopkg.in/ldap.v2/filter.go → vendor/gopkg.in/ldap.v3/filter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,3 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
							
								
								
									
										86
									
								
								vendor/gopkg.in/ldap.v2/ldap.go → vendor/gopkg.in/ldap.v3/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										86
									
								
								vendor/gopkg.in/ldap.v2/ldap.go → vendor/gopkg.in/ldap.v3/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,11 +1,8 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
@@ -101,13 +98,13 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
 | 
			
		||||
 | 
			
		||||
	switch application {
 | 
			
		||||
	case ApplicationBindRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationBindResponse:
 | 
			
		||||
		addDefaultLDAPResponseDescriptions(packet)
 | 
			
		||||
		err = addDefaultLDAPResponseDescriptions(packet)
 | 
			
		||||
	case ApplicationUnbindRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationSearchRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationSearchResultEntry:
 | 
			
		||||
		packet.Children[1].Children[0].Description = "Object Name"
 | 
			
		||||
		packet.Children[1].Children[1].Description = "Attributes"
 | 
			
		||||
@@ -120,37 +117,37 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if len(packet.Children) == 3 {
 | 
			
		||||
			addControlDescriptions(packet.Children[2])
 | 
			
		||||
			err = addControlDescriptions(packet.Children[2])
 | 
			
		||||
		}
 | 
			
		||||
	case ApplicationSearchResultDone:
 | 
			
		||||
		addDefaultLDAPResponseDescriptions(packet)
 | 
			
		||||
		err = addDefaultLDAPResponseDescriptions(packet)
 | 
			
		||||
	case ApplicationModifyRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationModifyResponse:
 | 
			
		||||
	case ApplicationAddRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationAddResponse:
 | 
			
		||||
	case ApplicationDelRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationDelResponse:
 | 
			
		||||
	case ApplicationModifyDNRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationModifyDNResponse:
 | 
			
		||||
	case ApplicationCompareRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationCompareResponse:
 | 
			
		||||
	case ApplicationAbandonRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationSearchResultReference:
 | 
			
		||||
	case ApplicationExtendedRequest:
 | 
			
		||||
		addRequestDescriptions(packet)
 | 
			
		||||
		err = addRequestDescriptions(packet)
 | 
			
		||||
	case ApplicationExtendedResponse:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
func addControlDescriptions(packet *ber.Packet) error {
 | 
			
		||||
	packet.Description = "Controls"
 | 
			
		||||
	for _, child := range packet.Children {
 | 
			
		||||
		var value *ber.Packet
 | 
			
		||||
@@ -159,7 +156,7 @@ func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
		switch len(child.Children) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			// at least one child is required for control type
 | 
			
		||||
			continue
 | 
			
		||||
			return fmt.Errorf("at least one child is required for control type")
 | 
			
		||||
 | 
			
		||||
		case 1:
 | 
			
		||||
			// just type, no criticality or value
 | 
			
		||||
@@ -188,8 +185,9 @@ func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			// more than 3 children is invalid
 | 
			
		||||
			continue
 | 
			
		||||
			return fmt.Errorf("more than 3 children for control packet found")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if value == nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
@@ -197,7 +195,10 @@ func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
		case ControlTypePaging:
 | 
			
		||||
			value.Description += " (Paging)"
 | 
			
		||||
			if value.Value != nil {
 | 
			
		||||
				valueChildren := ber.DecodePacket(value.Data.Bytes())
 | 
			
		||||
				valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
				value.Data.Truncate(0)
 | 
			
		||||
				value.Value = nil
 | 
			
		||||
				valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
 | 
			
		||||
@@ -210,7 +211,10 @@ func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
		case ControlTypeBeheraPasswordPolicy:
 | 
			
		||||
			value.Description += " (Password Policy - Behera Draft)"
 | 
			
		||||
			if value.Value != nil {
 | 
			
		||||
				valueChildren := ber.DecodePacket(value.Data.Bytes())
 | 
			
		||||
				valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
				value.Data.Truncate(0)
 | 
			
		||||
				value.Value = nil
 | 
			
		||||
				value.AppendChild(valueChildren)
 | 
			
		||||
@@ -220,7 +224,10 @@ func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
				if child.Tag == 0 {
 | 
			
		||||
					//Warning
 | 
			
		||||
					warningPacket := child.Children[0]
 | 
			
		||||
					packet := ber.DecodePacket(warningPacket.Data.Bytes())
 | 
			
		||||
					packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
					}
 | 
			
		||||
					val, ok := packet.Value.(int64)
 | 
			
		||||
					if ok {
 | 
			
		||||
						if warningPacket.Tag == 0 {
 | 
			
		||||
@@ -235,7 +242,10 @@ func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
					}
 | 
			
		||||
				} else if child.Tag == 1 {
 | 
			
		||||
					// Error
 | 
			
		||||
					packet := ber.DecodePacket(child.Data.Bytes())
 | 
			
		||||
					packet, err := ber.DecodePacketErr(child.Data.Bytes())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return fmt.Errorf("failed to decode data bytes: %s", err)
 | 
			
		||||
					}
 | 
			
		||||
					val, ok := packet.Value.(int8)
 | 
			
		||||
					if !ok {
 | 
			
		||||
						val = -1
 | 
			
		||||
@@ -246,28 +256,31 @@ func addControlDescriptions(packet *ber.Packet) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addRequestDescriptions(packet *ber.Packet) {
 | 
			
		||||
func addRequestDescriptions(packet *ber.Packet) error {
 | 
			
		||||
	packet.Description = "LDAP Request"
 | 
			
		||||
	packet.Children[0].Description = "Message ID"
 | 
			
		||||
	packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
 | 
			
		||||
	if len(packet.Children) == 3 {
 | 
			
		||||
		addControlDescriptions(packet.Children[2])
 | 
			
		||||
		return addControlDescriptions(packet.Children[2])
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
 | 
			
		||||
	resultCode, _ := getLDAPResultCode(packet)
 | 
			
		||||
	packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
 | 
			
		||||
	packet.Children[1].Children[1].Description = "Matched DN"
 | 
			
		||||
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error {
 | 
			
		||||
	err := GetLDAPError(packet)
 | 
			
		||||
	packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[err.(*Error).ResultCode] + ")"
 | 
			
		||||
	packet.Children[1].Children[1].Description = "Matched DN (" + err.(*Error).MatchedDN + ")"
 | 
			
		||||
	packet.Children[1].Children[2].Description = "Error Message"
 | 
			
		||||
	if len(packet.Children[1].Children) > 3 {
 | 
			
		||||
		packet.Children[1].Children[3].Description = "Referral"
 | 
			
		||||
	}
 | 
			
		||||
	if len(packet.Children) == 3 {
 | 
			
		||||
		addControlDescriptions(packet.Children[2])
 | 
			
		||||
		return addControlDescriptions(packet.Children[2])
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DebugBinaryFile reads and prints packets from the given filename
 | 
			
		||||
@@ -277,8 +290,13 @@ func DebugBinaryFile(fileName string) error {
 | 
			
		||||
		return NewError(ErrorDebugging, err)
 | 
			
		||||
	}
 | 
			
		||||
	ber.PrintBytes(os.Stdout, file, "")
 | 
			
		||||
	packet := ber.DecodePacket(file)
 | 
			
		||||
	addLDAPDescriptions(packet)
 | 
			
		||||
	packet, err := ber.DecodePacketErr(file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to decode packet: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := addLDAPDescriptions(packet); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	ber.PrintPacket(packet)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
							
								
								
									
										104
									
								
								vendor/gopkg.in/ldap.v3/moddn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/gopkg.in/ldap.v3/moddn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
// Package ldap - moddn.go contains ModifyDN functionality
 | 
			
		||||
//
 | 
			
		||||
// https://tools.ietf.org/html/rfc4511
 | 
			
		||||
// ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
 | 
			
		||||
//      entry           LDAPDN,
 | 
			
		||||
//      newrdn          RelativeLDAPDN,
 | 
			
		||||
//      deleteoldrdn    BOOLEAN,
 | 
			
		||||
//      newSuperior     [0] LDAPDN OPTIONAL }
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
package ldap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"log"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/asn1-ber.v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ModifyDNRequest holds the request to modify a DN
 | 
			
		||||
type ModifyDNRequest struct {
 | 
			
		||||
	DN           string
 | 
			
		||||
	NewRDN       string
 | 
			
		||||
	DeleteOldRDN bool
 | 
			
		||||
	NewSuperior  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewModifyDNRequest creates a new request which can be passed to ModifyDN().
 | 
			
		||||
//
 | 
			
		||||
// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an
 | 
			
		||||
// empty string for just changing the object's RDN.
 | 
			
		||||
//
 | 
			
		||||
// For moving the object without renaming, the "rdn" must be the first
 | 
			
		||||
// RDN of the given DN.
 | 
			
		||||
//
 | 
			
		||||
// A call like
 | 
			
		||||
//   mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "")
 | 
			
		||||
// will setup the request to just rename uid=someone,dc=example,dc=org to
 | 
			
		||||
// uid=newname,dc=example,dc=org.
 | 
			
		||||
func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest {
 | 
			
		||||
	return &ModifyDNRequest{
 | 
			
		||||
		DN:           dn,
 | 
			
		||||
		NewRDN:       rdn,
 | 
			
		||||
		DeleteOldRDN: delOld,
 | 
			
		||||
		NewSuperior:  newSup,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m ModifyDNRequest) encode() *ber.Packet {
 | 
			
		||||
	request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request")
 | 
			
		||||
	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
 | 
			
		||||
	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.NewRDN, "New RDN"))
 | 
			
		||||
	request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, m.DeleteOldRDN, "Delete old RDN"))
 | 
			
		||||
	if m.NewSuperior != "" {
 | 
			
		||||
		request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior"))
 | 
			
		||||
	}
 | 
			
		||||
	return request
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument
 | 
			
		||||
// to NewModifyDNRequest() is not "").
 | 
			
		||||
func (l *Conn) ModifyDN(m *ModifyDNRequest) error {
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 | 
			
		||||
	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 | 
			
		||||
	packet.AppendChild(m.encode())
 | 
			
		||||
 | 
			
		||||
	l.Debug.PrintPacket(packet)
 | 
			
		||||
 | 
			
		||||
	msgCtx, err := l.sendMessage(packet)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer l.finishMessage(msgCtx)
 | 
			
		||||
 | 
			
		||||
	l.Debug.Printf("%d: waiting for response", msgCtx.id)
 | 
			
		||||
	packetResponse, ok := <-msgCtx.responses
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return NewError(ErrorNetwork, errors.New("ldap: channel closed"))
 | 
			
		||||
	}
 | 
			
		||||
	packet, err = packetResponse.ReadPacket()
 | 
			
		||||
	l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if l.Debug {
 | 
			
		||||
		if err := addLDAPDescriptions(packet); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		ber.PrintPacket(packet)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if packet.Children[1].Tag == ApplicationModifyDNResponse {
 | 
			
		||||
		err := GetLDAPError(packet)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.Debug.Printf("%d: returning", msgCtx.id)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								vendor/gopkg.in/ldap.v2/modify.go → vendor/gopkg.in/ldap.v3/modify.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										75
									
								
								vendor/gopkg.in/ldap.v2/modify.go → vendor/gopkg.in/ldap.v3/modify.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,3 @@
 | 
			
		||||
// Copyright 2014 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
//
 | 
			
		||||
// File contains Modify functionality
 | 
			
		||||
//
 | 
			
		||||
// https://tools.ietf.org/html/rfc4511
 | 
			
		||||
@@ -62,54 +58,56 @@ func (p *PartialAttribute) encode() *ber.Packet {
 | 
			
		||||
	return seq
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
 | 
			
		||||
type Change struct {
 | 
			
		||||
	// Operation is the type of change to be made
 | 
			
		||||
	Operation uint
 | 
			
		||||
	// Modification is the attribute to be modified
 | 
			
		||||
	Modification PartialAttribute
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Change) encode() *ber.Packet {
 | 
			
		||||
	change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
 | 
			
		||||
	change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation"))
 | 
			
		||||
	change.AppendChild(c.Modification.encode())
 | 
			
		||||
	return change
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
 | 
			
		||||
type ModifyRequest struct {
 | 
			
		||||
	// DN is the distinguishedName of the directory entry to modify
 | 
			
		||||
	DN string
 | 
			
		||||
	// AddAttributes contain the attributes to add
 | 
			
		||||
	AddAttributes []PartialAttribute
 | 
			
		||||
	// DeleteAttributes contain the attributes to delete
 | 
			
		||||
	DeleteAttributes []PartialAttribute
 | 
			
		||||
	// ReplaceAttributes contain the attributes to replace
 | 
			
		||||
	ReplaceAttributes []PartialAttribute
 | 
			
		||||
	// Changes contain the attributes to modify
 | 
			
		||||
	Changes []Change
 | 
			
		||||
	// Controls hold optional controls to send with the request
 | 
			
		||||
	Controls []Control
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add inserts the given attribute to the list of attributes to add
 | 
			
		||||
// Add appends the given attribute to the list of changes to be made
 | 
			
		||||
func (m *ModifyRequest) Add(attrType string, attrVals []string) {
 | 
			
		||||
	m.AddAttributes = append(m.AddAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
 | 
			
		||||
	m.appendChange(AddAttribute, attrType, attrVals)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Delete inserts the given attribute to the list of attributes to delete
 | 
			
		||||
// Delete appends the given attribute to the list of changes to be made
 | 
			
		||||
func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
 | 
			
		||||
	m.DeleteAttributes = append(m.DeleteAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
 | 
			
		||||
	m.appendChange(DeleteAttribute, attrType, attrVals)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Replace inserts the given attribute to the list of attributes to replace
 | 
			
		||||
// Replace appends the given attribute to the list of changes to be made
 | 
			
		||||
func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
 | 
			
		||||
	m.ReplaceAttributes = append(m.ReplaceAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
 | 
			
		||||
	m.appendChange(ReplaceAttribute, attrType, attrVals)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
 | 
			
		||||
	m.Changes = append(m.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m ModifyRequest) encode() *ber.Packet {
 | 
			
		||||
	request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
 | 
			
		||||
	request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
 | 
			
		||||
	changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
 | 
			
		||||
	for _, attribute := range m.AddAttributes {
 | 
			
		||||
		change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
 | 
			
		||||
		change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation"))
 | 
			
		||||
		change.AppendChild(attribute.encode())
 | 
			
		||||
		changes.AppendChild(change)
 | 
			
		||||
	}
 | 
			
		||||
	for _, attribute := range m.DeleteAttributes {
 | 
			
		||||
		change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
 | 
			
		||||
		change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation"))
 | 
			
		||||
		change.AppendChild(attribute.encode())
 | 
			
		||||
		changes.AppendChild(change)
 | 
			
		||||
	}
 | 
			
		||||
	for _, attribute := range m.ReplaceAttributes {
 | 
			
		||||
		change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
 | 
			
		||||
		change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation"))
 | 
			
		||||
		change.AppendChild(attribute.encode())
 | 
			
		||||
		changes.AppendChild(change)
 | 
			
		||||
	for _, change := range m.Changes {
 | 
			
		||||
		changes.AppendChild(change.encode())
 | 
			
		||||
	}
 | 
			
		||||
	request.AppendChild(changes)
 | 
			
		||||
	return request
 | 
			
		||||
@@ -118,9 +116,11 @@ func (m ModifyRequest) encode() *ber.Packet {
 | 
			
		||||
// NewModifyRequest creates a modify request for the given DN
 | 
			
		||||
func NewModifyRequest(
 | 
			
		||||
	dn string,
 | 
			
		||||
	controls []Control,
 | 
			
		||||
) *ModifyRequest {
 | 
			
		||||
	return &ModifyRequest{
 | 
			
		||||
		DN:       dn,
 | 
			
		||||
		Controls: controls,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -129,6 +129,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
 | 
			
		||||
	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
 | 
			
		||||
	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
 | 
			
		||||
	packet.AppendChild(modifyRequest.encode())
 | 
			
		||||
	if len(modifyRequest.Controls) > 0 {
 | 
			
		||||
		packet.AppendChild(encodeControls(modifyRequest.Controls))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.Debug.PrintPacket(packet)
 | 
			
		||||
 | 
			
		||||
@@ -157,9 +160,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if packet.Children[1].Tag == ApplicationModifyResponse {
 | 
			
		||||
		resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
		if resultCode != 0 {
 | 
			
		||||
			return NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
		err := GetLDAPError(packet)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/gopkg.in/ldap.v2/passwdmodify.go → vendor/gopkg.in/ldap.v3/passwdmodify.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/gopkg.in/ldap.v2/passwdmodify.go → vendor/gopkg.in/ldap.v3/passwdmodify.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -32,6 +32,8 @@ type PasswordModifyRequest struct {
 | 
			
		||||
type PasswordModifyResult struct {
 | 
			
		||||
	// GeneratedPassword holds a password generated by the server, if present
 | 
			
		||||
	GeneratedPassword string
 | 
			
		||||
	// Referral are the returned referral
 | 
			
		||||
	Referral string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
 | 
			
		||||
@@ -124,12 +126,19 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if packet.Children[1].Tag == ApplicationExtendedResponse {
 | 
			
		||||
		resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
		if resultCode != 0 {
 | 
			
		||||
			return nil, NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
		err := GetLDAPError(packet)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if IsErrorWithCode(err, LDAPResultReferral) {
 | 
			
		||||
				for _, child := range packet.Children[1].Children {
 | 
			
		||||
					if child.Tag == 3 {
 | 
			
		||||
						result.Referral = child.Children[0].Value.(string)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return result, err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
 | 
			
		||||
		return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	extendedResponse := packet.Children[1]
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/gopkg.in/ldap.v2/search.go → vendor/gopkg.in/ldap.v3/search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/gopkg.in/ldap.v2/search.go → vendor/gopkg.in/ldap.v3/search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,3 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
//
 | 
			
		||||
// File contains Search functionality
 | 
			
		||||
//
 | 
			
		||||
// https://tools.ietf.org/html/rfc4511
 | 
			
		||||
@@ -313,10 +309,10 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32)
 | 
			
		||||
	} else {
 | 
			
		||||
		castControl, ok := control.(*ControlPaging)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, fmt.Errorf("Expected paging control to be of type *ControlPaging, got %v", control)
 | 
			
		||||
			return nil, fmt.Errorf("expected paging control to be of type *ControlPaging, got %v", control)
 | 
			
		||||
		}
 | 
			
		||||
		if castControl.PagingSize != pagingSize {
 | 
			
		||||
			return nil, fmt.Errorf("Paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
 | 
			
		||||
			return nil, fmt.Errorf("paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
 | 
			
		||||
		}
 | 
			
		||||
		pagingControl = castControl
 | 
			
		||||
	}
 | 
			
		||||
@@ -379,7 +375,7 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
 | 
			
		||||
	}
 | 
			
		||||
	packet.AppendChild(encodedSearchRequest)
 | 
			
		||||
	// encode search controls
 | 
			
		||||
	if searchRequest.Controls != nil {
 | 
			
		||||
	if len(searchRequest.Controls) > 0 {
 | 
			
		||||
		packet.AppendChild(encodeControls(searchRequest.Controls))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -431,13 +427,17 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
 | 
			
		||||
			}
 | 
			
		||||
			result.Entries = append(result.Entries, entry)
 | 
			
		||||
		case 5:
 | 
			
		||||
			resultCode, resultDescription := getLDAPResultCode(packet)
 | 
			
		||||
			if resultCode != 0 {
 | 
			
		||||
				return result, NewError(resultCode, errors.New(resultDescription))
 | 
			
		||||
			err := GetLDAPError(packet)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if len(packet.Children) == 3 {
 | 
			
		||||
				for _, child := range packet.Children[2].Children {
 | 
			
		||||
					result.Controls = append(result.Controls, DecodeControl(child))
 | 
			
		||||
					decodedChild, err := DecodeControl(child)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, fmt.Errorf("failed to decode child control: %s", err)
 | 
			
		||||
					}
 | 
			
		||||
					result.Controls = append(result.Controls, decodedChild)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			foundSearchResultDone = true
 | 
			
		||||
		Reference in New Issue
	
	Block a user