Begin implementing integrations support

This commit is contained in:
Brandon Keepers 2016-10-12 11:17:19 -05:00
parent 17fc921ead
commit d53e792f31
No known key found for this signature in database
GPG Key ID: F9533396D5FACBF6
6 changed files with 142 additions and 1 deletions

45
lib/installations.js Normal file
View File

@ -0,0 +1,45 @@
const jwt = require('./jwt');
const GitHubApi = require('github');
const github = new GitHubApi();
const installations = {};
module.exports = {
load: function() {
github.authenticate({type: 'integration', token: jwt()});
github.integrations.getInstallations({per_page: 100}).then(data => {
data.forEach(this.register);
});
},
register: function(installation) {
installations[installation.account.login] = installation;
},
unregister: function(installation) {
delete installations[installation.account.login];
},
for: function(account) {
return installations[account];
},
listen: function(webhook) {
webhook.on('integration_installation', function(event) {
if (event.payload.action == 'create') {
this.register(event.payload.installation);
} else if (event.payload.action == 'deleted') {
this.unregister(event.payload.installation);
}
});
},
authAs: function(installation) {
const github = new GitHubApi();
github.authenticate({type: 'integration', token: jwt()});
return github.integrations.createInstallationToken({
installation_id: installation.id
});
}
}

22
lib/jwt.js Normal file
View File

@ -0,0 +1,22 @@
const fs = require('fs');
const jwt = require('jsonwebtoken');
const process = require('process');
// sign with RSA SHA256
// FIXME: move to env var
const cert = fs.readFileSync('private-key.pem'); // get private key
module.exports = generate;
function generate () {
var payload = {
// issued at time
iat: Math.floor(new Date() / 1000),
// JWT expiration time
exp: Math.floor(new Date() / 1000) + 60 * 5,
// Integration's GitHub identifier
iss: process.env.INTEGRATION_ID
}
return jwt.sign(payload, cert, { algorithm: 'RS256'});
}

View File

@ -16,7 +16,8 @@
"github-webhook-handler": "^0.6.0",
"handlebars": "^4.0.5",
"js-yaml": "^3.6.1",
"jsdoc": "^3.4.2"
"jsdoc": "^3.4.2",
"jsonwebtoken": "^7.1.9"
},
"devDependencies": {
"mocha": "^3.0.2",

View File

@ -6,13 +6,20 @@ const createHandler = require('github-webhook-handler');
const GitHubApi = require('github');
const Configuration = require('./lib/configuration');
const Dispatcher = require('./lib/dispatcher');
const installations = require('./lib/installations');
const PORT = process.env.PORT || 3000;
const webhook = createHandler({path: '/', secret: process.env.WEBHOOK_SECRET || 'development'});
// Cache installations
installations.load();
// Listen for new installations
installations.listen(webhook);
const github = new GitHubApi({
debug: true
});
github.authenticate({
type: 'oauth',
token: process.env.GITHUB_TOKEN

View File

@ -0,0 +1,46 @@
{
"action": "deleted",
"installation": {
"id": 1729,
"account": {
"login": "bkeepers-inc",
"id": 11724939,
"avatar_url": "https://avatars.githubusercontent.com/u/11724939?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/bkeepers-inc",
"html_url": "https://github.com/bkeepers-inc",
"followers_url": "https://api.github.com/users/bkeepers-inc/followers",
"following_url": "https://api.github.com/users/bkeepers-inc/following{/other_user}",
"gists_url": "https://api.github.com/users/bkeepers-inc/gists{/gist_id}",
"starred_url": "https://api.github.com/users/bkeepers-inc/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/bkeepers-inc/subscriptions",
"organizations_url": "https://api.github.com/users/bkeepers-inc/orgs",
"repos_url": "https://api.github.com/users/bkeepers-inc/repos",
"events_url": "https://api.github.com/users/bkeepers-inc/events{/privacy}",
"received_events_url": "https://api.github.com/users/bkeepers-inc/received_events",
"type": "Organization",
"site_admin": false
},
"access_tokens_url": "https://api.github.com/installations/1729/access_tokens",
"repositories_url": "https://api.github.com/installation/repositories"
},
"sender": {
"login": "bkeepers",
"id": 173,
"avatar_url": "https://avatars.githubusercontent.com/u/173?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/bkeepers",
"html_url": "https://github.com/bkeepers",
"followers_url": "https://api.github.com/users/bkeepers/followers",
"following_url": "https://api.github.com/users/bkeepers/following{/other_user}",
"gists_url": "https://api.github.com/users/bkeepers/gists{/gist_id}",
"starred_url": "https://api.github.com/users/bkeepers/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/bkeepers/subscriptions",
"organizations_url": "https://api.github.com/users/bkeepers/orgs",
"repos_url": "https://api.github.com/users/bkeepers/repos",
"events_url": "https://api.github.com/users/bkeepers/events{/privacy}",
"received_events_url": "https://api.github.com/users/bkeepers/received_events",
"type": "User",
"site_admin": true
}
}

20
test/installation.js Normal file
View File

@ -0,0 +1,20 @@
const expect = require('expect');
const installations = require('../lib/installations');
const payload = require ('./fixtures/webhook/installation.deleted');
describe('installation', () => {
describe('register', () => {
it('registers the installation', () => {
installations.register(payload.installation);
expect(installations.for('bkeepers-inc')).toEqual(payload.installation);
})
});
describe('unregister', () => {
it('unregisters the installation', () => {
installations.register(payload.installation);
installations.unregister(payload.installation);
expect(installations.for('bkeepers-inc')).toBe(undefined);
})
});
});