Browse Source

Merge pull request #118 from matrix-org/kegan/realm-docs

Add realm documentation
kegan/guggy-tests
Kegsay 8 years ago
committed by GitHub
parent
commit
38350ede7f
  1. 103
      README.md
  2. 125
      src/github.com/matrix-org/go-neb/realms/github/github.go
  3. 182
      src/github.com/matrix-org/go-neb/realms/jira/jira.go
  4. 10
      src/github.com/matrix-org/go-neb/services/github/github.go
  5. 12
      src/github.com/matrix-org/go-neb/services/github/github_webhook.go
  6. 28
      src/github.com/matrix-org/go-neb/services/jira/jira.go
  7. 23
      src/github.com/matrix-org/go-neb/services/jira/webhook/webhook.go

103
README.md

@ -122,7 +122,7 @@ service you're interested in for the additional keys, if any.
- [HTTP API Docs](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/api/handlers/index.html#ConfigureService.OnIncomingRequest)
- [JSON Request Body Docs](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/api/index.html#ConfigureServiceRequest)
List of services:
List of Services:
- [Echo](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/services/echo/) - An example service
- [Giphy](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/services/giphy/) - A GIF bot
- [Github](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/services/github/) - A Github bot
@ -138,102 +138,21 @@ Realms are how Go-NEB authenticates users on third-party websites.
- [HTTP API Docs](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/api/handlers/index.html#ConfigureAuthRealm.OnIncomingRequest)
- [JSON Request Body Docs](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/api/index.html#ConfigureAuthRealmRequest)
### Github Realm
This has the `Type` of `github`. To set up this realm:
```bash
curl -X POST localhost:4050/admin/configureAuthRealm --data-binary '{
"ID": "mygithubrealm",
"Type": "github",
"Config": {
"ClientSecret": "YOUR_CLIENT_SECRET",
"ClientID": "YOUR_CLIENT_ID",
"StarterLink": "https://example.com/requestGithubOAuthToken"
}
}'
```
- `ClientSecret`: Your Github application client secret
- `ClientID`: Your Github application client ID
- `StarterLink`: Optional. If supplied, `!github` commands will return this link whenever someone is prompted to login to Github.
#### Github authentication
Once you have configured a Github realm, you can associate any Matrix user ID with any Github user. To do this:
```bash
curl -X POST localhost:4050/admin/requestAuthSession --data-binary '{
"RealmID": "mygithubrealm",
"UserID": "@real_matrix_user:localhost",
"Config": {
"RedirectURL": "https://optional-url.com/to/redirect/to/after/auth"
}
}'
```
- `UserID`: The Matrix user ID to associate with.
- `RedirectURL`: Optional. The URL to redirect to after authentication.
This request will return an OAuth URL:
```json
{
"URL": "https://github.com/login/oauth/authorize?client_id=abcdef&client_secret=acascacac...."
}
```
Follow this link to associate this user ID with this Github account. Once this is complete, Go-NEB will have an OAuth token for this user ID and will be able to create issues as their real Github account.
### Github
- [Realm configuration](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/realms/github/index.html#Realm)
To remove this session:
#### Authentication of Matrix users
```bash
curl -X POST localhost:4050/admin/removeAuthSession --data-binary '{
"RealmID": "mygithubrealm",
"UserID": "@real_matrix_user:localhost",
"Config": {}
}'
```
### JIRA Realm
This has the `Type` of `jira`. To set up this realm:
```bash
curl -X POST localhost:4050/admin/configureAuthRealm --data-binary '{
"ID": "jirarealm",
"Type": "jira",
"Config": {
"JIRAEndpoint": "matrix.org/jira/",
"ConsumerName": "goneb",
"ConsumerKey": "goneb",
"ConsumerSecret": "random_long_string",
"PrivateKeyPEM": "-----BEGIN RSA PRIVATE KEY-----\r\nMIIEowIBAAKCAQEA39UhbOvQHEkBP9fGnhU+eSObTWBDGWygVYzbcONOlqEOTJUN\r\n8gmnellWqJO45S4jB1vLLnuXiHqEWnmaShIvbUem3QnDDqghu0gfqXHMlQr5R8ZP\r\norTt1F2idWy1wk5rVXeLKSG7uriYhDVOVS69WuefoW5v55b5YZV283v2jROjxHuj\r\ngAsJA7k6tvpYiSXApUl6YHmECfBoiwG9bwItkHwhZ\/fG9i4H8\/aOyr3WlaWbVeKX\r\n+m38lmYZvzQFRAk5ab1vzCGz4cyc\r\nTk2qmZpcjHRd1ijcOkgC23KF8lHWF5Zx0tySR+DWL1JeGm8NJxKMRJZuE8MIkJYF\r\nryE7kjspNItk6npkA3\/A4PWwElhddI4JpiuK+29mMNipRcYYy9e0vH\/igejv7ayd\r\nPLCRMQKBgBDSNWlZT0nNd2DXVqTW9p+MG72VKhDgmEwFB1acOw0lpu1XE8R1wmwG\r\nZRl\/xzri3LOW2Gpc77xu6fs3NIkzQw3v1ifYhX3OrVsCIRBbDjPQI3yYjkhGx24s\r\nVhhZ5S\/TkGk3Kw59bDC6KGqAuQAwX9req2l1NiuNaPU9rE7tf6Bk\r\n-----END RSA PRIVATE KEY-----"
}
}'
```
- `JIRAEndpoint`: The base URL of the JIRA installation you wish to talk to.
- `ConsumerName`: The desired "Consumer Name" field of the "Application Links" admin page on JIRA. Generally this is the name of the service. Users will need to enter this string into their JIRA admin web form.
- `ConsumerKey`: The desired "Consumer Key" field of the "Application Links" admin page on JIRA. Generally this is the name of the service. Users will need to enter this string into their JIRA admin web form.
- `ConsumerSecret`: The desired "Consumer Secret" field of the "Application Links" admin page on JIRA. This should be a random long string. Users will need to enter this string into their JIRA admin web form.
- `PrivateKeyPEM`: A string which contains the private key for performing OAuth 1.0 requests. This MUST be in PEM format. It must NOT have a password. Go-NEB will convert this into a **public** key in PEM format and return this to users. Users will need to enter the public key into their JIRA admin web form.
- `StarterLink`: Optional. If supplied, `!jira` commands will return this link whenever someone is prompted to login to JIRA.
To generate a private key PEM: (JIRA does not support bit lengths >2048)
```bash
openssl genrsa -out privkey.pem 2048
cat privkey.pem
```
* [Configuration for config file](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/realms/github/index.html#Session)
* [Configuration for HTTP](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/realms/github/index.html#Realm.RequestAuthSession)
#### JIRA authentication
### JIRA
- [Realm configuration](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/realms/jira/index.html#Realm)
```
curl -X POST localhost:4050/admin/requestAuthSession --data-binary '{
"RealmID": "jirarealm",
"UserID": "@example:localhost",
"Config": {
"RedirectURL": "https://optional-url.com/to/redirect/to/after/auth"
}
}'
```
#### Authentication of Matrix users
* [Configuration for config file](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/realms/jira/index.html#Session)
* [Configuration for HTTP](https://matrix-org.github.io/go-neb/pkg/github.com/matrix-org/go-neb/realms/jira/index.html#Realm.RequestAuthSession)
Returns:
```json
{
"URL":"https://jira.somewhere.com/plugins/servlet/oauth/authorize?oauth_token=7yeuierbgweguiegrTbOT"
}
```
# Developing
There's a bunch more tools this project uses when developing in order to do

125
src/github.com/matrix-org/go-neb/realms/github/github.go

@ -1,48 +1,76 @@
package realms
// Package github implements OAuth2 support for github.com
package github
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
log "github.com/Sirupsen/logrus"
"github.com/google/go-github/github"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/services/github/client"
"github.com/matrix-org/go-neb/types"
"io/ioutil"
"net/http"
"net/url"
)
// GithubRealm can handle OAuth processes with github.com
type GithubRealm struct {
id string
redirectURL string
// RealmType of the Github Realm
const RealmType = "github"
// Realm can handle OAuth processes with github.com
//
// Example request:
// {
// "ClientSecret": "YOUR_CLIENT_SECRET",
// "ClientID": "YOUR_CLIENT_ID"
// }
type Realm struct {
id string
redirectURL string
// The client secret for this Github application.
ClientSecret string
ClientID string
StarterLink string
// The client ID for this Github application.
ClientID string
// Optional. The URL to redirect the client to after authentication.
StarterLink string
}
// GithubSession represents an authenticated github session
type GithubSession struct {
// The client-supplied URL to redirect them to after the auth process is complete.
ClientsRedirectURL string
// AccessToken is the github access token for the user
AccessToken string
// Scopes are the set of *ALLOWED* scopes (which may not be the same as the requested scopes)
Scopes string
// Session represents an authenticated github session
type Session struct {
id string
userID string
realmID string
// AccessToken is the github access token for the user
AccessToken string
// Scopes are the set of *ALLOWED* scopes (which may not be the same as the requested scopes)
Scopes string
// Optional. The client-supplied URL to redirect them to after the auth process is complete.
ClientsRedirectURL string
}
// AuthRequest is a request for authenticating with github.com
type AuthRequest struct {
// Optional. The URL to redirect to after authentication.
RedirectURL string
}
// AuthResponse is a response to an AuthRequest.
type AuthResponse struct {
// The URL to visit to perform OAuth on github.com
URL string
}
// Authenticated returns true if the user has completed the auth process
func (s *GithubSession) Authenticated() bool {
func (s *Session) Authenticated() bool {
return s.AccessToken != ""
}
// Info returns a list of possible repositories that this session can integrate with.
func (s *GithubSession) Info() interface{} {
func (s *Session) Info() interface{} {
logger := log.WithFields(log.Fields{
"user_id": s.userID,
"realm_id": s.realmID,
@ -72,9 +100,9 @@ func (s *GithubSession) Info() interface{} {
break
}
opts.ListOptions.Page = resp.NextPage
logger.Print("GithubSession.Info() Next => ", resp.NextPage)
logger.Print("Session.Info() Next => ", resp.NextPage)
}
logger.Print("GithubSession.Info() Returning ", len(repos), " repos")
logger.Print("Session.Info() Returning ", len(repos), " repos")
return struct {
Repos []client.TrimmedRepository
@ -82,42 +110,53 @@ func (s *GithubSession) Info() interface{} {
}
// UserID returns the user_id who authorised with Github
func (s *GithubSession) UserID() string {
func (s *Session) UserID() string {
return s.userID
}
// RealmID returns the realm ID of the realm which performed the authentication
func (s *GithubSession) RealmID() string {
func (s *Session) RealmID() string {
return s.realmID
}
// ID returns the session ID
func (s *GithubSession) ID() string {
func (s *Session) ID() string {
return s.id
}
// ID returns the realm ID
func (r *GithubRealm) ID() string {
func (r *Realm) ID() string {
return r.id
}
// Type is github
func (r *GithubRealm) Type() string {
return "github"
func (r *Realm) Type() string {
return RealmType
}
// Init does nothing.
func (r *GithubRealm) Init() error {
func (r *Realm) Init() error {
return nil
}
// Register does nothing.
func (r *GithubRealm) Register() error {
func (r *Realm) Register() error {
return nil
}
// RequestAuthSession generates an OAuth2 URL for this user to auth with github via.
func (r *GithubRealm) RequestAuthSession(userID string, req json.RawMessage) interface{} {
// The request body is of type "github.AuthRequest". The response is of type "github.AuthResponse".
//
// Request example:
// {
// "RedirectURL": "https://optional-url.com/to/redirect/to/after/auth"
// }
//
// Response example:
// {
// "URL": "https://github.com/login/oauth/authorize?client_id=abcdef&client_secret=acascacac...."
// }
func (r *Realm) RequestAuthSession(userID string, req json.RawMessage) interface{} {
state, err := randomString(10)
if err != nil {
log.WithError(err).Print("Failed to generate state param")
@ -132,16 +171,14 @@ func (r *GithubRealm) RequestAuthSession(userID string, req json.RawMessage) int
q.Set("redirect_uri", r.redirectURL)
q.Set("scope", "admin:repo_hook,admin:org_hook,repo")
u.RawQuery = q.Encode()
session := &GithubSession{
session := &Session{
id: state, // key off the state for redirects
userID: userID,
realmID: r.ID(),
}
// check if they supplied a redirect URL
var reqBody struct {
RedirectURL string
}
var reqBody AuthRequest
if err = json.Unmarshal(req, &reqBody); err != nil {
log.WithError(err).Print("Failed to decode request body")
return nil
@ -158,13 +195,11 @@ func (r *GithubRealm) RequestAuthSession(userID string, req json.RawMessage) int
return nil
}
return &struct {
URL string
}{u.String()}
return &AuthResponse{u.String()}
}
// OnReceiveRedirect processes OAuth redirect requests from Github
func (r *GithubRealm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request) {
func (r *Realm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request) {
// parse out params from the request
code := req.URL.Query().Get("code")
state := req.URL.Query().Get("state")
@ -183,7 +218,7 @@ func (r *GithubRealm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request
failWith(logger, w, 400, "Provided ?state= param is not recognised.", err)
return
}
ghSession, ok := session.(*GithubSession)
ghSession, ok := session.(*Session)
if !ok {
failWith(logger, w, 500, "Unexpected session found.", nil)
return
@ -228,7 +263,7 @@ func (r *GithubRealm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request
)
}
func (r *GithubRealm) redirectOr(w http.ResponseWriter, code int, msg string, logger *log.Entry, ghSession *GithubSession) {
func (r *Realm) redirectOr(w http.ResponseWriter, code int, msg string, logger *log.Entry, ghSession *Session) {
if ghSession.ClientsRedirectURL != "" {
w.Header().Set("Location", ghSession.ClientsRedirectURL)
w.WriteHeader(302)
@ -239,9 +274,9 @@ func (r *GithubRealm) redirectOr(w http.ResponseWriter, code int, msg string, lo
}
}
// AuthSession returns a GithubSession for this user
func (r *GithubRealm) AuthSession(id, userID, realmID string) types.AuthSession {
return &GithubSession{
// AuthSession returns a Github Session for this user
func (r *Realm) AuthSession(id, userID, realmID string) types.AuthSession {
return &Session{
id: id,
userID: userID,
realmID: realmID,
@ -267,6 +302,6 @@ func randomString(length int) (string, error) {
func init() {
types.RegisterAuthRealm(func(realmID, redirectURL string) types.AuthRealm {
return &GithubRealm{id: realmID, redirectURL: redirectURL}
return &Realm{id: realmID, redirectURL: redirectURL}
})
}

182
src/github.com/matrix-org/go-neb/realms/jira/jira.go

@ -1,4 +1,5 @@
package realms
// Package jira implements OAuth1.0a support for arbitrary JIRA installations.
package jira
import (
"crypto/rsa"
@ -8,84 +9,145 @@ import (
"encoding/pem"
"errors"
"fmt"
"net/http"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/andygrunwald/go-jira"
jira "github.com/andygrunwald/go-jira"
"github.com/dghubble/oauth1"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/realms/jira/urls"
"github.com/matrix-org/go-neb/types"
"golang.org/x/net/context"
"net/http"
"strings"
)
// JIRARealm is an AuthRealm which can process JIRA installations
type JIRARealm struct {
id string
redirectURL string
privateKey *rsa.PrivateKey
JIRAEndpoint string
Server string // clobbered based on /serverInfo request
Version string // clobbered based on /serverInfo request
ConsumerName string
ConsumerKey string
// RealmType of the JIRA realm
const RealmType = "jira"
// Realm is an AuthRealm which can process JIRA installations.
//
// Example request:
// {
// "JIRAEndpoint": "matrix.org/jira/",
// "ConsumerName": "goneb",
// "ConsumerKey": "goneb",
// "ConsumerSecret": "random_long_string",
// "PrivateKeyPEM": "-----BEGIN RSA PRIVATE KEY-----\r\nMIIEowIBAAKCAQEA39UhbOvQHEkBP9fGnhU+eSObTAwX9req2l1NiuNaPU9rE7tf6Bk\r\n-----END RSA PRIVATE KEY-----"
// }
type Realm struct {
id string
redirectURL string
privateKey *rsa.PrivateKey
// The HTTPS URL of the JIRA installation to authenticate with.
JIRAEndpoint string
// The desired "Consumer Name" field of the "Application Links" admin page on JIRA.
// Generally this is the name of the service. Users will need to enter this string
// into their JIRA admin web form.
ConsumerName string
// The desired "Consumer Key" field of the "Application Links" admin page on JIRA.
// Generally this is the name of the service. Users will need to enter this string
// into their JIRA admin web form.
ConsumerKey string
// The desired "Consumer Secret" field of the "Application Links" admin page on JIRA.
// This should be a random long string. Users will need to enter this string into
// their JIRA admin web form.
ConsumerSecret string
PublicKeyPEM string // clobbered based on PrivateKeyPEM
PrivateKeyPEM string
HasWebhook bool // clobbered based on NEB
StarterLink string
// A string which contains the private key for performing OAuth 1.0 requests.
// This MUST be in PEM format. It must NOT have a password. Go-NEB will convert this
// into a public key in PEM format and return this to users. Users will need to enter
// the *public* key into their JIRA admin web form.
//
// To generate a private key PEM: (JIRA does not support bit lengths >2048):
// $ openssl genrsa -out privkey.pem 2048
// $ cat privkey.pem
PrivateKeyPEM string
// Optional. If supplied, !jira commands will return this link whenever someone is
// prompted to login to JIRA.
StarterLink string
// The server name of the JIRA installation from /serverInfo.
// This is an informational field populated by Go-NEB post-creation.
Server string
// The JIRA version string from /serverInfo.
// This is an informational field populated by Go-NEB post-creation.
Version string
// The public key for the given private key. This is populated by Go-NEB.
PublicKeyPEM string
// Internal field. True if this realm has already registered a webhook with the JIRA installation.
HasWebhook bool
}
// JIRASession represents a single authentication session between a user and a JIRA endpoint.
// Session represents a single authentication session between a user and a JIRA endpoint.
// The endpoint is dictated by the realm ID.
type JIRASession struct {
id string // request token
userID string
realmID string
RequestSecret string
AccessToken string
AccessSecret string
ClientsRedirectURL string // where to redirect the client to after auth
type Session struct {
id string // request token
userID string
realmID string
// Configuration fields
// The secret obtained when requesting an authentication session with JIRA.
RequestSecret string
// A JIRA access token for a Matrix user ID.
AccessToken string
// A JIRA access secret for a Matrix user ID.
AccessSecret string
// Optional. The URL to redirect the client to after authentication.
ClientsRedirectURL string
}
// AuthRequest is a request for authenticating with JIRA
type AuthRequest struct {
// Optional. The URL to redirect to after authentication.
RedirectURL string
}
// AuthResponse is a response to an AuthRequest.
type AuthResponse struct {
// The URL to visit to perform OAuth on this JIRA installation.
URL string
}
// Authenticated returns true if the user has completed the auth process
func (s *JIRASession) Authenticated() bool {
func (s *Session) Authenticated() bool {
return s.AccessToken != "" && s.AccessSecret != ""
}
// Info returns nothing
func (s *JIRASession) Info() interface{} {
func (s *Session) Info() interface{} {
return nil
}
// UserID returns the ID of the user performing the authentication.
func (s *JIRASession) UserID() string {
func (s *Session) UserID() string {
return s.userID
}
// RealmID returns the JIRA realm ID which created this session.
func (s *JIRASession) RealmID() string {
func (s *Session) RealmID() string {
return s.realmID
}
// ID returns the OAuth1 request_token which is used when looking up sessions in the redirect
// handler.
func (s *JIRASession) ID() string {
func (s *Session) ID() string {
return s.id
}
// ID returns the ID of this JIRA realm.
func (r *JIRARealm) ID() string {
func (r *Realm) ID() string {
return r.id
}
// Type returns the type of realm this is.
func (r *JIRARealm) Type() string {
return "jira"
func (r *Realm) Type() string {
return RealmType
}
// Init initialises the private key for this JIRA realm.
func (r *JIRARealm) Init() error {
func (r *Realm) Init() error {
if err := r.parsePrivateKey(); err != nil {
log.WithError(err).Print("Failed to parse private key")
return err
@ -101,7 +163,7 @@ func (r *JIRARealm) Init() error {
}
// Register is called when this realm is being created from an external entity
func (r *JIRARealm) Register() error {
func (r *Realm) Register() error {
if r.ConsumerName == "" || r.ConsumerKey == "" || r.ConsumerSecret == "" || r.PrivateKeyPEM == "" {
return errors.New("ConsumerName, ConsumerKey, ConsumerSecret, PrivateKeyPEM must be specified.")
}
@ -130,14 +192,22 @@ func (r *JIRARealm) Register() error {
return nil
}
// RequestAuthSession is called by a user wishing to auth with this JIRA realm
func (r *JIRARealm) RequestAuthSession(userID string, req json.RawMessage) interface{} {
// RequestAuthSession is called by a user wishing to auth with this JIRA realm.
// The request body is of type "jira.AuthRequest". Returns a "jira.AuthResponse".
//
// Request example:
// {
// "RedirectURL": "https://somewhere.somehow"
// }
// Response example:
// {
// "URL": "https://jira.somewhere.com/plugins/servlet/oauth/authorize?oauth_token=7yeuierbgweguiegrTbOT"
// }
func (r *Realm) RequestAuthSession(userID string, req json.RawMessage) interface{} {
logger := log.WithField("jira_url", r.JIRAEndpoint)
// check if they supplied a redirect URL
var reqBody struct {
RedirectURL string
}
var reqBody AuthRequest
if err := json.Unmarshal(req, &reqBody); err != nil {
log.WithError(err).Print("Failed to decode request body")
return nil
@ -156,7 +226,7 @@ func (r *JIRARealm) RequestAuthSession(userID string, req json.RawMessage) inter
return nil
}
_, err = database.GetServiceDB().StoreAuthSession(&JIRASession{
_, err = database.GetServiceDB().StoreAuthSession(&Session{
id: reqToken,
userID: userID,
realmID: r.id,
@ -168,13 +238,11 @@ func (r *JIRARealm) RequestAuthSession(userID string, req json.RawMessage) inter
return nil
}
return &struct {
URL string
}{authURL.String()}
return &AuthResponse{authURL.String()}
}
// OnReceiveRedirect is called when JIRA installations redirect back to NEB
func (r *JIRARealm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request) {
func (r *Realm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request) {
logger := log.WithField("jira_url", r.JIRAEndpoint)
requestToken, verifier, err := oauth1.ParseAuthorizationCallback(req)
@ -190,7 +258,7 @@ func (r *JIRARealm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request)
failWith(logger, w, 400, "Unrecognised request token", err)
return
}
jiraSession, ok := session.(*JIRASession)
jiraSession, ok := session.(*Session)
if !ok {
failWith(logger, w, 500, "Unexpected session type found.", nil)
return
@ -230,8 +298,8 @@ func (r *JIRARealm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request)
}
// AuthSession returns a JIRASession with the given parameters
func (r *JIRARealm) AuthSession(id, userID, realmID string) types.AuthSession {
return &JIRASession{
func (r *Realm) AuthSession(id, userID, realmID string) types.AuthSession {
return &Session{
id: id,
userID: userID,
realmID: realmID,
@ -242,7 +310,7 @@ func (r *JIRARealm) AuthSession(id, userID, realmID string) types.AuthSession {
// An authenticated client for userID will be used if one exists, else an
// unauthenticated client will be used, which may not be able to see the complete list
// of projects.
func (r *JIRARealm) ProjectKeyExists(userID, projectKey string) (bool, error) {
func (r *Realm) ProjectKeyExists(userID, projectKey string) (bool, error) {
cli, err := r.JIRAClient(userID, true)
if err != nil {
return false, err
@ -276,7 +344,7 @@ func (r *JIRARealm) ProjectKeyExists(userID, projectKey string) (bool, error) {
// JIRAClient returns an authenticated jira.Client for the given userID. Returns an unauthenticated
// client if allowUnauth is true and no authenticated session is found, else returns an error.
func (r *JIRARealm) JIRAClient(userID string, allowUnauth bool) (*jira.Client, error) {
func (r *Realm) JIRAClient(userID string, allowUnauth bool) (*jira.Client, error) {
// Check if user has an auth session.
session, err := database.GetServiceDB().LoadAuthSessionByUser(r.id, userID)
if err != nil {
@ -289,9 +357,9 @@ func (r *JIRARealm) JIRAClient(userID string, allowUnauth bool) (*jira.Client, e
return nil, err
}
jsession, ok := session.(*JIRASession)
jsession, ok := session.(*Session)
if !ok {
return nil, errors.New("Failed to cast user session to a JIRASession")
return nil, errors.New("Failed to cast user session to a Session")
}
// Make sure they finished the auth process
if jsession.AccessSecret == "" || jsession.AccessToken == "" {
@ -310,7 +378,7 @@ func (r *JIRARealm) JIRAClient(userID string, allowUnauth bool) (*jira.Client, e
return jira.NewClient(httpClient, r.JIRAEndpoint)
}
func (r *JIRARealm) parsePrivateKey() error {
func (r *Realm) parsePrivateKey() error {
if r.privateKey != nil {
return nil
}
@ -327,7 +395,7 @@ func (r *JIRARealm) parsePrivateKey() error {
return nil
}
func (r *JIRARealm) oauth1Config(jiraBaseURL string) *oauth1.Config {
func (r *Realm) oauth1Config(jiraBaseURL string) *oauth1.Config {
return &oauth1.Config{
ConsumerKey: r.ConsumerKey,
ConsumerSecret: r.ConsumerSecret,
@ -402,6 +470,6 @@ func failWith(logger *log.Entry, w http.ResponseWriter, code int, msg string, er
func init() {
types.RegisterAuthRealm(func(realmID, redirectURL string) types.AuthRealm {
return &JIRARealm{id: realmID, redirectURL: redirectURL}
return &Realm{id: realmID, redirectURL: redirectURL}
})
}

10
src/github.com/matrix-org/go-neb/services/github/github.go

@ -12,7 +12,7 @@ import (
"strings"
log "github.com/Sirupsen/logrus"
"github.com/google/go-github/github"
gogithub "github.com/google/go-github/github"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/realms/github"
@ -61,7 +61,7 @@ func (s *Service) cmdGithubCreate(roomID, userID string, args []string) (interfa
if err != nil {
return nil, err
}
ghRealm, ok := r.(*realms.GithubRealm)
ghRealm, ok := r.(*github.Realm)
if !ok {
return nil, fmt.Errorf("Failed to cast realm %s into a GithubRealm", s.RealmID)
}
@ -115,7 +115,7 @@ func (s *Service) cmdGithubCreate(roomID, userID string, args []string) (interfa
title = &joinedTitle
}
issue, res, err := cli.Issues.Create(ownerRepoGroups[1], ownerRepoGroups[2], &github.IssueRequest{
issue, res, err := cli.Issues.Create(ownerRepoGroups[1], ownerRepoGroups[2], &gogithub.IssueRequest{
Title: title,
Body: desc,
})
@ -268,7 +268,7 @@ func (s *Service) defaultRepo(roomID string) string {
return defaultRepo
}
func (s *Service) githubClientFor(userID string, allowUnauth bool) *github.Client {
func (s *Service) githubClientFor(userID string, allowUnauth bool) *gogithub.Client {
token, err := getTokenForUser(s.RealmID, userID)
if err != nil {
log.WithFields(log.Fields{
@ -300,7 +300,7 @@ func getTokenForUser(realmID, userID string) (string, error) {
if err != nil {
return "", err
}
ghSession, ok := session.(*realms.GithubSession)
ghSession, ok := session.(*github.Session)
if !ok {
return "", fmt.Errorf("Session is not a github session: %s", session.ID())
}

12
src/github.com/matrix-org/go-neb/services/github/github_webhook.go

@ -7,7 +7,7 @@ import (
"strings"
log "github.com/Sirupsen/logrus"
"github.com/google/go-github/github"
gogithub "github.com/google/go-github/github"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/services/github/client"
@ -285,7 +285,7 @@ func (s *WebhookService) repoList() []string {
return repos
}
func (s *WebhookService) createHook(cli *github.Client, ownerRepo string) error {
func (s *WebhookService) createHook(cli *gogithub.Client, ownerRepo string) error {
o := strings.Split(ownerRepo, "/")
owner := o[0]
repo := o[1]
@ -299,14 +299,14 @@ func (s *WebhookService) createHook(cli *github.Client, ownerRepo string) error
cfg["secret"] = s.SecretToken
}
events := []string{"push", "pull_request", "issues", "issue_comment", "pull_request_review_comment"}
_, res, err := cli.Repositories.CreateHook(owner, repo, &github.Hook{
_, res, err := cli.Repositories.CreateHook(owner, repo, &gogithub.Hook{
Name: &name,
Config: cfg,
Events: events,
})
if res.StatusCode == 422 {
errResponse, ok := err.(*github.ErrorResponse)
errResponse, ok := err.(*gogithub.ErrorResponse)
if !ok {
return err
}
@ -341,7 +341,7 @@ func (s *WebhookService) deleteHook(owner, repo string) error {
if err != nil {
return err
}
var hook *github.Hook
var hook *gogithub.Hook
for _, h := range hooks {
if h.Config["url"] == nil {
logger.Print("Ignoring nil config.url")
@ -396,7 +396,7 @@ func sameRepos(a *WebhookService, b *WebhookService) bool {
return true
}
func (s *WebhookService) githubClientFor(userID string, allowUnauth bool) *github.Client {
func (s *WebhookService) githubClientFor(userID string, allowUnauth bool) *gogithub.Client {
token, err := getTokenForUser(s.RealmID, userID)
if err != nil {
log.WithFields(log.Fields{

28
src/github.com/matrix-org/go-neb/services/jira/jira.go

@ -13,7 +13,7 @@ import (
"strings"
log "github.com/Sirupsen/logrus"
jira "github.com/andygrunwald/go-jira"
gojira "github.com/andygrunwald/go-jira"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/realms/jira"
@ -81,7 +81,7 @@ func (s *Service) Register(oldService types.Service, client *matrix.Client) erro
if err != nil {
return err
}
jrealm, ok := realm.(*realms.JIRARealm)
jrealm, ok := realm.(*jira.Realm)
if !ok {
return errors.New("Realm ID doesn't map to a JIRA realm")
}
@ -123,15 +123,15 @@ func (s *Service) cmdJiraCreate(roomID, userID string, args []string) (interface
return nil, errors.New("No known project exists with that project key.")
}
iss := jira.Issue{
Fields: &jira.IssueFields{
iss := gojira.Issue{
Fields: &gojira.IssueFields{
Summary: title,
Description: desc,
Project: jira.Project{
Project: gojira.Project{
Key: pkey,
},
// FIXME: This may vary depending on the JIRA install!
Type: jira.IssueType{
Type: gojira.IssueType{
Name: "Bug",
},
},
@ -192,10 +192,10 @@ func (s *Service) expandIssue(roomID, userID string, issueKeyGroups []string) in
}).Print("Failed to load realm")
return nil
}
jrealm, ok := r.(*realms.JIRARealm)
jrealm, ok := r.(*jira.Realm)
if !ok {
logger.WithField("realm_id", realmID).Print(
"Realm cannot be typecast to JIRARealm",
"Realm cannot be typecast to jira.Realm",
)
}
logger.WithFields(log.Fields{
@ -323,7 +323,7 @@ func (s *Service) realmIDForProject(roomID, projectKey string) string {
return ""
}
func (s *Service) projectToRealm(userID, pkey string) (*realms.JIRARealm, error) {
func (s *Service) projectToRealm(userID, pkey string) (*jira.Realm, error) {
// We don't know which JIRA installation this project maps to, so:
// - Get all known JIRA realms and f.e query their endpoints with the
// given user ID's credentials (so if it is a private project they
@ -341,13 +341,13 @@ func (s *Service) projectToRealm(userID, pkey string) (*realms.JIRARealm, error)
return nil, err
}
// typecast and move ones which the user has authed with to the front of the queue
var queue []*realms.JIRARealm
var unauthRealms []*realms.JIRARealm
var queue []*jira.Realm
var unauthRealms []*jira.Realm
for _, r := range knownRealms {
jrealm, ok := r.(*realms.JIRARealm)
jrealm, ok := r.(*jira.Realm)
if !ok {
logger.WithField("realm_id", r.ID()).Print(
"Failed to type-cast 'jira' type realm into JIRARealm",
"Failed to type-cast 'jira' type realm into jira.Realm",
)
continue
}
@ -402,7 +402,7 @@ func projectsAndRealmsToTrack(s *Service) map[string][]string {
return ridsToProjects
}
func htmlSummaryForIssue(issue *jira.Issue) string {
func htmlSummaryForIssue(issue *gojira.Issue) string {
// form a summary of the issue being affected e.g:
// "Flibble Wibble [P1, In Progress]"
status := html.EscapeString(issue.Fields.Status.Name)

23
src/github.com/matrix-org/go-neb/services/jira/webhook/webhook.go

@ -3,13 +3,14 @@ package webhook
import (
"encoding/json"
"fmt"
"net/http"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/andygrunwald/go-jira"
gojira "github.com/andygrunwald/go-jira"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/errors"
"github.com/matrix-org/go-neb/realms/jira"
"net/http"
"strings"
)
type jiraWebhook struct {
@ -24,14 +25,14 @@ type jiraWebhook struct {
// Event represents an incoming JIRA webhook event
type Event struct {
WebhookEvent string `json:"webhookEvent"`
Timestamp int64 `json:"timestamp"`
User jira.User `json:"user"`
Issue jira.Issue `json:"issue"`
WebhookEvent string `json:"webhookEvent"`
Timestamp int64 `json:"timestamp"`
User gojira.User `json:"user"`
Issue gojira.Issue `json:"issue"`
}
// RegisterHook checks to see if this user is allowed to track the given projects and then tracks them.
func RegisterHook(jrealm *realms.JIRARealm, projects []string, userID, webhookEndpointURL string) error {
func RegisterHook(jrealm *jira.Realm, projects []string, userID, webhookEndpointURL string) error {
// Tracking means that a webhook may need to be created on the remote JIRA installation.
// We need to make sure that the user has permission to do this. If they don't, it may still be okay if
// there is an existing webhook set up for this installation by someone else, *PROVIDED* that the projects
@ -117,7 +118,7 @@ func OnReceiveRequest(req *http.Request) (string, *Event, *errors.HTTPError) {
return projKey, &whe, nil
}
func createWebhook(jrealm *realms.JIRARealm, webhookEndpointURL, userID string) error {
func createWebhook(jrealm *jira.Realm, webhookEndpointURL, userID string) error {
cli, err := jrealm.JIRAClient(userID, false)
if err != nil {
return err
@ -152,7 +153,7 @@ func createWebhook(jrealm *realms.JIRARealm, webhookEndpointURL, userID string)
return err
}
func getWebhook(cli *jira.Client, webhookEndpointURL string) (*jiraWebhook, *errors.HTTPError) {
func getWebhook(cli *gojira.Client, webhookEndpointURL string) (*jiraWebhook, *errors.HTTPError) {
req, err := cli.NewRequest("GET", "rest/webhooks/1.0/webhook", nil)
if err != nil {
return nil, &errors.HTTPError{err, "Failed to prepare webhook request", 500}
@ -180,7 +181,7 @@ func getWebhook(cli *jira.Client, webhookEndpointURL string) (*jiraWebhook, *err
return nebWH, nil
}
func checkProjectsArePublic(jrealm *realms.JIRARealm, projects []string, userID string) *errors.HTTPError {
func checkProjectsArePublic(jrealm *jira.Realm, projects []string, userID string) *errors.HTTPError {
publicCli, err := jrealm.JIRAClient("", true)
if err != nil {
return &errors.HTTPError{err, "Cannot create public JIRA client", 500}

Loading…
Cancel
Save