mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-19 14:01:08 +00:00
Compare commits
60 Commits
v1.7.0-dev
...
v1.7.3
| 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 | ||
|
|
dfad569e40 | ||
|
|
c3b67ff2f6 | ||
|
|
5c30817b5f | ||
|
|
438848a2ca | ||
|
|
9d4aa78113 | ||
|
|
e5af93af20 | ||
|
|
3f802a2846 | ||
|
|
0190d3c243 | ||
|
|
4fe1a3050e | ||
|
|
29799537a7 | ||
|
|
d3a334d99a | ||
|
|
28d9305ea3 | ||
|
|
8a9f5b3b50 | ||
|
|
f28e17473c | ||
|
|
2c26521579 | ||
|
|
f635041c98 | ||
|
|
3fa49f3780 | ||
|
|
4577cddd28 | ||
|
|
8da5237107 | ||
|
|
8006b1bc7a | ||
|
|
8d400320c6 | ||
|
|
e9c4609410 | ||
|
|
176a6048b4 | ||
|
|
483aa06b07 | ||
|
|
551dc58a4d | ||
|
|
41a2bfe3ae | ||
|
|
652e09fc3e | ||
|
|
c9b57a5135 | ||
|
|
2904d8d6aa | ||
|
|
109fc7975b | ||
|
|
3ee3a4b595 | ||
|
|
14e218cbd1 | ||
|
|
b5f4911afa |
@@ -211,7 +211,7 @@ pipeline:
|
|||||||
branch: [ master ]
|
branch: [ master ]
|
||||||
|
|
||||||
static:
|
static:
|
||||||
image: karalabe/xgo-latest:latest
|
image: techknowlogick/xgo:latest
|
||||||
pull: true
|
pull: true
|
||||||
environment:
|
environment:
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
|||||||
76
CHANGELOG.md
76
CHANGELOG.md
@@ -4,7 +4,62 @@ 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
|
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).
|
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
|
|
||||||
## [1.7.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-02
|
## [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)
|
||||||
|
* Only allow local login if password is non-empty (#5906) (#5908)
|
||||||
|
* Fix go-get URL generation (#5905) (#5907)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix TLS errors when using acme/autocert for local connections (#5820) (#5826)
|
||||||
|
* Request for public keys only if LDAP attribute is set (#5816) (#5819)
|
||||||
|
* Fix delete correct temp directory (#5840) (#5839)
|
||||||
|
* Fix an error while adding a dependency via UI (#5862) (#5876)
|
||||||
|
* Fix null pointer in attempt to Sudo if not logged in (#5872) (#5884)
|
||||||
|
* When creating new repository fsck option should be enabled (#5817) (#5885)
|
||||||
|
* Prevent nil dereference in mailIssueCommentToParticipants (#5891) (#5895) (#5894)
|
||||||
|
* Fix bug when read public repo lfs file (#5913) (#5912)
|
||||||
|
* Respect value of REQUIRE_SIGNIN_VIEW (#5901) (#5915)
|
||||||
|
* Fix compare button on upstream repo leading to 404 (#5877) (#5914)
|
||||||
|
* DOCS
|
||||||
|
* Added docs for the tree api (#5835)
|
||||||
|
* MISC
|
||||||
|
* Include Go toolchain to --version (#5832) (#5830)
|
||||||
|
|
||||||
|
## [1.7.0](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-22
|
||||||
|
* SECURITY
|
||||||
|
* Do not display the raw OpenID error in the UI (#5705) (#5712)
|
||||||
|
* When redirecting clean the path to avoid redirecting to external site (#5669) (#5679)
|
||||||
|
* Prevent DeleteFilePost doing arbitrary deletion (#5631)
|
||||||
* BREAKING
|
* BREAKING
|
||||||
* Restrict permission check on repositories and fix some problems (#5314)
|
* Restrict permission check on repositories and fix some problems (#5314)
|
||||||
* Show only opened milestones on issues page milestone filter (#5051)
|
* Show only opened milestones on issues page milestone filter (#5051)
|
||||||
@@ -23,6 +78,13 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
|||||||
* Give user a link to create PR after push (#4716)
|
* Give user a link to create PR after push (#4716)
|
||||||
* Add rebase with merge commit merge style (#3844) (#4052)
|
* Add rebase with merge commit merge style (#3844) (#4052)
|
||||||
* BUGFIXES
|
* BUGFIXES
|
||||||
|
* Disallow empty titles (#5785) (#5794)
|
||||||
|
* Fix sqlite deadlock when assigning to a PR (#5640) (#5642)
|
||||||
|
* Don't close issues via commits on non-default branch. (#5622) (#5643)
|
||||||
|
* Fix commit page showing status for current default branch (#5650) (#5653)
|
||||||
|
* Only count users own actions for heatmap contributions (#5647) (#5655)
|
||||||
|
* Update xorm to fix issue postgresql dumping issues (#5680) (#5692)
|
||||||
|
* Use correct value for "MSpan Structures Obtained" (#5706) (#5716)
|
||||||
* Fix bug on modifying sshd username (#5624)
|
* Fix bug on modifying sshd username (#5624)
|
||||||
* Delete tags in mirror which are removed for original repo. (#5609)
|
* Delete tags in mirror which are removed for original repo. (#5609)
|
||||||
* Fix wrong text getting saved on editing second comment on an issue. (#5608)
|
* Fix wrong text getting saved on editing second comment on an issue. (#5608)
|
||||||
@@ -149,6 +211,18 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
|||||||
* Git-Trees API (#5403)
|
* Git-Trees API (#5403)
|
||||||
* Only chown directories during docker setup if necessary. Fix #4425 (#5064)
|
* Only chown directories during docker setup if necessary. Fix #4425 (#5064)
|
||||||
|
|
||||||
|
## [1.6.4](https://github.com/go-gitea/gitea/releases/tag/v1.6.4) - 2019-01-15
|
||||||
|
* BUGFIX
|
||||||
|
* Fix SSH key now can be reused as public key after deleting as deploy key (#5671) (#5685)
|
||||||
|
* When redirecting clean the path to avoid redirecting to external site (#5669) (#5703)
|
||||||
|
* Fix to use correct value for "MSpan Structures Obtained" (#5706) (#5715)
|
||||||
|
|
||||||
|
## [1.6.3](https://github.com/go-gitea/gitea/releases/tag/v1.6.3) - 2019-01-04
|
||||||
|
* SECURITY
|
||||||
|
* Prevent DeleteFilePost doing arbitrary deletion (#5631)
|
||||||
|
* BUGFIX
|
||||||
|
* Fix wrong text getting saved on editing second comment on an issue (#5608)
|
||||||
|
|
||||||
## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21
|
## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21
|
||||||
* SECURITY
|
* SECURITY
|
||||||
* Sanitize uploaded file names (#5571) (#5573)
|
* Sanitize uploaded file names (#5571) (#5573)
|
||||||
|
|||||||
15
Gopkg.lock
generated
15
Gopkg.lock
generated
@@ -406,11 +406,11 @@
|
|||||||
version = "v0.6.0"
|
version = "v0.6.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:931a62a1aacc37a5e4c309a111642ec4da47b4dc453cd4ba5481b12eedb04a5d"
|
digest = "1:d366480c27ab51b3f7e995f25503063e7a6ebc7feb269df2499c33471f35cd62"
|
||||||
name = "github.com/go-xorm/xorm"
|
name = "github.com/go-xorm/xorm"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "401f4ee8ff8cbc40a4754cb12192fbe4f02f3979"
|
revision = "1cd2662be938bfee0e34af92fe448513e0560fb1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -1005,12 +1005,12 @@
|
|||||||
version = "v1.31.1"
|
version = "v1.31.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:01f4ac37c52bda6f7e1bd73680a99f88733c0408aaa159ecb1ba53a1ade9423c"
|
digest = "1:8a502dedecf5b6d56e36f0d0e6196392baf616634af2c23108b6e8bb89ec57fc"
|
||||||
name = "gopkg.in/ldap.v2"
|
name = "gopkg.in/ldap.v3"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "d0a5ced67b4dc310b9158d63a2c6f9c5ec13f105"
|
revision = "214f299a0ecb2a6c6f6d2b0f13977032b207dc58"
|
||||||
version = "v2.4.1"
|
version = "v3.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:cfe1730a152ff033ad7d9c115d22e36b19eec6d5928c06146b9119be45d39dc0"
|
digest = "1:cfe1730a152ff033ad7d9c115d22e36b19eec6d5928c06146b9119be45d39dc0"
|
||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"github.com/keybase/go-crypto/openpgp",
|
"github.com/keybase/go-crypto/openpgp",
|
||||||
"github.com/keybase/go-crypto/openpgp/armor",
|
"github.com/keybase/go-crypto/openpgp/armor",
|
||||||
"github.com/keybase/go-crypto/openpgp/packet",
|
"github.com/keybase/go-crypto/openpgp/packet",
|
||||||
|
"github.com/klauspost/compress/gzip",
|
||||||
"github.com/lafriks/xormstore",
|
"github.com/lafriks/xormstore",
|
||||||
"github.com/lib/pq",
|
"github.com/lib/pq",
|
||||||
"github.com/lunny/dingtalk_webhook",
|
"github.com/lunny/dingtalk_webhook",
|
||||||
@@ -1214,7 +1215,7 @@
|
|||||||
"gopkg.in/editorconfig/editorconfig-core-go.v1",
|
"gopkg.in/editorconfig/editorconfig-core-go.v1",
|
||||||
"gopkg.in/gomail.v2",
|
"gopkg.in/gomail.v2",
|
||||||
"gopkg.in/ini.v1",
|
"gopkg.in/ini.v1",
|
||||||
"gopkg.in/ldap.v2",
|
"gopkg.in/ldap.v3",
|
||||||
"gopkg.in/macaron.v1",
|
"gopkg.in/macaron.v1",
|
||||||
"gopkg.in/testfixtures.v2",
|
"gopkg.in/testfixtures.v2",
|
||||||
"strk.kbt.io/projects/go/libravatar",
|
"strk.kbt.io/projects/go/libravatar",
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ ignored = ["google.golang.org/appengine*"]
|
|||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/go-xorm/xorm"
|
name = "github.com/go-xorm/xorm"
|
||||||
revision = "401f4ee8ff8cbc40a4754cb12192fbe4f02f3979"
|
revision = "1cd2662be938bfee0e34af92fe448513e0560fb1"
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/go-xorm/builder"
|
name = "github.com/go-xorm/builder"
|
||||||
@@ -97,8 +97,8 @@ ignored = ["google.golang.org/appengine*"]
|
|||||||
version = "1.31.1"
|
version = "1.31.1"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "gopkg.in/ldap.v2"
|
name = "gopkg.in/ldap.v3"
|
||||||
version = "2.4.1"
|
version = "3.0.1"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "gopkg.in/macaron.v1"
|
name = "gopkg.in/macaron.v1"
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ func argsSet(c *cli.Context, args ...string) error {
|
|||||||
return errors.New(a + " is not set")
|
return errors.New(a + " is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(strings.TrimSpace(c.String(a))) == 0 {
|
if util.IsEmptyString(a) {
|
||||||
return errors.New(a + " is required")
|
return errors.New(a + " is required")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
cmd/serv.go
22
cmd/serv.go
@@ -70,6 +70,7 @@ func checkLFSVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setup(logPath string) {
|
func setup(logPath string) {
|
||||||
|
log.DelLogger("console")
|
||||||
setting.NewContext()
|
setting.NewContext()
|
||||||
checkLFSVersion()
|
checkLFSVersion()
|
||||||
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
|
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
|
||||||
@@ -233,23 +234,30 @@ func runServ(c *cli.Context) error {
|
|||||||
|
|
||||||
// Check deploy key or user key.
|
// Check deploy key or user key.
|
||||||
if key.Type == models.KeyTypeDeploy {
|
if key.Type == models.KeyTypeDeploy {
|
||||||
if key.Mode < requestedMode {
|
// Now we have to get the deploy key for this repo
|
||||||
fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
|
deployKey, err := private.GetDeployKey(key.ID, repo.ID)
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this deploy key belongs to current repository.
|
|
||||||
has, err := private.HasDeployKey(key.ID, repo.ID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
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)
|
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.
|
// Update deploy key activity.
|
||||||
if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
|
if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
|
||||||
fail("Internal error", "UpdateDeployKey: %v", err)
|
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 {
|
} else {
|
||||||
user, err = private.GetUserByKeyID(key.ID)
|
user, err = private.GetUserByKeyID(key.ID)
|
||||||
if err != nil {
|
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
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/git"
|
"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"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,160 +24,86 @@ const (
|
|||||||
bigSize = 128 * 1024 * 1024 //128Mo
|
bigSize = 128 * 1024 * 1024 //128Mo
|
||||||
)
|
)
|
||||||
|
|
||||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) {
|
func TestGit(t *testing.T) {
|
||||||
prepareTestEnv(t)
|
onGiteaRun(t, testGit)
|
||||||
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) {
|
func testGit(t *testing.T, u *url.URL) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
username := "user2"
|
||||||
u.Path = "user2/repo1.git"
|
baseAPITestContext := NewAPITestContext(t, username, "repo1")
|
||||||
|
|
||||||
t.Run("HTTP", func(t *testing.T) {
|
u.Path = baseAPITestContext.GitPath()
|
||||||
dstPath, err := ioutil.TempDir("", "repo-tmp-17")
|
|
||||||
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")))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("CreateRepo", func(t *testing.T) {
|
t.Run("HTTP", func(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
httpContext := baseAPITestContext
|
||||||
token := getTokenForLoggedInUser(t, session)
|
httpContext.Reponame = "repo-tmp-17"
|
||||||
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)
|
|
||||||
})
|
|
||||||
|
|
||||||
u.Path = "user2/repo-tmp-17.git"
|
dstPath, err := ioutil.TempDir("", httpContext.Reponame)
|
||||||
u.User = url.UserPassword("user2", userPassword)
|
assert.NoError(t, err)
|
||||||
t.Run("Clone", func(t *testing.T) {
|
defer os.RemoveAll(dstPath)
|
||||||
err = git.Clone(u.String(), dstPath, git.CloneRepoOptions{})
|
t.Run("Standard", func(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
ensureAnonymousClone(t, u)
|
||||||
assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("PushCommit", func(t *testing.T) {
|
t.Run("CreateRepo", doAPICreateRepository(httpContext, false))
|
||||||
t.Run("Little", func(t *testing.T) {
|
|
||||||
commitAndPush(t, littleSize, dstPath)
|
|
||||||
})
|
|
||||||
t.Run("Big", func(t *testing.T) {
|
|
||||||
commitAndPush(t, bigSize, dstPath)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
t.Run("LFS", func(t *testing.T) {
|
|
||||||
t.Run("PushCommit", func(t *testing.T) {
|
|
||||||
//Setup git LFS
|
|
||||||
_, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
_, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = git.AddChanges(dstPath, false, ".gitattributes")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
t.Run("Little", func(t *testing.T) {
|
u.Path = httpContext.GitPath()
|
||||||
commitAndPush(t, littleSize, dstPath)
|
u.User = url.UserPassword(username, userPassword)
|
||||||
})
|
|
||||||
t.Run("Big", func(t *testing.T) {
|
t.Run("Clone", doGitClone(dstPath, u))
|
||||||
commitAndPush(t, bigSize, dstPath)
|
|
||||||
})
|
t.Run("PushCommit", func(t *testing.T) {
|
||||||
|
t.Run("Little", func(t *testing.T) {
|
||||||
|
commitAndPush(t, littleSize, dstPath)
|
||||||
})
|
})
|
||||||
t.Run("Locks", func(t *testing.T) {
|
t.Run("Big", func(t *testing.T) {
|
||||||
lockTest(t, u.String(), dstPath)
|
commitAndPush(t, bigSize, dstPath)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
t.Run("SSH", func(t *testing.T) {
|
t.Run("LFS", func(t *testing.T) {
|
||||||
//Setup remote link
|
t.Run("PushCommit", func(t *testing.T) {
|
||||||
u.Scheme = "ssh"
|
//Setup git LFS
|
||||||
u.User = url.User("git")
|
_, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
|
||||||
u.Host = fmt.Sprintf("%s:%d", setting.SSH.ListenHost, setting.SSH.ListenPort)
|
assert.NoError(t, err)
|
||||||
u.Path = "user2/repo-tmp-18.git"
|
_, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = git.AddChanges(dstPath, false, ".gitattributes")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
//Setup key
|
t.Run("Little", func(t *testing.T) {
|
||||||
keyFile := filepath.Join(setting.AppDataPath, "my-testing-key")
|
commitAndPush(t, littleSize, dstPath)
|
||||||
err := exec.Command("ssh-keygen", "-f", keyFile, "-t", "rsa", "-N", "").Run()
|
})
|
||||||
assert.NoError(t, err)
|
t.Run("Big", func(t *testing.T) {
|
||||||
defer os.RemoveAll(keyFile)
|
commitAndPush(t, bigSize, dstPath)
|
||||||
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)
|
t.Run("Locks", func(t *testing.T) {
|
||||||
|
lockTest(t, u.String(), dstPath)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
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 ssh wrapper
|
//Setup remote link
|
||||||
os.Setenv("GIT_SSH_COMMAND",
|
sshURL := createSSHUrl(sshContext.GitPath(), u)
|
||||||
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
|
|
||||||
filepath.Join(setting.AppWorkPath, keyFile))
|
|
||||||
os.Setenv("GIT_SSH_VARIANT", "ssh")
|
|
||||||
|
|
||||||
//Setup clone folder
|
//Setup clone folder
|
||||||
dstPath, err := ioutil.TempDir("", "repo-tmp-18")
|
dstPath, err := ioutil.TempDir("", sshContext.Reponame)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(dstPath)
|
defer os.RemoveAll(dstPath)
|
||||||
|
|
||||||
t.Run("Standard", func(t *testing.T) {
|
t.Run("Standard", func(t *testing.T) {
|
||||||
t.Run("CreateRepo", func(t *testing.T) {
|
t.Run("CreateRepo", doAPICreateRepository(sshContext, false))
|
||||||
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)
|
|
||||||
})
|
|
||||||
//TODO get url from api
|
//TODO get url from api
|
||||||
t.Run("Clone", func(t *testing.T) {
|
t.Run("Clone", doGitClone(dstPath, sshURL))
|
||||||
_, err = git.NewCommand("clone").AddArguments(u.String(), dstPath).Run()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
|
|
||||||
})
|
|
||||||
//time.Sleep(5 * time.Minute)
|
//time.Sleep(5 * time.Minute)
|
||||||
t.Run("PushCommit", func(t *testing.T) {
|
t.Run("PushCommit", func(t *testing.T) {
|
||||||
t.Run("Little", 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)
|
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) {
|
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
|
_, err := git.NewCommand("remote").AddArguments("set-url", "origin", remote).RunInDir(repoPath) //TODO add test ssh git-lfs-creds
|
||||||
assert.NoError(t, err)
|
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)
|
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
|
// Check that user4 does not see draft and still see 10 latest releases
|
||||||
session2 := loginUser(t, "user3")
|
session2 := loginUser(t, "user4")
|
||||||
checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", i18n.Tr("en", "repo.release.stable"), 10)
|
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))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
5
main.go
5
main.go
@@ -8,6 +8,7 @@ package main // import "code.gitea.io/gitea"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/cmd"
|
"code.gitea.io/gitea/cmd"
|
||||||
@@ -61,8 +62,8 @@ arguments - which can alternatively be run by running the subcommand web.`
|
|||||||
|
|
||||||
func formatBuiltWith(Tags string) string {
|
func formatBuiltWith(Tags string) string {
|
||||||
if len(Tags) == 0 {
|
if len(Tags) == 0 {
|
||||||
return ""
|
return " built with " + runtime.Version()
|
||||||
}
|
}
|
||||||
|
|
||||||
return " built with: " + strings.Replace(Tags, " ", ", ", -1)
|
return " built with " + runtime.Version() + " : " + strings.Replace(Tags, " ", ", ", -1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,8 +476,34 @@ func getIssueFromRef(repo *Repository, ref string) (*Issue, error) {
|
|||||||
return issue, nil
|
return issue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func changeIssueStatus(repo *Repository, doer *User, ref string, refMarked map[int64]bool, status bool) error {
|
||||||
|
issue, err := getIssueFromRef(repo, ref)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if issue == nil || refMarked[issue.ID] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
refMarked[issue.ID] = true
|
||||||
|
|
||||||
|
if issue.RepoID != repo.ID || issue.IsClosed == status {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
issue.Repo = repo
|
||||||
|
if err = issue.ChangeStatus(doer, status); err != nil {
|
||||||
|
// Don't return an error when dependencies are open as this would let the push fail
|
||||||
|
if IsErrDependenciesLeft(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateIssuesCommit checks if issues are manipulated by commit message.
|
// UpdateIssuesCommit checks if issues are manipulated by commit message.
|
||||||
func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) error {
|
func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, branchName string) error {
|
||||||
// Commits are appended in the reverse order.
|
// Commits are appended in the reverse order.
|
||||||
for i := len(commits) - 1; i >= 0; i-- {
|
for i := len(commits) - 1; i >= 0; i-- {
|
||||||
c := commits[i]
|
c := commits[i]
|
||||||
@@ -500,51 +526,21 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Change issue status only if the commit has been pushed to the default branch.
|
||||||
|
if repo.DefaultBranch != branchName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
refMarked = make(map[int64]bool)
|
refMarked = make(map[int64]bool)
|
||||||
// FIXME: can merge this one and next one to a common function.
|
|
||||||
for _, ref := range issueCloseKeywordsPat.FindAllString(c.Message, -1) {
|
for _, ref := range issueCloseKeywordsPat.FindAllString(c.Message, -1) {
|
||||||
issue, err := getIssueFromRef(repo, ref)
|
if err := changeIssueStatus(repo, doer, ref, refMarked, true); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if issue == nil || refMarked[issue.ID] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
refMarked[issue.ID] = true
|
|
||||||
|
|
||||||
if issue.RepoID != repo.ID || issue.IsClosed {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
issue.Repo = repo
|
|
||||||
if err = issue.ChangeStatus(doer, true); err != nil {
|
|
||||||
// Don't return an error when dependencies are open as this would let the push fail
|
|
||||||
if IsErrDependenciesLeft(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is conflict to have close and reopen at same time, so refsMarked doesn't need to reinit here.
|
// It is conflict to have close and reopen at same time, so refsMarked doesn't need to reinit here.
|
||||||
for _, ref := range issueReopenKeywordsPat.FindAllString(c.Message, -1) {
|
for _, ref := range issueReopenKeywordsPat.FindAllString(c.Message, -1) {
|
||||||
issue, err := getIssueFromRef(repo, ref)
|
if err := changeIssueStatus(repo, doer, ref, refMarked, false); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if issue == nil || refMarked[issue.ID] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
refMarked[issue.ID] = true
|
|
||||||
|
|
||||||
if issue.RepoID != repo.ID || !issue.IsClosed {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
issue.Repo = repo
|
|
||||||
if err = issue.ChangeStatus(doer, false); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -609,7 +605,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
|||||||
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits); err != nil {
|
if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits, refName); err != nil {
|
||||||
log.Error(4, "updateIssuesCommit: %v", err)
|
log.Error(4, "updateIssuesCommit: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,10 +227,37 @@ func TestUpdateIssuesCommit(t *testing.T) {
|
|||||||
|
|
||||||
AssertNotExistsBean(t, commentBean)
|
AssertNotExistsBean(t, commentBean)
|
||||||
AssertNotExistsBean(t, &Issue{RepoID: repo.ID, Index: 2}, "is_closed=1")
|
AssertNotExistsBean(t, &Issue{RepoID: repo.ID, Index: 2}, "is_closed=1")
|
||||||
assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits))
|
assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, repo.DefaultBranch))
|
||||||
AssertExistsAndLoadBean(t, commentBean)
|
AssertExistsAndLoadBean(t, commentBean)
|
||||||
AssertExistsAndLoadBean(t, issueBean, "is_closed=1")
|
AssertExistsAndLoadBean(t, issueBean, "is_closed=1")
|
||||||
CheckConsistencyFor(t, &Action{})
|
CheckConsistencyFor(t, &Action{})
|
||||||
|
|
||||||
|
// Test that push to a non-default branch closes no issue.
|
||||||
|
pushCommits = []*PushCommit{
|
||||||
|
{
|
||||||
|
Sha1: "abcdef1",
|
||||||
|
CommitterEmail: "user2@example.com",
|
||||||
|
CommitterName: "User Two",
|
||||||
|
AuthorEmail: "user4@example.com",
|
||||||
|
AuthorName: "User Four",
|
||||||
|
Message: "close #1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
repo = AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
|
||||||
|
commentBean = &Comment{
|
||||||
|
Type: CommentTypeCommitRef,
|
||||||
|
CommitSHA: "abcdef1",
|
||||||
|
PosterID: user.ID,
|
||||||
|
IssueID: 6,
|
||||||
|
}
|
||||||
|
issueBean = &Issue{RepoID: repo.ID, Index: 1}
|
||||||
|
|
||||||
|
AssertNotExistsBean(t, commentBean)
|
||||||
|
AssertNotExistsBean(t, &Issue{RepoID: repo.ID, Index: 1}, "is_closed=1")
|
||||||
|
assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, "non-existing-branch"))
|
||||||
|
AssertExistsAndLoadBean(t, commentBean)
|
||||||
|
AssertNotExistsBean(t, issueBean, "is_closed=1")
|
||||||
|
CheckConsistencyFor(t, &Action{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCorrectRepoAction(t *testing.T, opts CommitRepoActionOptions, actionBean *Action) {
|
func testCorrectRepoAction(t *testing.T, opts CommitRepoActionOptions, actionBean *Action) {
|
||||||
|
|||||||
@@ -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)
|
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.
|
// ErrEmailAlreadyUsed represents a "EmailAlreadyUsed" kind of error.
|
||||||
type ErrEmailAlreadyUsed struct {
|
type ErrEmailAlreadyUsed struct {
|
||||||
Email string
|
Email string
|
||||||
|
|||||||
@@ -1402,7 +1402,7 @@ func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memberIDs := make([]int64, 0, user.NumMembers)
|
memberIDs := make([]int64, 0, user.NumMembers)
|
||||||
orgUsers, err := GetOrgUsersByOrgID(user.ID)
|
orgUsers, err := getOrgUsersByOrgID(e, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetOrgUsersByOrgID [%d]: %v", user.ID, err)
|
return fmt.Errorf("GetOrgUsersByOrgID [%d]: %v", user.ID, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ func (issue *Issue) loadAssignees(e Engine) (err error) {
|
|||||||
|
|
||||||
// GetAssigneesByIssue returns everyone assigned to that issue
|
// GetAssigneesByIssue returns everyone assigned to that issue
|
||||||
func GetAssigneesByIssue(issue *Issue) (assignees []*User, err error) {
|
func GetAssigneesByIssue(issue *Issue) (assignees []*User, err error) {
|
||||||
err = issue.loadAssignees(x)
|
return getAssigneesByIssue(x, issue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAssigneesByIssue(e Engine, issue *Issue) (assignees []*User, err error) {
|
||||||
|
err = issue.loadAssignees(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return assignees, err
|
return assignees, err
|
||||||
}
|
}
|
||||||
@@ -173,7 +177,7 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
|
|||||||
issue.PullRequest.Issue = issue
|
issue.PullRequest.Issue = issue
|
||||||
apiPullRequest := &api.PullRequestPayload{
|
apiPullRequest := &api.PullRequestPayload{
|
||||||
Index: issue.Index,
|
Index: issue.Index,
|
||||||
PullRequest: issue.PullRequest.APIFormat(),
|
PullRequest: issue.PullRequest.apiFormat(sess),
|
||||||
Repository: issue.Repo.innerAPIFormat(sess, mode, false),
|
Repository: issue.Repo.innerAPIFormat(sess, mode, false),
|
||||||
Sender: doer.APIFormat(),
|
Sender: doer.APIFormat(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -748,6 +748,9 @@ func createIssueDependencyComment(e *xorm.Session, doer *User, issue *Issue, dep
|
|||||||
if !add {
|
if !add {
|
||||||
cType = CommentTypeRemoveDependency
|
cType = CommentTypeRemoveDependency
|
||||||
}
|
}
|
||||||
|
if err = issue.loadRepo(e); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Make two comments, one in each issue
|
// Make two comments, one in each issue
|
||||||
_, err = createComment(e, &CreateCommentOptions{
|
_, err = createComment(e, &CreateCommentOptions{
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ func TestCreateIssueDependency(t *testing.T) {
|
|||||||
|
|
||||||
issue1, err := GetIssueByID(1)
|
issue1, err := GetIssueByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
issue1.LoadAttributes()
|
|
||||||
|
|
||||||
issue2, err := GetIssueByID(2)
|
issue2, err := GetIssueByID(2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
issue2.LoadAttributes()
|
|
||||||
|
|
||||||
// Create a dependency and check if it was successful
|
// Create a dependency and check if it was successful
|
||||||
err = CreateIssueDependency(user1, issue1, issue2)
|
err = CreateIssueDependency(user1, issue1, issue2)
|
||||||
|
|||||||
@@ -39,16 +39,16 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
|
|||||||
|
|
||||||
// In case the issue poster is not watching the repository and is active,
|
// In case the issue poster is not watching the repository and is active,
|
||||||
// even if we have duplicated in watchers, can be safely filtered out.
|
// even if we have duplicated in watchers, can be safely filtered out.
|
||||||
poster, err := getUserByID(e, issue.PosterID)
|
err = issue.loadPoster(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
|
return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
|
||||||
}
|
}
|
||||||
if issue.PosterID != doer.ID && poster.IsActive && !poster.ProhibitLogin {
|
if issue.PosterID != doer.ID && issue.Poster.IsActive && !issue.Poster.ProhibitLogin {
|
||||||
participants = append(participants, issue.Poster)
|
participants = append(participants, issue.Poster)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assignees must receive any communications
|
// Assignees must receive any communications
|
||||||
assignees, err := GetAssigneesByIssue(issue)
|
assignees, err := getAssigneesByIssue(e, issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -88,6 +88,10 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
|
|||||||
names = append(names, participants[i].Name)
|
names = append(names, participants[i].Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := issue.loadRepo(e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, to := range tos {
|
for _, to := range tos {
|
||||||
SendIssueCommentMail(issue, doer, content, comment, []string{to})
|
SendIssueCommentMail(issue, doer, content, comment, []string{to})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func newIssueUsers(e Engine, repo *Repository, issue *Issue) error {
|
|||||||
func updateIssueAssignee(e *xorm.Session, issue *Issue, assigneeID int64) (removed bool, err error) {
|
func updateIssueAssignee(e *xorm.Session, issue *Issue, assigneeID int64) (removed bool, err error) {
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
assignee, err := GetUserByID(assigneeID)
|
assignee, err := getUserByID(e, assigneeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -600,16 +600,29 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
|
|||||||
return nil, ErrLoginSourceNotActived
|
return nil, ErrLoginSourceNotActived
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
switch source.Type {
|
switch source.Type {
|
||||||
case LoginLDAP, LoginDLDAP:
|
case LoginLDAP, LoginDLDAP:
|
||||||
return LoginViaLDAP(user, login, password, source, autoRegister)
|
user, err = LoginViaLDAP(user, login, password, source, autoRegister)
|
||||||
case LoginSMTP:
|
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:
|
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.
|
// UserSignIn validates user name and password.
|
||||||
@@ -644,7 +657,13 @@ func UserSignIn(username, password string) (*User, error) {
|
|||||||
if hasUser {
|
if hasUser {
|
||||||
switch user.LoginType {
|
switch user.LoginType {
|
||||||
case LoginNoType, LoginPlain, LoginOAuth2:
|
case LoginNoType, LoginPlain, LoginOAuth2:
|
||||||
if user.ValidatePassword(password) {
|
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
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -393,8 +393,12 @@ func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
|
|||||||
|
|
||||||
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
|
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
|
||||||
func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) {
|
func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) {
|
||||||
|
return getOrgUsersByOrgID(x, orgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOrgUsersByOrgID(e Engine, orgID int64) ([]*OrgUser, error) {
|
||||||
ous := make([]*OrgUser, 0, 10)
|
ous := make([]*OrgUser, 0, 10)
|
||||||
err := x.
|
err := e.
|
||||||
Where("org_id=?", orgID).
|
Where("org_id=?", orgID).
|
||||||
Find(&ous)
|
Find(&ous)
|
||||||
return ous, err
|
return ous, err
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
|||||||
return fmt.Errorf("Failed to create dir %s: %v", tmpBasePath, err)
|
return fmt.Errorf("Failed to create dir %s: %v", tmpBasePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer os.RemoveAll(path.Dir(tmpBasePath))
|
defer os.RemoveAll(tmpBasePath)
|
||||||
|
|
||||||
var stderr string
|
var stderr string
|
||||||
if _, stderr, err = process.GetManager().ExecTimeout(5*time.Minute,
|
if _, stderr, err = process.GetManager().ExecTimeout(5*time.Minute,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
@@ -34,8 +35,8 @@ import (
|
|||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/mcuadros/go-version"
|
version "github.com/mcuadros/go-version"
|
||||||
"gopkg.in/ini.v1"
|
ini "gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var repoWorkingPool = sync.NewExclusivePool()
|
var repoWorkingPool = sync.NewExclusivePool()
|
||||||
@@ -824,7 +825,7 @@ type CloneLink struct {
|
|||||||
|
|
||||||
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
|
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
|
||||||
func ComposeHTTPSCloneURL(owner, repo string) string {
|
func ComposeHTTPSCloneURL(owner, repo string) string {
|
||||||
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, owner, repo)
|
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.QueryEscape(owner), url.QueryEscape(repo))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) cloneLink(e Engine, isWiki bool) *CloneLink {
|
func (repo *Repository) cloneLink(e Engine, isWiki bool) *CloneLink {
|
||||||
@@ -1345,26 +1346,27 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
|
|||||||
|
|
||||||
if err = watchRepo(e, doer.ID, repo.ID, true); err != nil {
|
if err = watchRepo(e, doer.ID, repo.ID, true); err != nil {
|
||||||
return fmt.Errorf("watchRepo: %v", err)
|
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 fmt.Errorf("newRepoAction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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) {
|
func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err error) {
|
||||||
if !doer.IsAdmin && !u.CanCreateRepo() {
|
if !doer.IsAdmin && !u.CanCreateRepo() {
|
||||||
return nil, ErrReachLimitOfRepo{u.MaxRepoCreation}
|
return nil, ErrReachLimitOfRepo{u.MaxRepoCreation}
|
||||||
}
|
}
|
||||||
|
|
||||||
repo := &Repository{
|
repo := &Repository{
|
||||||
OwnerID: u.ID,
|
OwnerID: u.ID,
|
||||||
Owner: u,
|
Owner: u,
|
||||||
Name: opts.Name,
|
Name: opts.Name,
|
||||||
LowerName: strings.ToLower(opts.Name),
|
LowerName: strings.ToLower(opts.Name),
|
||||||
Description: opts.Description,
|
Description: opts.Description,
|
||||||
IsPrivate: opts.IsPrivate,
|
IsPrivate: opts.IsPrivate,
|
||||||
|
IsFsckEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
@@ -1741,6 +1743,17 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
|||||||
return ErrRepoNotExist{repoID, uid, "", ""}
|
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 {
|
if cnt, err := sess.ID(repoID).Delete(&Repository{}); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if cnt != 1 {
|
} else if cnt != 1 {
|
||||||
@@ -1772,6 +1785,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
|||||||
&Webhook{RepoID: repoID},
|
&Webhook{RepoID: repoID},
|
||||||
&HookTask{RepoID: repoID},
|
&HookTask{RepoID: repoID},
|
||||||
&Notification{RepoID: repoID},
|
&Notification{RepoID: repoID},
|
||||||
|
&CommitStatus{RepoID: repoID},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("deleteBeans: %v", err)
|
return fmt.Errorf("deleteBeans: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1882,6 +1896,12 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
if 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)
|
return fmt.Errorf("Commit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,15 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
|
|||||||
return
|
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 {
|
for _, u := range repo.Units {
|
||||||
var found bool
|
var found bool
|
||||||
for _, team := range teams {
|
for _, team := range teams {
|
||||||
|
|||||||
@@ -219,6 +219,17 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
|
|||||||
assert.True(t, perm.CanWrite(unit.Type))
|
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
|
// org member team tester
|
||||||
tester := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
|
tester := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
|
||||||
perm, err = GetUserRepoPermission(repo, tester)
|
perm, err = GetUserRepoPermission(repo, tester)
|
||||||
|
|||||||
@@ -113,15 +113,15 @@ func notifyWatchers(e Engine, act *Action) error {
|
|||||||
|
|
||||||
switch act.OpType {
|
switch act.OpType {
|
||||||
case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionDeleteBranch:
|
case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionDeleteBranch:
|
||||||
if !act.Repo.CheckUnitUser(act.UserID, false, UnitTypeCode) {
|
if !act.Repo.checkUnitUser(e, act.UserID, false, UnitTypeCode) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue:
|
case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue:
|
||||||
if !act.Repo.CheckUnitUser(act.UserID, false, UnitTypeIssues) {
|
if !act.Repo.checkUnitUser(e, act.UserID, false, UnitTypeIssues) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case ActionCreatePullRequest, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest:
|
case ActionCreatePullRequest, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest:
|
||||||
if !act.Repo.CheckUnitUser(act.UserID, false, UnitTypePullRequests) {
|
if !act.Repo.checkUnitUser(e, act.UserID, false, UnitTypePullRequests) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ type PublicKey struct {
|
|||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||||
Name string `xorm:"NOT NULL"`
|
Name string `xorm:"NOT NULL"`
|
||||||
Fingerprint string `xorm:"NOT NULL"`
|
Fingerprint string `xorm:"INDEX NOT NULL"`
|
||||||
Content string `xorm:"TEXT NOT NULL"`
|
Content string `xorm:"TEXT NOT NULL"`
|
||||||
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
||||||
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
||||||
@@ -350,7 +350,6 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
|
|||||||
func checkKeyFingerprint(e Engine, fingerprint string) error {
|
func checkKeyFingerprint(e Engine, fingerprint string) error {
|
||||||
has, err := e.Get(&PublicKey{
|
has, err := e.Get(&PublicKey{
|
||||||
Fingerprint: fingerprint,
|
Fingerprint: fingerprint,
|
||||||
Type: KeyTypeUser,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -401,12 +400,18 @@ func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*Pu
|
|||||||
return nil, err
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key name of same user cannot be duplicated.
|
// Key name of same user cannot be duplicated.
|
||||||
has, err := x.
|
has, err := sess.
|
||||||
Where("owner_id = ? AND name = ?", ownerID, name).
|
Where("owner_id = ? AND name = ?", ownerID, name).
|
||||||
Get(new(PublicKey))
|
Get(new(PublicKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -415,12 +420,6 @@ func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*Pu
|
|||||||
return nil, ErrKeyNameAlreadyUsed{ownerID, name}
|
return nil, ErrKeyNameAlreadyUsed{ownerID, name}
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
if err = sess.Begin(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
key := &PublicKey{
|
key := &PublicKey{
|
||||||
OwnerID: ownerID,
|
OwnerID: ownerID,
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -519,7 +518,7 @@ func UpdatePublicKeyUpdated(id int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deletePublicKeys does the actual key deletion but does not update authorized_keys file.
|
// 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 {
|
if len(keyIDs) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -728,24 +727,28 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey
|
|||||||
accessMode = AccessModeWrite
|
accessMode = AccessModeWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
pkey := &PublicKey{
|
|
||||||
Fingerprint: fingerprint,
|
|
||||||
Mode: accessMode,
|
|
||||||
Type: KeyTypeDeploy,
|
|
||||||
}
|
|
||||||
has, err := x.Get(pkey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
if err = sess.Begin(); err != nil {
|
if err = sess.Begin(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// First time use this deploy key.
|
pkey := &PublicKey{
|
||||||
if !has {
|
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.
|
||||||
|
pkey.Mode = accessMode
|
||||||
|
pkey.Type = KeyTypeDeploy
|
||||||
pkey.Content = content
|
pkey.Content = content
|
||||||
pkey.Name = name
|
pkey.Name = name
|
||||||
if err = addKey(sess, pkey); err != nil {
|
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.
|
// GetDeployKeyByID returns deploy key by given ID.
|
||||||
func GetDeployKeyByID(id int64) (*DeployKey, error) {
|
func GetDeployKeyByID(id int64) (*DeployKey, error) {
|
||||||
|
return getDeployKeyByID(x, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDeployKeyByID(e Engine, id int64) (*DeployKey, error) {
|
||||||
key := new(DeployKey)
|
key := new(DeployKey)
|
||||||
has, err := x.ID(id).Get(key)
|
has, err := e.ID(id).Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} 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.
|
// GetDeployKeyByRepo returns deploy key by given public key ID and repository ID.
|
||||||
func GetDeployKeyByRepo(keyID, repoID int64) (*DeployKey, error) {
|
func GetDeployKeyByRepo(keyID, repoID int64) (*DeployKey, error) {
|
||||||
|
return getDeployKeyByRepo(x, keyID, repoID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDeployKeyByRepo(e Engine, keyID, repoID int64) (*DeployKey, error) {
|
||||||
key := &DeployKey{
|
key := &DeployKey{
|
||||||
KeyID: keyID,
|
KeyID: keyID,
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
}
|
}
|
||||||
has, err := x.Get(key)
|
has, err := e.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
@@ -802,7 +813,19 @@ func UpdateDeployKey(key *DeployKey) error {
|
|||||||
|
|
||||||
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
|
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
|
||||||
func DeleteDeployKey(doer *User, id int64) error {
|
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 err != nil {
|
||||||
if IsErrDeployKeyNotExist(err) {
|
if IsErrDeployKeyNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
@@ -812,11 +835,11 @@ func DeleteDeployKey(doer *User, id int64) error {
|
|||||||
|
|
||||||
// Check if user has access to delete this key.
|
// Check if user has access to delete this key.
|
||||||
if !doer.IsAdmin {
|
if !doer.IsAdmin {
|
||||||
repo, err := GetRepositoryByID(key.RepoID)
|
repo, err := getRepositoryByID(sess, key.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetRepositoryByID: %v", err)
|
return fmt.Errorf("GetRepositoryByID: %v", err)
|
||||||
}
|
}
|
||||||
has, err := IsUserRepoAdmin(repo, doer)
|
has, err := isUserRepoAdmin(sess, repo, doer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetUserRepoPermission: %v", err)
|
return fmt.Errorf("GetUserRepoPermission: %v", err)
|
||||||
} else if !has {
|
} 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 {
|
if _, err = sess.ID(key.ID).Delete(new(DeployKey)); err != nil {
|
||||||
return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err)
|
return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err)
|
||||||
}
|
}
|
||||||
@@ -844,15 +861,24 @@ func DeleteDeployKey(doer *User, id int64) error {
|
|||||||
if err = deletePublicKeys(sess, key.KeyID); err != nil {
|
if err = deletePublicKeys(sess, key.KeyID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// after deleted the public keys, should rewrite the public keys file
|
||||||
|
if err = rewriteAllPublicKeys(sess); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListDeployKeys returns all deploy keys by given repository ID.
|
// ListDeployKeys returns all deploy keys by given repository ID.
|
||||||
func ListDeployKeys(repoID int64) ([]*DeployKey, error) {
|
func ListDeployKeys(repoID int64) ([]*DeployKey, error) {
|
||||||
|
return listDeployKeys(x, repoID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listDeployKeys(e Engine, repoID int64) ([]*DeployKey, error) {
|
||||||
keys := make([]*DeployKey, 0, 5)
|
keys := make([]*DeployKey, 0, 5)
|
||||||
return keys, x.
|
return keys, e.
|
||||||
Where("repo_id = ?", repoID).
|
Where("repo_id = ?", repoID).
|
||||||
Find(&keys)
|
Find(&keys)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1461,9 +1461,12 @@ func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []str
|
|||||||
// Get Public Keys from LDAP and skip duplicate keys
|
// Get Public Keys from LDAP and skip duplicate keys
|
||||||
var ldapKeys []string
|
var ldapKeys []string
|
||||||
for _, v := range SSHPublicKeys {
|
for _, v := range SSHPublicKeys {
|
||||||
ldapKey := strings.Join(strings.Split(v, " ")[:2], " ")
|
sshKeySplit := strings.Split(v, " ")
|
||||||
if !util.ExistsInSlice(ldapKey, ldapKeys) {
|
if len(sshKeySplit) > 1 {
|
||||||
ldapKeys = append(ldapKeys, ldapKey)
|
ldapKey := strings.Join(sshKeySplit[:2], " ")
|
||||||
|
if !util.ExistsInSlice(ldapKey, ldapKeys) {
|
||||||
|
ldapKeys = append(ldapKeys, ldapKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,22 @@ func GetUserHeatmapDataByUser(user *User) ([]*UserHeatmapData, error) {
|
|||||||
groupByName = groupBy
|
groupByName = groupBy
|
||||||
}
|
}
|
||||||
|
|
||||||
err := x.Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
sess := x.Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
||||||
Table("action").
|
Table("action").
|
||||||
Where("user_id = ?", user.ID).
|
Where("user_id = ?", user.ID).
|
||||||
And("created_unix > ?", (util.TimeStampNow() - 31536000)).
|
And("created_unix > ?", (util.TimeStampNow() - 31536000))
|
||||||
GroupBy(groupByName).
|
|
||||||
|
// * Heatmaps for individual users only include actions that the user themself
|
||||||
|
// did.
|
||||||
|
// * For organizations actions by all users that were made in owned
|
||||||
|
// repositories are counted.
|
||||||
|
if user.Type == UserTypeIndividual {
|
||||||
|
sess = sess.And("act_user_id = ?", user.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := sess.GroupBy(groupByName).
|
||||||
OrderBy("timestamp").
|
OrderBy("timestamp").
|
||||||
Find(&hdata)
|
Find(&hdata)
|
||||||
|
|
||||||
return hdata, err
|
return hdata, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title)
|
||||||
text = p.PullRequest.Body
|
text = p.PullRequest.Body
|
||||||
case api.HookIssueAssigned:
|
case api.HookIssueAssigned:
|
||||||
list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
|
list := make([]string, len(p.PullRequest.Assignees))
|
||||||
if err != nil {
|
for i, user := range p.PullRequest.Assignees {
|
||||||
return &DingtalkPayload{}, err
|
list[i] = user.UserName
|
||||||
}
|
}
|
||||||
title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName,
|
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
|
text = p.PullRequest.Body
|
||||||
case api.HookIssueUnassigned:
|
case api.HookIssueUnassigned:
|
||||||
title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title)
|
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
|
text = p.PullRequest.Body
|
||||||
color = warnColor
|
color = warnColor
|
||||||
case api.HookIssueAssigned:
|
case api.HookIssueAssigned:
|
||||||
list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
|
list := make([]string, len(p.PullRequest.Assignees))
|
||||||
if err != nil {
|
for i, user := range p.PullRequest.Assignees {
|
||||||
return &DiscordPayload{}, err
|
list[i] = user.UserName
|
||||||
}
|
}
|
||||||
title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName,
|
title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d by %s", p.Repository.FullName,
|
||||||
list, p.Index, p.PullRequest.Title)
|
strings.Join(list, ", "),
|
||||||
|
p.Index, p.PullRequest.Title)
|
||||||
text = p.PullRequest.Body
|
text = p.PullRequest.Body
|
||||||
color = successColor
|
color = successColor
|
||||||
case api.HookIssueUnassigned:
|
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)
|
text = fmt.Sprintf("[%s] Issue labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||||
case api.HookIssueSynchronized:
|
case api.HookIssueSynchronized:
|
||||||
text = fmt.Sprintf("[%s] Issue synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
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{
|
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)
|
text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||||
attachmentText = SlackTextFormatter(p.PullRequest.Body)
|
attachmentText = SlackTextFormatter(p.PullRequest.Body)
|
||||||
case api.HookIssueAssigned:
|
case api.HookIssueAssigned:
|
||||||
list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
|
list := make([]string, len(p.PullRequest.Assignees))
|
||||||
if err != nil {
|
for i, user := range p.PullRequest.Assignees {
|
||||||
return &SlackPayload{}, err
|
list[i] = SlackLinkFormatter(setting.AppURL+user.UserName, user.UserName)
|
||||||
}
|
}
|
||||||
text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName,
|
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)
|
titleLink, senderLink)
|
||||||
case api.HookIssueUnassigned:
|
case api.HookIssueUnassigned:
|
||||||
text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
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)
|
text = fmt.Sprintf("[%s] Pull request labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
||||||
case api.HookIssueSynchronized:
|
case api.HookIssueSynchronized:
|
||||||
text = fmt.Sprintf("[%s] Pull request synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
|
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{
|
return &SlackPayload{
|
||||||
|
|||||||
@@ -135,15 +135,56 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
|||||||
if len(baHead) > 0 {
|
if len(baHead) > 0 {
|
||||||
auths := strings.Fields(baHead)
|
auths := strings.Fields(baHead)
|
||||||
if len(auths) == 2 && auths[0] == "Basic" {
|
if len(auths) == 2 && auths[0] == "Basic" {
|
||||||
|
var u *models.User
|
||||||
|
|
||||||
uname, passwd, _ := base.BasicAuthDecode(auths[1])
|
uname, passwd, _ := base.BasicAuthDecode(auths[1])
|
||||||
|
|
||||||
u, err := models.UserSignIn(uname, passwd)
|
// Check if username or password is a token
|
||||||
if err != nil {
|
isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic"
|
||||||
if !models.IsErrUserNotExist(err) {
|
// Assume username is token
|
||||||
log.Error(4, "UserSignIn: %v", err)
|
authToken := uname
|
||||||
}
|
if !isUsernameToken {
|
||||||
return nil, false
|
// 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
|
ctx.Data["IsApiToken"] = true
|
||||||
return u, true
|
return u, true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gopkg.in/ldap.v2"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
|
ldap "gopkg.in/ldap.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SecurityProtocol protocol type
|
// SecurityProtocol protocol type
|
||||||
@@ -247,11 +247,17 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
|
||||||
|
|
||||||
|
attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
|
||||||
|
if isAttributeSSHPublicKeySet {
|
||||||
|
attribs = append(attribs, ls.AttributeSSHPublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, userDN)
|
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, userDN)
|
||||||
search := ldap.NewSearchRequest(
|
search := ldap.NewSearchRequest(
|
||||||
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
||||||
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey},
|
attribs, nil)
|
||||||
nil)
|
|
||||||
|
|
||||||
sr, err := l.Search(search)
|
sr, err := l.Search(search)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -267,11 +273,15 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sshPublicKey []string
|
||||||
|
|
||||||
username := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
|
username := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
|
||||||
firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
|
firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
|
||||||
surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
|
surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
|
||||||
mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
|
mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
|
||||||
sshPublicKey := sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
|
if isAttributeSSHPublicKeySet {
|
||||||
|
sshPublicKey = sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
|
||||||
|
}
|
||||||
isAdmin := checkAdmin(l, ls, userDN)
|
isAdmin := checkAdmin(l, ls, userDN)
|
||||||
|
|
||||||
if !directBind && ls.AttributesInBind {
|
if !directBind && ls.AttributesInBind {
|
||||||
@@ -320,11 +330,17 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
|||||||
|
|
||||||
userFilter := fmt.Sprintf(ls.Filter, "*")
|
userFilter := fmt.Sprintf(ls.Filter, "*")
|
||||||
|
|
||||||
|
var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
|
||||||
|
|
||||||
|
attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
|
||||||
|
if isAttributeSSHPublicKeySet {
|
||||||
|
attribs = append(attribs, ls.AttributeSSHPublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, ls.UserBase)
|
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, ls.UserBase)
|
||||||
search := ldap.NewSearchRequest(
|
search := ldap.NewSearchRequest(
|
||||||
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
||||||
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey},
|
attribs, nil)
|
||||||
nil)
|
|
||||||
|
|
||||||
var sr *ldap.SearchResult
|
var sr *ldap.SearchResult
|
||||||
if ls.UsePagedSearch() {
|
if ls.UsePagedSearch() {
|
||||||
@@ -341,12 +357,14 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
|||||||
|
|
||||||
for i, v := range sr.Entries {
|
for i, v := range sr.Entries {
|
||||||
result[i] = &SearchResult{
|
result[i] = &SearchResult{
|
||||||
Username: v.GetAttributeValue(ls.AttributeUsername),
|
Username: v.GetAttributeValue(ls.AttributeUsername),
|
||||||
Name: v.GetAttributeValue(ls.AttributeName),
|
Name: v.GetAttributeValue(ls.AttributeName),
|
||||||
Surname: v.GetAttributeValue(ls.AttributeSurname),
|
Surname: v.GetAttributeValue(ls.AttributeSurname),
|
||||||
Mail: v.GetAttributeValue(ls.AttributeMail),
|
Mail: v.GetAttributeValue(ls.AttributeMail),
|
||||||
SSHPublicKey: v.GetAttributeValues(ls.AttributeSSHPublicKey),
|
IsAdmin: checkAdmin(l, ls, v.DN),
|
||||||
IsAdmin: checkAdmin(l, ls, v.DN),
|
}
|
||||||
|
if isAttributeSSHPublicKeySet {
|
||||||
|
result[i].SSHPublicKey = v.GetAttributeValues(ls.AttributeSSHPublicKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/auth"
|
"code.gitea.io/gitea/modules/auth"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"github.com/go-macaron/csrf"
|
"github.com/go-macaron/csrf"
|
||||||
macaron "gopkg.in/macaron.v1"
|
macaron "gopkg.in/macaron.v1"
|
||||||
@@ -32,8 +33,12 @@ func Toggle(options *ToggleOptions) macaron.Handler {
|
|||||||
|
|
||||||
// Check prohibit login users.
|
// Check prohibit login users.
|
||||||
if ctx.IsSigned {
|
if ctx.IsSigned {
|
||||||
|
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
|
||||||
if ctx.User.ProhibitLogin {
|
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.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
||||||
ctx.HTML(200, "user/auth/prohibit_login")
|
ctx.HTML(200, "user/auth/prohibit_login")
|
||||||
return
|
return
|
||||||
@@ -42,7 +47,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
|
|||||||
// prevent infinite redirection
|
// prevent infinite redirection
|
||||||
// also make sure that the form cannot be accessed by
|
// also make sure that the form cannot be accessed by
|
||||||
// users who don't need this
|
// 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 {
|
if !ctx.User.MustChangePassword {
|
||||||
ctx.Redirect(setting.AppSubURL + "/")
|
ctx.Redirect(setting.AppSubURL + "/")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ func Contexter() macaron.Handler {
|
|||||||
if err == nil && len(repo.DefaultBranch) > 0 {
|
if err == nil && len(repo.DefaultBranch) > 0 {
|
||||||
branchName = repo.DefaultBranch
|
branchName = repo.DefaultBranch
|
||||||
}
|
}
|
||||||
prefix := setting.AppURL + path.Join(ownerName, repoName, "src", "branch", branchName)
|
prefix := setting.AppURL + path.Join(url.QueryEscape(ownerName), url.QueryEscape(repoName), "src", "branch", branchName)
|
||||||
c.Header().Set("Content-Type", "text/html")
|
c.Header().Set("Content-Type", "text/html")
|
||||||
c.WriteHeader(http.StatusOK)
|
c.WriteHeader(http.StatusOK)
|
||||||
c.Write([]byte(com.Expand(`<!doctype html>
|
c.Write([]byte(com.Expand(`<!doctype html>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package context
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -162,7 +163,7 @@ func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
|
|||||||
|
|
||||||
// ComposeGoGetImport returns go-get-import meta content.
|
// ComposeGoGetImport returns go-get-import meta content.
|
||||||
func ComposeGoGetImport(owner, repo string) string {
|
func ComposeGoGetImport(owner, repo string) string {
|
||||||
return path.Join(setting.Domain, setting.AppSubURL, owner, repo)
|
return path.Join(setting.Domain, setting.AppSubURL, url.QueryEscape(owner), url.QueryEscape(repo))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
|
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
|
||||||
|
|||||||
@@ -497,12 +497,15 @@ func authenticate(ctx *context.Context, repository *models.Repository, authoriza
|
|||||||
accessMode = models.AccessModeWrite
|
accessMode = models.AccessModeWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ctx.IsSigned is unnecessary here, this will be checked in perm.CanAccess
|
||||||
perm, err := models.GetUserRepoPermission(repository, ctx.User)
|
perm, err := models.GetUserRepoPermission(repository, ctx.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if ctx.IsSigned {
|
|
||||||
return perm.CanAccess(accessMode, models.UnitTypeCode)
|
canRead := perm.CanAccess(accessMode, models.UnitTypeCode)
|
||||||
|
if canRead {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
user, repo, opStr, err := parseToken(authorization)
|
user, repo, opStr, err := parseToken(authorization)
|
||||||
@@ -582,7 +585,7 @@ func parseToken(authorization string) (*models.User, *models.Repository, string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "basic", err
|
return nil, nil, "basic", err
|
||||||
}
|
}
|
||||||
if !u.ValidatePassword(password) {
|
if !u.IsPasswordSet() || !u.ValidatePassword(password) {
|
||||||
return nil, nil, "basic", fmt.Errorf("Basic auth failed")
|
return nil, nil, "basic", fmt.Errorf("Basic auth failed")
|
||||||
}
|
}
|
||||||
return u, nil, "basic", nil
|
return u, nil, "basic", nil
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package markup
|
package markup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
|
|
||||||
@@ -31,7 +32,13 @@ func (Parser) Extensions() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render renders orgmode rawbytes to HTML
|
// 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_USE_XHTML
|
||||||
htmlFlags |= blackfriday.HTML_SKIP_STYLE
|
htmlFlags |= blackfriday.HTML_SKIP_STYLE
|
||||||
htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
|
htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
|
||||||
@@ -40,9 +47,8 @@ func Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki b
|
|||||||
URLPrefix: urlPrefix,
|
URLPrefix: urlPrefix,
|
||||||
IsWiki: isWiki,
|
IsWiki: isWiki,
|
||||||
}
|
}
|
||||||
|
result = goorgeous.Org(rawBytes, renderer)
|
||||||
result := goorgeous.Org(rawBytes, renderer)
|
return
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderString reners orgmode string to HTML string
|
// RenderString reners orgmode string to HTML string
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ func decodeJSONError(resp *http.Response) *Response {
|
|||||||
func newInternalRequest(url, method string) *httplib.Request {
|
func newInternalRequest(url, method string) *httplib.Request {
|
||||||
req := newRequest(url, method).SetTLSClientConfig(&tls.Config{
|
req := newRequest(url, method).SetTLSClientConfig(&tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: setting.Domain,
|
||||||
})
|
})
|
||||||
if setting.Protocol == setting.UnixSocket {
|
if setting.Protocol == setting.UnixSocket {
|
||||||
req.SetTransport(&http.Transport{
|
req.SetTransport(&http.Transport{
|
||||||
|
|||||||
@@ -32,6 +32,31 @@ func UpdateDeployKeyUpdated(keyID int64, repoID int64) error {
|
|||||||
return nil
|
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
|
// HasDeployKey check if repo has deploy key
|
||||||
func HasDeployKey(keyID, repoID int64) (bool, error) {
|
func HasDeployKey(keyID, repoID int64) (bool, error) {
|
||||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/has-keys/%d", repoID, keyID)
|
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/has-keys/%d", repoID, keyID)
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func (opts *Options) handle(ctx *macaron.Context, log *log.Logger, opt *Options)
|
|||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
// Redirect if missing trailing slash.
|
// Redirect if missing trailing slash.
|
||||||
if !strings.HasSuffix(ctx.Req.URL.Path, "/") {
|
if !strings.HasSuffix(ctx.Req.URL.Path, "/") {
|
||||||
http.Redirect(ctx.Resp, ctx.Req.Request, ctx.Req.URL.Path+"/", http.StatusFound)
|
http.Redirect(ctx.Resp, ctx.Req.Request, path.Clean(ctx.Req.URL.Path+"/"), http.StatusFound)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,3 +98,8 @@ func Min(a, b int) int {
|
|||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsEmptyString checks if the provided string is empty
|
||||||
|
func IsEmptyString(s string) bool {
|
||||||
|
return len(strings.TrimSpace(s)) == 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -77,3 +77,20 @@ func TestIsExternalURL(t *testing.T) {
|
|||||||
assert.Equal(t, test.Expected, IsExternalURL(test.RawURL))
|
assert.Equal(t, test.Expected, IsExternalURL(test.RawURL))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsEmptyString(t *testing.T) {
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
s string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{"", true},
|
||||||
|
{" ", true},
|
||||||
|
{" ", true},
|
||||||
|
{" a", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range cases {
|
||||||
|
assert.Equal(t, v.expected, IsEmptyString(v.s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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>.
|
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_key = Add SSH Key
|
||||||
add_new_gpg_key = Add GPG 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.
|
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_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.
|
gpg_no_key_email_found = This GPG key is not usable with any email address associated with your account.
|
||||||
@@ -655,6 +655,7 @@ ext_issues.desc = Link to an external issue tracker.
|
|||||||
|
|
||||||
issues.desc = Organize bug reports, tasks and milestones.
|
issues.desc = Organize bug reports, tasks and milestones.
|
||||||
issues.new = New Issue
|
issues.new = New Issue
|
||||||
|
issues.new.title_empty = Title cannot be empty
|
||||||
issues.new.labels = Labels
|
issues.new.labels = Labels
|
||||||
issues.new.no_label = No Label
|
issues.new.no_label = No Label
|
||||||
issues.new.clear_labels = Clear labels
|
issues.new.clear_labels = Clear labels
|
||||||
|
|||||||
@@ -859,6 +859,7 @@ pulls.title_wip_desc=`<a href="#">Sāciet virsrakstu ar <strong>%s</strong></a>,
|
|||||||
pulls.cannot_merge_work_in_progress=Šis izmaiņu pieprasījums ir atzīmēts, ka pie tā vēl notiek izstrāde. Noņemiet <strong>%s</strong> no virsraksta sākuma, kad tas ir pabeigts.
|
pulls.cannot_merge_work_in_progress=Šis izmaiņu pieprasījums ir atzīmēts, ka pie tā vēl notiek izstrāde. Noņemiet <strong>%s</strong> no virsraksta sākuma, kad tas ir pabeigts.
|
||||||
pulls.data_broken=Izmaiņu pieprasījums ir bojāts, jo dzēsta informācija no atdalītā repozitorija.
|
pulls.data_broken=Izmaiņu pieprasījums ir bojāts, jo dzēsta informācija no atdalītā repozitorija.
|
||||||
pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu.
|
pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu.
|
||||||
|
pulls.blocked_by_approvals=Šim izmaiņu pieprasījumam nav nepieciešamais apstiprinājumu daudzums. %d no %d apstiprinājumi piešķirti.
|
||||||
pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski sapludināt.
|
pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski sapludināt.
|
||||||
pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski sapludināts konfliktu dēļ.
|
pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski sapludināts konfliktu dēļ.
|
||||||
pulls.cannot_auto_merge_helper=Sapludiniet manuāli, lai atrisinātu konfliktus.
|
pulls.cannot_auto_merge_helper=Sapludiniet manuāli, lai atrisinātu konfliktus.
|
||||||
@@ -867,6 +868,7 @@ pulls.no_merge_helper=Lai sapludinātu šo izmaiņu pieprasījumu, iespējojiet
|
|||||||
pulls.no_merge_wip=Šo izmaiņu pieprasījumu nav iespējams sapludināt, jo tas ir atzīmēts, ka darbs pie tā vēl nav pabeigts.
|
pulls.no_merge_wip=Šo izmaiņu pieprasījumu nav iespējams sapludināt, jo tas ir atzīmēts, ka darbs pie tā vēl nav pabeigts.
|
||||||
pulls.merge_pull_request=Izmaiņu pieprasījuma sapludināšana
|
pulls.merge_pull_request=Izmaiņu pieprasījuma sapludināšana
|
||||||
pulls.rebase_merge_pull_request=Pārbāzēt un sapludināt
|
pulls.rebase_merge_pull_request=Pārbāzēt un sapludināt
|
||||||
|
pulls.rebase_merge_commit_pull_request=Pārbāzēt un sapludināt (--no-ff)
|
||||||
pulls.squash_merge_pull_request=Saspiest un sapludināt
|
pulls.squash_merge_pull_request=Saspiest un sapludināt
|
||||||
pulls.invalid_merge_option=Nav iespējams izmantot šādu sapludināšanas veidu šim izmaiņu pieprasījumam.
|
pulls.invalid_merge_option=Nav iespējams izmantot šādu sapludināšanas veidu šim izmaiņu pieprasījumam.
|
||||||
pulls.open_unmerged_pull_exists=`Jūs nevarat veikt atkārtotas atvēršanas darbību, jo jau eksistē izmaiņu pieprasījums (#%d) ar šādu sapludināšanas informāciju.`
|
pulls.open_unmerged_pull_exists=`Jūs nevarat veikt atkārtotas atvēršanas darbību, jo jau eksistē izmaiņu pieprasījums (#%d) ar šādu sapludināšanas informāciju.`
|
||||||
@@ -1012,6 +1014,7 @@ settings.pulls_desc=Iespējot repozitorija izmaiņu pieprasījumus
|
|||||||
settings.pulls.ignore_whitespace=Pārbaudot konfliktus, ignorēt izmaiņas atstarpēs
|
settings.pulls.ignore_whitespace=Pārbaudot konfliktus, ignorēt izmaiņas atstarpēs
|
||||||
settings.pulls.allow_merge_commits=Iespējot revīziju sapludināšanu
|
settings.pulls.allow_merge_commits=Iespējot revīziju sapludināšanu
|
||||||
settings.pulls.allow_rebase_merge=Iespējot pārbāzēšanu sapludinot revīzijas
|
settings.pulls.allow_rebase_merge=Iespējot pārbāzēšanu sapludinot revīzijas
|
||||||
|
settings.pulls.allow_rebase_merge_commit=Iespējot pārbāzēšanu sapludinot revīzijas (--no-ff)
|
||||||
settings.pulls.allow_squash_commits=Iespējot saspiešanu sapludinot revīzijas
|
settings.pulls.allow_squash_commits=Iespējot saspiešanu sapludinot revīzijas
|
||||||
settings.admin_settings=Administratora iestatījumi
|
settings.admin_settings=Administratora iestatījumi
|
||||||
settings.admin_enable_health_check=Iespējot veselības pārbaudi (git fsck) šim repozitorijam
|
settings.admin_enable_health_check=Iespējot veselības pārbaudi (git fsck) šim repozitorijam
|
||||||
@@ -1098,6 +1101,7 @@ settings.event_issue_comment_desc=Problēmas komentārs pievienots, labots vai d
|
|||||||
settings.event_release=Laidiens
|
settings.event_release=Laidiens
|
||||||
settings.event_release_desc=Publicēts, atjaunots vai dzēsts laidiens repozitorijā.
|
settings.event_release_desc=Publicēts, atjaunots vai dzēsts laidiens repozitorijā.
|
||||||
settings.event_pull_request=Izmaiņu pieprasījums
|
settings.event_pull_request=Izmaiņu pieprasījums
|
||||||
|
settings.event_pull_request_desc=Izmaiņu pieprasījums izveidots, slēgts, atkārtoti atvērts, labots, apstiprināts, noraidīts, recenzēts, piešķirts, pievienots vai noņemts atbildīgais, pievienota etiķete, noņemta etiķete, pievienots vai noņemts atskaites punkts.
|
||||||
settings.event_push=Izmaiņu nosūtīšana
|
settings.event_push=Izmaiņu nosūtīšana
|
||||||
settings.event_push_desc=Git izmaiņu nosūtīšana uz repozitoriju.
|
settings.event_push_desc=Git izmaiņu nosūtīšana uz repozitoriju.
|
||||||
settings.event_repository=Repozitorijs
|
settings.event_repository=Repozitorijs
|
||||||
@@ -1148,6 +1152,10 @@ settings.protect_merge_whitelist_committers=Iespējot sapludināšanas ierobežo
|
|||||||
settings.protect_merge_whitelist_committers_desc=Atļaut tikai noteiktiem lietotājiem vai komandām sapludināt izmaiņu pieprasījumus šajā atzarā.
|
settings.protect_merge_whitelist_committers_desc=Atļaut tikai noteiktiem lietotājiem vai komandām sapludināt izmaiņu pieprasījumus šajā atzarā.
|
||||||
settings.protect_merge_whitelist_users=Lietotāji, kas var veikt izmaiņu sapludināšanu:
|
settings.protect_merge_whitelist_users=Lietotāji, kas var veikt izmaiņu sapludināšanu:
|
||||||
settings.protect_merge_whitelist_teams=Komandas, kas var veikt izmaiņu sapludināšanu:
|
settings.protect_merge_whitelist_teams=Komandas, kas var veikt izmaiņu sapludināšanu:
|
||||||
|
settings.protect_required_approvals=Vajadzīgi apstiprinājumi:
|
||||||
|
settings.protect_required_approvals_desc=Atļaut tikai noteiktiem lietotājiem vai komandām sapludināt izmaiņu pieprasījumu, kam veikts noteikts daudzums pozitīvu recenziju.
|
||||||
|
settings.protect_approvals_whitelist_users=Lietotāji, kas var veikt recenzijas:
|
||||||
|
settings.protect_approvals_whitelist_teams=Komandas, kas var veikt recenzijas:
|
||||||
settings.add_protected_branch=Iespējot aizsargāšanu
|
settings.add_protected_branch=Iespējot aizsargāšanu
|
||||||
settings.delete_protected_branch=Atspējot aizsargāšanu
|
settings.delete_protected_branch=Atspējot aizsargāšanu
|
||||||
settings.update_protect_branch_success=Atzara aizsardzība atzaram '%s' tika saglabāta.
|
settings.update_protect_branch_success=Atzara aizsardzība atzaram '%s' tika saglabāta.
|
||||||
@@ -1158,6 +1166,7 @@ settings.default_branch_desc=Norādiet noklusēto repozitorija atzaru izmaiņu p
|
|||||||
settings.choose_branch=Izvēlieties atzaru…
|
settings.choose_branch=Izvēlieties atzaru…
|
||||||
settings.no_protected_branch=Nav neviena aizsargātā atzara.
|
settings.no_protected_branch=Nav neviena aizsargātā atzara.
|
||||||
settings.edit_protected_branch=Labot
|
settings.edit_protected_branch=Labot
|
||||||
|
settings.protected_branch_required_approvals_min=Pieprasīto recenziju skaits nevar būt negatīvs.
|
||||||
|
|
||||||
diff.browse_source=Pārlūkot izejas kodu
|
diff.browse_source=Pārlūkot izejas kodu
|
||||||
diff.parent=vecāks
|
diff.parent=vecāks
|
||||||
|
|||||||
@@ -7,6 +7,115 @@ function htmlEncode(text) {
|
|||||||
var csrf;
|
var csrf;
|
||||||
var suburl;
|
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) {
|
function initCommentPreviewTab($form) {
|
||||||
var $tabMenu = $form.find('.tabular.menu');
|
var $tabMenu = $form.find('.tabular.menu');
|
||||||
$tabMenu.find('.item').tab();
|
$tabMenu.find('.item').tab();
|
||||||
@@ -2348,7 +2457,6 @@ function initHeatmap(appElementId, heatmapUser, locale) {
|
|||||||
this.getColor(4),
|
this.getColor(4),
|
||||||
this.getColor(5)
|
this.getColor(5)
|
||||||
];
|
];
|
||||||
console.log(this.colorRange);
|
|
||||||
this.endDate = new Date();
|
this.endDate = new Date();
|
||||||
this.loadHeatmap(this.user);
|
this.loadHeatmap(this.user);
|
||||||
},
|
},
|
||||||
|
|||||||
9
public/vendor/librejs.html
vendored
9
public/vendor/librejs.html
vendored
@@ -48,7 +48,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><a href="./plugins/vue/vue.min.js">vue.min.js</a></td>
|
<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/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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="./plugins/emojify/emojify.min.js">emojify.min.js</a></td>
|
<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>
|
<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>
|
||||||
<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/blob/master/README.md">MIT</a></td>
|
||||||
<td><a href="https://github.com/WildCodeSchool/vue-calendar-heatmap/archive/master.zip">7f48b20.zip</a></td>
|
<td><a href="https://github.com/WildCodeSchool/vue-calendar-heatmap/archive/master.zip">7f48b20.zip</a></td>
|
||||||
</tr>
|
</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/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>
|
<td><a href="https://github.com/moment/moment/archive/2.22.2.tar.gz">0.4.1.tar.gz</a></td>
|
||||||
</tr>
|
</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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</body>
|
</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
@@ -85,7 +85,7 @@ func sudo() macaron.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(sudo) > 0 {
|
if len(sudo) > 0 {
|
||||||
if ctx.User.IsAdmin {
|
if ctx.IsSigned && ctx.User.IsAdmin {
|
||||||
user, err := models.GetUserByName(sudo)
|
user, err := models.GetUserByName(sudo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if models.IsErrUserNotExist(err) {
|
if models.IsErrUserNotExist(err) {
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ func GetIssue(ctx *context.APIContext) {
|
|||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/Issue"
|
// "$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 err != nil {
|
||||||
if models.IsErrIssueNotExist(err) {
|
if models.IsErrIssueNotExist(err) {
|
||||||
ctx.Status(404)
|
ctx.Status(404)
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ func ListIssueLabels(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := issue.LoadAttributes(); err != nil {
|
||||||
|
ctx.Error(500, "LoadAttributes", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
apiLabels := make([]*api.Label, len(issue.Labels))
|
apiLabels := make([]*api.Label, len(issue.Labels))
|
||||||
for i := range issue.Labels {
|
for i := range issue.Labels {
|
||||||
apiLabels[i] = issue.Labels[i].APIFormat()
|
apiLabels[i] = issue.Labels[i].APIFormat()
|
||||||
|
|||||||
@@ -159,6 +159,8 @@ func HandleCheckKeyStringError(ctx *context.APIContext, err error) {
|
|||||||
// HandleAddKeyError handle add key error
|
// HandleAddKeyError handle add key error
|
||||||
func HandleAddKeyError(ctx *context.APIContext, err error) {
|
func HandleAddKeyError(ctx *context.APIContext, err error) {
|
||||||
switch {
|
switch {
|
||||||
|
case models.IsErrDeployKeyAlreadyExist(err):
|
||||||
|
ctx.Error(422, "", "This key has already been added to this repository")
|
||||||
case models.IsErrKeyAlreadyExist(err):
|
case models.IsErrKeyAlreadyExist(err):
|
||||||
ctx.Error(422, "", "Key content has been used as non-deploy key")
|
ctx.Error(422, "", "Key content has been used as non-deploy key")
|
||||||
case models.IsErrKeyNameAlreadyUsed(err):
|
case models.IsErrKeyNameAlreadyUsed(err):
|
||||||
|
|||||||
@@ -668,8 +668,8 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
|
|||||||
ctx.ServerError("GetUserRepoPermission", err)
|
ctx.ServerError("GetUserRepoPermission", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
if !perm.CanWrite(models.UnitTypeCode) {
|
if !perm.CanReadIssuesOrPulls(true) {
|
||||||
log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
|
log.Trace("ParseCompareInfo[%d]: cannot create/read pull requests", baseRepo.ID)
|
||||||
ctx.Status(404)
|
ctx.Status(404)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,6 +400,11 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
|||||||
RemoteAddr: remoteAddr,
|
RemoteAddr: remoteAddr,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if models.IsErrRepoAlreadyExist(err) {
|
||||||
|
ctx.Error(409, "", "The repository with the same name already exists.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = util.URLSanitizedError(err, remoteAddr)
|
err = util.URLSanitizedError(err, remoteAddr)
|
||||||
if repo != nil {
|
if repo != nil {
|
||||||
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
|
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
|
||||||
|
|||||||
@@ -16,6 +16,30 @@ import (
|
|||||||
|
|
||||||
// GetTree get the tree of a repository.
|
// GetTree get the tree of a repository.
|
||||||
func GetTree(ctx *context.APIContext) {
|
func GetTree(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /repos/{owner}/{repo}/git/trees/{sha} repository GetTree
|
||||||
|
// ---
|
||||||
|
// summary: Gets the tree of a repository.
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: sha
|
||||||
|
// in: path
|
||||||
|
// description: sha of the commit
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/GitTreeResponse"
|
||||||
sha := ctx.Params("sha")
|
sha := ctx.Params("sha")
|
||||||
if len(sha) == 0 {
|
if len(sha) == 0 {
|
||||||
ctx.Error(400, "sha not provided", nil)
|
ctx.Error(400, "sha not provided", nil)
|
||||||
|
|||||||
@@ -133,3 +133,10 @@ type swaggerResponseAttachment struct {
|
|||||||
//in: body
|
//in: body
|
||||||
Body api.Attachment `json:"body"`
|
Body api.Attachment `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GitTreeResponse
|
||||||
|
// swagger:response GitTreeResponse
|
||||||
|
type swaggerGitTreeResponse struct {
|
||||||
|
//in: body
|
||||||
|
Body api.GitTreeResponse `json:"body"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/search"
|
"code.gitea.io/gitea/modules/search"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@@ -38,6 +39,10 @@ func Home(ctx *context.Context) {
|
|||||||
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
|
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
|
||||||
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||||
ctx.HTML(200, user.TplActivate)
|
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 {
|
} else {
|
||||||
user.Dashboard(ctx)
|
user.Dashboard(ctx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func Metrics(ctx *context.Context) {
|
|||||||
promhttp.Handler().ServeHTTP(ctx.Resp, ctx.Req.Request)
|
promhttp.Handler().ServeHTTP(ctx.Resp, ctx.Req.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
header := ctx.Header().Get("Authorization")
|
header := ctx.Req.Header.Get("Authorization")
|
||||||
if header == "" {
|
if header == "" {
|
||||||
ctx.Error(401)
|
ctx.Error(401)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -288,8 +288,6 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
models.UpdateTeamUnits(t, units)
|
models.UpdateTeamUnits(t, units)
|
||||||
} else {
|
|
||||||
models.UpdateTeamUnits(t, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.HasError() {
|
if ctx.HasError() {
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Post("/repositories/:repoid/keys/:keyid/update", UpdateDeployKey)
|
m.Post("/repositories/:repoid/keys/:keyid/update", UpdateDeployKey)
|
||||||
m.Get("/repositories/:repoid/user/:userid/checkunituser", CheckUnitUser)
|
m.Get("/repositories/:repoid/user/:userid/checkunituser", CheckUnitUser)
|
||||||
m.Get("/repositories/:repoid/has-keys/:keyid", HasDeployKey)
|
m.Get("/repositories/:repoid/has-keys/:keyid", HasDeployKey)
|
||||||
|
m.Get("/repositories/:repoid/keys/:keyid", GetDeployKey)
|
||||||
m.Get("/repositories/:repoid/wiki/init", InitWiki)
|
m.Get("/repositories/:repoid/wiki/init", InitWiki)
|
||||||
m.Post("/push/update", PushUpdate)
|
m.Post("/push/update", PushUpdate)
|
||||||
m.Get("/protectedbranch/:pbid/:userid", CanUserPush)
|
m.Get("/protectedbranch/:pbid/:userid", CanUserPush)
|
||||||
|
|||||||
@@ -72,6 +72,24 @@ func GetUserByKeyID(ctx *macaron.Context) {
|
|||||||
ctx.JSON(200, user)
|
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
|
//HasDeployKey chainload to models.HasDeployKey
|
||||||
func HasDeployKey(ctx *macaron.Context) {
|
func HasDeployKey(ctx *macaron.Context) {
|
||||||
repoID := ctx.ParamsInt64(":repoid")
|
repoID := ctx.ParamsInt64(":repoid")
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ func Diff(ctx *context.Context) {
|
|||||||
commitID = commit.ID.String()
|
commitID = commit.ID.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository, ctx.Repo.Commit.ID.String(), 0)
|
statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository, commitID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(3, "GetLatestCommitStatus: %v", err)
|
log.Error(3, "GetLatestCommitStatus: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,11 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
|||||||
branchName = form.NewBranchName
|
branchName = form.NewBranchName
|
||||||
}
|
}
|
||||||
|
|
||||||
form.TreePath = strings.Trim(path.Clean("/"+form.TreePath), " /")
|
form.TreePath = cleanUploadFileName(form.TreePath)
|
||||||
|
if len(form.TreePath) == 0 {
|
||||||
|
ctx.Error(500, "Upload file name is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
||||||
|
|
||||||
ctx.Data["TreePath"] = form.TreePath
|
ctx.Data["TreePath"] = form.TreePath
|
||||||
@@ -373,6 +377,13 @@ func DeleteFile(ctx *context.Context) {
|
|||||||
func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||||
ctx.Data["PageIsDelete"] = true
|
ctx.Data["PageIsDelete"] = true
|
||||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
|
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
|
||||||
|
|
||||||
|
ctx.Repo.TreePath = cleanUploadFileName(ctx.Repo.TreePath)
|
||||||
|
if len(ctx.Repo.TreePath) == 0 {
|
||||||
|
ctx.Error(500, "Delete file name is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Data["TreePath"] = ctx.Repo.TreePath
|
ctx.Data["TreePath"] = ctx.Repo.TreePath
|
||||||
canCommit := renderCommitRights(ctx)
|
canCommit := renderCommitRights(ctx)
|
||||||
|
|
||||||
@@ -477,7 +488,12 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
|
|||||||
branchName = form.NewBranchName
|
branchName = form.NewBranchName
|
||||||
}
|
}
|
||||||
|
|
||||||
form.TreePath = strings.Trim(path.Clean("/"+form.TreePath), " /")
|
form.TreePath = cleanUploadFileName(form.TreePath)
|
||||||
|
if len(form.TreePath) == 0 {
|
||||||
|
ctx.Error(500, "Upload file name is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
||||||
if len(treeNames) == 0 {
|
if len(treeNames) == 0 {
|
||||||
// We must at least have one element for user to input.
|
// We must at least have one element for user to input.
|
||||||
|
|||||||
@@ -113,24 +113,24 @@ func HTTP(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
authUser, err = models.UserSignIn(authUsername, authPasswd)
|
// Check if username or password is a token
|
||||||
if err != nil {
|
isUsernameToken := len(authPasswd) == 0 || authPasswd == "x-oauth-basic"
|
||||||
if !models.IsErrUserNotExist(err) {
|
// Assume username is token
|
||||||
ctx.ServerError("UserSignIn error: %v", err)
|
authToken := authUsername
|
||||||
return
|
if !isUsernameToken {
|
||||||
}
|
// Assume password is token
|
||||||
|
authToken = authPasswd
|
||||||
}
|
}
|
||||||
|
// Assume password is a token.
|
||||||
if authUser == nil {
|
token, err := models.GetAccessTokenBySHA(authToken)
|
||||||
isUsernameToken := len(authPasswd) == 0 || authPasswd == "x-oauth-basic"
|
if err == nil {
|
||||||
|
if isUsernameToken {
|
||||||
// Assume username is token
|
authUser, err = models.GetUserByID(token.UID)
|
||||||
authToken := authUsername
|
if err != nil {
|
||||||
|
ctx.ServerError("GetUserByID", err)
|
||||||
if !isUsernameToken {
|
return
|
||||||
// Assume password is token
|
}
|
||||||
authToken = authPasswd
|
} else {
|
||||||
|
|
||||||
authUser, err = models.GetUserByName(authUsername)
|
authUser, err = models.GetUserByName(authUsername)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if models.IsErrUserNotExist(err) {
|
if models.IsErrUserNotExist(err) {
|
||||||
@@ -140,37 +140,37 @@ func HTTP(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
if authUser.ID != token.UID {
|
||||||
|
|
||||||
// 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")
|
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
|
return
|
||||||
}
|
}
|
||||||
} else if authUser.ID != token.UID {
|
|
||||||
ctx.HandleText(http.StatusUnauthorized, "invalid credentials")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
token.UpdatedUnix = util.TimeStampNow()
|
token.UpdatedUnix = util.TimeStampNow()
|
||||||
if err = models.UpdateAccessToken(token); err != nil {
|
if err = models.UpdateAccessToken(token); err != nil {
|
||||||
ctx.ServerError("UpdateAccessToken", err)
|
ctx.ServerError("UpdateAccessToken", err)
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
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
|
// 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")
|
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")
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIssue render createing issue page
|
// NewIssue render creating issue page
|
||||||
func NewIssue(ctx *context.Context) {
|
func NewIssue(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||||
ctx.Data["PageIsIssueList"] = true
|
ctx.Data["PageIsIssueList"] = true
|
||||||
@@ -494,6 +494,11 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if util.IsEmptyString(form.Title) {
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplIssueNew, form)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
issue := &models.Issue{
|
issue := &models.Issue{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
Title: form.Title,
|
Title: form.Title,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
)
|
)
|
||||||
@@ -683,8 +684,8 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
|
|||||||
ctx.ServerError("GetUserRepoPermission", err)
|
ctx.ServerError("GetUserRepoPermission", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
if !perm.CanWrite(models.UnitTypeCode) {
|
if !perm.CanReadIssuesOrPulls(true) {
|
||||||
log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
|
log.Trace("ParseCompareInfo[%d]: cannot create/read pull requests", baseRepo.ID)
|
||||||
ctx.NotFound("ParseCompareInfo", nil)
|
ctx.NotFound("ParseCompareInfo", nil)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
@@ -860,6 +861,16 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if util.IsEmptyString(form.Title) {
|
||||||
|
PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplComparePull, form)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
|
patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetPatch", err)
|
ctx.ServerError("GetPatch", err)
|
||||||
|
|||||||
@@ -256,6 +256,11 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
|
|||||||
return
|
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
|
// remoteAddr may contain credentials, so we sanitize it
|
||||||
err = util.URLSanitizedError(err, remoteAddr)
|
err = util.URLSanitizedError(err, remoteAddr)
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ const (
|
|||||||
func Settings(ctx *context.Context) {
|
func Settings(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
||||||
ctx.Data["PageIsSettingsOptions"] = true
|
ctx.Data["PageIsSettingsOptions"] = true
|
||||||
|
ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate
|
||||||
ctx.HTML(200, tplSettingsOptions)
|
ctx.HTML(200, tplSettingsOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +96,12 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visibilityChanged := repo.IsPrivate != form.Private
|
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
|
repo.IsPrivate = form.Private
|
||||||
if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
|
if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
|
||||||
ctx.ServerError("UpdateRepository", err)
|
ctx.ServerError("UpdateRepository", err)
|
||||||
@@ -581,6 +589,9 @@ func DeployKeysPost(ctx *context.Context, form auth.AddKeyForm) {
|
|||||||
case models.IsErrDeployKeyAlreadyExist(err):
|
case models.IsErrDeployKeyAlreadyExist(err):
|
||||||
ctx.Data["Err_Content"] = true
|
ctx.Data["Err_Content"] = true
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form)
|
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):
|
case models.IsErrKeyNameAlreadyUsed(err):
|
||||||
ctx.Data["Err_Title"] = true
|
ctx.Data["Err_Title"] = true
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
|
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
|
||||||
|
|||||||
@@ -341,6 +341,11 @@ func NewWikiPost(ctx *context.Context, form auth.NewWikiForm) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if util.IsEmptyString(form.Title) {
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplWikiNew, form)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
wikiName := models.NormalizeWikiName(form.Title)
|
wikiName := models.NormalizeWikiName(form.Title)
|
||||||
if err := ctx.Repo.Repository.AddWikiPage(ctx.User, wikiName, form.Content, form.Message); err != nil {
|
if err := ctx.Repo.Repository.AddWikiPage(ctx.User, wikiName, form.Content, form.Message); err != nil {
|
||||||
if models.IsErrWikiReservedName(err) {
|
if models.IsErrWikiReservedName(err) {
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ func NewMacaron() *macaron.Macaron {
|
|||||||
Langs: setting.Langs,
|
Langs: setting.Langs,
|
||||||
Names: setting.Names,
|
Names: setting.Names,
|
||||||
DefaultLang: "en-US",
|
DefaultLang: "en-US",
|
||||||
Redirect: true,
|
Redirect: false,
|
||||||
}))
|
}))
|
||||||
m.Use(cache.Cacher(cache.Options{
|
m.Use(cache.Cacher(cache.Options{
|
||||||
Adapter: setting.CacheService.Adapter,
|
Adapter: setting.CacheService.Adapter,
|
||||||
@@ -643,7 +643,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
}
|
}
|
||||||
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
||||||
})
|
})
|
||||||
}, context.RepoAssignment(), context.UnitTypes(), reqRepoReleaseReader)
|
}, ignSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoReleaseReader)
|
||||||
|
|
||||||
m.Group("/:username/:reponame", func() {
|
m.Group("/:username/:reponame", func() {
|
||||||
m.Post("/topics", repo.TopicsPost)
|
m.Post("/topics", repo.TopicsPost)
|
||||||
|
|||||||
@@ -161,6 +161,19 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) {
|
|||||||
} else if models.IsErrEmailAlreadyUsed(err) {
|
} else if models.IsErrEmailAlreadyUsed(err) {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
|
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
|
||||||
log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
|
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 {
|
} else {
|
||||||
ctx.ServerError("UserSignIn", err)
|
ctx.ServerError("UserSignIn", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ func SignInOpenIDPost(ctx *context.Context, form auth.SignInOpenIDForm) {
|
|||||||
redirectTo := setting.AppURL + "user/login/openid"
|
redirectTo := setting.AppURL + "user/login/openid"
|
||||||
url, err := openid.RedirectURL(id, redirectTo, setting.AppURL)
|
url, err := openid.RedirectURL(id, redirectTo, setting.AppURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.RenderWithErr(err.Error(), tplSignInOpenID, &form)
|
log.Error(1, "Error in OpenID redirect URL: %s, %v", redirectTo, err.Error())
|
||||||
|
ctx.RenderWithErr(fmt.Sprintf("Unable to find OpenID provider in %s", redirectTo), tplSignInOpenID, &form)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,15 @@ func Security(ctx *context.Context) {
|
|||||||
|
|
||||||
// DeleteAccountLink delete a single account link
|
// DeleteAccountLink delete a single account link
|
||||||
func DeleteAccountLink(ctx *context.Context) {
|
func DeleteAccountLink(ctx *context.Context) {
|
||||||
if _, err := models.RemoveAccountLink(ctx.User, ctx.QueryInt64("loginSourceID")); err != nil {
|
id := ctx.QueryInt64("id")
|
||||||
ctx.Flash.Error("RemoveAccountLink: " + err.Error())
|
if id <= 0 {
|
||||||
|
ctx.Flash.Error("Account link id is not given")
|
||||||
} else {
|
} else {
|
||||||
ctx.Flash.Success(ctx.Tr("settings.remove_account_link_success"))
|
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{}{
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_usage"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_usage"}}</dt>
|
||||||
<dd>{{.SysStatus.MSpanInuse}}</dd>
|
<dd>{{.SysStatus.MSpanInuse}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_obtained"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_obtained"}}</dt>
|
||||||
<dd>{{.SysStatus.HeapSys}}</dd>
|
<dd>{{.SysStatus.MSpanSys}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_usage"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_usage"}}</dt>
|
||||||
<dd>{{.SysStatus.MCacheInuse}}</dd>
|
<dd>{{.SysStatus.MCacheInuse}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_obtained"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_obtained"}}</dt>
|
||||||
|
|||||||
@@ -112,6 +112,7 @@
|
|||||||
<script src="{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js"></script>
|
<script src="{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js"></script>
|
||||||
<script src="{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}"></script>
|
<script src="{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}"></script>
|
||||||
{{if .EnableHeatmap}}
|
{{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/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 src="{{AppSubUrl}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|||||||
@@ -54,8 +54,8 @@
|
|||||||
<div class="ui stackable secondary menu mobile--margin-between-items mobile--no-negative-margins">
|
<div class="ui stackable secondary menu mobile--margin-between-items mobile--no-negative-margins">
|
||||||
{{if and .PullRequestCtx.Allowed .IsViewBranch}}
|
{{if and .PullRequestCtx.Allowed .IsViewBranch}}
|
||||||
<div class="fitted item">
|
<div class="fitted item">
|
||||||
<a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{.Repository.Owner.Name}}:{{.BranchName | EscapePound}}">
|
<a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{if 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>
|
<button class="ui green tiny compact button"><i class="octicon octicon-git-compare"></i></button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label>{{.i18n.Tr "repo.visibility"}}</label>
|
<label>{{.i18n.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1663,6 +1663,46 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/repos/{owner}/{repo}/git/trees/{sha}": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"repository"
|
||||||
|
],
|
||||||
|
"summary": "Gets the tree of a repository.",
|
||||||
|
"operationId": "GetTree",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "sha of the commit",
|
||||||
|
"name": "sha",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/GitTreeResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/repos/{owner}/{repo}/hooks": {
|
"/repos/{owner}/{repo}/hooks": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -7040,6 +7080,38 @@
|
|||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
},
|
},
|
||||||
|
"GitEntry": {
|
||||||
|
"description": "GitEntry represents a git tree",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Mode"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Path"
|
||||||
|
},
|
||||||
|
"sha": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "SHA"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"x-go-name": "Size"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Type"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "URL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
|
},
|
||||||
"GitObject": {
|
"GitObject": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "GitObject represents a Git object.",
|
"title": "GitObject represents a Git object.",
|
||||||
@@ -7059,6 +7131,32 @@
|
|||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
},
|
},
|
||||||
|
"GitTreeResponse": {
|
||||||
|
"description": "GitTreeResponse returns a git tree",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"sha": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "SHA"
|
||||||
|
},
|
||||||
|
"tree": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/GitEntry"
|
||||||
|
},
|
||||||
|
"x-go-name": "Entries"
|
||||||
|
},
|
||||||
|
"truncated": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "Truncated"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "URL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
|
},
|
||||||
"Issue": {
|
"Issue": {
|
||||||
"description": "Issue represents an issue in a repository",
|
"description": "Issue represents an issue in a repository",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -8200,6 +8298,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"GitTreeResponse": {
|
||||||
|
"description": "GitTreeResponse",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/GitTreeResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Hook": {
|
"Hook": {
|
||||||
"description": "Hook",
|
"description": "Hook",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|||||||
@@ -44,12 +44,14 @@
|
|||||||
<div v-show="tab === 'repos'" class="ui tab active list dashboard-repos">
|
<div v-show="tab === 'repos'" class="ui tab active list dashboard-repos">
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{.i18n.Tr "home.my_repos"}} <span class="ui grey label">${reposTotalCount}</span>
|
{{.i18n.Tr "home.my_repos"}} <span class="ui grey label">${reposTotalCount}</span>
|
||||||
|
{{if or (not .ContextUser.IsOrganization) .IsOrganizationOwner}}
|
||||||
<div class="ui right">
|
<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>
|
<i class="plus icon"></i>
|
||||||
<span class="sr-only">{{.i18n.Tr "new_repo"}}</span>
|
<span class="sr-only">{{.i18n.Tr "new_repo"}}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached secondary segment repos-search">
|
<div class="ui attached secondary segment repos-search">
|
||||||
<div class="ui fluid icon input" :class="{loading: isLoading}">
|
<div class="ui fluid icon input" :class="{loading: isLoading}">
|
||||||
|
|||||||
6
vendor/github.com/go-xorm/xorm/dialect_postgres.go
generated
vendored
6
vendor/github.com/go-xorm/xorm/dialect_postgres.go
generated
vendored
@@ -822,7 +822,7 @@ func (db *postgres) SqlType(c *core.Column) string {
|
|||||||
case core.NVarchar:
|
case core.NVarchar:
|
||||||
res = core.Varchar
|
res = core.Varchar
|
||||||
case core.Uuid:
|
case core.Uuid:
|
||||||
res = core.Uuid
|
return core.Uuid
|
||||||
case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob:
|
case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob:
|
||||||
return core.Bytea
|
return core.Bytea
|
||||||
case core.Double:
|
case core.Double:
|
||||||
@@ -834,6 +834,10 @@ func (db *postgres) SqlType(c *core.Column) string {
|
|||||||
res = t
|
res = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.EqualFold(res, "bool") {
|
||||||
|
// for bool, we don't need length information
|
||||||
|
return res
|
||||||
|
}
|
||||||
hasLen1 := (c.Length > 0)
|
hasLen1 := (c.Length > 0)
|
||||||
hasLen2 := (c.Length2 > 0)
|
hasLen2 := (c.Length2 > 0)
|
||||||
|
|
||||||
|
|||||||
5
vendor/github.com/go-xorm/xorm/engine.go
generated
vendored
5
vendor/github.com/go-xorm/xorm/engine.go
generated
vendored
@@ -481,7 +481,8 @@ func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.D
|
|||||||
}
|
}
|
||||||
|
|
||||||
cols := table.ColumnsSeq()
|
cols := table.ColumnsSeq()
|
||||||
colNames := dialect.Quote(strings.Join(cols, dialect.Quote(", ")))
|
colNames := engine.dialect.Quote(strings.Join(cols, engine.dialect.Quote(", ")))
|
||||||
|
destColNames := dialect.Quote(strings.Join(cols, dialect.Quote(", ")))
|
||||||
|
|
||||||
rows, err := engine.DB().Query("SELECT " + colNames + " FROM " + engine.Quote(table.Name))
|
rows, err := engine.DB().Query("SELECT " + colNames + " FROM " + engine.Quote(table.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -496,7 +497,7 @@ func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.D
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+colNames+") VALUES (")
|
_, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+destColNames+") VALUES (")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
27
vendor/gopkg.in/ldap.v2/LICENSE
generated
vendored
27
vendor/gopkg.in/ldap.v2/LICENSE
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
148
vendor/gopkg.in/ldap.v2/error.go
generated
vendored
148
vendor/gopkg.in/ldap.v2/error.go
generated
vendored
@@ -1,148 +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",
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
22
vendor/gopkg.in/ldap.v3/LICENSE
generated
vendored
Normal file
22
vendor/gopkg.in/ldap.v3/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)
|
||||||
|
Portions copyright (c) 2015-2016 go-ldap Authors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
16
vendor/gopkg.in/ldap.v2/add.go → vendor/gopkg.in/ldap.v3/add.go
generated
vendored
16
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
|
DN string
|
||||||
// Attributes list the attributes of the new entry
|
// Attributes list the attributes of the new entry
|
||||||
Attributes []Attribute
|
Attributes []Attribute
|
||||||
|
// Controls hold optional controls to send with the request
|
||||||
|
Controls []Control
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AddRequest) encode() *ber.Packet {
|
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
|
// 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{
|
return &AddRequest{
|
||||||
DN: dn,
|
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 := 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(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
packet.AppendChild(addRequest.encode())
|
packet.AppendChild(addRequest.encode())
|
||||||
|
if len(addRequest.Controls) > 0 {
|
||||||
|
packet.AppendChild(encodeControls(addRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
l.Debug.PrintPacket(packet)
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
@@ -100,9 +106,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationAddResponse {
|
if packet.Children[1].Tag == ApplicationAddResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
if err != nil {
|
||||||
return NewError(resultCode, errors.New(resultDescription))
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
108
vendor/gopkg.in/ldap.v2/bind.go → vendor/gopkg.in/ldap.v3/bind.go
generated
vendored
108
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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gopkg.in/asn1-ber.v1"
|
"gopkg.in/asn1-ber.v1"
|
||||||
)
|
)
|
||||||
@@ -18,6 +15,9 @@ type SimpleBindRequest struct {
|
|||||||
Password string
|
Password string
|
||||||
// Controls are optional controls to send with the bind request
|
// Controls are optional controls to send with the bind request
|
||||||
Controls []Control
|
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
|
// SimpleBindResult contains the response from the server
|
||||||
@@ -28,9 +28,10 @@ type SimpleBindResult struct {
|
|||||||
// NewSimpleBindRequest returns a bind request
|
// NewSimpleBindRequest returns a bind request
|
||||||
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
|
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
|
||||||
return &SimpleBindRequest{
|
return &SimpleBindRequest{
|
||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
Controls: controls,
|
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.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name"))
|
||||||
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
|
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
|
||||||
|
|
||||||
request.AppendChild(encodeControls(bindRequest.Controls))
|
|
||||||
|
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleBind performs the simple bind operation defined in the given request
|
// SimpleBind performs the simple bind operation defined in the given request
|
||||||
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
|
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 := 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(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
encodedBindRequest := simpleBindRequest.encode()
|
encodedBindRequest := simpleBindRequest.encode()
|
||||||
packet.AppendChild(encodedBindRequest)
|
packet.AppendChild(encodedBindRequest)
|
||||||
|
if len(simpleBindRequest.Controls) > 0 {
|
||||||
|
packet.AppendChild(encodeControls(simpleBindRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
if l.Debug {
|
if l.Debug {
|
||||||
ber.PrintPacket(packet)
|
ber.PrintPacket(packet)
|
||||||
@@ -73,7 +79,7 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if l.Debug {
|
if l.Debug {
|
||||||
if err := addLDAPDescriptions(packet); err != nil {
|
if err = addLDAPDescriptions(packet); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ber.PrintPacket(packet)
|
ber.PrintPacket(packet)
|
||||||
@@ -85,59 +91,45 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
|
|||||||
|
|
||||||
if len(packet.Children) == 3 {
|
if len(packet.Children) == 3 {
|
||||||
for _, child := range packet.Children[2].Children {
|
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)
|
err = GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
return result, err
|
||||||
return result, NewError(resultCode, errors.New(resultDescription))
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
func (l *Conn) Bind(username, password string) error {
|
||||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
req := &SimpleBindRequest{
|
||||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
Username: username,
|
||||||
bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
|
Password: password,
|
||||||
bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
|
AllowEmptyPassword: false,
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
_, err := l.SimpleBind(req)
|
||||||
msgCtx, err := l.sendMessage(packet)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
// UnauthenticatedBind performs an unauthenticated bind.
|
||||||
defer l.finishMessage(msgCtx)
|
//
|
||||||
|
// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
|
||||||
packetResponse, ok := <-msgCtx.responses
|
// authenticated or otherwise validated by the LDAP server.
|
||||||
if !ok {
|
//
|
||||||
return NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
|
// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
|
||||||
}
|
// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
|
||||||
packet, err = packetResponse.ReadPacket()
|
func (l *Conn) UnauthenticatedBind(username string) error {
|
||||||
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
|
req := &SimpleBindRequest{
|
||||||
if err != nil {
|
Username: username,
|
||||||
return err
|
Password: "",
|
||||||
}
|
AllowEmptyPassword: true,
|
||||||
|
}
|
||||||
if l.Debug {
|
_, err := l.SimpleBind(req)
|
||||||
if err := addLDAPDescriptions(packet); err != nil {
|
return err
|
||||||
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
|
Add(addRequest *AddRequest) error
|
||||||
Del(delRequest *DelRequest) error
|
Del(delRequest *DelRequest) error
|
||||||
Modify(modifyRequest *ModifyRequest) error
|
Modify(modifyRequest *ModifyRequest) error
|
||||||
|
ModifyDN(modifyDNRequest *ModifyDNRequest) error
|
||||||
|
|
||||||
Compare(dn, attribute, value string) (bool, error)
|
Compare(dn, attribute, value string) (bool, error)
|
||||||
PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, 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
|
// File contains Compare functionality
|
||||||
//
|
//
|
||||||
// https://tools.ietf.org/html/rfc4511
|
// 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 := 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.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)
|
request.AppendChild(ava)
|
||||||
packet.AppendChild(request)
|
packet.AppendChild(request)
|
||||||
|
|
||||||
@@ -72,14 +68,16 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationCompareResponse {
|
if packet.Children[1].Tag == ApplicationCompareResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode == LDAPResultCompareTrue {
|
|
||||||
|
switch {
|
||||||
|
case IsErrorWithCode(err, LDAPResultCompareTrue):
|
||||||
return true, nil
|
return true, nil
|
||||||
} else if resultCode == LDAPResultCompareFalse {
|
case IsErrorWithCode(err, LDAPResultCompareFalse):
|
||||||
return false, nil
|
return false, nil
|
||||||
} else {
|
default:
|
||||||
return false, NewError(resultCode, errors.New(resultDescription))
|
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)
|
||||||
}
|
}
|
||||||
151
vendor/gopkg.in/ldap.v2/conn.go → vendor/gopkg.in/ldap.v3/conn.go
generated
vendored
151
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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -10,7 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/asn1-ber.v1"
|
"gopkg.in/asn1-ber.v1"
|
||||||
@@ -29,6 +27,13 @@ const (
|
|||||||
MessageTimeout = 4
|
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
|
// PacketResponse contains the packet or error encountered reading a response
|
||||||
type PacketResponse struct {
|
type PacketResponse struct {
|
||||||
// Packet is the packet read from the server
|
// Packet is the packet read from the server
|
||||||
@@ -80,22 +85,22 @@ const (
|
|||||||
|
|
||||||
// Conn represents an LDAP Connection
|
// Conn represents an LDAP Connection
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
|
// requestTimeout is loaded atomically
|
||||||
|
// so we need to ensure 64-bit alignment on 32-bit platforms.
|
||||||
|
requestTimeout int64
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
isTLS bool
|
isTLS bool
|
||||||
isClosing bool
|
closing uint32
|
||||||
closeErr error
|
closeErr atomic.Value
|
||||||
isStartingTLS bool
|
isStartingTLS bool
|
||||||
Debug debugging
|
Debug debugging
|
||||||
chanConfirm chan bool
|
chanConfirm chan struct{}
|
||||||
messageContexts map[int64]*messageContext
|
messageContexts map[int64]*messageContext
|
||||||
chanMessage chan *messagePacket
|
chanMessage chan *messagePacket
|
||||||
chanMessageID chan int64
|
chanMessageID chan int64
|
||||||
wgSender sync.WaitGroup
|
|
||||||
wgClose sync.WaitGroup
|
wgClose sync.WaitGroup
|
||||||
once sync.Once
|
|
||||||
outstandingRequests uint
|
outstandingRequests uint
|
||||||
messageMutex sync.Mutex
|
messageMutex sync.Mutex
|
||||||
requestTimeout time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Client = &Conn{}
|
var _ Client = &Conn{}
|
||||||
@@ -122,27 +127,56 @@ func Dial(network, addr string) (*Conn, error) {
|
|||||||
// DialTLS connects to the given address on the given network using tls.Dial
|
// DialTLS connects to the given address on the given network using tls.Dial
|
||||||
// and then returns a new Conn for the connection.
|
// and then returns a new Conn for the connection.
|
||||||
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, NewError(ErrorNetwork, err)
|
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 := NewConn(c, true)
|
||||||
conn.Start()
|
conn.Start()
|
||||||
return conn, nil
|
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.
|
// NewConn returns a new Conn using conn for network I/O.
|
||||||
func NewConn(conn net.Conn, isTLS bool) *Conn {
|
func NewConn(conn net.Conn, isTLS bool) *Conn {
|
||||||
return &Conn{
|
return &Conn{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
chanConfirm: make(chan bool),
|
chanConfirm: make(chan struct{}),
|
||||||
chanMessageID: make(chan int64),
|
chanMessageID: make(chan int64),
|
||||||
chanMessage: make(chan *messagePacket, 10),
|
chanMessage: make(chan *messagePacket, 10),
|
||||||
messageContexts: map[int64]*messageContext{},
|
messageContexts: map[int64]*messageContext{},
|
||||||
@@ -158,12 +192,22 @@ func (l *Conn) Start() {
|
|||||||
l.wgClose.Add(1)
|
l.wgClose.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsClosing returns whether or not we're currently closing.
|
||||||
|
func (l *Conn) IsClosing() bool {
|
||||||
|
return atomic.LoadUint32(&l.closing) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// setClosing sets the closing value to true
|
||||||
|
func (l *Conn) setClosing() bool {
|
||||||
|
return atomic.CompareAndSwapUint32(&l.closing, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
// Close closes the connection.
|
// Close closes the connection.
|
||||||
func (l *Conn) Close() {
|
func (l *Conn) Close() {
|
||||||
l.once.Do(func() {
|
l.messageMutex.Lock()
|
||||||
l.isClosing = true
|
defer l.messageMutex.Unlock()
|
||||||
l.wgSender.Wait()
|
|
||||||
|
|
||||||
|
if l.setClosing() {
|
||||||
l.Debug.Printf("Sending quit message and waiting for confirmation")
|
l.Debug.Printf("Sending quit message and waiting for confirmation")
|
||||||
l.chanMessage <- &messagePacket{Op: MessageQuit}
|
l.chanMessage <- &messagePacket{Op: MessageQuit}
|
||||||
<-l.chanConfirm
|
<-l.chanConfirm
|
||||||
@@ -171,27 +215,25 @@ func (l *Conn) Close() {
|
|||||||
|
|
||||||
l.Debug.Printf("Closing network connection")
|
l.Debug.Printf("Closing network connection")
|
||||||
if err := l.conn.Close(); err != nil {
|
if err := l.conn.Close(); err != nil {
|
||||||
log.Print(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
l.wgClose.Done()
|
l.wgClose.Done()
|
||||||
})
|
}
|
||||||
l.wgClose.Wait()
|
l.wgClose.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTimeout sets the time after a request is sent that a MessageTimeout triggers
|
// SetTimeout sets the time after a request is sent that a MessageTimeout triggers
|
||||||
func (l *Conn) SetTimeout(timeout time.Duration) {
|
func (l *Conn) SetTimeout(timeout time.Duration) {
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
l.requestTimeout = timeout
|
atomic.StoreInt64(&l.requestTimeout, int64(timeout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the next available messageID
|
// Returns the next available messageID
|
||||||
func (l *Conn) nextMessageID() int64 {
|
func (l *Conn) nextMessageID() int64 {
|
||||||
if l.chanMessageID != nil {
|
if messageID, ok := <-l.chanMessageID; ok {
|
||||||
if messageID, ok := <-l.chanMessageID; ok {
|
return messageID
|
||||||
return messageID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -235,30 +277,41 @@ func (l *Conn) StartTLS(config *tls.Config) error {
|
|||||||
ber.PrintPacket(packet)
|
ber.PrintPacket(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
if resultCode, message := getLDAPResultCode(packet); resultCode == LDAPResultSuccess {
|
if err := GetLDAPError(packet); err == nil {
|
||||||
conn := tls.Client(l.conn, config)
|
conn := tls.Client(l.conn, config)
|
||||||
|
|
||||||
if err := conn.Handshake(); err != nil {
|
if connErr := conn.Handshake(); connErr != nil {
|
||||||
l.Close()
|
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.isTLS = true
|
||||||
l.conn = conn
|
l.conn = conn
|
||||||
} else {
|
} else {
|
||||||
return NewError(resultCode, fmt.Errorf("ldap: cannot StartTLS (%s)", message))
|
return err
|
||||||
}
|
}
|
||||||
go l.reader()
|
go l.reader()
|
||||||
|
|
||||||
return nil
|
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) {
|
func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) {
|
||||||
return l.sendMessageWithFlags(packet, 0)
|
return l.sendMessageWithFlags(packet, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) {
|
func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) {
|
||||||
if l.isClosing {
|
if l.IsClosing() {
|
||||||
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
|
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
|
||||||
}
|
}
|
||||||
l.messageMutex.Lock()
|
l.messageMutex.Lock()
|
||||||
@@ -297,7 +350,7 @@ func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags)
|
|||||||
func (l *Conn) finishMessage(msgCtx *messageContext) {
|
func (l *Conn) finishMessage(msgCtx *messageContext) {
|
||||||
close(msgCtx.done)
|
close(msgCtx.done)
|
||||||
|
|
||||||
if l.isClosing {
|
if l.IsClosing() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,12 +369,12 @@ func (l *Conn) finishMessage(msgCtx *messageContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
|
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
|
||||||
if l.isClosing {
|
l.messageMutex.Lock()
|
||||||
|
defer l.messageMutex.Unlock()
|
||||||
|
if l.IsClosing() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
l.wgSender.Add(1)
|
|
||||||
l.chanMessage <- message
|
l.chanMessage <- message
|
||||||
l.wgSender.Done()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,15 +386,14 @@ func (l *Conn) processMessages() {
|
|||||||
for messageID, msgCtx := range l.messageContexts {
|
for messageID, msgCtx := range l.messageContexts {
|
||||||
// If we are closing due to an error, inform anyone who
|
// If we are closing due to an error, inform anyone who
|
||||||
// is waiting about the error.
|
// is waiting about the error.
|
||||||
if l.isClosing && l.closeErr != nil {
|
if l.IsClosing() && l.closeErr.Load() != nil {
|
||||||
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr})
|
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
|
||||||
}
|
}
|
||||||
l.Debug.Printf("Closing channel for MessageID %d", messageID)
|
l.Debug.Printf("Closing channel for MessageID %d", messageID)
|
||||||
close(msgCtx.responses)
|
close(msgCtx.responses)
|
||||||
delete(l.messageContexts, messageID)
|
delete(l.messageContexts, messageID)
|
||||||
}
|
}
|
||||||
close(l.chanMessageID)
|
close(l.chanMessageID)
|
||||||
l.chanConfirm <- true
|
|
||||||
close(l.chanConfirm)
|
close(l.chanConfirm)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -350,11 +402,7 @@ func (l *Conn) processMessages() {
|
|||||||
select {
|
select {
|
||||||
case l.chanMessageID <- messageID:
|
case l.chanMessageID <- messageID:
|
||||||
messageID++
|
messageID++
|
||||||
case message, ok := <-l.chanMessage:
|
case message := <-l.chanMessage:
|
||||||
if !ok {
|
|
||||||
l.Debug.Printf("Shutting down - message channel is closed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch message.Op {
|
switch message.Op {
|
||||||
case MessageQuit:
|
case MessageQuit:
|
||||||
l.Debug.Printf("Shutting down - quit message received")
|
l.Debug.Printf("Shutting down - quit message received")
|
||||||
@@ -377,14 +425,15 @@ func (l *Conn) processMessages() {
|
|||||||
l.messageContexts[message.MessageID] = message.Context
|
l.messageContexts[message.MessageID] = message.Context
|
||||||
|
|
||||||
// Add timeout if defined
|
// Add timeout if defined
|
||||||
if l.requestTimeout > 0 {
|
requestTimeout := time.Duration(atomic.LoadInt64(&l.requestTimeout))
|
||||||
|
if requestTimeout > 0 {
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
log.Printf("ldap: recovered panic in RequestTimeout: %v", err)
|
log.Printf("ldap: recovered panic in RequestTimeout: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
time.Sleep(l.requestTimeout)
|
time.Sleep(requestTimeout)
|
||||||
timeoutMessage := &messagePacket{
|
timeoutMessage := &messagePacket{
|
||||||
Op: MessageTimeout,
|
Op: MessageTimeout,
|
||||||
MessageID: message.MessageID,
|
MessageID: message.MessageID,
|
||||||
@@ -397,7 +446,7 @@ func (l *Conn) processMessages() {
|
|||||||
if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
|
if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
|
||||||
msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
|
msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
|
||||||
} else {
|
} 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)
|
ber.PrintPacket(message.Packet)
|
||||||
}
|
}
|
||||||
case MessageTimeout:
|
case MessageTimeout:
|
||||||
@@ -439,8 +488,8 @@ func (l *Conn) reader() {
|
|||||||
packet, err := ber.ReadPacket(l.conn)
|
packet, err := ber.ReadPacket(l.conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// A read error is expected here if we are closing the connection...
|
// A read error is expected here if we are closing the connection...
|
||||||
if !l.isClosing {
|
if !l.IsClosing() {
|
||||||
l.closeErr = fmt.Errorf("unable to read LDAP response packet: %s", err)
|
l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err))
|
||||||
l.Debug.Printf("reader error: %s", err.Error())
|
l.Debug.Printf("reader error: %s", err.Error())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
129
vendor/gopkg.in/ldap.v2/control.go → vendor/gopkg.in/ldap.v3/control.go
generated
vendored
129
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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -22,13 +18,20 @@ const (
|
|||||||
ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
|
ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
|
||||||
// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
|
// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
|
||||||
ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
|
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
|
// ControlTypeMap maps controls to text descriptions
|
||||||
var ControlTypeMap = map[string]string{
|
var ControlTypeMap = map[string]string{
|
||||||
ControlTypePaging: "Paging",
|
ControlTypePaging: "Paging",
|
||||||
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
|
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
|
||||||
ControlTypeManageDsaIT: "Manage DSA IT",
|
ControlTypeManageDsaIT: "Manage DSA IT",
|
||||||
|
ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
|
||||||
|
ControlTypeMicrosoftShowDeleted: "Show Deleted Objects - Microsoft",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control defines an interface controls provide to encode and describe themselves
|
// Control defines an interface controls provide to encode and describe themselves
|
||||||
@@ -242,6 +245,64 @@ func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
|
|||||||
return &ControlManageDsaIT{Criticality: Criticality}
|
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
|
// FindControl returns the first control of the given type in the list, or nil
|
||||||
func FindControl(controls []Control, controlType string) Control {
|
func FindControl(controls []Control, controlType string) Control {
|
||||||
for _, c := range controls {
|
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
|
// 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 (
|
var (
|
||||||
ControlType = ""
|
ControlType = ""
|
||||||
Criticality = false
|
Criticality = false
|
||||||
@@ -263,7 +324,7 @@ func DecodeControl(packet *ber.Packet) Control {
|
|||||||
switch len(packet.Children) {
|
switch len(packet.Children) {
|
||||||
case 0:
|
case 0:
|
||||||
// at least one child is required for control type
|
// 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:
|
case 1:
|
||||||
// just type, no criticality or value
|
// just type, no criticality or value
|
||||||
@@ -296,17 +357,20 @@ func DecodeControl(packet *ber.Packet) Control {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
// more than 3 children is invalid
|
// more than 3 children is invalid
|
||||||
return nil
|
return nil, fmt.Errorf("more than 3 children is invalid for controls")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ControlType {
|
switch ControlType {
|
||||||
case ControlTypeManageDsaIT:
|
case ControlTypeManageDsaIT:
|
||||||
return NewControlManageDsaIT(Criticality)
|
return NewControlManageDsaIT(Criticality), nil
|
||||||
case ControlTypePaging:
|
case ControlTypePaging:
|
||||||
value.Description += " (Paging)"
|
value.Description += " (Paging)"
|
||||||
c := new(ControlPaging)
|
c := new(ControlPaging)
|
||||||
if value.Value != nil {
|
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.Data.Truncate(0)
|
||||||
value.Value = nil
|
value.Value = nil
|
||||||
value.AppendChild(valueChildren)
|
value.AppendChild(valueChildren)
|
||||||
@@ -318,12 +382,15 @@ func DecodeControl(packet *ber.Packet) Control {
|
|||||||
c.PagingSize = uint32(value.Children[0].Value.(int64))
|
c.PagingSize = uint32(value.Children[0].Value.(int64))
|
||||||
c.Cookie = value.Children[1].Data.Bytes()
|
c.Cookie = value.Children[1].Data.Bytes()
|
||||||
value.Children[1].Value = c.Cookie
|
value.Children[1].Value = c.Cookie
|
||||||
return c
|
return c, nil
|
||||||
case ControlTypeBeheraPasswordPolicy:
|
case ControlTypeBeheraPasswordPolicy:
|
||||||
value.Description += " (Password Policy - Behera)"
|
value.Description += " (Password Policy - Behera)"
|
||||||
c := NewControlBeheraPasswordPolicy()
|
c := NewControlBeheraPasswordPolicy()
|
||||||
if value.Value != nil {
|
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.Data.Truncate(0)
|
||||||
value.Value = nil
|
value.Value = nil
|
||||||
value.AppendChild(valueChildren)
|
value.AppendChild(valueChildren)
|
||||||
@@ -334,23 +401,29 @@ func DecodeControl(packet *ber.Packet) Control {
|
|||||||
for _, child := range sequence.Children {
|
for _, child := range sequence.Children {
|
||||||
if child.Tag == 0 {
|
if child.Tag == 0 {
|
||||||
//Warning
|
//Warning
|
||||||
child := child.Children[0]
|
warningPacket := child.Children[0]
|
||||||
packet := ber.DecodePacket(child.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)
|
val, ok := packet.Value.(int64)
|
||||||
if ok {
|
if ok {
|
||||||
if child.Tag == 0 {
|
if warningPacket.Tag == 0 {
|
||||||
//timeBeforeExpiration
|
//timeBeforeExpiration
|
||||||
c.Expire = val
|
c.Expire = val
|
||||||
child.Value = c.Expire
|
warningPacket.Value = c.Expire
|
||||||
} else if child.Tag == 1 {
|
} else if warningPacket.Tag == 1 {
|
||||||
//graceAuthNsRemaining
|
//graceAuthNsRemaining
|
||||||
c.Grace = val
|
c.Grace = val
|
||||||
child.Value = c.Grace
|
warningPacket.Value = c.Grace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if child.Tag == 1 {
|
} else if child.Tag == 1 {
|
||||||
// Error
|
// 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)
|
val, ok := packet.Value.(int8)
|
||||||
if !ok {
|
if !ok {
|
||||||
// what to do?
|
// what to do?
|
||||||
@@ -361,22 +434,26 @@ func DecodeControl(packet *ber.Packet) Control {
|
|||||||
c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
|
c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c, nil
|
||||||
case ControlTypeVChuPasswordMustChange:
|
case ControlTypeVChuPasswordMustChange:
|
||||||
c := &ControlVChuPasswordMustChange{MustChange: true}
|
c := &ControlVChuPasswordMustChange{MustChange: true}
|
||||||
return c
|
return c, nil
|
||||||
case ControlTypeVChuPasswordWarning:
|
case ControlTypeVChuPasswordWarning:
|
||||||
c := &ControlVChuPasswordWarning{Expire: -1}
|
c := &ControlVChuPasswordWarning{Expire: -1}
|
||||||
expireStr := ber.DecodeString(value.Data.Bytes())
|
expireStr := ber.DecodeString(value.Data.Bytes())
|
||||||
|
|
||||||
expire, err := strconv.ParseInt(expireStr, 10, 64)
|
expire, err := strconv.ParseInt(expireStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil, fmt.Errorf("failed to parse value as int: %s", err)
|
||||||
}
|
}
|
||||||
c.Expire = expire
|
c.Expire = expire
|
||||||
value.Value = c.Expire
|
value.Value = c.Expire
|
||||||
|
|
||||||
return c
|
return c, nil
|
||||||
|
case ControlTypeMicrosoftNotification:
|
||||||
|
return NewControlMicrosoftNotification(), nil
|
||||||
|
case ControlTypeMicrosoftShowDeleted:
|
||||||
|
return NewControlMicrosoftShowDeleted(), nil
|
||||||
default:
|
default:
|
||||||
c := new(ControlString)
|
c := new(ControlString)
|
||||||
c.ControlType = ControlType
|
c.ControlType = ControlType
|
||||||
@@ -384,7 +461,7 @@ func DecodeControl(packet *ber.Packet) Control {
|
|||||||
if value != nil {
|
if value != nil {
|
||||||
c.ControlValue = value.Value.(string)
|
c.ControlValue = value.Value.(string)
|
||||||
}
|
}
|
||||||
return c
|
return c, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
2
vendor/gopkg.in/ldap.v2/debug.go → vendor/gopkg.in/ldap.v3/debug.go
generated
vendored
2
vendor/gopkg.in/ldap.v2/debug.go → vendor/gopkg.in/ldap.v3/debug.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
|||||||
"gopkg.in/asn1-ber.v1"
|
"gopkg.in/asn1-ber.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// debbuging type
|
// debugging type
|
||||||
// - has a Printf method to write the debug output
|
// - has a Printf method to write the debug output
|
||||||
type debugging bool
|
type debugging bool
|
||||||
|
|
||||||
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 := 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(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
packet.AppendChild(delRequest.encode())
|
packet.AppendChild(delRequest.encode())
|
||||||
if delRequest.Controls != nil {
|
if len(delRequest.Controls) > 0 {
|
||||||
packet.AppendChild(encodeControls(delRequest.Controls))
|
packet.AppendChild(encodeControls(delRequest.Controls))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,9 +71,9 @@ func (l *Conn) Del(delRequest *DelRequest) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationDelResponse {
|
if packet.Children[1].Tag == ApplicationDelResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
if err != nil {
|
||||||
return NewError(resultCode, errors.New(resultDescription))
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
131
vendor/gopkg.in/ldap.v2/dn.go → vendor/gopkg.in/ldap.v3/dn.go
generated
vendored
131
vendor/gopkg.in/ldap.v2/dn.go → vendor/gopkg.in/ldap.v3/dn.go
generated
vendored
@@ -1,8 +1,4 @@
|
|||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
// File contains DN parsing functionality
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
//
|
|
||||||
// File contains DN parsing functionallity
|
|
||||||
//
|
//
|
||||||
// https://tools.ietf.org/html/rfc4514
|
// https://tools.ietf.org/html/rfc4514
|
||||||
//
|
//
|
||||||
@@ -52,7 +48,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
ber "gopkg.in/asn1-ber.v1"
|
"gopkg.in/asn1-ber.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514
|
// AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514
|
||||||
@@ -83,9 +79,20 @@ func ParseDN(str string) (*DN, error) {
|
|||||||
attribute := new(AttributeTypeAndValue)
|
attribute := new(AttributeTypeAndValue)
|
||||||
escaping := false
|
escaping := false
|
||||||
|
|
||||||
|
unescapedTrailingSpaces := 0
|
||||||
|
stringFromBuffer := func() string {
|
||||||
|
s := buffer.String()
|
||||||
|
s = s[0 : len(s)-unescapedTrailingSpaces]
|
||||||
|
buffer.Reset()
|
||||||
|
unescapedTrailingSpaces = 0
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < len(str); i++ {
|
for i := 0; i < len(str); i++ {
|
||||||
char := str[i]
|
char := str[i]
|
||||||
if escaping {
|
switch {
|
||||||
|
case escaping:
|
||||||
|
unescapedTrailingSpaces = 0
|
||||||
escaping = false
|
escaping = false
|
||||||
switch char {
|
switch char {
|
||||||
case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\':
|
case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\':
|
||||||
@@ -94,23 +101,23 @@ func ParseDN(str string) (*DN, error) {
|
|||||||
}
|
}
|
||||||
// Not a special character, assume hex encoded octet
|
// Not a special character, assume hex encoded octet
|
||||||
if len(str) == i+1 {
|
if len(str) == i+1 {
|
||||||
return nil, errors.New("Got corrupted escaped character")
|
return nil, errors.New("got corrupted escaped character")
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := []byte{0}
|
dst := []byte{0}
|
||||||
n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
|
n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
|
||||||
if err != nil {
|
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 {
|
} 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])
|
buffer.WriteByte(dst[0])
|
||||||
i++
|
i++
|
||||||
} else if char == '\\' {
|
case char == '\\':
|
||||||
|
unescapedTrailingSpaces = 0
|
||||||
escaping = true
|
escaping = true
|
||||||
} else if char == '=' {
|
case char == '=':
|
||||||
attribute.Type = buffer.String()
|
attribute.Type = stringFromBuffer()
|
||||||
buffer.Reset()
|
|
||||||
// Special case: If the first character in the value is # the
|
// Special case: If the first character in the value is # the
|
||||||
// following data is BER encoded so we can just fast forward
|
// following data is BER encoded so we can just fast forward
|
||||||
// and decode.
|
// and decode.
|
||||||
@@ -125,15 +132,21 @@ func ParseDN(str string) (*DN, error) {
|
|||||||
}
|
}
|
||||||
rawBER, err := enchex.DecodeString(data)
|
rawBER, err := enchex.DecodeString(data)
|
||||||
if err != nil {
|
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())
|
buffer.WriteString(packet.Data.String())
|
||||||
i += len(data) - 1
|
i += len(data) - 1
|
||||||
}
|
}
|
||||||
} else if char == ',' || char == '+' {
|
case char == ',' || char == '+':
|
||||||
// We're done with this RDN or value, push it
|
// We're done with this RDN or value, push it
|
||||||
attribute.Value = buffer.String()
|
if len(attribute.Type) == 0 {
|
||||||
|
return nil, errors.New("incomplete type, value pair")
|
||||||
|
}
|
||||||
|
attribute.Value = stringFromBuffer()
|
||||||
rdn.Attributes = append(rdn.Attributes, attribute)
|
rdn.Attributes = append(rdn.Attributes, attribute)
|
||||||
attribute = new(AttributeTypeAndValue)
|
attribute = new(AttributeTypeAndValue)
|
||||||
if char == ',' {
|
if char == ',' {
|
||||||
@@ -141,8 +154,17 @@ func ParseDN(str string) (*DN, error) {
|
|||||||
rdn = new(RelativeDN)
|
rdn = new(RelativeDN)
|
||||||
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
||||||
}
|
}
|
||||||
buffer.Reset()
|
case char == ' ' && buffer.Len() == 0:
|
||||||
} else {
|
// ignore unescaped leading spaces
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
if char == ' ' {
|
||||||
|
// Track unescaped spaces in case they are trailing and we need to remove them
|
||||||
|
unescapedTrailingSpaces++
|
||||||
|
} else {
|
||||||
|
// Reset if we see a non-space char
|
||||||
|
unescapedTrailingSpaces = 0
|
||||||
|
}
|
||||||
buffer.WriteByte(char)
|
buffer.WriteByte(char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,9 +172,76 @@ func ParseDN(str string) (*DN, error) {
|
|||||||
if len(attribute.Type) == 0 {
|
if len(attribute.Type) == 0 {
|
||||||
return nil, errors.New("DN ended with incomplete type, value pair")
|
return nil, errors.New("DN ended with incomplete type, value pair")
|
||||||
}
|
}
|
||||||
attribute.Value = buffer.String()
|
attribute.Value = stringFromBuffer()
|
||||||
rdn.Attributes = append(rdn.Attributes, attribute)
|
rdn.Attributes = append(rdn.Attributes, attribute)
|
||||||
dn.RDNs = append(dn.RDNs, rdn)
|
dn.RDNs = append(dn.RDNs, rdn)
|
||||||
}
|
}
|
||||||
return dn, nil
|
return dn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
|
||||||
|
// Returns true if they have the same number of relative distinguished names
|
||||||
|
// and corresponding relative distinguished names (by position) are the same.
|
||||||
|
func (d *DN) Equal(other *DN) bool {
|
||||||
|
if len(d.RDNs) != len(other.RDNs) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range d.RDNs {
|
||||||
|
if !d.RDNs[i].Equal(other.RDNs[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// AncestorOf returns true if the other DN consists of at least one RDN followed by all the RDNs of the current DN.
|
||||||
|
// "ou=widgets,o=acme.com" is an ancestor of "ou=sprockets,ou=widgets,o=acme.com"
|
||||||
|
// "ou=widgets,o=acme.com" is not an ancestor of "ou=sprockets,ou=widgets,o=foo.com"
|
||||||
|
// "ou=widgets,o=acme.com" is not an ancestor of "ou=widgets,o=acme.com"
|
||||||
|
func (d *DN) AncestorOf(other *DN) bool {
|
||||||
|
if len(d.RDNs) >= len(other.RDNs) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Take the last `len(d.RDNs)` RDNs from the other DN to compare against
|
||||||
|
otherRDNs := other.RDNs[len(other.RDNs)-len(d.RDNs):]
|
||||||
|
for i := range d.RDNs {
|
||||||
|
if !d.RDNs[i].Equal(otherRDNs[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
|
||||||
|
// Relative distinguished names are the same if and only if they have the same number of AttributeTypeAndValues
|
||||||
|
// and each attribute of the first RDN is the same as the attribute of the second RDN with the same attribute type.
|
||||||
|
// The order of attributes is not significant.
|
||||||
|
// Case of attribute types is not significant.
|
||||||
|
func (r *RelativeDN) Equal(other *RelativeDN) bool {
|
||||||
|
if len(r.Attributes) != len(other.Attributes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return r.hasAllAttributes(other.Attributes) && other.hasAllAttributes(r.Attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RelativeDN) hasAllAttributes(attrs []*AttributeTypeAndValue) bool {
|
||||||
|
for _, attr := range attrs {
|
||||||
|
found := false
|
||||||
|
for _, myattr := range r.Attributes {
|
||||||
|
if myattr.Equal(attr) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns true if the AttributeTypeAndValue is equivalent to the specified AttributeTypeAndValue
|
||||||
|
// Case of the attribute type is not significant
|
||||||
|
func (a *AttributeTypeAndValue) Equal(other *AttributeTypeAndValue) bool {
|
||||||
|
return strings.EqualFold(a.Type, other.Type) && a.Value == other.Value
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
9
vendor/gopkg.in/ldap.v2/filter.go → vendor/gopkg.in/ldap.v3/filter.go
generated
vendored
9
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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -82,7 +78,10 @@ func CompileFilter(filter string) (*ber.Packet, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if pos != len(filter) {
|
switch {
|
||||||
|
case pos > len(filter):
|
||||||
|
return nil, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
|
||||||
|
case pos < len(filter):
|
||||||
return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
|
return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
|
||||||
}
|
}
|
||||||
return packet, nil
|
return packet, nil
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user