added token to post-commit hooks
This commit is contained in:
parent
dfb0210cf5
commit
7009778176
11 changed files with 172 additions and 13 deletions
2
Makefile
2
Makefile
|
@ -88,5 +88,5 @@ rpm:
|
||||||
# DRONE_STAGING_USER -- the username used to login
|
# DRONE_STAGING_USER -- the username used to login
|
||||||
# DRONE_STAGING_KEY -- the identity file path (~/.ssh/id_rsa)
|
# DRONE_STAGING_KEY -- the identity file path (~/.ssh/id_rsa)
|
||||||
deploy:
|
deploy:
|
||||||
scp -i $$DRONE_STAGING_KEY debian/drone.deb $$DRONE_STAGING_USER@$$DRONE_STAGING_HOST:/tmp
|
scp -i $$DRONE_STAGING_KEY packaging/output/drone.deb $$DRONE_STAGING_USER@$$DRONE_STAGING_HOST:/tmp
|
||||||
ssh -i $$DRONE_STAGING_KEY $$DRONE_STAGING_USER@$$DRONE_STAGING_HOST -- dpkg -i /tmp/drone.deb
|
ssh -i $$DRONE_STAGING_KEY $$DRONE_STAGING_USER@$$DRONE_STAGING_HOST -- dpkg -i /tmp/drone.deb
|
||||||
|
|
|
@ -135,7 +135,7 @@ func (r *Gitlab) Activate(user *model.User, repo *model.Repo, link string) error
|
||||||
|
|
||||||
// append the repo owner / name to the hook url since gitlab
|
// append the repo owner / name to the hook url since gitlab
|
||||||
// doesn't send this detail in the post-commit hook
|
// doesn't send this detail in the post-commit hook
|
||||||
link += "?owner=" + repo.Owner + "&name=" + repo.Name
|
link += "&owner=" + repo.Owner + "&name=" + repo.Name
|
||||||
|
|
||||||
// add the hook
|
// add the hook
|
||||||
return client.AddProjectHook(path, link, true, false, true)
|
return client.AddProjectHook(path, link, true, false, true)
|
||||||
|
|
|
@ -37,6 +37,7 @@ func Connect(driver, datasource string) (*sql.DB, error) {
|
||||||
migration.DefaultSetVersion = migrate.SetVersion
|
migration.DefaultSetVersion = migrate.SetVersion
|
||||||
var migrations = []migration.Migrator{
|
var migrations = []migration.Migrator{
|
||||||
migrate.Setup,
|
migrate.Setup,
|
||||||
|
migrate.Migrate_20142110,
|
||||||
}
|
}
|
||||||
return migration.Open(driver, datasource, migrations)
|
return migration.Open(driver, datasource, migrations)
|
||||||
}
|
}
|
||||||
|
|
146
server/datastore/migrate/migrate.go
Normal file
146
server/datastore/migrate/migrate.go
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
package migrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/BurntSushi/migration"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Setup is the database migration function that
|
||||||
|
// will setup the initial SQL database structure.
|
||||||
|
func Setup(tx migration.LimitedTx) error {
|
||||||
|
var stmts = []string{
|
||||||
|
blobTable,
|
||||||
|
userTable,
|
||||||
|
repoTable,
|
||||||
|
permTable,
|
||||||
|
commitTable,
|
||||||
|
}
|
||||||
|
for _, stmt := range stmts {
|
||||||
|
_, err := tx.Exec(transform(stmt))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate_20142110 is a database migration on Oct-10 2014.
|
||||||
|
func Migrate_20142110(tx migration.LimitedTx) error {
|
||||||
|
var stmts = []string{
|
||||||
|
commitRepoIndex, // index the commit table repo_id column
|
||||||
|
repoTokenColumn, // add the repo token column
|
||||||
|
repoTokenUpdate, // update the repo token column to empty string
|
||||||
|
}
|
||||||
|
for _, stmt := range stmts {
|
||||||
|
_, err := tx.Exec(transform(stmt))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var userTable = `
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
user_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||||
|
,user_remote VARCHAR(255)
|
||||||
|
,user_login VARCHAR(255)
|
||||||
|
,user_access VARCHAR(255)
|
||||||
|
,user_secret VARCHAR(255)
|
||||||
|
,user_name VARCHAR(255)
|
||||||
|
,user_email VARCHAR(255)
|
||||||
|
,user_gravatar VARCHAR(255)
|
||||||
|
,user_token VARCHAR(255)
|
||||||
|
,user_admin BOOLEAN
|
||||||
|
,user_active BOOLEAN
|
||||||
|
,user_syncing BOOLEAN
|
||||||
|
,user_created INTEGER
|
||||||
|
,user_updated INTEGER
|
||||||
|
,user_synced INTEGER
|
||||||
|
,UNIQUE(user_token)
|
||||||
|
,UNIQUE(user_remote, user_login)
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
var permTable = `
|
||||||
|
CREATE TABLE IF NOT EXISTS perms (
|
||||||
|
perm_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||||
|
,user_id INTEGER
|
||||||
|
,repo_id INTEGER
|
||||||
|
,perm_read BOOLEAN
|
||||||
|
,perm_write BOOLEAN
|
||||||
|
,perm_admin BOOLEAN
|
||||||
|
,perm_created INTEGER
|
||||||
|
,perm_updated INTEGER
|
||||||
|
,UNIQUE (repo_id, user_id)
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
var repoTable = `
|
||||||
|
CREATE TABLE IF NOT EXISTS repos (
|
||||||
|
repo_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||||
|
,user_id INTEGER
|
||||||
|
,repo_remote VARCHAR(255)
|
||||||
|
,repo_host VARCHAR(255)
|
||||||
|
,repo_owner VARCHAR(255)
|
||||||
|
,repo_name VARCHAR(255)
|
||||||
|
,repo_url VARCHAR(1024)
|
||||||
|
,repo_clone_url VARCHAR(255)
|
||||||
|
,repo_git_url VARCHAR(255)
|
||||||
|
,repo_ssh_url VARCHAR(255)
|
||||||
|
,repo_active BOOLEAN
|
||||||
|
,repo_private BOOLEAN
|
||||||
|
,repo_privileged BOOLEAN
|
||||||
|
,repo_post_commit BOOLEAN
|
||||||
|
,repo_pull_request BOOLEAN
|
||||||
|
,repo_public_key BLOB
|
||||||
|
,repo_private_key BLOB
|
||||||
|
,repo_params BLOB
|
||||||
|
,repo_timeout INTEGER
|
||||||
|
,repo_created INTEGER
|
||||||
|
,repo_updated INTEGER
|
||||||
|
,UNIQUE(repo_host, repo_owner, repo_name)
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
var repoTokenColumn = `
|
||||||
|
ALTER TABLE repos ADD COLUMN repo_token VARCHAR(40)
|
||||||
|
`
|
||||||
|
|
||||||
|
var repoTokenUpdate = `
|
||||||
|
UPDATE repos SET repo_token = '';
|
||||||
|
`
|
||||||
|
|
||||||
|
var commitTable = `
|
||||||
|
CREATE TABLE IF NOT EXISTS commits (
|
||||||
|
commit_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||||
|
,repo_id INTEGER
|
||||||
|
,commit_status VARCHAR(255)
|
||||||
|
,commit_started INTEGER
|
||||||
|
,commit_finished INTEGER
|
||||||
|
,commit_duration INTEGER
|
||||||
|
,commit_sha VARCHAR(255)
|
||||||
|
,commit_branch VARCHAR(255)
|
||||||
|
,commit_pr VARCHAR(255)
|
||||||
|
,commit_author VARCHAR(255)
|
||||||
|
,commit_gravatar VARCHAR(255)
|
||||||
|
,commit_timestamp VARCHAR(255)
|
||||||
|
,commit_message VARCHAR(255)
|
||||||
|
,commit_yaml BLOB
|
||||||
|
,commit_created INTEGER
|
||||||
|
,commit_updated INTEGER
|
||||||
|
,UNIQUE(commit_sha, commit_branch, repo_id)
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
var commitRepoIndex = `
|
||||||
|
CREATE INDEX commit_repo_id_idx ON commits (repo_id);
|
||||||
|
`
|
||||||
|
|
||||||
|
var blobTable = `
|
||||||
|
CREATE TABLE IF NOT EXISTS blobs (
|
||||||
|
blob_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||||
|
,blob_path VARCHAR(255)
|
||||||
|
,blob_data BLOB
|
||||||
|
,UNIQUE(blob_path)
|
||||||
|
);
|
||||||
|
`
|
|
@ -1,6 +1,7 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ import (
|
||||||
func PostHook(c web.C, w http.ResponseWriter, r *http.Request) {
|
func PostHook(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
var ctx = context.FromC(c)
|
var ctx = context.FromC(c)
|
||||||
var host = c.URLParams["host"]
|
var host = c.URLParams["host"]
|
||||||
|
var token = r.FormValue("token")
|
||||||
var remote = remote.Lookup(host)
|
var remote = remote.Lookup(host)
|
||||||
if remote == nil {
|
if remote == nil {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
@ -52,6 +54,14 @@ func PostHook(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// each hook contains a token to verify the sender. If the token
|
||||||
|
// is not provided or does not match, exit
|
||||||
|
if len(repo.Token) == 0 || repo.Token != token {
|
||||||
|
log.Printf("Rejected post commit hook for %s. Token mismatch\n", repo.Name)
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if repo.Active == false ||
|
if repo.Active == false ||
|
||||||
(repo.PostCommit == false && len(hook.PullRequest) == 0) ||
|
(repo.PostCommit == false && len(hook.PullRequest) == 0) ||
|
||||||
(repo.PullRequest == false && len(hook.PullRequest) != 0) {
|
(repo.PullRequest == false && len(hook.PullRequest) != 0) {
|
||||||
|
|
|
@ -80,6 +80,7 @@ func PostRepo(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
repo.PostCommit = true
|
repo.PostCommit = true
|
||||||
repo.UserID = user.ID
|
repo.UserID = user.ID
|
||||||
repo.Timeout = 3600 // default to 1 hour
|
repo.Timeout = 3600 // default to 1 hour
|
||||||
|
repo.Token = model.GenerateToken()
|
||||||
|
|
||||||
// generates the rsa key
|
// generates the rsa key
|
||||||
key, err := sshutil.GeneratePrivateKey()
|
key, err := sshutil.GeneratePrivateKey()
|
||||||
|
@ -98,7 +99,7 @@ func PostRepo(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// setup the post-commit hook with the remote system and
|
// setup the post-commit hook with the remote system and
|
||||||
// if necessary, register the public key
|
// if necessary, register the public key
|
||||||
var hook = fmt.Sprintf("%s/api/hook/%s", httputil.GetURL(r), repo.Remote)
|
var hook = fmt.Sprintf("%s/api/hook/%s?token=%s", httputil.GetURL(r), repo.Remote, repo.Token)
|
||||||
if err := remote.Activate(user, repo, hook); err != nil {
|
if err := remote.Activate(user, repo, hook); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|
|
@ -26,7 +26,7 @@ type Commit struct {
|
||||||
// SetAuthor sets the author's email address and calculate the Gravatar hash.
|
// SetAuthor sets the author's email address and calculate the Gravatar hash.
|
||||||
func (c *Commit) SetAuthor(email string) {
|
func (c *Commit) SetAuthor(email string) {
|
||||||
c.Author = email
|
c.Author = email
|
||||||
c.Gravatar = createGravatar(email)
|
c.Gravatar = CreateGravatar(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the Short (--short) Commit Hash.
|
// Returns the Short (--short) Commit Hash.
|
||||||
|
|
|
@ -18,6 +18,7 @@ type RepoParams map[string]string
|
||||||
type Repo struct {
|
type Repo struct {
|
||||||
ID int64 `meddler:"repo_id,pk" json:"-"`
|
ID int64 `meddler:"repo_id,pk" json:"-"`
|
||||||
UserID int64 `meddler:"user_id" json:"-"`
|
UserID int64 `meddler:"user_id" json:"-"`
|
||||||
|
Token string `meddler:"repo_token" json:"-"`
|
||||||
Remote string `meddler:"repo_remote" json:"remote"`
|
Remote string `meddler:"repo_remote" json:"remote"`
|
||||||
Host string `meddler:"repo_host" json:"host"`
|
Host string `meddler:"repo_host" json:"host"`
|
||||||
Owner string `meddler:"repo_owner" json:"owner"`
|
Owner string `meddler:"repo_owner" json:"owner"`
|
||||||
|
|
|
@ -24,7 +24,7 @@ type User struct {
|
||||||
|
|
||||||
func NewUser(remote, login, email string) *User {
|
func NewUser(remote, login, email string) *User {
|
||||||
user := User{}
|
user := User{}
|
||||||
user.Token = generateToken()
|
user.Token = GenerateToken()
|
||||||
user.Login = login
|
user.Login = login
|
||||||
user.Remote = remote
|
user.Remote = remote
|
||||||
user.Active = true
|
user.Active = true
|
||||||
|
@ -35,7 +35,7 @@ func NewUser(remote, login, email string) *User {
|
||||||
// SetEmail sets the email address and calculate the Gravatar hash.
|
// SetEmail sets the email address and calculate the Gravatar hash.
|
||||||
func (u *User) SetEmail(email string) {
|
func (u *User) SetEmail(email string) {
|
||||||
u.Email = email
|
u.Email = email
|
||||||
u.Gravatar = createGravatar(email)
|
u.Gravatar = CreateGravatar(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) IsStale() bool {
|
func (u *User) IsStale() bool {
|
||||||
|
|
|
@ -14,9 +14,9 @@ var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567
|
||||||
// default token length
|
// default token length
|
||||||
var length = 40
|
var length = 40
|
||||||
|
|
||||||
// generateToken generates random strings good for use in URIs to
|
// GenerateToken generates random strings good for use in URIs to
|
||||||
// identify unique objects.
|
// identify unique objects.
|
||||||
func generateToken() string {
|
func GenerateToken() string {
|
||||||
b := make([]byte, length)
|
b := make([]byte, length)
|
||||||
r := make([]byte, length+(length/4)) // storage for random bytes.
|
r := make([]byte, length+(length/4)) // storage for random bytes.
|
||||||
clen := byte(len(chars))
|
clen := byte(len(chars))
|
||||||
|
@ -40,7 +40,7 @@ func generateToken() string {
|
||||||
|
|
||||||
// helper function to create a Gravatar Hash
|
// helper function to create a Gravatar Hash
|
||||||
// for the given Email address.
|
// for the given Email address.
|
||||||
func createGravatar(email string) string {
|
func CreateGravatar(email string) string {
|
||||||
email = strings.ToLower(strings.TrimSpace(email))
|
email = strings.ToLower(strings.TrimSpace(email))
|
||||||
hash := md5.New()
|
hash := md5.New()
|
||||||
hash.Write([]byte(email))
|
hash.Write([]byte(email))
|
||||||
|
|
|
@ -4,15 +4,15 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_createGravatar(t *testing.T) {
|
func Test_CreateGravatar(t *testing.T) {
|
||||||
var got, want = createGravatar("dr_cooper@caltech.edu"), "2b77ba83e2216ddcd11fe8c24b70c2a3"
|
var got, want = CreateGravatar("dr_cooper@caltech.edu"), "2b77ba83e2216ddcd11fe8c24b70c2a3"
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("Got gravatar hash %s, want %s", got, want)
|
t.Errorf("Got gravatar hash %s, want %s", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_generateToken(t *testing.T) {
|
func Test_GenerateToken(t *testing.T) {
|
||||||
token := generateToken()
|
token := GenerateToken()
|
||||||
if len(token) != length {
|
if len(token) != length {
|
||||||
t.Errorf("Want token length %d, got %d", length, len(token))
|
t.Errorf("Want token length %d, got %d", length, len(token))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue