Skip to content

Commit

Permalink
Add Medium. Closes hapijs#291
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse committed Jan 24, 2017
1 parent 139268b commit bd3702d
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 15 deletions.
2 changes: 1 addition & 1 deletion examples/slack.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Hapi = require('hapi');
const Hoek = require('hoek');
const Bell = require('../');


const server = new Hapi.Server();
server.connection({ port: 8000 });

Expand Down Expand Up @@ -38,5 +39,4 @@ server.register(Bell, (err) => {
console.log('Server started at:', server.info.uri);

});

});
3 changes: 2 additions & 1 deletion lib/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ exports.v2 = function (settings) {
Wreck.post(settings.provider.token, requestOptions, (err, tokenRes, payload) => {

if (err ||
tokenRes.statusCode !== 200) {
tokenRes.statusCode < 200 ||
tokenRes.statusCode > 299) {

return reply(Boom.internal('Failed obtaining ' + name + ' access token', err || payload));
}
Expand Down
1 change: 1 addition & 0 deletions lib/providers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ exports = module.exports = {
instagram: require('./instagram'),
linkedin: require('./linkedin'),
live: require('./live'),
medium: require('./medium'),
nest: require('./nest'),
slack: require('./slack'),
twitter: require('./twitter'),
Expand Down
28 changes: 28 additions & 0 deletions lib/providers/medium.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

exports = module.exports = function (options) {

return {
protocol: 'oauth2',
useParamsAuth: true,
auth: 'https://medium.com/m/oauth/authorize',
token: 'https://medium.com/v1/tokens',
scope: ['basicProfile'],
scopeSeparator: ',',
headers: { 'User-Agent': 'hapi-bell-medium' },
profile: function (credentials, params, get, callback) {

get('https://api.medium.com/v1/me', null, (profile) => {

credentials.profile = {
id: profile.data.id,
username: profile.data.username,
displayName: profile.data.name,
raw: profile.data
};

return callback();
});
}
};
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bell",
"description": "Third-party login plugin for hapi",
"version": "8.4.0",
"version": "8.5.0",
"repository": "git://github.com/hapijs/bell",
"main": "lib/index.js",
"keywords": [
Expand All @@ -21,6 +21,7 @@
"gitlab",
"google",
"instagram",
"medium",
"linkedin",
"live",
"meetup",
Expand Down
2 changes: 1 addition & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ describe('Bell', () => {

it('authenticates an endpoint via oauth2 and basic authentication', (done) => {

const mock = new Mock.V2(false);
const mock = new Mock.V2({ useParamsAuth: false });
mock.start((provider) => {

const server = new Hapi.Server();
Expand Down
19 changes: 9 additions & 10 deletions test/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,13 @@ internals.V1.prototype.stop = function (callback) {
};


exports.V2 = internals.V2 = function (useParamsAuth) {
exports.V2 = internals.V2 = function (options) {

this.codes = {};
options = options || {};

if (typeof useParamsAuth === 'undefined') {
useParamsAuth = true;
}
this.useParamsAuth = useParamsAuth;
this.codes = {};

this.useParamsAuth = (options.useParamsAuth === false ? false : true);
this.server = new Hapi.Server();
this.server.connection({ host: 'localhost' });
this.server.route([
Expand All @@ -181,7 +179,7 @@ exports.V2 = internals.V2 = function (useParamsAuth) {
client_id: request.query.client_id
};

reply().redirect(request.query.redirect_uri + '?code=' + code + '&state=' + request.query.state);
return reply().redirect(request.query.redirect_uri + '?code=' + code + '&state=' + request.query.state);
}
}
},
Expand All @@ -195,7 +193,7 @@ exports.V2 = internals.V2 = function (useParamsAuth) {
const code = this.codes[request.payload.code];
expect(code).to.exist();
expect(code.redirect_uri).to.equal(request.payload.redirect_uri);
if (useParamsAuth) {
if (this.useParamsAuth) {
expect(code.client_id).to.equal(request.payload.client_id);
expect(request.headers.authorization).to.be.undefined();
}
Expand Down Expand Up @@ -232,7 +230,7 @@ exports.V2 = internals.V2 = function (useParamsAuth) {
payload.id = 'https://login.salesforce.com/id/foo/bar';
}

reply(payload);
return reply(payload).code(options.code || 200);
}
}
}
Expand Down Expand Up @@ -278,7 +276,8 @@ exports.override = function (uri, payload) {
}

if (payload instanceof Error) {
return Hoek.nextTick(callback)(null, { statusCode: 400 }, JSON.stringify({ message: payload.message }));
const statusCode = (payload && payload.output ? payload.output.statusCode : 400);
return Hoek.nextTick(callback)(null, { statusCode }, JSON.stringify({ message: payload.message }));
}

if (payload === null) {
Expand Down
58 changes: 57 additions & 1 deletion test/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -1757,7 +1757,7 @@ describe('Bell', () => {
});
});

it('errors on errored token request', { parallel: false }, (done) => {
it('errors on errored token request (500)', { parallel: false }, (done) => {

const mock = new Mock.V2();
mock.start((provider) => {
Expand Down Expand Up @@ -1811,6 +1811,62 @@ describe('Bell', () => {
});
});

it('errors on errored token request (<200)', { parallel: false }, (done) => {

const mock = new Mock.V2();
mock.start((provider) => {

const server = new Hapi.Server();
server.connection({ host: 'localhost', port: 80 });
server.register(Bell, (err) => {

expect(err).to.not.exist();

const custom = Bell.providers.facebook();
Hoek.merge(custom, provider);

const error = Boom.badRequest();
error.output.statusCode = 199;
Mock.override(provider.token, error);

server.auth.strategy('custom', 'bell', {
password: 'cookie_encryption_password_secure',
isSecure: false,
clientId: 'facebook',
clientSecret: 'secret',
provider: custom
});

server.route({
method: '*',
path: '/login',
config: {
auth: 'custom',
handler: function (request, reply) {

reply(request.auth.credentials);
}
}
});

server.inject('/login', (res) => {

const cookie = res.headers['set-cookie'][0].split(';')[0] + ';';

mock.server.inject(res.headers.location, (mockRes) => {

server.inject({ url: mockRes.headers.location, headers: { cookie } }, (response) => {

Mock.clear();
expect(response.statusCode).to.equal(500);
mock.stop(done);
});
});
});
});
});
});

it('errors on invalid token request response', { parallel: false }, (done) => {

const mock = new Mock.V2();
Expand Down
104 changes: 104 additions & 0 deletions test/providers/medium.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict';

// Load modules

const Bell = require('../../');
const Code = require('code');
const Hapi = require('hapi');
const Hoek = require('hoek');
const Lab = require('lab');
const Mock = require('../mock');


// Test shortcuts

const lab = exports.lab = Lab.script();
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;


describe('medium', () => {

it('authenticates with mock', { parallel: false }, (done) => {

const mock = new Mock.V2({ code: 201 });
mock.start((provider) => {

const server = new Hapi.Server();
server.connection({ host: 'localhost', port: 80 });
server.register(Bell, (err) => {

expect(err).to.not.exist();

const custom = Bell.providers.medium();
Hoek.merge(custom, provider);

const profile = {
data: {
id: '5303d74c64f66366f00cb9b2a94f3251bf5',
username: 'majelbstoat',
name: 'Jamie Talbot',
url: 'https://medium.com/@majelbstoat',
imageUrl: 'https://images.medium.com/0*fkfQiTzT7TlUGGyI.png'
}
};

Mock.override('https://api.medium.com/v1/me', profile);

server.auth.strategy('custom', 'bell', {
password: 'cookie_encryption_password_secure',
isSecure: false,
clientId: 'medium',
clientSecret: 'secret',
provider: custom
});

server.route({
method: '*',
path: '/login',
config: {
auth: 'custom',
handler: function (request, reply) {

reply(request.auth.credentials);
}
}
});

server.inject('/login', (res) => {

const cookie = res.headers['set-cookie'][0].split(';')[0] + ';';
mock.server.inject(res.headers.location, (mockRes) => {

server.inject({ url: mockRes.headers.location, headers: { cookie } }, (response) => {

Mock.clear();
expect(response.result).to.equal({
provider: 'custom',
token: '456',
expiresIn: 3600,
refreshToken: undefined,
query: {},
profile: {
id: '5303d74c64f66366f00cb9b2a94f3251bf5',
username: 'majelbstoat',
displayName: 'Jamie Talbot',
raw: {
id: '5303d74c64f66366f00cb9b2a94f3251bf5',
username: 'majelbstoat',
name: 'Jamie Talbot',
url: 'https://medium.com/@majelbstoat',
imageUrl: 'https://images.medium.com/0*fkfQiTzT7TlUGGyI.png'
}
}
});

mock.stop(done);
});
});
});
});
});
});
});

0 comments on commit bd3702d

Please sign in to comment.