Browse Source

Merge branch 'master' into kegan/github-webhook

kegan/github-webhook
Kegan Dougal 8 years ago
parent
commit
51a5b97aad
  1. 26
      src/github.com/matrix-org/go-neb/api.go
  2. 13
      src/github.com/matrix-org/go-neb/auth/auth.go
  3. 22
      src/github.com/matrix-org/go-neb/auth/github/github.go
  4. 32
      src/github.com/matrix-org/go-neb/database/db.go
  5. 46
      src/github.com/matrix-org/go-neb/database/schema.go
  6. 5
      src/github.com/matrix-org/go-neb/goneb.go
  7. 36
      src/github.com/matrix-org/go-neb/types/types.go

26
src/github.com/matrix-org/go-neb/api.go

@ -17,6 +17,32 @@ func (*heartbeatHandler) OnIncomingRequest(req *http.Request) (interface{}, *err
return &struct{}{}, nil
}
type configureAuthHandler struct {
db *database.ServiceDB
}
func (*configureAuthHandler) OnIncomingRequest(req *http.Request) (interface{}, *errors.HTTPError) {
if req.Method != "POST" {
return nil, &errors.HTTPError{nil, "Unsupported Method", 405}
}
var tpa types.ThirdPartyAuth
if err := json.NewDecoder(req.Body).Decode(&tpa); err != nil {
return nil, &errors.HTTPError{err, "Error parsing request JSON", 400}
}
am := types.GetAuthModule(tpa.Type)
if am == nil {
return nil, &errors.HTTPError{nil, "Bad auth type: " + tpa.Type, 400}
}
err := am.Process(tpa)
if err != nil {
return nil, &errors.HTTPError{err, "Failed to persist auth", 500}
}
return nil, nil
}
type webhookHandler struct {
db *database.ServiceDB
clients *clients.Clients

13
src/github.com/matrix-org/go-neb/auth/auth.go

@ -0,0 +1,13 @@
package auth
import (
"github.com/matrix-org/go-neb/auth/github"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/types"
)
// RegisterModules registers all known modules so they can be retrieved via
// type.GetAuthModule
func RegisterModules(db *database.ServiceDB) {
types.RegisterAuthModule(&github.AuthModule{Database: db})
}

22
src/github.com/matrix-org/go-neb/auth/github/github.go

@ -0,0 +1,22 @@
package github
import (
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/types"
)
// AuthModule for github
type AuthModule struct {
Database *database.ServiceDB
}
// Type of the auth module
func (*AuthModule) Type() string {
return "github"
}
// Process a third-party auth request
func (am *AuthModule) Process(tpa types.ThirdPartyAuth) (err error) {
_, err = am.Database.StoreThirdPartyAuth(tpa)
return
}

32
src/github.com/matrix-org/go-neb/database/db.go

@ -95,6 +95,38 @@ func (d *ServiceDB) LoadServicesInRoom(serviceUserID, roomID string) (services [
return
}
// LoadThirdPartyAuth loads third-party credentials that the given userID
// has linked to the given resource. Returns sql.ErrNoRows if there are no
// credentials for the given resource/user combination.
func (d *ServiceDB) LoadThirdPartyAuth(resource, userID string) (tpa types.ThirdPartyAuth, err error) {
err = runTransaction(d.db, func(txn *sql.Tx) error {
tpa, err = selectThirdPartyAuthTxn(txn, resource, userID)
if err != nil {
return err
}
return nil
})
return
}
// StoreThirdPartyAuth stores the ThirdPartyAuth for the given Service. Updates the
// time added/updated values.
// If the auth already exists then it will be updated, otherwise a new auth
// will be inserted. The previous auth is returned.
func (d *ServiceDB) StoreThirdPartyAuth(tpa types.ThirdPartyAuth) (old types.ThirdPartyAuth, err error) {
err = runTransaction(d.db, func(txn *sql.Tx) error {
old, err = selectThirdPartyAuthTxn(txn, tpa.Resource, tpa.UserID)
if err == sql.ErrNoRows {
return insertThirdPartyAuthTxn(txn, tpa)
} else if err != nil {
return err
} else {
return updateThirdPartyAuthTxn(txn, tpa)
}
})
return
}
// StoreService stores a service into the database either by inserting a new
// service or updating an existing service. Returns the old service if there
// was one.

46
src/github.com/matrix-org/go-neb/database/schema.go

@ -34,6 +34,16 @@ CREATE TABLE IF NOT EXISTS matrix_clients (
time_updated_ms BIGINT NOT NULL,
UNIQUE(user_id)
);
CREATE TABLE IF NOT EXISTS third_party_auth (
user_id TEXT NOT NULL,
type TEXT NOT NULL,
resource TEXT NOT NULL,
auth_json TEXT NOT NULL,
time_added_ms BIGINT NOT NULL,
time_updated_ms BIGINT NOT NULL,
UNIQUE(user_id, resource)
);
`
const selectServiceUserIDsSQL = `
@ -201,3 +211,39 @@ func selectRoomServicesTxn(txn *sql.Tx, serviceUserID, roomID string) (serviceID
}
return
}
const selectThirdPartyAuthSQL = `
SELECT type, auth_json FROM third_party_auth WHERE user_id=$1 AND resource=$2
`
func selectThirdPartyAuthTxn(txn *sql.Tx, resource, userID string) (tpa types.ThirdPartyAuth, err error) {
tpa.Resource = resource
tpa.UserID = userID
err = txn.QueryRow(selectThirdPartyAuthSQL, userID, resource).Scan(&tpa.Type, &tpa.AuthJSON)
return
}
const insertThirdPartyAuthSQL = `
INSERT INTO third_party_auth(
user_id, type, resource, auth_json, time_added_ms, time_updated_ms
) VALUES($1, $2, $3, $4, $5, $6)
`
func insertThirdPartyAuthTxn(txn *sql.Tx, tpa types.ThirdPartyAuth) (err error) {
timeAddedMs := time.Now().UnixNano() / 1000000
_, err = txn.Exec(insertThirdPartyAuthSQL, tpa.UserID, tpa.Type, tpa.Resource,
[]byte(tpa.AuthJSON), timeAddedMs, timeAddedMs)
return
}
const updateThirdPartyAuthSQL = `
UPDATE third_party_auth SET auth_json=$1, time_updated_ms=$2
WHERE user_id=$3 AND resource=$4
`
func updateThirdPartyAuthTxn(txn *sql.Tx, tpa types.ThirdPartyAuth) (err error) {
timeUpdatedMs := time.Now().UnixNano() / 1000000
_, err = txn.Exec(updateThirdPartyAuthSQL, []byte(tpa.AuthJSON), timeUpdatedMs,
tpa.UserID, tpa.Resource)
return err
}

5
src/github.com/matrix-org/go-neb/goneb.go

@ -2,6 +2,7 @@ package main
import (
log "github.com/Sirupsen/logrus"
"github.com/matrix-org/go-neb/auth"
"github.com/matrix-org/go-neb/clients"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/server"
@ -28,10 +29,12 @@ func main() {
log.Panic(err)
}
auth.RegisterModules(db)
http.Handle("/test", server.MakeJSONAPI(&heartbeatHandler{}))
http.Handle("/admin/configureClient", server.MakeJSONAPI(&configureClientHandler{db: db, clients: clients}))
http.Handle("/admin/configureService", server.MakeJSONAPI(&configureServiceHandler{db: db, clients: clients}))
http.Handle("/admin/configureAuth", server.MakeJSONAPI(&configureAuthHandler{db: db}))
wh := &webhookHandler{db: db, clients: clients}
http.HandleFunc("/services/hooks/", wh.handle)

36
src/github.com/matrix-org/go-neb/types/types.go

@ -1,6 +1,7 @@
package types
import (
"encoding/json"
"errors"
"github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/plugin"
@ -52,3 +53,38 @@ func CreateService(serviceID, serviceType string) Service {
}
return f(serviceID)
}
// AuthModule represents a thing which can handle auth requests of a given type.
type AuthModule interface {
Type() string
Process(tpa ThirdPartyAuth) error
}
var authModulesByType = map[string]AuthModule{}
// ThirdPartyAuth represents an individual authorisation entry between
// a third party and the Matrix user.
type ThirdPartyAuth struct {
// The ID of the matrix user who has authed with the third party
UserID string
// The type of auth (e.g. "jira", "github"). This determines which
// auth module is loaded to process the auth.
Type string
// The location of the third party resource e.g. "github.com".
// This is mainly relevant for decentralised services like JIRA which
// may have many different locations (e.g. "matrix.org/jira") for the
// same ServiceType ("jira").
Resource string
// An opaque JSON blob of stored auth data.
AuthJSON json.RawMessage
}
// RegisterAuthModule so it can be used by other parts of NEB.
func RegisterAuthModule(am AuthModule) {
authModulesByType[am.Type()] = am
}
// GetAuthModule for the given auth type. Returns nil if no match.
func GetAuthModule(authType string) AuthModule {
return authModulesByType[authType]
}
Loading…
Cancel
Save