2014-06-12 23:41:04 +00:00
|
|
|
package database
|
2014-06-04 21:25:38 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"time"
|
|
|
|
|
2014-06-12 23:41:04 +00:00
|
|
|
"github.com/drone/drone/shared/model"
|
2014-06-04 21:25:38 +00:00
|
|
|
"github.com/russross/meddler"
|
|
|
|
)
|
|
|
|
|
|
|
|
type PermManager interface {
|
|
|
|
// Grant will grant the user read, write and admin persmissions
|
|
|
|
// to the specified repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
Grant(u *model.User, r *model.Repo, read, write, admin bool) error
|
2014-06-04 21:25:38 +00:00
|
|
|
|
|
|
|
// Revoke will revoke all user permissions to the specified repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
Revoke(u *model.User, r *model.Repo) error
|
2014-06-04 21:25:38 +00:00
|
|
|
|
2014-07-13 22:23:33 +00:00
|
|
|
// Find returns the user's permission to access the specified repository.
|
|
|
|
Find(u *model.User, r *model.Repo) *model.Perm
|
|
|
|
|
2014-06-04 21:25:38 +00:00
|
|
|
// Read returns true if the specified user has read
|
|
|
|
// access to the repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
Read(u *model.User, r *model.Repo) (bool, error)
|
2014-06-04 21:25:38 +00:00
|
|
|
|
|
|
|
// Write returns true if the specified user has write
|
|
|
|
// access to the repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
Write(u *model.User, r *model.Repo) (bool, error)
|
2014-06-04 21:25:38 +00:00
|
|
|
|
|
|
|
// Admin returns true if the specified user is an
|
|
|
|
// administrator of the repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
Admin(u *model.User, r *model.Repo) (bool, error)
|
2014-06-22 09:04:07 +00:00
|
|
|
|
|
|
|
// Member returns true if the specified user is a
|
|
|
|
// collaborator on the repository.
|
|
|
|
Member(u *model.User, r *model.Repo) (bool, error)
|
2014-06-04 21:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// permManager manages user permissions to access repositories.
|
|
|
|
type permManager struct {
|
|
|
|
*sql.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
// SQL query to retrieve a user's permission to
|
|
|
|
// access a repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
const findPermQuery = `
|
2014-06-04 21:25:38 +00:00
|
|
|
SELECT *
|
|
|
|
FROM perms
|
|
|
|
WHERE user_id=?
|
|
|
|
AND repo_id=?
|
|
|
|
LIMIT 1
|
|
|
|
`
|
|
|
|
|
|
|
|
// SQL statement to delete a permission.
|
2014-06-12 23:41:04 +00:00
|
|
|
const deletePermStmt = `
|
2014-06-04 21:25:38 +00:00
|
|
|
DELETE FROM perms WHERE user_id=? AND repo_id=?
|
|
|
|
`
|
|
|
|
|
|
|
|
// NewManager initiales a new PermManager intended to
|
|
|
|
// manage user permission and access control.
|
2014-06-12 23:41:04 +00:00
|
|
|
func NewPermManager(db *sql.DB) PermManager {
|
2014-06-04 21:25:38 +00:00
|
|
|
return &permManager{db}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grant will grant the user read, write and admin persmissions
|
|
|
|
// to the specified repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
func (db *permManager) Grant(u *model.User, r *model.Repo, read, write, admin bool) error {
|
2014-06-04 21:25:38 +00:00
|
|
|
// attempt to get existing permissions from the database
|
|
|
|
perm, err := db.find(u, r)
|
|
|
|
if err != nil && err != sql.ErrNoRows {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// if this is a new permission set the user ID,
|
|
|
|
// repository ID and created timestamp.
|
|
|
|
if perm.ID == 0 {
|
|
|
|
perm.UserID = u.ID
|
|
|
|
perm.RepoID = r.ID
|
|
|
|
perm.Created = time.Now().Unix()
|
|
|
|
}
|
|
|
|
|
|
|
|
// set all the permission values
|
|
|
|
perm.Read = read
|
|
|
|
perm.Write = write
|
|
|
|
perm.Admin = admin
|
|
|
|
perm.Updated = time.Now().Unix()
|
|
|
|
|
|
|
|
// update the database
|
|
|
|
return meddler.Save(db, "perms", perm)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Revoke will revoke all user permissions to the specified repository.
|
2014-06-12 23:41:04 +00:00
|
|
|
func (db *permManager) Revoke(u *model.User, r *model.Repo) error {
|
|
|
|
_, err := db.Exec(deletePermStmt, u.ID, r.ID)
|
2014-06-04 21:25:38 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-07-13 22:23:33 +00:00
|
|
|
func (db *permManager) Find(u *model.User, r *model.Repo) *model.Perm {
|
|
|
|
// if the user is a gues they should only be granted
|
|
|
|
// read access to public repositories.
|
|
|
|
switch {
|
|
|
|
case u == nil && r.Private:
|
|
|
|
return &model.Perm{
|
|
|
|
Read: false,
|
|
|
|
Write: false,
|
|
|
|
Admin: false}
|
|
|
|
case u == nil && !r.Private:
|
|
|
|
return &model.Perm{
|
|
|
|
Read: true,
|
|
|
|
Write: false,
|
|
|
|
Admin: false}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the user is authenticated we'll retireive the
|
|
|
|
// permission details from the database.
|
|
|
|
perm, err := db.find(u, r)
|
|
|
|
if err != nil {
|
|
|
|
return perm
|
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
// if the user is a system admin grant super access.
|
|
|
|
case u.Admin == true:
|
|
|
|
perm.Read = true
|
|
|
|
perm.Write = true
|
|
|
|
perm.Admin = true
|
|
|
|
|
|
|
|
// if the repo is public, grant read access only.
|
|
|
|
case r.Private == false:
|
|
|
|
perm.Read = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return perm
|
|
|
|
}
|
|
|
|
|
2014-06-12 23:41:04 +00:00
|
|
|
func (db *permManager) Read(u *model.User, r *model.Repo) (bool, error) {
|
2014-06-04 21:25:38 +00:00
|
|
|
switch {
|
|
|
|
// if the repo is public, grant access.
|
|
|
|
case r.Private == false:
|
|
|
|
return true, nil
|
|
|
|
// if the repo is private and the user is nil, deny access
|
|
|
|
case r.Private == true && u == nil:
|
|
|
|
return false, nil
|
|
|
|
// if the user is a system admin, grant access
|
|
|
|
case u.Admin == true:
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the permissions from the database
|
|
|
|
perm, err := db.find(u, r)
|
|
|
|
return perm.Read, err
|
|
|
|
}
|
|
|
|
|
2014-06-12 23:41:04 +00:00
|
|
|
func (db *permManager) Write(u *model.User, r *model.Repo) (bool, error) {
|
2014-06-04 21:25:38 +00:00
|
|
|
switch {
|
|
|
|
// if the user is nil, deny access
|
|
|
|
case u == nil:
|
|
|
|
return false, nil
|
|
|
|
// if the user is a system admin, grant access
|
|
|
|
case u.Admin == true:
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the permissions from the database
|
|
|
|
perm, err := db.find(u, r)
|
|
|
|
return perm.Write, err
|
|
|
|
}
|
|
|
|
|
2014-06-12 23:41:04 +00:00
|
|
|
func (db *permManager) Admin(u *model.User, r *model.Repo) (bool, error) {
|
2014-06-04 21:25:38 +00:00
|
|
|
switch {
|
|
|
|
// if the user is nil, deny access
|
|
|
|
case u == nil:
|
|
|
|
return false, nil
|
|
|
|
// if the user is a system admin, grant access
|
|
|
|
case u.Admin == true:
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the permissions from the database
|
|
|
|
perm, err := db.find(u, r)
|
|
|
|
return perm.Admin, err
|
|
|
|
}
|
|
|
|
|
2014-06-22 09:04:07 +00:00
|
|
|
func (db *permManager) Member(u *model.User, r *model.Repo) (bool, error) {
|
|
|
|
switch {
|
|
|
|
// if the user is nil, deny access
|
|
|
|
case u == nil:
|
|
|
|
return false, nil
|
|
|
|
case u.ID == r.UserID:
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the permissions from the database
|
|
|
|
perm, err := db.find(u, r)
|
|
|
|
return perm.Read, err
|
|
|
|
}
|
|
|
|
|
2014-07-13 22:23:33 +00:00
|
|
|
func (db *permManager) find(u *model.User, r *model.Repo) (*model.Perm, error) {
|
|
|
|
var dst = model.Perm{}
|
2014-06-12 23:41:04 +00:00
|
|
|
var err = meddler.QueryRow(db, &dst, findPermQuery, u.ID, r.ID)
|
2014-06-04 21:25:38 +00:00
|
|
|
return &dst, err
|
|
|
|
}
|