You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
18 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. # Go-NEB
  2. Go-NEB is a [Matrix](https://matrix.org) bot written in Go. It is the successor to [Matrix-NEB](https://github.com/matrix-org/Matrix-NEB), the original Matrix bot written in Python.
  3. # Table of Contents
  4. * [Quick Start](#quick-start)
  5. * [Features](#features)
  6. * [Installing](#installing)
  7. * [Running](#running)
  8. * [Configuring clients](#configuring-clients)
  9. * [Configuring services](#configuring-services)
  10. * [Echo Service](#echo-service)
  11. * [Github Service](#github-service)
  12. * [Github Webhook Service](#github-webhook-service)
  13. * [JIRA Service](#jira-service)
  14. * [Giphy Service](#giphy-service)
  15. * [Configuring realms](#configuring-realms)
  16. * [Github Realm](#github-realm)
  17. * [Github Authentication](#github-authentication)
  18. * [JIRA Realm](#jira-realm)
  19. * [Developing](#developing)
  20. * [Architecture](#architecture)
  21. # Quick Start
  22. Clone and run (Requires Go 1.5+ and GB):
  23. ```bash
  24. gb build github.com/matrix-org/go-neb
  25. BIND_ADDRESS=:4050 DATABASE_TYPE=sqlite3 DATABASE_URL=go-neb.db BASE_URL=http://localhost:4050 bin/go-neb
  26. ```
  27. Get a Matrix user ID and access token and give it to Go-NEB:
  28. ```bash
  29. curl -X POST localhost:4050/admin/configureClient --data-binary '{
  30. "UserID": "@goneb:localhost",
  31. "HomeserverURL": "http://localhost:8008",
  32. "AccessToken": "<access_token>",
  33. "Sync": true,
  34. "AutoJoinRooms": true,
  35. "DisplayName": "My Bot"
  36. }'
  37. ```
  38. Tell it what service to run:
  39. ```bash
  40. curl -X POST localhost:4050/admin/configureService --data-binary '{
  41. "Type": "echo",
  42. "Id": "myserviceid",
  43. "UserID": "@goneb:localhost",
  44. "Config": {}
  45. }'
  46. ```
  47. Invite the bot user into a Matrix room and type `!echo hello world`. It will reply with `hello world`.
  48. ## Features
  49. ### Github
  50. - Login with OAuth2.
  51. - Ability to create Github issues on any project.
  52. - Ability to track updates (add webhooks) to projects. This includes new issues, pull requests as well as commits.
  53. - Ability to expand issues when mentioned as `foo/bar#1234`.
  54. - Ability to assign a "default repository" for a Matrix room to allow `#1234` to automatically expand, as well as shorter issue creation command syntax.
  55. ### JIRA
  56. - Login with OAuth1.
  57. - Ability to create JIRA issues on a project.
  58. - Ability to expand JIRA issues when mentioned as `FOO-1234`.
  59. ### Giphy
  60. - Ability to query Giphy's "text-to-gif" engine.
  61. # Installing
  62. Go-NEB is built using Go 1.5+ and [GB](https://getgb.io/). Once you have installed Go, run the following commands:
  63. ```bash
  64. # Install gb
  65. go get github.com/constabulary/gb/...
  66. # Clone the go-neb repository
  67. git clone https://github.com/matrix-org/go-neb
  68. cd go-neb
  69. # Build go-neb
  70. gb build github.com/matrix-org/go-neb
  71. ```
  72. # Running
  73. Go-NEB uses environment variables to configure its SQLite database and bind address. To run Go-NEB, run the following command:
  74. ```bash
  75. BIND_ADDRESS=:4050 DATABASE_TYPE=sqlite3 DATABASE_URL=go-neb.db BASE_URL=https://public.facing.endpoint bin/go-neb
  76. ```
  77. - `BIND_ADDRESS` is the port to listen on.
  78. - `DATABASE_TYPE` MUST be "sqlite3". No other type is supported.
  79. - `DATABASE_URL` is where to find the database file. One will be created if it does not exist.
  80. - `BASE_URL` should be the public-facing endpoint that sites like Github can send webhooks to.
  81. Go-NEB needs to be "configured" with clients and services before it will do anything useful.
  82. ## Configuring Clients
  83. Go-NEB needs to connect as a matrix user to receive messages. Go-NEB can listen for messages as multiple matrix users. The users are configured using an HTTP API and the config is stored in the database. To create a user:
  84. ```bash
  85. curl -X POST localhost:4050/admin/configureClient --data-binary '{
  86. "UserID": "@goneb:localhost:8448",
  87. "HomeserverURL": "http://localhost:8008",
  88. "AccessToken": "<access_token>",
  89. "Sync": true,
  90. "AutoJoinRooms": true,
  91. "DisplayName": "My Bot"
  92. }'
  93. ```
  94. - `UserID` is the complete user ID of the client to connect as. The user MUST already exist.
  95. - `HomeserverURL` is the complete Homeserver URL for the given user ID.
  96. - `AccessToken` is the user's access token.
  97. - `Sync`, if `true`, will start a `/sync` stream so this client will receive incoming messages. This is required for services which need a live stream to the server (e.g. to respond to `!commands` and expand issues). It is not required for services which do not respond to Matrix users (e.g. webhook notifications).
  98. - `AutoJoinRooms`, if `true`, will automatically join rooms when an invite is received. This option is only valid when `Sync: true`.
  99. - `DisplayName`, if set, will set the given user's profile display name to the string given.
  100. Go-NEB will respond with the previous configuration for this client, if one exists, as well as echo back the complete configuration for the client:
  101. ```json
  102. {
  103. "OldClient": {},
  104. "NewClient": {
  105. "UserID": "@goneb:localhost:8448",
  106. "HomeserverURL": "http://localhost:8008",
  107. "AccessToken": "<access_token>",
  108. "Sync": true,
  109. "AutoJoinRooms": true,
  110. "DisplayName": "My Bot"
  111. }
  112. }
  113. ```
  114. ## Configuring Services
  115. Services contain all the useful functionality in Go-NEB. They require a client to operate. Services are configured using an HTTP API and the config is stored in the database. Services use one of the matrix users configured on Go-NEB to send/receive matrix messages.
  116. Every service MUST have the following fields:
  117. - `Type` : The type of service. This determines which code is executed.
  118. - `Id` : An arbitrary string which you can use to identify this service.
  119. - `UserID` : A user ID of a client which has been previously configured on Go-NEB. If this user does not exist, an error will be returned.
  120. - `Config` : A JSON object. The contents of this object depends on the service.
  121. The information about a Service can be retrieved based on their `Id` like so:
  122. ```bash
  123. curl -X POST localhost:4050/admin/getService --data-binary '{
  124. "Id": "myserviceid"
  125. }'
  126. ```
  127. This will return:
  128. ```yaml
  129. # HTTP 200 OK
  130. {
  131. "Type": "echo",
  132. "Id": "myserviceid",
  133. "UserID": "@goneb:localhost:8448",
  134. "Config": {}
  135. }
  136. ```
  137. If the service is not found, this will return:
  138. ```yaml
  139. # HTTP 404 Not Found
  140. { "message": "Service not found" }
  141. ```
  142. If you configure an existing Service (based on ID), the entire service will be replaced with the new information.
  143. ### Echo Service
  144. The simplest service. This will echo back any `!echo` command. To configure one:
  145. ```bash
  146. curl -X POST localhost:4050/admin/configureService --data-binary '{
  147. "Type": "echo",
  148. "Id": "myserviceid",
  149. "UserID": "@goneb:localhost:8448",
  150. "Config": {
  151. }
  152. }'
  153. ```
  154. Then invite `@goneb:localhost:8448` to any Matrix room and it will automatically join (if the client was configured to do so). Then try typing `!echo hello world` and the bot will respond with `hello world`.
  155. ### Github Service
  156. *Before you can set up a Github Service, you need to set up a [Github Realm](#github-realm).*
  157. *This service [requires a client](#configuring-clients) which has `Sync: true`.*
  158. This service will add the following command for [users who have associated their account with Github](#github-authentication):
  159. ```
  160. !github create owner/repo "Some title" "Some description"
  161. ```
  162. This service will also expand the following string into a short summary of the Github issue:
  163. ```
  164. owner/repo#1234
  165. ```
  166. You can create this service like so:
  167. ```bash
  168. curl -X POST localhost:4050/admin/configureService --data-binary '{
  169. "Type": "github",
  170. "Id": "githubcommands",
  171. "UserID": "@goneb:localhost",
  172. "Config": {
  173. "RealmID": "mygithubrealm"
  174. }
  175. }'
  176. ```
  177. - `RealmID`: The ID of the Github Realm you created earlier.
  178. You can set a "default repository" for a Matrix room by sending a `m.room.bot.options` state event which has the following `content`:
  179. ```json
  180. {
  181. "github": {
  182. "default_repo": "owner/repo"
  183. }
  184. }
  185. ```
  186. This will allow you to omit the `owner/repo` from both commands and expansions e.g `#12` will be treated as `owner/repo#12`.
  187. ### Github Webhook Service
  188. *Before you can set up a Github Webhook Service, you need to set up a [Github Realm](#github-realm).*
  189. This service will send notices into a Matrix room when Github sends webhook events to it. It requires a public domain which Github can reach. This service does not require a syncing client. Notices will be sent as the given `UserID`. To create this service:
  190. ```bash
  191. curl -X POST localhost:4050/admin/configureService --data-binary '{
  192. "Type": "github-webhook",
  193. "Id": "ghwebhooks",
  194. "UserID": "@goneb:localhost",
  195. "Config": {
  196. "RealmID": "mygithubrealm",
  197. "SecretToken": "a random string",
  198. "ClientUserID": "@a_real_user:localhost",
  199. "Rooms": {
  200. "!wefiuwegfiuwhe:localhost": {
  201. "Repos": {
  202. "owner/repo": {
  203. "Events": ["push"]
  204. },
  205. "owner/another-repo": {
  206. "Events": ["issues"]
  207. }
  208. }
  209. }
  210. }
  211. }
  212. }'
  213. ```
  214. - `RealmID`: The ID of the Github realm you created earlier.
  215. - `SecretToken`: Optional. If supplied, Go-NEB will perform security checks on incoming webhook requests using this token.
  216. - `ClientUserID`: The user ID of the Github user to setup webhooks as. This user MUST have [associated their user ID with a Github account](#github-authentication). Webhooks will be created using their OAuth token.
  217. - `Rooms`: A map of room IDs to room info.
  218. - `Repos`: A map of repositories to repo info.
  219. - `Events`: A list of webhook events to send into this room. Can be any of:
  220. - `push`: When users push to this repository.
  221. - `pull_request`: When a pull request is made to this repository.
  222. - `issues`: When an issue is opened/closed.
  223. - `issue_comment`: When an issue or pull request is commented on.
  224. - `pull_request_review_comment`: When a line comment is made on a pull request.
  225. ### JIRA Service
  226. *Before you can set up a JIRA Service, you need to set up a [JIRA Realm](#jira-realm).*
  227. TODO: Expand this section.
  228. ```
  229. curl -X POST localhost:4050/admin/configureService --data-binary '{
  230. "Type": "jira",
  231. "Id": "jid",
  232. "UserID": "@goneb:localhost",
  233. "Config": {
  234. "ClientUserID": "@example:localhost",
  235. "Rooms": {
  236. "!EmwxeXCVubhskuWvaw:localhost": {
  237. "Realms": {
  238. "jira_realm_id": {
  239. "Projects": {
  240. "BOTS": {
  241. "Expand": true,
  242. "Track": true
  243. }
  244. }
  245. }
  246. }
  247. }
  248. }
  249. }
  250. }'
  251. ```
  252. ### Giphy Service
  253. A simple service that adds the ability to use the `!giphy` command. To configure one:
  254. ```bash
  255. curl -X POST localhost:4050/admin/configureService --data-binary '{
  256. "Type": "giphy",
  257. "Id": "giphyid",
  258. "UserID": "@goneb:localhost",
  259. "Config": {
  260. "APIKey": "YOUR_API_KEY"
  261. }
  262. }'
  263. ```
  264. Then invite the user into a room and type `!giphy food` and it will respond with a GIF.
  265. ## Configuring Realms
  266. Realms are how Go-NEB authenticates users on third-party websites. Every realm MUST have the following fields:
  267. - `ID` : An arbitrary string you can use to remember what the realm is.
  268. - `Type`: The type of realm. This determines what code gets executed.
  269. - `Config`: A JSON object. The contents depends on the realm `Type`.
  270. They are configured like so:
  271. ```bash
  272. curl -X POST localhost:4050/admin/configureAuthRealm --data-binary '{
  273. "ID": "some_arbitrary_string",
  274. "Type": "some_realm_type",
  275. "Config": {
  276. ...
  277. }
  278. }'
  279. ```
  280. ### Github Realm
  281. This has the `Type` of `github`. To set up this realm:
  282. ```bash
  283. curl -X POST localhost:4050/admin/configureAuthRealm --data-binary '{
  284. "ID": "mygithubrealm",
  285. "Type": "github",
  286. "Config": {
  287. "ClientSecret": "YOUR_CLIENT_SECRET",
  288. "ClientID": "YOUR_CLIENT_ID",
  289. "StarterLink": "https://example.com/requestGithubOAuthToken"
  290. }
  291. }'
  292. ```
  293. - `ClientSecret`: Your Github application client secret
  294. - `ClientID`: Your Github application client ID
  295. - `StarterLink`: Optional. If supplied, `!github` commands will return this link whenever someone is prompted to login to Github.
  296. #### Github authentication
  297. Once you have configured a Github realm, you can associate any Matrix user ID with any Github user. To do this:
  298. ```bash
  299. curl -X POST localhost:4050/admin/requestAuthSession --data-binary '{
  300. "RealmID": "mygithubrealm",
  301. "UserID": "@real_matrix_user:localhost",
  302. "Config": {
  303. "RedirectURL": "https://optional-url.com/to/redirect/to/after/auth"
  304. }
  305. }'
  306. ```
  307. - `UserID`: The Matrix user ID to associate with.
  308. - `RedirectURL`: Optional. The URL to redirect to after authentication.
  309. This request will return an OAuth URL:
  310. ```json
  311. {
  312. "URL": "https://github.com/login/oauth/authorize?client_id=abcdef&client_secret=acascacac...."
  313. }
  314. ```
  315. 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.
  316. To remove this session:
  317. ```bash
  318. curl -X POST localhost:4050/admin/removeAuthSession --data-binary '{
  319. "RealmID": "mygithubrealm",
  320. "UserID": "@real_matrix_user:localhost",
  321. "Config": {}
  322. }'
  323. ```
  324. ### JIRA Realm
  325. This has the `Type` of `jira`. To set up this realm:
  326. ```bash
  327. curl -X POST localhost:4050/admin/configureAuthRealm --data-binary '{
  328. "ID": "jirarealm",
  329. "Type": "jira",
  330. "Config": {
  331. "JIRAEndpoint": "matrix.org/jira/",
  332. "ConsumerName": "goneb",
  333. "ConsumerKey": "goneb",
  334. "ConsumerSecret": "random_long_string",
  335. "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-----"
  336. }
  337. }'
  338. ```
  339. - `JIRAEndpoint`: The base URL of the JIRA installation you wish to talk to.
  340. - `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.
  341. - `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.
  342. - `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.
  343. - `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.
  344. - `StarterLink`: Optional. If supplied, `!jira` commands will return this link whenever someone is prompted to login to JIRA.
  345. To generate a private key PEM: (JIRA does not support bit lengths >2048)
  346. ```bash
  347. openssl genrsa -out privkey.pem 2048
  348. cat privkey.pem
  349. ```
  350. #### JIRA authentication
  351. ```
  352. curl -X POST localhost:4050/admin/requestAuthSession --data-binary '{
  353. "RealmID": "jirarealm",
  354. "UserID": "@example:localhost",
  355. "Config": {
  356. "RedirectURL": "https://optional-url.com/to/redirect/to/after/auth"
  357. }
  358. }'
  359. ```
  360. Returns:
  361. ```json
  362. {
  363. "URL":"https://jira.somewhere.com/plugins/servlet/oauth/authorize?oauth_token=7yeuierbgweguiegrTbOT"
  364. }
  365. ```
  366. # Developing
  367. There's a bunch more tools this project uses when developing in order to do
  368. things like linting. Some of them are bundled with go (fmt and vet) but some
  369. are not. You should install the ones which are not:
  370. ```bash
  371. go get github.com/golang/lint/golint
  372. go get github.com/fzipp/gocyclo
  373. ```
  374. You can then install the pre-commit hook:
  375. ```bash
  376. ./hooks/install.sh
  377. ```
  378. ## Architecture
  379. ```
  380. HOMESERVER
  381. |
  382. +=============================================================+
  383. | | Go-NEB |
  384. | +---------+ |
  385. | | Clients | |
  386. | +---------+ |
  387. | | |
  388. | +---------+ +------------+ +--------------+ |
  389. | | Service |-------| Auth Realm |------| Auth Session |-+ |
  390. | +---------+ +------------+ +--------------+ | |
  391. | ^ ^ +---------------+ |
  392. | | | |
  393. +=============================================================+
  394. | |
  395. WEBHOOK REDIRECT
  396. REQUEST REQUEST
  397. Clients = A thing which can talk to homeservers and listen for events. /configureClient makes these.
  398. Service = An individual bot, configured by a user. /configureService makes these.
  399. Auth Realm = A place where a user can authenticate with. /configureAuthRealm makes these.
  400. Auth Session = An individual authentication session /requestAuthSession makes these.
  401. ```
  402. ## Viewing the API docs.
  403. ```
  404. # Start a documentation server listening on :6060
  405. GOPATH=$GOPATH:$(pwd) godoc -v -http=localhost:6060 &
  406. # Open up the documentation for go-neb in a browser.
  407. sensible-browser http://localhost:6060/pkg/github.com/matrix-org/go-neb
  408. ```