added token to post-commit hooks

This commit is contained in:
Brad Rydzewski 2014-10-22 00:13:47 -07:00
parent dfb0210cf5
commit 7009778176
11 changed files with 172 additions and 13 deletions

View file

@ -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

View file

@ -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)

View file

@ -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)
} }

View 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)
);
`

View file

@ -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) {

View file

@ -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

View file

@ -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.

View file

@ -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"`

View file

@ -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 {

View file

@ -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))

View file

@ -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))
} }