mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-21 01:21:18 +02:00
Compare commits
26 Commits
0d00ec7eed
...
v1.4.0
Author | SHA1 | Date | |
---|---|---|---|
|
832e2ebe91 | ||
|
68134e6441 | ||
|
3022681432 | ||
|
c0e0fb7d39 | ||
|
0c612124f9 | ||
|
5d0c9872a9 | ||
|
92a3061753 | ||
|
efc5a7171b | ||
|
93f34fd8a2 | ||
|
dd784396ce | ||
|
4a0ce6896b | ||
|
d87fb0a6fd | ||
|
e55eaa8545 | ||
|
423c642fdb | ||
|
ed2ba84525 | ||
|
e8015a59bb | ||
|
8327300809 | ||
|
ade183957d | ||
|
c503eac206 | ||
|
221e502297 | ||
|
1c3d712fe7 | ||
|
85f90187f3 | ||
|
c0675ef6c2 | ||
|
4e27cc4813 | ||
|
f61ef28f26 | ||
|
b27e10d6e4 |
17
CHANGELOG.md
17
CHANGELOG.md
@@ -4,11 +4,15 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.4.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.4.0-rc1) - 2018-01-31
|
||||
## [1.4.0](https://github.com/go-gitea/gitea/releases/tag/v1.4.0) - 2018-03-25
|
||||
* BREAKING
|
||||
* Drop deprecated GOGS\_WORK\_DIR use (#2946)
|
||||
* Fix API status code for hook creation (#2814)
|
||||
* SECURITY
|
||||
* Escape branch name in dropdown menu (#3691) (#3692)
|
||||
* Refactor and simplify to correctly validate redirect to URL (#3674) (#3676)
|
||||
* Fix escaping changed title in comments (#3530) (#3534)
|
||||
* Escape search query (#3486) (#3488)
|
||||
* Sanitize logs for mirror sync (#3057)
|
||||
* FEATURE
|
||||
* Serve .patch and .diff for pull requests (#3305, #3293)
|
||||
@@ -24,6 +28,17 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
* Add dingtalk webhook (#2777)
|
||||
* Responsive view (#2750)
|
||||
* BUGFIXES
|
||||
* Fix wiki inter-links with spaces (#3560) (#3632)
|
||||
* Fix query protected branch bug (#3563) (#3571)
|
||||
* Fix remove team member issue (#3566) (#3570)
|
||||
* Fix the protected branch panic issue (#3567) (#3569)
|
||||
* If Mirrors repository no content is fetched, updated time should not be changed (#3551) (#3565)
|
||||
* Bug fix for mirrored repository releases sorted (#3522) (#3555)
|
||||
* Add issue closed time column to fix activity closed issues list (#3537) (#3540)
|
||||
* Update markbates/goth library to support OAuth2 with new dropbox API (#3533) (#3539)
|
||||
* Fixes missing avatars in offline mode (#3471) (#3477)
|
||||
* Fix synchronization bug in repo indexer (#3455) (#3461)
|
||||
* Fix rendering of wiki page list if wiki repo contains other files (#3454) (#3463)
|
||||
* Fix webhook X-GitHub-* headers casing for better compatibility (#3429)
|
||||
* Add content type and doctype to requests made with go-get (#3426, #3423)
|
||||
* Fix SQL type error for webhooks (#3424)
|
||||
|
@@ -128,7 +128,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||
- `REPO_INDEXER_ENABLED`: **false**: Enables code search (uses a lot of disk space).
|
||||
- `REPO_INDEXER_PATH`: **indexers/repos.bleve**: Index file used for code search.
|
||||
- `UPDATE_BUFFER_LEN`: **20**: Buffer length of index request.
|
||||
- `MAX_FILE_SIZE`: **1048576**: Maximum size in bytes of each index files.
|
||||
- `MAX_FILE_SIZE`: **1048576**: Maximum size in bytes of files to be indexed.
|
||||
|
||||
## Security (`security`)
|
||||
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testPullCreate(t *testing.T, session *TestSession, user, repo, branch string) *httptest.ResponseRecorder {
|
||||
func testPullCreate(t *testing.T, session *TestSession, user, repo, branch, title string) *httptest.ResponseRecorder {
|
||||
req := NewRequest(t, "GET", path.Join(user, repo))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
@@ -35,7 +35,7 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo, branch strin
|
||||
assert.True(t, exists, "The template has changed")
|
||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"title": "This is a pull title",
|
||||
"title": title,
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusFound)
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestPullCreate(t *testing.T) {
|
||||
session := loginUser(t, "user1")
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
|
||||
|
||||
// check the redirected URL
|
||||
url := resp.HeaderMap.Get("Location")
|
||||
@@ -68,3 +68,38 @@ func TestPullCreate(t *testing.T) {
|
||||
assert.Regexp(t, `Subject: \[PATCH\] Update 'README.md'`, resp.Body)
|
||||
assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
|
||||
}
|
||||
|
||||
func TestPullCreate_TitleEscape(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
session := loginUser(t, "user1")
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master", "<i>XSS PR</i>")
|
||||
|
||||
// check the redirected URL
|
||||
url := resp.HeaderMap.Get("Location")
|
||||
assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
|
||||
|
||||
// Edit title
|
||||
req := NewRequest(t, "GET", url)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url")
|
||||
assert.True(t, exists, "The template has changed")
|
||||
|
||||
req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"title": "<u>XSS PR</u>",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
req = NewRequest(t, "GET", url)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||
titleHTML, err := htmlDoc.doc.Find(".comments .event .text b").First().Html()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "<i>XSS PR</i>", titleHTML)
|
||||
titleHTML, err = htmlDoc.doc.Find(".comments .event .text b").Next().Html()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "<u>XSS PR</u>", titleHTML)
|
||||
}
|
||||
|
@@ -56,7 +56,7 @@ func TestPullMerge(t *testing.T) {
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
|
||||
|
||||
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||
assert.EqualValues(t, "pulls", elem[3])
|
||||
@@ -69,7 +69,7 @@ func TestPullRebase(t *testing.T) {
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
|
||||
|
||||
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||
assert.EqualValues(t, "pulls", elem[3])
|
||||
@@ -83,7 +83,7 @@ func TestPullSquash(t *testing.T) {
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
|
||||
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
|
||||
|
||||
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||
assert.EqualValues(t, "pulls", elem[3])
|
||||
@@ -96,7 +96,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
|
||||
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "feature/test")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "feature/test", "This is a pull title")
|
||||
|
||||
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||
assert.EqualValues(t, "pulls", elem[3])
|
||||
|
@@ -22,16 +22,16 @@ func TestRepoActivity(t *testing.T) {
|
||||
// Create PRs (1 merged & 2 proposed)
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
|
||||
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||
assert.EqualValues(t, "pulls", elem[3])
|
||||
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
|
||||
|
||||
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/better_readme", "README.md", "Hello, World (Edited Again)\n")
|
||||
testPullCreate(t, session, "user1", "repo1", "feat/better_readme")
|
||||
testPullCreate(t, session, "user1", "repo1", "feat/better_readme", "This is a pull title")
|
||||
|
||||
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/much_better_readme", "README.md", "Hello, World (Edited More)\n")
|
||||
testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme")
|
||||
testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme", "This is a pull title")
|
||||
|
||||
// Create issues (3 new issues)
|
||||
testNewIssue(t, session, "user2", "repo1", "Issue 1", "Description 1")
|
||||
|
@@ -742,5 +742,14 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
|
||||
}
|
||||
|
||||
actions := make([]*Action, 0, 20)
|
||||
return actions, x.Limit(20).Desc("id").Where(cond).Find(&actions)
|
||||
|
||||
if err := x.Limit(20).Desc("id").Where(cond).Find(&actions); err != nil {
|
||||
return nil, fmt.Errorf("Find: %v", err)
|
||||
}
|
||||
|
||||
if err := ActionList(actions).LoadAttributes(); err != nil {
|
||||
return nil, fmt.Errorf("LoadAttributes: %v", err)
|
||||
}
|
||||
|
||||
return actions, nil
|
||||
}
|
||||
|
98
models/action_list.go
Normal file
98
models/action_list.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2018 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 models
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ActionList defines a list of actions
|
||||
type ActionList []*Action
|
||||
|
||||
func (actions ActionList) getUserIDs() []int64 {
|
||||
userIDs := make(map[int64]struct{}, len(actions))
|
||||
for _, action := range actions {
|
||||
if _, ok := userIDs[action.ActUserID]; !ok {
|
||||
userIDs[action.ActUserID] = struct{}{}
|
||||
}
|
||||
}
|
||||
return keysInt64(userIDs)
|
||||
}
|
||||
|
||||
func (actions ActionList) loadUsers(e Engine) ([]*User, error) {
|
||||
if len(actions) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
userIDs := actions.getUserIDs()
|
||||
userMaps := make(map[int64]*User, len(userIDs))
|
||||
err := e.
|
||||
In("id", userIDs).
|
||||
Find(&userMaps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("find user: %v", err)
|
||||
}
|
||||
|
||||
for _, action := range actions {
|
||||
action.ActUser = userMaps[action.ActUserID]
|
||||
}
|
||||
return valuesUser(userMaps), nil
|
||||
}
|
||||
|
||||
// LoadUsers loads actions' all users
|
||||
func (actions ActionList) LoadUsers() ([]*User, error) {
|
||||
return actions.loadUsers(x)
|
||||
}
|
||||
|
||||
func (actions ActionList) getRepoIDs() []int64 {
|
||||
repoIDs := make(map[int64]struct{}, len(actions))
|
||||
for _, action := range actions {
|
||||
if _, ok := repoIDs[action.RepoID]; !ok {
|
||||
repoIDs[action.RepoID] = struct{}{}
|
||||
}
|
||||
}
|
||||
return keysInt64(repoIDs)
|
||||
}
|
||||
|
||||
func (actions ActionList) loadRepositories(e Engine) ([]*Repository, error) {
|
||||
if len(actions) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
repoIDs := actions.getRepoIDs()
|
||||
repoMaps := make(map[int64]*Repository, len(repoIDs))
|
||||
err := e.
|
||||
In("id", repoIDs).
|
||||
Find(&repoMaps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("find repository: %v", err)
|
||||
}
|
||||
|
||||
for _, action := range actions {
|
||||
action.Repo = repoMaps[action.RepoID]
|
||||
}
|
||||
return valuesRepository(repoMaps), nil
|
||||
}
|
||||
|
||||
// LoadRepositories loads actions' all repositories
|
||||
func (actions ActionList) LoadRepositories() ([]*Repository, error) {
|
||||
return actions.loadRepositories(x)
|
||||
}
|
||||
|
||||
// loadAttributes loads all attributes
|
||||
func (actions ActionList) loadAttributes(e Engine) (err error) {
|
||||
if _, err = actions.loadUsers(e); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = actions.loadRepositories(e); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAttributes loads attributes of the actions
|
||||
func (actions ActionList) LoadAttributes() error {
|
||||
return actions.loadAttributes(x)
|
||||
}
|
@@ -6,7 +6,6 @@ package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
@@ -70,7 +69,7 @@ func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) {
|
||||
|
||||
// GetProtectedBranchBy getting protected branch by ID/Name
|
||||
func GetProtectedBranchBy(repoID int64, BranchName string) (*ProtectedBranch, error) {
|
||||
rel := &ProtectedBranch{RepoID: repoID, BranchName: strings.ToLower(BranchName)}
|
||||
rel := &ProtectedBranch{RepoID: repoID, BranchName: BranchName}
|
||||
has, err := x.Get(rel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -156,6 +155,10 @@ func (repo *Repository) GetProtectedBranches() ([]*ProtectedBranch, error) {
|
||||
|
||||
// IsProtectedBranch checks if branch is protected
|
||||
func (repo *Repository) IsProtectedBranch(branchName string, doer *User) (bool, error) {
|
||||
if doer == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
protectedBranch := &ProtectedBranch{
|
||||
RepoID: repo.ID,
|
||||
BranchName: branchName,
|
||||
|
@@ -216,6 +216,21 @@ func (err ErrWikiReservedName) Error() string {
|
||||
return fmt.Sprintf("wiki title is reserved: %s", err.Title)
|
||||
}
|
||||
|
||||
// ErrWikiInvalidFileName represents an invalid wiki file name.
|
||||
type ErrWikiInvalidFileName struct {
|
||||
FileName string
|
||||
}
|
||||
|
||||
// IsErrWikiInvalidFileName checks if an error is an ErrWikiInvalidFileName.
|
||||
func IsErrWikiInvalidFileName(err error) bool {
|
||||
_, ok := err.(ErrWikiInvalidFileName)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrWikiInvalidFileName) Error() string {
|
||||
return fmt.Sprintf("Invalid wiki filename: %s", err.FileName)
|
||||
}
|
||||
|
||||
// __________ ___. .__ .__ ____ __.
|
||||
// \______ \__ _\_ |__ | | |__| ____ | |/ _|____ ___.__.
|
||||
// | ___/ | \ __ \| | | |/ ___\ | <_/ __ < | |
|
||||
|
@@ -49,6 +49,7 @@ type Issue struct {
|
||||
DeadlineUnix util.TimeStamp `xorm:"INDEX"`
|
||||
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||
ClosedUnix util.TimeStamp `xorm:"INDEX"`
|
||||
|
||||
Attachments []*Attachment `xorm:"-"`
|
||||
Comments []*Comment `xorm:"-"`
|
||||
@@ -612,8 +613,13 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository,
|
||||
return nil
|
||||
}
|
||||
issue.IsClosed = isClosed
|
||||
if isClosed {
|
||||
issue.ClosedUnix = util.TimeStampNow()
|
||||
} else {
|
||||
issue.ClosedUnix = 0
|
||||
}
|
||||
|
||||
if err = updateIssueCols(e, issue, "is_closed"); err != nil {
|
||||
if err = updateIssueCols(e, issue, "is_closed", "closed_unix"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -214,13 +214,15 @@ func TestChangeMilestoneIssueStats(t *testing.T) {
|
||||
"is_closed=0").(*Issue)
|
||||
|
||||
issue.IsClosed = true
|
||||
_, err := x.Cols("is_closed").Update(issue)
|
||||
issue.ClosedUnix = util.TimeStampNow()
|
||||
_, err := x.Cols("is_closed", "closed_unix").Update(issue)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, changeMilestoneIssueStats(x.NewSession(), issue))
|
||||
CheckConsistencyFor(t, &Milestone{})
|
||||
|
||||
issue.IsClosed = false
|
||||
_, err = x.Cols("is_closed").Update(issue)
|
||||
issue.ClosedUnix = 0
|
||||
_, err = x.Cols("is_closed", "closed_unix").Update(issue)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, changeMilestoneIssueStats(x.NewSession(), issue))
|
||||
CheckConsistencyFor(t, &Milestone{})
|
||||
|
@@ -166,6 +166,8 @@ var migrations = []Migration{
|
||||
NewMigration("add writable deploy keys", addModeToDeploKeys),
|
||||
// v56 -> v57
|
||||
NewMigration("remove is_owner, num_teams columns from org_user", removeIsOwnerColumnFromOrgUser),
|
||||
// v57 -> v58
|
||||
NewMigration("add closed_unix column for issues", addIssueClosedTime),
|
||||
}
|
||||
|
||||
// Migrate database to current version
|
||||
@@ -215,6 +217,66 @@ Please try to upgrade to a lower version (>= v0.6.0) first, then upgrade to curr
|
||||
return nil
|
||||
}
|
||||
|
||||
func dropTableColumns(x *xorm.Engine, tableName string, columnNames ...string) (err error) {
|
||||
if tableName == "" || len(columnNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case setting.UseSQLite3:
|
||||
log.Warn("Unable to drop columns in SQLite")
|
||||
case setting.UseMySQL, setting.UseTiDB, setting.UsePostgreSQL:
|
||||
cols := ""
|
||||
for _, col := range columnNames {
|
||||
if cols != "" {
|
||||
cols += ", "
|
||||
}
|
||||
cols += "DROP COLUMN `" + col + "`"
|
||||
}
|
||||
if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
|
||||
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
|
||||
}
|
||||
case setting.UseMSSQL:
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cols := ""
|
||||
for _, col := range columnNames {
|
||||
if cols != "" {
|
||||
cols += ", "
|
||||
}
|
||||
cols += "`" + strings.ToLower(col) + "`"
|
||||
}
|
||||
sql := fmt.Sprintf("SELECT Name FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('%[1]s') AND PARENT_COLUMN_ID IN (SELECT column_id FROM sys.columns WHERE lower(NAME) IN (%[2]s) AND object_id = OBJECT_ID('%[1]s'))",
|
||||
tableName, strings.Replace(cols, "`", "'", -1))
|
||||
constraints := make([]string, 0)
|
||||
if err := sess.SQL(sql).Find(&constraints); err != nil {
|
||||
sess.Rollback()
|
||||
return fmt.Errorf("Find constraints: %v", err)
|
||||
}
|
||||
for _, constraint := range constraints {
|
||||
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP CONSTRAINT `%s`", tableName, constraint)); err != nil {
|
||||
sess.Rollback()
|
||||
return fmt.Errorf("Drop table `%s` constraint `%s`: %v", tableName, constraint, err)
|
||||
}
|
||||
}
|
||||
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN %s", tableName, cols)); err != nil {
|
||||
sess.Rollback()
|
||||
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
default:
|
||||
log.Fatal(4, "Unrecognized DB")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fixLocaleFileLoadPanic(_ *xorm.Engine) error {
|
||||
cfg, err := ini.Load(setting.CustomConf)
|
||||
if err != nil {
|
||||
|
@@ -5,29 +5,9 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
func removeIsOwnerColumnFromOrgUser(x *xorm.Engine) (err error) {
|
||||
switch {
|
||||
case setting.UseSQLite3:
|
||||
log.Warn("Unable to drop columns in SQLite")
|
||||
case setting.UseMySQL, setting.UseTiDB, setting.UsePostgreSQL:
|
||||
if _, err := x.Exec("ALTER TABLE org_user DROP COLUMN is_owner, DROP COLUMN num_teams"); err != nil {
|
||||
return fmt.Errorf("DROP COLUMN org_user.is_owner, org_user.num_teams: %v", err)
|
||||
}
|
||||
case setting.UseMSSQL:
|
||||
if _, err := x.Exec("ALTER TABLE org_user DROP COLUMN is_owner, num_teams"); err != nil {
|
||||
return fmt.Errorf("DROP COLUMN org_user.is_owner, org_user.num_teams: %v", err)
|
||||
}
|
||||
default:
|
||||
log.Fatal(4, "Unrecognized DB")
|
||||
}
|
||||
|
||||
return nil
|
||||
return dropTableColumns(x, "org_user", "is_owner", "num_teams")
|
||||
}
|
||||
|
30
models/migrations/v57.go
Normal file
30
models/migrations/v57.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2017 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 migrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
func addIssueClosedTime(x *xorm.Engine) error {
|
||||
// Issue see models/issue.go
|
||||
type Issue struct {
|
||||
ClosedUnix util.TimeStamp `xorm:"INDEX"`
|
||||
}
|
||||
|
||||
if err := x.Sync2(new(Issue)); err != nil {
|
||||
return fmt.Errorf("Sync2: %v", err)
|
||||
}
|
||||
|
||||
if _, err := x.Exec("UPDATE `issue` SET `closed_unix` = `updated_unix` WHERE `is_closed` = ?", true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -436,8 +436,7 @@ func AddOrgUser(orgID, uid int64) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// RemoveOrgUser removes user from given organization.
|
||||
func RemoveOrgUser(orgID, userID int64) error {
|
||||
func removeOrgUser(sess *xorm.Session, orgID, userID int64) error {
|
||||
ou := new(OrgUser)
|
||||
|
||||
has, err := x.
|
||||
@@ -473,12 +472,6 @@ func RemoveOrgUser(orgID, userID int64) error {
|
||||
}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.ID(ou.ID).Delete(ou); err != nil {
|
||||
return err
|
||||
} else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil {
|
||||
@@ -520,6 +513,19 @@ func RemoveOrgUser(orgID, userID int64) error {
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveOrgUser removes user from given organization.
|
||||
func RemoveOrgUser(orgID, userID int64) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := removeOrgUser(sess, orgID, userID); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
const ownerTeamName = "Owners"
|
||||
@@ -521,7 +523,7 @@ func AddTeamMember(team *Team, userID int64) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func removeTeamMember(e Engine, team *Team, userID int64) error {
|
||||
func removeTeamMember(e *xorm.Session, team *Team, userID int64) error {
|
||||
isMember, err := isTeamMember(e, team.OrgID, team.ID, userID)
|
||||
if err != nil || !isMember {
|
||||
return err
|
||||
@@ -558,6 +560,16 @@ func removeTeamMember(e Engine, team *Team, userID int64) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the user is a member of any team in the organization.
|
||||
if count, err := e.Count(&TeamUser{
|
||||
UID: userID,
|
||||
OrgID: team.OrgID,
|
||||
}); err != nil {
|
||||
return err
|
||||
} else if count == 0 {
|
||||
return removeOrgUser(e, team.OrgID, userID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -36,7 +36,7 @@ type Release struct {
|
||||
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
|
||||
IsTag bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Attachments []*Attachment `xorm:"-"`
|
||||
CreatedUnix util.TimeStamp `xorm:"created INDEX"`
|
||||
CreatedUnix util.TimeStamp `xorm:"INDEX"`
|
||||
}
|
||||
|
||||
func (r *Release) loadAttributes(e Engine) error {
|
||||
@@ -134,6 +134,8 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsCount: %v", err)
|
||||
}
|
||||
} else {
|
||||
rel.CreatedUnix = util.TimeStampNow()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -176,7 +176,7 @@ func (stats *ActivityStats) FillIssues(repoID int64, fromTime time.Time) error {
|
||||
|
||||
// Closed issues
|
||||
sess := issuesForActivityStatement(repoID, fromTime, true, false)
|
||||
sess.OrderBy("issue.updated_unix DESC")
|
||||
sess.OrderBy("issue.closed_unix DESC")
|
||||
stats.ClosedIssues = make(IssueList, 0)
|
||||
if err = sess.Find(&stats.ClosedIssues); err != nil {
|
||||
return err
|
||||
@@ -228,7 +228,11 @@ func issuesForActivityStatement(repoID int64, fromTime time.Time, closed, unreso
|
||||
|
||||
if !unresolved {
|
||||
sess.And("issue.is_pull = ?", false)
|
||||
sess.And("issue.created_unix >= ?", fromTime.Unix())
|
||||
if closed {
|
||||
sess.And("issue.closed_unix >= ?", fromTime.Unix())
|
||||
} else {
|
||||
sess.And("issue.created_unix >= ?", fromTime.Unix())
|
||||
}
|
||||
} else {
|
||||
sess.And("issue.created_unix < ?", fromTime.Unix())
|
||||
sess.And("issue.updated_unix >= ?", fromTime.Unix())
|
||||
|
@@ -5,9 +5,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -16,8 +14,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/indexer"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
)
|
||||
|
||||
// RepoIndexerStatus status of a repo's entry in the repo indexer
|
||||
@@ -132,7 +128,11 @@ func populateRepoIndexer(maxRepoID int64) {
|
||||
}
|
||||
|
||||
func updateRepoIndexer(repo *Repository) error {
|
||||
changes, err := getRepoChanges(repo)
|
||||
sha, err := getDefaultBranchSha(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
changes, err := getRepoChanges(repo, sha)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if changes == nil {
|
||||
@@ -140,12 +140,12 @@ func updateRepoIndexer(repo *Repository) error {
|
||||
}
|
||||
|
||||
batch := indexer.RepoIndexerBatch()
|
||||
for _, filename := range changes.UpdatedFiles {
|
||||
if err := addUpdate(filename, repo, batch); err != nil {
|
||||
for _, update := range changes.Updates {
|
||||
if err := addUpdate(update, repo, batch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, filename := range changes.RemovedFiles {
|
||||
for _, filename := range changes.RemovedFilenames {
|
||||
if err := addDelete(filename, repo, batch); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -153,56 +153,61 @@ func updateRepoIndexer(repo *Repository) error {
|
||||
if err = batch.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
return updateLastIndexSync(repo)
|
||||
return repo.updateIndexerStatus(sha)
|
||||
}
|
||||
|
||||
// repoChanges changes (file additions/updates/removals) to a repo
|
||||
type repoChanges struct {
|
||||
UpdatedFiles []string
|
||||
RemovedFiles []string
|
||||
Updates []fileUpdate
|
||||
RemovedFilenames []string
|
||||
}
|
||||
|
||||
type fileUpdate struct {
|
||||
Filename string
|
||||
BlobSha string
|
||||
}
|
||||
|
||||
func getDefaultBranchSha(repo *Repository) (string, error) {
|
||||
stdout, err := git.NewCommand("show-ref", "-s", repo.DefaultBranch).RunInDir(repo.RepoPath())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(stdout), nil
|
||||
}
|
||||
|
||||
// getRepoChanges returns changes to repo since last indexer update
|
||||
func getRepoChanges(repo *Repository) (*repoChanges, error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err := repo.UpdateLocalCopyBranch(""); err != nil {
|
||||
return nil, err
|
||||
} else if !git.IsBranchExist(repo.LocalCopyPath(), repo.DefaultBranch) {
|
||||
// repo does not have any commits yet, so nothing to update
|
||||
return nil, nil
|
||||
} else if err = repo.UpdateLocalCopyBranch(repo.DefaultBranch); err != nil {
|
||||
return nil, err
|
||||
} else if err = repo.getIndexerStatus(); err != nil {
|
||||
func getRepoChanges(repo *Repository, revision string) (*repoChanges, error) {
|
||||
if err := repo.getIndexerStatus(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(repo.IndexerStatus.CommitSha) == 0 {
|
||||
return genesisChanges(repo)
|
||||
return genesisChanges(repo, revision)
|
||||
}
|
||||
return nonGenesisChanges(repo)
|
||||
return nonGenesisChanges(repo, revision)
|
||||
}
|
||||
|
||||
func addUpdate(filename string, repo *Repository, batch *indexer.Batch) error {
|
||||
filepath := path.Join(repo.LocalCopyPath(), filename)
|
||||
if stat, err := os.Stat(filepath); err != nil {
|
||||
func addUpdate(update fileUpdate, repo *Repository, batch *indexer.Batch) error {
|
||||
stdout, err := git.NewCommand("cat-file", "-s", update.BlobSha).
|
||||
RunInDir(repo.RepoPath())
|
||||
if err != nil {
|
||||
return err
|
||||
} else if stat.Size() > setting.Indexer.MaxIndexerFileSize {
|
||||
return nil
|
||||
} else if stat.IsDir() {
|
||||
// file could actually be a directory, if it is the root of a submodule.
|
||||
// We do not index submodule contents, so don't do anything.
|
||||
}
|
||||
if size, err := strconv.Atoi(strings.TrimSpace(stdout)); err != nil {
|
||||
return fmt.Errorf("Misformatted git cat-file output: %v", err)
|
||||
} else if int64(size) > setting.Indexer.MaxIndexerFileSize {
|
||||
return nil
|
||||
}
|
||||
fileContents, err := ioutil.ReadFile(filepath)
|
||||
|
||||
fileContents, err := git.NewCommand("cat-file", "blob", update.BlobSha).
|
||||
RunInDirBytes(repo.RepoPath())
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !base.IsTextFile(fileContents) {
|
||||
return nil
|
||||
}
|
||||
return batch.Add(indexer.RepoIndexerUpdate{
|
||||
Filepath: filename,
|
||||
Filepath: update.Filename,
|
||||
Op: indexer.RepoIndexerOpUpdate,
|
||||
Data: &indexer.RepoIndexerData{
|
||||
RepoID: repo.ID,
|
||||
@@ -221,42 +226,76 @@ func addDelete(filename string, repo *Repository, batch *indexer.Batch) error {
|
||||
})
|
||||
}
|
||||
|
||||
// genesisChanges get changes to add repo to the indexer for the first time
|
||||
func genesisChanges(repo *Repository) (*repoChanges, error) {
|
||||
var changes repoChanges
|
||||
stdout, err := git.NewCommand("ls-files").RunInDir(repo.LocalCopyPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
filename := strings.TrimSpace(line)
|
||||
if len(filename) == 0 {
|
||||
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
|
||||
func parseGitLsTreeOutput(stdout string) ([]fileUpdate, error) {
|
||||
lines := strings.Split(stdout, "\n")
|
||||
updates := make([]fileUpdate, 0, len(lines))
|
||||
for _, line := range lines {
|
||||
// expect line to be "<mode> <object-type> <object-sha>\t<filename>"
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
} else if filename[0] == '"' {
|
||||
}
|
||||
firstSpaceIndex := strings.IndexByte(line, ' ')
|
||||
if firstSpaceIndex < 0 {
|
||||
log.Error(4, "Misformatted git ls-tree output: %s", line)
|
||||
continue
|
||||
}
|
||||
tabIndex := strings.IndexByte(line, '\t')
|
||||
if tabIndex < 42+firstSpaceIndex || tabIndex == len(line)-1 {
|
||||
log.Error(4, "Misformatted git ls-tree output: %s", line)
|
||||
continue
|
||||
}
|
||||
if objectType := line[firstSpaceIndex+1 : tabIndex-41]; objectType != "blob" {
|
||||
// submodules appear as commit objects, we do not index submodules
|
||||
continue
|
||||
}
|
||||
|
||||
blobSha := line[tabIndex-40 : tabIndex]
|
||||
filename := line[tabIndex+1:]
|
||||
if filename[0] == '"' {
|
||||
var err error
|
||||
filename, err = strconv.Unquote(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
changes.UpdatedFiles = append(changes.UpdatedFiles, filename)
|
||||
updates = append(updates, fileUpdate{
|
||||
Filename: filename,
|
||||
BlobSha: blobSha,
|
||||
})
|
||||
}
|
||||
return &changes, nil
|
||||
return updates, nil
|
||||
}
|
||||
|
||||
// genesisChanges get changes to add repo to the indexer for the first time
|
||||
func genesisChanges(repo *Repository, revision string) (*repoChanges, error) {
|
||||
var changes repoChanges
|
||||
stdout, err := git.NewCommand("ls-tree", "--full-tree", "-r", revision).
|
||||
RunInDir(repo.RepoPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes.Updates, err = parseGitLsTreeOutput(stdout)
|
||||
return &changes, err
|
||||
}
|
||||
|
||||
// nonGenesisChanges get changes since the previous indexer update
|
||||
func nonGenesisChanges(repo *Repository) (*repoChanges, error) {
|
||||
func nonGenesisChanges(repo *Repository, revision string) (*repoChanges, error) {
|
||||
diffCmd := git.NewCommand("diff", "--name-status",
|
||||
repo.IndexerStatus.CommitSha, "HEAD")
|
||||
stdout, err := diffCmd.RunInDir(repo.LocalCopyPath())
|
||||
repo.IndexerStatus.CommitSha, revision)
|
||||
stdout, err := diffCmd.RunInDir(repo.RepoPath())
|
||||
if err != nil {
|
||||
// previous commit sha may have been removed by a force push, so
|
||||
// try rebuilding from scratch
|
||||
log.Warn("git diff: %v", err)
|
||||
if err = indexer.DeleteRepoFromIndexer(repo.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return genesisChanges(repo)
|
||||
return genesisChanges(repo, revision)
|
||||
}
|
||||
var changes repoChanges
|
||||
updatedFilenames := make([]string, 0, 10)
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
@@ -274,23 +313,22 @@ func nonGenesisChanges(repo *Repository) (*repoChanges, error) {
|
||||
|
||||
switch status := line[0]; status {
|
||||
case 'M', 'A':
|
||||
changes.UpdatedFiles = append(changes.UpdatedFiles, filename)
|
||||
updatedFilenames = append(updatedFilenames, filename)
|
||||
case 'D':
|
||||
changes.RemovedFiles = append(changes.RemovedFiles, filename)
|
||||
changes.RemovedFilenames = append(changes.RemovedFilenames, filename)
|
||||
default:
|
||||
log.Warn("Unrecognized status: %c (line=%s)", status, line)
|
||||
}
|
||||
}
|
||||
return &changes, nil
|
||||
}
|
||||
|
||||
func updateLastIndexSync(repo *Repository) error {
|
||||
stdout, err := git.NewCommand("rev-parse", "HEAD").RunInDir(repo.LocalCopyPath())
|
||||
cmd := git.NewCommand("ls-tree", "--full-tree", revision, "--")
|
||||
cmd.AddArguments(updatedFilenames...)
|
||||
stdout, err = cmd.RunInDir(repo.RepoPath())
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
sha := strings.TrimSpace(stdout)
|
||||
return repo.updateIndexerStatus(sha)
|
||||
changes.Updates, err = parseGitLsTreeOutput(stdout)
|
||||
return &changes, err
|
||||
}
|
||||
|
||||
func processRepoIndexerOperationQueue() {
|
||||
|
@@ -244,6 +244,8 @@ func MirrorUpdate() {
|
||||
// SyncMirrors checks and syncs mirrors.
|
||||
// TODO: sync more mirrors at same time.
|
||||
func SyncMirrors() {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
// Start listening on new sync requests.
|
||||
for repoID := range MirrorQueue.Queue() {
|
||||
log.Trace("SyncMirrors [repo_id: %v]", repoID)
|
||||
@@ -260,10 +262,22 @@ func SyncMirrors() {
|
||||
}
|
||||
|
||||
m.ScheduleNextUpdate()
|
||||
if err = UpdateMirror(m); err != nil {
|
||||
if err = updateMirror(sess, m); err != nil {
|
||||
log.Error(4, "UpdateMirror [%s]: %v", repoID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Get latest commit date and update to current repository updated time
|
||||
commitDate, err := git.GetLatestCommitTime(m.Repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(2, "GetLatestCommitDate [%s]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err = sess.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", commitDate.Unix(), m.RepoID); err != nil {
|
||||
log.Error(2, "Update repository 'updated_unix' [%s]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
@@ -72,6 +73,18 @@ func createTestEngine(fixturesDir string) error {
|
||||
return InitFixtures(&testfixtures.SQLite{}, fixturesDir)
|
||||
}
|
||||
|
||||
func removeAllWithRetry(dir string) error {
|
||||
var err error
|
||||
for i := 0; i < 20; i++ {
|
||||
err = os.RemoveAll(dir)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// PrepareTestDatabase load test fixtures into test database
|
||||
func PrepareTestDatabase() error {
|
||||
return LoadFixtures()
|
||||
@@ -81,7 +94,7 @@ func PrepareTestDatabase() error {
|
||||
// by tests that use the above MainTest(..) function.
|
||||
func PrepareTestEnv(t testing.TB) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
|
||||
assert.NoError(t, removeAllWithRetry(setting.RepoRootPath))
|
||||
metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
|
||||
assert.NoError(t, com.CopyDir(metaPath, setting.RepoRootPath))
|
||||
}
|
||||
|
@@ -299,7 +299,9 @@ func (u *User) generateRandomAvatar(e Engine) error {
|
||||
}
|
||||
// NOTICE for random avatar, it still uses id as avatar name, but custom avatar use md5
|
||||
// since random image is not a user's photo, there is no security for enumable
|
||||
u.Avatar = fmt.Sprintf("%d", u.ID)
|
||||
if u.Avatar == "" {
|
||||
u.Avatar = fmt.Sprintf("%d", u.ID)
|
||||
}
|
||||
if err = os.MkdirAll(filepath.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("MkdirAll: %v", err)
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ func WikiNameToFilename(name string) string {
|
||||
// WikiFilenameToName converts a wiki filename to its corresponding page name.
|
||||
func WikiFilenameToName(filename string) (string, error) {
|
||||
if !strings.HasSuffix(filename, ".md") {
|
||||
return "", fmt.Errorf("Invalid wiki filename: %s", filename)
|
||||
return "", ErrWikiInvalidFileName{filename}
|
||||
}
|
||||
basename := filename[:len(filename)-3]
|
||||
unescaped, err := url.QueryUnescape(basename)
|
||||
|
@@ -77,11 +77,14 @@ func TestWikiFilenameToName(t *testing.T) {
|
||||
for _, badFilename := range []string{
|
||||
"nofileextension",
|
||||
"wrongfileextension.txt",
|
||||
"badescaping%%.md",
|
||||
} {
|
||||
_, err := WikiFilenameToName(badFilename)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrWikiInvalidFileName(err))
|
||||
}
|
||||
_, err := WikiFilenameToName("badescaping%%.md")
|
||||
assert.Error(t, err)
|
||||
assert.False(t, IsErrWikiInvalidFileName(err))
|
||||
}
|
||||
|
||||
func TestWikiNameToFilenameToName(t *testing.T) {
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -75,6 +76,26 @@ func (ctx *Context) HasValue(name string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// RedirectToFirst redirects to first not empty URL
|
||||
func (ctx *Context) RedirectToFirst(location ...string) {
|
||||
for _, loc := range location {
|
||||
if len(loc) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
u, err := url.Parse(loc)
|
||||
if err != nil || (u.Scheme != "" && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
|
||||
continue
|
||||
}
|
||||
|
||||
ctx.Redirect(loc)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
return
|
||||
}
|
||||
|
||||
// HTML calls Context.HTML and converts template name to string.
|
||||
func (ctx *Context) HTML(status int, name base.TplName) {
|
||||
log.Debug("Template: %s", name)
|
||||
|
@@ -391,7 +391,11 @@ func RenderShortLinks(rawBytes []byte, urlPrefix string, noLink bool, isWikiMark
|
||||
}
|
||||
absoluteLink := isLink([]byte(link))
|
||||
if !absoluteLink {
|
||||
link = strings.Replace(link, " ", "+", -1)
|
||||
if image {
|
||||
link = strings.Replace(link, " ", "+", -1)
|
||||
} else {
|
||||
link = strings.Replace(link, " ", "-", -1)
|
||||
}
|
||||
}
|
||||
if image {
|
||||
if !absoluteLink {
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"mime"
|
||||
"net/url"
|
||||
@@ -179,6 +180,7 @@ func NewFuncMap() []template.FuncMap {
|
||||
return dict, nil
|
||||
},
|
||||
"Printf": fmt.Sprintf,
|
||||
"Escape": Escape,
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -197,6 +199,11 @@ func Str2html(raw string) template.HTML {
|
||||
return template.HTML(markup.Sanitize(raw))
|
||||
}
|
||||
|
||||
// Escape escapes a HTML string
|
||||
func Escape(raw string) string {
|
||||
return html.EscapeString(raw)
|
||||
}
|
||||
|
||||
// List traversings the list
|
||||
func List(l *list.List) chan interface{} {
|
||||
e := l.Front()
|
||||
|
@@ -307,11 +307,7 @@ func Action(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
redirectTo := ctx.Query("redirect_to")
|
||||
if len(redirectTo) == 0 {
|
||||
redirectTo = ctx.Repo.RepoLink
|
||||
}
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.RedirectToFirst(ctx.Query("redirect_to"), ctx.Repo.RepoLink)
|
||||
}
|
||||
|
||||
// Download download an archive of a repository
|
||||
|
@@ -128,6 +128,9 @@ func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *gi
|
||||
}
|
||||
wikiName, err := models.WikiFilenameToName(entry.Name())
|
||||
if err != nil {
|
||||
if models.IsErrWikiInvalidFileName(err) {
|
||||
continue
|
||||
}
|
||||
ctx.ServerError("WikiFilenameToName", err)
|
||||
return nil, nil
|
||||
} else if wikiName == "_Sidebar" || wikiName == "_Footer" {
|
||||
@@ -262,6 +265,9 @@ func WikiPages(ctx *context.Context) {
|
||||
}
|
||||
wikiName, err := models.WikiFilenameToName(entry.Name())
|
||||
if err != nil {
|
||||
if models.IsErrWikiInvalidFileName(err) {
|
||||
continue
|
||||
}
|
||||
ctx.ServerError("WikiFilenameToName", err)
|
||||
return
|
||||
}
|
||||
|
@@ -7,36 +7,52 @@ package repo
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/git"
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const content = "Wiki contents for unit tests"
|
||||
const message = "Wiki commit message for unit tests"
|
||||
|
||||
func wikiPath(repo *models.Repository, wikiName string) string {
|
||||
return filepath.Join(repo.LocalWikiPath(), models.WikiNameToFilename(wikiName))
|
||||
func wikiEntry(t *testing.T, repo *models.Repository, wikiName string) *git.TreeEntry {
|
||||
wikiRepo, err := git.OpenRepository(repo.WikiPath())
|
||||
assert.NoError(t, err)
|
||||
commit, err := wikiRepo.GetBranchCommit("master")
|
||||
assert.NoError(t, err)
|
||||
entries, err := commit.ListEntries()
|
||||
assert.NoError(t, err)
|
||||
for _, entry := range entries {
|
||||
if entry.Name() == models.WikiNameToFilename(wikiName) {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func wikiContent(t *testing.T, repo *models.Repository, wikiName string) string {
|
||||
bytes, err := ioutil.ReadFile(wikiPath(repo, wikiName))
|
||||
entry := wikiEntry(t, repo, wikiName)
|
||||
if !assert.NotNil(t, entry) {
|
||||
return ""
|
||||
}
|
||||
reader, err := entry.Blob().Data()
|
||||
assert.NoError(t, err)
|
||||
bytes, err := ioutil.ReadAll(reader)
|
||||
assert.NoError(t, err)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func assertWikiExists(t *testing.T, repo *models.Repository, wikiName string) {
|
||||
assert.True(t, com.IsExist(wikiPath(repo, wikiName)))
|
||||
assert.NotNil(t, wikiEntry(t, repo, wikiName))
|
||||
}
|
||||
|
||||
func assertWikiNotExists(t *testing.T, repo *models.Repository, wikiName string) {
|
||||
assert.False(t, com.IsExist(wikiPath(repo, wikiName)))
|
||||
assert.Nil(t, wikiEntry(t, repo, wikiName))
|
||||
}
|
||||
|
||||
func assertPagesMetas(t *testing.T, expectedNames []string, metas interface{}) {
|
||||
|
@@ -93,12 +93,8 @@ func checkAutoLogin(ctx *context.Context) bool {
|
||||
}
|
||||
|
||||
if isSucceed {
|
||||
if len(redirectTo) > 0 {
|
||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||
ctx.Redirect(redirectTo)
|
||||
} else {
|
||||
ctx.Redirect(setting.AppSubURL + string(setting.LandingPageURL))
|
||||
}
|
||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||
ctx.RedirectToFirst(redirectTo, setting.AppSubURL+string(setting.LandingPageURL))
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -350,7 +346,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
|
||||
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||
if obeyRedirect {
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.RedirectToFirst(redirectTo)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -439,7 +435,7 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context
|
||||
|
||||
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.RedirectToFirst(redirectTo)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -49,12 +49,8 @@ func SignInOpenID(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if isSucceed {
|
||||
if len(redirectTo) > 0 {
|
||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||
ctx.Redirect(redirectTo)
|
||||
} else {
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
}
|
||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||
ctx.RedirectToFirst(redirectTo)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -66,12 +66,14 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) {
|
||||
if ctx.User != nil {
|
||||
userCache[ctx.User.ID] = ctx.User
|
||||
}
|
||||
repoCache := map[int64]*models.Repository{}
|
||||
for _, act := range actions {
|
||||
// Cache results to reduce queries.
|
||||
u, ok := userCache[act.ActUserID]
|
||||
if act.ActUser != nil {
|
||||
userCache[act.ActUserID] = act.ActUser
|
||||
}
|
||||
|
||||
repoOwner, ok := userCache[act.Repo.OwnerID]
|
||||
if !ok {
|
||||
u, err = models.GetUserByID(act.ActUserID)
|
||||
repoOwner, err = models.GetUserByID(act.Repo.OwnerID)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
continue
|
||||
@@ -79,35 +81,9 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) {
|
||||
ctx.ServerError("GetUserByID", err)
|
||||
return
|
||||
}
|
||||
userCache[act.ActUserID] = u
|
||||
userCache[repoOwner.ID] = repoOwner
|
||||
}
|
||||
act.ActUser = u
|
||||
|
||||
repo, ok := repoCache[act.RepoID]
|
||||
if !ok {
|
||||
repo, err = models.GetRepositoryByID(act.RepoID)
|
||||
if err != nil {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
continue
|
||||
}
|
||||
ctx.ServerError("GetRepositoryByID", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
act.Repo = repo
|
||||
|
||||
repoOwner, ok := userCache[repo.OwnerID]
|
||||
if !ok {
|
||||
repoOwner, err = models.GetUserByID(repo.OwnerID)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
continue
|
||||
}
|
||||
ctx.ServerError("GetUserByID", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
repo.Owner = repoOwner
|
||||
act.Repo.Owner = repoOwner
|
||||
}
|
||||
ctx.Data["Feeds"] = actions
|
||||
}
|
||||
@@ -154,7 +130,8 @@ func Dashboard(ctx *context.Context) {
|
||||
ctx.Data["MirrorCount"] = len(mirrors)
|
||||
ctx.Data["Mirrors"] = mirrors
|
||||
|
||||
retrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser,
|
||||
retrieveFeeds(ctx, models.GetFeedsOptions{
|
||||
RequestedUser: ctxUser,
|
||||
IncludePrivate: true,
|
||||
OnlyPerformedBy: false,
|
||||
IncludeDeleted: false,
|
||||
|
@@ -271,9 +271,5 @@ func Action(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
redirectTo := ctx.Query("redirect_to")
|
||||
if len(redirectTo) == 0 {
|
||||
redirectTo = u.HomeLink()
|
||||
}
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.RedirectToFirst(ctx.Query("redirect_to"), u.HomeLink())
|
||||
}
|
||||
|
@@ -134,7 +134,7 @@
|
||||
<p class="desc">
|
||||
<div class="ui red label">{{$.i18n.Tr "repo.activity.closed_issue_label"}}</div>
|
||||
#{{.Index}} <a class="title has-emoji" href="{{$.Repository.HTMLURL}}/issues/{{.Index}}">{{.Title}}</a>
|
||||
{{TimeSinceUnix .UpdatedUnix $.Lang}}
|
||||
{{TimeSinceUnix .ClosedUnix $.Lang}}
|
||||
</p>
|
||||
{{end}}
|
||||
</div>
|
||||
|
@@ -47,9 +47,9 @@
|
||||
</div>
|
||||
<div class="text small">
|
||||
{{if .IsViewBranch}}
|
||||
{{.i18n.Tr "repo.branch.create_from" .BranchName | Safe}}
|
||||
{{.i18n.Tr "repo.branch.create_from" .BranchName}}
|
||||
{{else}}
|
||||
{{.i18n.Tr "repo.branch.create_from" (ShortSha .BranchName) | Safe}}
|
||||
{{.i18n.Tr "repo.branch.create_from" (ShortSha .BranchName)}}
|
||||
{{end}}
|
||||
</div>
|
||||
</a>
|
||||
|
@@ -103,7 +103,7 @@
|
||||
<img src="{{.Poster.RelAvatarLink}}">
|
||||
</a>
|
||||
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
|
||||
{{if .Content}}{{$.i18n.Tr "repo.issues.add_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{end}}</span>
|
||||
{{if .Content}}{{$.i18n.Tr "repo.issues.add_label_at" .Label.ForegroundColor .Label.Color (.Label.Name|Escape) $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_label_at" .Label.ForegroundColor .Label.Color (.Label.Name|Escape) $createdStr | Safe}}{{end}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{else if eq .Type 8}}
|
||||
@@ -113,7 +113,7 @@
|
||||
<img src="{{.Poster.RelAvatarLink}}">
|
||||
</a>
|
||||
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
|
||||
{{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.change_milestone_at" .OldMilestone.Name .Milestone.Name $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_milestone_at" .OldMilestone.Name $createdStr | Safe}}{{end}}{{else if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.add_milestone_at" .Milestone.Name $createdStr | Safe}}{{end}}</span>
|
||||
{{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.change_milestone_at" (.OldMilestone.Name|Escape) (.Milestone.Name|Escape) $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_milestone_at" (.OldMilestone.Name|Escape) $createdStr | Safe}}{{end}}{{else if gt .MilestoneID 0}}{{$.i18n.Tr "repo.issues.add_milestone_at" (.Milestone.Name|Escape) $createdStr | Safe}}{{end}}</span>
|
||||
</div>
|
||||
{{else if eq .Type 9}}
|
||||
<div class="event">
|
||||
@@ -131,23 +131,23 @@
|
||||
{{else if eq .Type 10}}
|
||||
<div class="event">
|
||||
<span class="octicon octicon-primitive-dot"></span>
|
||||
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
|
||||
<img src="{{.Poster.RelAvatarLink}}">
|
||||
</a>
|
||||
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
|
||||
{{$.i18n.Tr "repo.issues.change_title_at" (.OldTitle|Escape) (.NewTitle|Escape) $createdStr | Safe}}
|
||||
</span>
|
||||
</div>
|
||||
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
|
||||
<img src="{{.Poster.RelAvatarLink}}">
|
||||
</a>
|
||||
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
|
||||
{{$.i18n.Tr "repo.issues.change_title_at" .OldTitle .NewTitle $createdStr | Safe}}
|
||||
</span>
|
||||
{{else if eq .Type 11}}
|
||||
<div class="event">
|
||||
<span class="octicon octicon-primitive-dot"></span>
|
||||
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
|
||||
<img src="{{.Poster.RelAvatarLink}}">
|
||||
</a>
|
||||
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
|
||||
{{$.i18n.Tr "repo.issues.delete_branch_at" .CommitSHA $createdStr | Safe}}
|
||||
</span>
|
||||
</div>
|
||||
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
|
||||
<img src="{{.Poster.RelAvatarLink}}">
|
||||
</a>
|
||||
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
|
||||
{{$.i18n.Tr "repo.issues.delete_branch_at" .CommitSHA $createdStr | Safe}}
|
||||
</span>
|
||||
{{else if eq .Type 12}}
|
||||
<div class="event">
|
||||
<span class="octicon octicon-primitive-dot"></span>
|
||||
|
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
{{if .Keyword}}
|
||||
<h3>
|
||||
{{.i18n.Tr "repo.search.results" .Keyword .RepoLink .RepoName | Str2html}}
|
||||
{{.i18n.Tr "repo.search.results" (.Keyword|Escape) .RepoLink .RepoName | Str2html }}
|
||||
</h3>
|
||||
<div class="repository search">
|
||||
{{range $result := .SearchResults}}
|
||||
|
@@ -104,7 +104,7 @@
|
||||
{{.i18n.Tr "repo.wiki.delete_page_button"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{.i18n.Tr "repo.wiki.delete_page_notice_1" $title | Safe}}</p>
|
||||
<p>{{.i18n.Tr "repo.wiki.delete_page_notice_1" ($title|Escape) | Safe}}</p>
|
||||
</div>
|
||||
{{template "base/delete_modal_actions" .}}
|
||||
</div>
|
||||
|
97
vendor/github.com/markbates/goth/README.md
generated
vendored
97
vendor/github.com/markbates/goth/README.md
generated
vendored
@@ -8,6 +8,10 @@ protocol providers, as long as they implement the `Provider` and `Session` inter
|
||||
|
||||
This package was inspired by [https://github.com/intridea/omniauth](https://github.com/intridea/omniauth).
|
||||
|
||||
## Goth Needs a New Maintainer
|
||||
|
||||
[https://blog.gobuffalo.io/goth-needs-a-new-maintainer-626cd47ca37b](https://blog.gobuffalo.io/goth-needs-a-new-maintainer-626cd47ca37b) - TL;DR: I, @markbates, won't be responding to any more issues, PRs, etc... for this package. A new maintainer needs to be found ASAP. Is this you?
|
||||
|
||||
## Installation
|
||||
|
||||
```text
|
||||
@@ -18,6 +22,8 @@ $ go get github.com/markbates/goth
|
||||
|
||||
* Amazon
|
||||
* Auth0
|
||||
* Azure AD
|
||||
* Battle.net
|
||||
* Bitbucket
|
||||
* Box
|
||||
* Cloud Foundry
|
||||
@@ -26,6 +32,7 @@ $ go get github.com/markbates/goth
|
||||
* Digital Ocean
|
||||
* Discord
|
||||
* Dropbox
|
||||
* Eve Online
|
||||
* Facebook
|
||||
* Fitbit
|
||||
* GitHub
|
||||
@@ -38,6 +45,7 @@ $ go get github.com/markbates/goth
|
||||
* Lastfm
|
||||
* Linkedin
|
||||
* Meetup
|
||||
* MicrosoftOnline
|
||||
* OneDrive
|
||||
* OpenID Connect (auto discovery)
|
||||
* Paypal
|
||||
@@ -50,7 +58,9 @@ $ go get github.com/markbates/goth
|
||||
* Twitch
|
||||
* Twitter
|
||||
* Uber
|
||||
* VK
|
||||
* Wepay
|
||||
* Xero
|
||||
* Yahoo
|
||||
* Yammer
|
||||
|
||||
@@ -71,17 +81,51 @@ $ go get github.com/markbates/goth
|
||||
```text
|
||||
$ cd goth/examples
|
||||
$ go get -v
|
||||
$ go build
|
||||
$ go build
|
||||
$ ./examples
|
||||
```
|
||||
|
||||
Now open up your browser and go to [http://localhost:3000](http://localhost:3000) to see the example.
|
||||
|
||||
To actually use the different providers, please make sure you configure them given the system environments as defined in the examples/main.go file
|
||||
To actually use the different providers, please make sure you set environment variables. Example given in the examples/main.go file
|
||||
|
||||
## Security Notes
|
||||
|
||||
By default, gothic uses a `CookieStore` from the `gorilla/sessions` package to store session data.
|
||||
|
||||
As configured, this default store (`gothic.Store`) will generate cookies with `Options`:
|
||||
|
||||
```go
|
||||
&Options{
|
||||
Path: "/",
|
||||
Domain: "",
|
||||
MaxAge: 86400 * 30,
|
||||
HttpOnly: true,
|
||||
Secure: false,
|
||||
}
|
||||
```
|
||||
|
||||
To tailor these fields for your application, you can override the `gothic.Store` variable at startup.
|
||||
|
||||
The follow snippet show one way to do this:
|
||||
|
||||
```go
|
||||
key := "" // Replace with your SESSION_SECRET or similar
|
||||
maxAge := 86400 * 30 // 30 days
|
||||
isProd := false // Set to true when serving over https
|
||||
|
||||
store := sessions.NewCookieStore([]byte(key))
|
||||
store.MaxAge(maxAge)
|
||||
store.Options.Path = "/"
|
||||
store.Options.HttpOnly = true // HttpOnly should always be enabled
|
||||
store.Options.Secure = isProd
|
||||
|
||||
gothic.Store = store
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
Issues always stand a significantly better chance of getting fixed if the are accompanied by a
|
||||
Issues always stand a significantly better chance of getting fixed if they are accompanied by a
|
||||
pull request.
|
||||
|
||||
## Contributing
|
||||
@@ -94,50 +138,3 @@ Would I love to see more providers? Certainly! Would you love to contribute one?
|
||||
4. Commit your changes (git commit -am 'Add some feature')
|
||||
5. Push to the branch (git push origin my-new-feature)
|
||||
6. Create new Pull Request
|
||||
|
||||
## Contributors
|
||||
|
||||
* Mark Bates
|
||||
* Tyler Bunnell
|
||||
* Corey McGrillis
|
||||
* willemvd
|
||||
* Rakesh Goyal
|
||||
* Andy Grunwald
|
||||
* Glenn Walker
|
||||
* Kevin Fitzpatrick
|
||||
* Ben Tranter
|
||||
* Sharad Ganapathy
|
||||
* Andrew Chilton
|
||||
* sharadgana
|
||||
* Aurorae
|
||||
* Craig P Jolicoeur
|
||||
* Zac Bergquist
|
||||
* Geoff Franks
|
||||
* Raphael Geronimi
|
||||
* Noah Shibley
|
||||
* lumost
|
||||
* oov
|
||||
* Felix Lamouroux
|
||||
* Rafael Quintela
|
||||
* Tyler
|
||||
* DenSm
|
||||
* Samy KACIMI
|
||||
* dante gray
|
||||
* Noah
|
||||
* Jacob Walker
|
||||
* Marin Martinic
|
||||
* Roy
|
||||
* Omni Adams
|
||||
* Sasa Brankovic
|
||||
* dkhamsing
|
||||
* Dante Swift
|
||||
* Attila Domokos
|
||||
* Albin Gilles
|
||||
* Syed Zubairuddin
|
||||
* Johnny Boursiquot
|
||||
* Jerome Touffe-Blin
|
||||
* bryanl
|
||||
* Masanobu YOSHIOKA
|
||||
* Jonathan Hall
|
||||
* HaiMing.Yin
|
||||
* Sairam Kunala
|
||||
|
181
vendor/github.com/markbates/goth/gothic/gothic.go
generated
vendored
181
vendor/github.com/markbates/goth/gothic/gothic.go
generated
vendored
@@ -8,10 +8,18 @@ See https://github.com/markbates/goth/examples/main.go to see this in action.
|
||||
package gothic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
@@ -27,15 +35,21 @@ var defaultStore sessions.Store
|
||||
|
||||
var keySet = false
|
||||
|
||||
var gothicRand *rand.Rand
|
||||
|
||||
func init() {
|
||||
key := []byte(os.Getenv("SESSION_SECRET"))
|
||||
keySet = len(key) != 0
|
||||
Store = sessions.NewCookieStore([]byte(key))
|
||||
|
||||
cookieStore := sessions.NewCookieStore([]byte(key))
|
||||
cookieStore.Options.HttpOnly = true
|
||||
Store = cookieStore
|
||||
defaultStore = Store
|
||||
gothicRand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
/*
|
||||
BeginAuthHandler is a convienence handler for starting the authentication process.
|
||||
BeginAuthHandler is a convenience handler for starting the authentication process.
|
||||
It expects to be able to get the name of the provider from the query parameters
|
||||
as either "provider" or ":provider".
|
||||
|
||||
@@ -65,8 +79,16 @@ var SetState = func(req *http.Request) string {
|
||||
return state
|
||||
}
|
||||
|
||||
return "state"
|
||||
|
||||
// If a state query param is not passed in, generate a random
|
||||
// base64-encoded nonce so that the state on the auth URL
|
||||
// is unguessable, preventing CSRF attacks, as described in
|
||||
//
|
||||
// https://auth0.com/docs/protocols/oauth2/oauth-state#keep-reading
|
||||
nonceBytes := make([]byte, 64)
|
||||
for i := 0; i < 64; i++ {
|
||||
nonceBytes[i] = byte(gothicRand.Int63() % 256)
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(nonceBytes)
|
||||
}
|
||||
|
||||
// GetState gets the state returned by the provider during the callback.
|
||||
@@ -87,7 +109,6 @@ I would recommend using the BeginAuthHandler instead of doing all of these steps
|
||||
yourself, but that's entirely up to you.
|
||||
*/
|
||||
func GetAuthURL(res http.ResponseWriter, req *http.Request) (string, error) {
|
||||
|
||||
if !keySet && defaultStore == Store {
|
||||
fmt.Println("goth/gothic: no SESSION_SECRET environment variable is set. The default cookie store is not available and any calls will fail. Ignore this warning if you are using a different store.")
|
||||
}
|
||||
@@ -111,7 +132,7 @@ func GetAuthURL(res http.ResponseWriter, req *http.Request) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = storeInSession(providerName, sess.Marshal(), req, res)
|
||||
err = StoreInSession(providerName, sess.Marshal(), req, res)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -130,7 +151,7 @@ as either "provider" or ":provider".
|
||||
See https://github.com/markbates/goth/examples/main.go to see this in action.
|
||||
*/
|
||||
var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
|
||||
|
||||
defer Logout(res, req)
|
||||
if !keySet && defaultStore == Store {
|
||||
fmt.Println("goth/gothic: no SESSION_SECRET environment variable is set. The default cookie store is not available and any calls will fail. Ignore this warning if you are using a different store.")
|
||||
}
|
||||
@@ -145,7 +166,7 @@ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.Us
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
value, err := getFromSession(providerName, req)
|
||||
value, err := GetFromSession(providerName, req)
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
@@ -155,6 +176,11 @@ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.Us
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
err = validateState(req, sess)
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
user, err := provider.FetchUser(sess)
|
||||
if err == nil {
|
||||
// user can be found with existing session data
|
||||
@@ -167,13 +193,49 @@ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.Us
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
err = storeInSession(providerName, sess.Marshal(), req, res)
|
||||
err = StoreInSession(providerName, sess.Marshal(), req, res)
|
||||
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
return provider.FetchUser(sess)
|
||||
gu, err := provider.FetchUser(sess)
|
||||
return gu, err
|
||||
}
|
||||
|
||||
// validateState ensures that the state token param from the original
|
||||
// AuthURL matches the one included in the current (callback) request.
|
||||
func validateState(req *http.Request, sess goth.Session) error {
|
||||
rawAuthURL, err := sess.GetAuthURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authURL, err := url.Parse(rawAuthURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
originalState := authURL.Query().Get("state")
|
||||
if originalState != "" && (originalState != req.URL.Query().Get("state")) {
|
||||
return errors.New("state token mismatch")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logout invalidates a user session.
|
||||
func Logout(res http.ResponseWriter, req *http.Request) error {
|
||||
session, err := Store.Get(req, SessionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Options.MaxAge = -1
|
||||
session.Values = make(map[interface{}]interface{})
|
||||
err = session.Save(req, res)
|
||||
if err != nil {
|
||||
return errors.New("Could not delete user session ")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetProviderName is a function used to get the name of a provider
|
||||
@@ -184,36 +246,99 @@ var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.Us
|
||||
var GetProviderName = getProviderName
|
||||
|
||||
func getProviderName(req *http.Request) (string, error) {
|
||||
provider := req.URL.Query().Get("provider")
|
||||
if provider == "" {
|
||||
if p, ok := mux.Vars(req)["provider"]; ok {
|
||||
|
||||
// get all the used providers
|
||||
providers := goth.GetProviders()
|
||||
|
||||
// loop over the used providers, if we already have a valid session for any provider (ie. user is already logged-in with a provider), then return that provider name
|
||||
for _, provider := range providers {
|
||||
p := provider.Name()
|
||||
session, _ := Store.Get(req, p+SessionName)
|
||||
value := session.Values[p]
|
||||
if _, ok := value.(string); ok {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
if provider == "" {
|
||||
provider = req.URL.Query().Get(":provider")
|
||||
|
||||
// try to get it from the url param "provider"
|
||||
if p := req.URL.Query().Get("provider"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
if provider == "" {
|
||||
return provider, errors.New("you must select a provider")
|
||||
|
||||
// try to get it from the url param ":provider"
|
||||
if p := req.URL.Query().Get(":provider"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
return provider, nil
|
||||
|
||||
// try to get it from the context's value of "provider" key
|
||||
if p, ok := mux.Vars(req)["provider"]; ok {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// try to get it from the go-context's value of "provider" key
|
||||
if p, ok := req.Context().Value("provider").(string); ok {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// if not found then return an empty string with the corresponding error
|
||||
return "", errors.New("you must select a provider")
|
||||
}
|
||||
|
||||
func storeInSession(key string, value string, req *http.Request, res http.ResponseWriter) error {
|
||||
session, _ := Store.Get(req, key + SessionName)
|
||||
// StoreInSession stores a specified key/value pair in the session.
|
||||
func StoreInSession(key string, value string, req *http.Request, res http.ResponseWriter) error {
|
||||
session, _ := Store.New(req, SessionName)
|
||||
|
||||
session.Values[key] = value
|
||||
if err := updateSessionValue(session, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Save(req, res)
|
||||
}
|
||||
|
||||
func getFromSession(key string, req *http.Request) (string, error) {
|
||||
session, _ := Store.Get(req, key + SessionName)
|
||||
|
||||
value := session.Values[key]
|
||||
if value == nil {
|
||||
// GetFromSession retrieves a previously-stored value from the session.
|
||||
// If no value has previously been stored at the specified key, it will return an error.
|
||||
func GetFromSession(key string, req *http.Request) (string, error) {
|
||||
session, _ := Store.Get(req, SessionName)
|
||||
value, err := getSessionValue(session, key)
|
||||
if err != nil {
|
||||
return "", errors.New("could not find a matching session for this request")
|
||||
}
|
||||
|
||||
return value.(string), nil
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func getSessionValue(session *sessions.Session, key string) (string, error) {
|
||||
value := session.Values[key]
|
||||
if value == nil {
|
||||
return "", fmt.Errorf("could not find a matching session for this request")
|
||||
}
|
||||
|
||||
rdata := strings.NewReader(value.(string))
|
||||
r, err := gzip.NewReader(rdata)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(s), nil
|
||||
}
|
||||
|
||||
func updateSessionValue(session *sessions.Session, key, value string) error {
|
||||
var b bytes.Buffer
|
||||
gz := gzip.NewWriter(&b)
|
||||
if _, err := gz.Write([]byte(value)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gz.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gz.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session.Values[key] = b.String()
|
||||
return nil
|
||||
}
|
||||
|
12
vendor/github.com/markbates/goth/providers/bitbucket/bitbucket.go
generated
vendored
12
vendor/github.com/markbates/goth/providers/bitbucket/bitbucket.go
generated
vendored
@@ -9,9 +9,9 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"fmt"
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -26,10 +26,10 @@ const (
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "bitbucket",
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "bitbucket",
|
||||
}
|
||||
p.config = newConfig(p, scopes)
|
||||
return p
|
||||
@@ -125,7 +125,7 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
|
||||
func userFromReader(reader io.Reader, user *goth.User) error {
|
||||
u := struct {
|
||||
ID string `json:"uuid"`
|
||||
ID string `json:"uuid"`
|
||||
Links struct {
|
||||
Avatar struct {
|
||||
URL string `json:"href"`
|
||||
|
62
vendor/github.com/markbates/goth/providers/dropbox/dropbox.go
generated
vendored
62
vendor/github.com/markbates/goth/providers/dropbox/dropbox.go
generated
vendored
@@ -2,21 +2,24 @@
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
authURL = "https://www.dropbox.com/1/oauth2/authorize"
|
||||
tokenURL = "https://api.dropbox.com/1/oauth2/token"
|
||||
accountURL = "https://api.dropbox.com/1/account/info"
|
||||
authURL = "https://www.dropbox.com/oauth2/authorize"
|
||||
tokenURL = "https://api.dropbox.com/oauth2/token"
|
||||
accountURL = "https://api.dropbox.com/2/users/get_current_account"
|
||||
)
|
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing Dropbox.
|
||||
@@ -24,6 +27,7 @@ type Provider struct {
|
||||
ClientKey string
|
||||
Secret string
|
||||
CallbackURL string
|
||||
AccountURL string
|
||||
HTTPClient *http.Client
|
||||
config *oauth2.Config
|
||||
providerName string
|
||||
@@ -40,10 +44,11 @@ type Session struct {
|
||||
// create one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "dropbox",
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
AccountURL: accountURL,
|
||||
providerName: "dropbox",
|
||||
}
|
||||
p.config = newConfig(p, scopes)
|
||||
return p
|
||||
@@ -86,7 +91,7 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", accountURL, nil)
|
||||
req, err := http.NewRequest("POST", p.AccountURL, nil)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -101,7 +106,17 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, resp.StatusCode)
|
||||
}
|
||||
|
||||
err = userFromReader(resp.Body, &user)
|
||||
bits, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
err = userFromReader(bytes.NewReader(bits), &user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
@@ -161,22 +176,29 @@ func newConfig(p *Provider, scopes []string) *oauth2.Config {
|
||||
|
||||
func userFromReader(r io.Reader, user *goth.User) error {
|
||||
u := struct {
|
||||
Name string `json:"display_name"`
|
||||
NameDetails struct {
|
||||
NickName string `json:"familiar_name"`
|
||||
} `json:"name_details"`
|
||||
Location string `json:"country"`
|
||||
Email string `json:"email"`
|
||||
AccountID string `json:"account_id"`
|
||||
Name struct {
|
||||
GivenName string `json:"given_name"`
|
||||
Surname string `json:"surname"`
|
||||
DisplayName string `json:"display_name"`
|
||||
} `json:"name"`
|
||||
Country string `json:"country"`
|
||||
Email string `json:"email"`
|
||||
ProfilePhotoURL string `json:"profile_photo_url"`
|
||||
}{}
|
||||
err := json.NewDecoder(r).Decode(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.UserID = u.AccountID // The user's unique Dropbox ID.
|
||||
user.FirstName = u.Name.GivenName
|
||||
user.LastName = u.Name.Surname
|
||||
user.Name = strings.TrimSpace(fmt.Sprintf("%s %s", u.Name.GivenName, u.Name.Surname))
|
||||
user.Description = u.Name.DisplayName // Full name plus parenthetical team naem
|
||||
user.Email = u.Email
|
||||
user.Name = u.Name
|
||||
user.NickName = u.NameDetails.NickName
|
||||
user.UserID = u.Email // Dropbox doesn't provide a separate user ID
|
||||
user.Location = u.Location
|
||||
user.NickName = u.Email // Email is the dropbox username
|
||||
user.Location = u.Country
|
||||
user.AvatarURL = u.ProfilePhotoURL // May be blank
|
||||
return nil
|
||||
}
|
||||
|
||||
|
16
vendor/github.com/markbates/goth/providers/facebook/facebook.go
generated
vendored
16
vendor/github.com/markbates/goth/providers/facebook/facebook.go
generated
vendored
@@ -11,12 +11,12 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
"fmt"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -30,10 +30,10 @@ const (
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "facebook",
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "facebook",
|
||||
}
|
||||
p.config = newConfig(p, scopes)
|
||||
return p
|
||||
@@ -129,7 +129,7 @@ func userFromReader(reader io.Reader, user *goth.User) error {
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Link string `json:"link"`
|
||||
Picture struct {
|
||||
Picture struct {
|
||||
Data struct {
|
||||
URL string `json:"url"`
|
||||
} `json:"data"`
|
||||
|
2
vendor/github.com/markbates/goth/providers/gitlab/gitlab.go
generated
vendored
2
vendor/github.com/markbates/goth/providers/gitlab/gitlab.go
generated
vendored
@@ -11,9 +11,9 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"fmt"
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// These vars define the Authentication, Token, and Profile URLS for Gitlab. If
|
||||
|
10
vendor/github.com/markbates/goth/providers/gplus/gplus.go
generated
vendored
10
vendor/github.com/markbates/goth/providers/gplus/gplus.go
generated
vendored
@@ -11,9 +11,9 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"fmt"
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -27,10 +27,10 @@ const (
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "gplus",
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "gplus",
|
||||
}
|
||||
p.config = newConfig(p, scopes)
|
||||
return p
|
||||
|
32
vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go
generated
vendored
32
vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go
generated
vendored
@@ -1,17 +1,17 @@
|
||||
package openidConnect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"errors"
|
||||
"golang.org/x/oauth2"
|
||||
"github.com/markbates/goth"
|
||||
"time"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -89,14 +89,14 @@ func New(clientKey, secret, callbackURL, openIDAutoDiscoveryURL string, scopes .
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
|
||||
UserIdClaims: []string{subjectClaim},
|
||||
NameClaims: []string{NameClaim},
|
||||
NickNameClaims: []string{NicknameClaim, PreferredUsernameClaim},
|
||||
EmailClaims: []string{EmailClaim},
|
||||
AvatarURLClaims:[]string{PictureClaim},
|
||||
FirstNameClaims:[]string{GivenNameClaim},
|
||||
LastNameClaims: []string{FamilyNameClaim},
|
||||
LocationClaims: []string{AddressClaim},
|
||||
UserIdClaims: []string{subjectClaim},
|
||||
NameClaims: []string{NameClaim},
|
||||
NickNameClaims: []string{NicknameClaim, PreferredUsernameClaim},
|
||||
EmailClaims: []string{EmailClaim},
|
||||
AvatarURLClaims: []string{PictureClaim},
|
||||
FirstNameClaims: []string{GivenNameClaim},
|
||||
LastNameClaims: []string{FamilyNameClaim},
|
||||
LocationClaims: []string{AddressClaim},
|
||||
|
||||
providerName: "openid-connect",
|
||||
}
|
||||
|
4
vendor/github.com/markbates/goth/providers/openidConnect/session.go
generated
vendored
4
vendor/github.com/markbates/goth/providers/openidConnect/session.go
generated
vendored
@@ -1,12 +1,12 @@
|
||||
package openidConnect
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/markbates/goth"
|
||||
"encoding/json"
|
||||
"golang.org/x/oauth2"
|
||||
"strings"
|
||||
"time"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// Session stores data during the auth process with the OpenID Connect provider.
|
||||
|
24
vendor/github.com/markbates/goth/providers/twitter/twitter.go
generated
vendored
24
vendor/github.com/markbates/goth/providers/twitter/twitter.go
generated
vendored
@@ -9,10 +9,11 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"github.com/mrjones/oauth"
|
||||
"golang.org/x/oauth2"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -30,10 +31,10 @@ var (
|
||||
// If you'd like to use authenticate instead of authorize, use NewAuthenticate instead.
|
||||
func New(clientKey, secret, callbackURL string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "twitter",
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "twitter",
|
||||
}
|
||||
p.consumer = newConsumer(p, authorizeURL)
|
||||
return p
|
||||
@@ -43,10 +44,10 @@ func New(clientKey, secret, callbackURL string) *Provider {
|
||||
// NewAuthenticate uses the authenticate URL instead of the authorize URL.
|
||||
func NewAuthenticate(clientKey, secret, callbackURL string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "twitter",
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "twitter",
|
||||
}
|
||||
p.consumer = newConsumer(p, authenticateURL)
|
||||
return p
|
||||
@@ -107,7 +108,7 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
|
||||
response, err := p.consumer.Get(
|
||||
endpointProfile,
|
||||
map[string]string{"include_entities": "false", "skip_status": "true"},
|
||||
map[string]string{"include_entities": "false", "skip_status": "true", "include_email": "true"},
|
||||
sess.AccessToken)
|
||||
if err != nil {
|
||||
return user, err
|
||||
@@ -126,6 +127,9 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
|
||||
user.Name = user.RawData["name"].(string)
|
||||
user.NickName = user.RawData["screen_name"].(string)
|
||||
if user.RawData["email"] != nil {
|
||||
user.Email = user.RawData["email"].(string)
|
||||
}
|
||||
user.Description = user.RawData["description"].(string)
|
||||
user.AvatarURL = user.RawData["profile_image_url"].(string)
|
||||
user.UserID = user.RawData["id_str"].(string)
|
||||
|
68
vendor/vendor.json
vendored
68
vendor/vendor.json
vendored
@@ -654,64 +654,74 @@
|
||||
"revisionTime": "2017-10-25T03:15:54Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "O3KUfEXQPfdQ+tCMpP2RAIRJJqY=",
|
||||
"checksumSHA1": "q9MD1ienC+kmKq5i51oAktQEV1E=",
|
||||
"origin": "github.com/go-gitea/goth",
|
||||
"path": "github.com/markbates/goth",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "MkFKwLV3icyUo4oP0BgEs+7+R1Y=",
|
||||
"checksumSHA1": "FISfgOkoMtn98wglLUvfBTZ6baE=",
|
||||
"origin": "github.com/go-gitea/goth/gothic",
|
||||
"path": "github.com/markbates/goth/gothic",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "crNSlQADjX6hcxykON2tFCqY4iw=",
|
||||
"checksumSHA1": "pJ+Cws/TU22K6tZ/ALFOvvH1K5U=",
|
||||
"origin": "github.com/go-gitea/goth/providers/bitbucket",
|
||||
"path": "github.com/markbates/goth/providers/bitbucket",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "1Kp4DKkJNVn135Xg8H4a6CFBNy8=",
|
||||
"checksumSHA1": "XsF5HI4240QHbFXbtWWnGgTsoq8=",
|
||||
"origin": "github.com/go-gitea/goth/providers/dropbox",
|
||||
"path": "github.com/markbates/goth/providers/dropbox",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "cGs1da29iOBJh5EAH0icKDbN8CA=",
|
||||
"checksumSHA1": "VzbroIA9R00Ig3iGnOlZLU7d4ls=",
|
||||
"origin": "github.com/go-gitea/goth/providers/facebook",
|
||||
"path": "github.com/markbates/goth/providers/facebook",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "P6nBZ850aaekpOcoXNdRhK86bH8=",
|
||||
"origin": "github.com/go-gitea/goth/providers/github",
|
||||
"path": "github.com/markbates/goth/providers/github",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "o/109paSRy9HqV87gR4zUZMMSzs=",
|
||||
"checksumSHA1": "ld488t+yGoTwtmiCSSggEX4fxVk=",
|
||||
"origin": "github.com/go-gitea/goth/providers/gitlab",
|
||||
"path": "github.com/markbates/goth/providers/gitlab",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "cX6kR9y94BWFZvI/7UFrsFsP3FQ=",
|
||||
"checksumSHA1": "qXEulD7vnwY9hFrxh91Pm5YrvTM=",
|
||||
"origin": "github.com/go-gitea/goth/providers/gplus",
|
||||
"path": "github.com/markbates/goth/providers/gplus",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "sMYKhqAUZXM1+T/TjlMhWh8Vveo=",
|
||||
"checksumSHA1": "wsOBzyp4LKDhfCPmX1LLP7T0S3U=",
|
||||
"origin": "github.com/go-gitea/goth/providers/openidConnect",
|
||||
"path": "github.com/markbates/goth/providers/openidConnect",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "1w0V6jYXaGlEtZcMeYTOAAucvgw=",
|
||||
"checksumSHA1": "o6RqMbbE8QNZhNT9TsAIRMPI8tg=",
|
||||
"origin": "github.com/go-gitea/goth/providers/twitter",
|
||||
"path": "github.com/markbates/goth/providers/twitter",
|
||||
"revision": "90362394a367f9d77730911973462a53d69662ba",
|
||||
"revisionTime": "2017-02-23T14:12:10Z"
|
||||
"revision": "3b54d96084a5e11030f19556cf68a6ab5d93ba20",
|
||||
"revisionTime": "2018-03-12T06:32:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "61HNjGetaBoMp8HBOpuEZRSim8g=",
|
||||
|
Reference in New Issue
Block a user