Родитель
b4413aefe8
Коммит
cc70645763
|
@ -14,6 +14,14 @@ const conf = convict({
|
|||
default: 1
|
||||
}
|
||||
},
|
||||
authServer: {
|
||||
url: {
|
||||
doc: 'URL of fxa-auth-server',
|
||||
env: 'AUTH_SERVER_URL',
|
||||
format: 'url',
|
||||
default: 'http://127.0.0.1:9000/v1'
|
||||
}
|
||||
},
|
||||
db: {
|
||||
driver: {
|
||||
env: 'DB',
|
||||
|
|
11
lib/error.js
11
lib/error.js
|
@ -138,5 +138,16 @@ AppError.oauthError = function oauthError(err) {
|
|||
});
|
||||
};
|
||||
|
||||
AppError.authError = function authError(err) {
|
||||
return new AppError({
|
||||
code: 503,
|
||||
error: 'Service Unavailable',
|
||||
errno: 105,
|
||||
message: 'Auth server error'
|
||||
}, {
|
||||
cause: err
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = AppError;
|
||||
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
const Joi = require('joi');
|
||||
|
||||
const AppError = require('../error');
|
||||
const config = require('../config');
|
||||
const logger = require('../logging')('routes.email');
|
||||
const request = require('../request');
|
||||
|
||||
const AUTH_SERVER_URL = config.get('authServer.url') + '/account/profile';
|
||||
|
||||
module.exports = {
|
||||
auth: {
|
||||
|
@ -17,14 +22,30 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
handler: function email(req, reply) {
|
||||
var email = req.auth.credentials.email;
|
||||
if (email) {
|
||||
request.get(AUTH_SERVER_URL, {
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + req.auth.token
|
||||
},
|
||||
json: true
|
||||
}, function(err, res, body) {
|
||||
if (err) {
|
||||
logger.error('request.auth_server.network', err);
|
||||
return reply(new AppError.authError('network error'));
|
||||
}
|
||||
if (res.statusCode >= 400) {
|
||||
logger.error('request.auth_server.fail', { code: res.statusCode });
|
||||
return reply(new AppError.authError('auth server error'));
|
||||
}
|
||||
|
||||
if (!body || !body.email) {
|
||||
return reply(
|
||||
new AppError.authError('email field missing from auth response')
|
||||
);
|
||||
}
|
||||
reply({
|
||||
email: email
|
||||
email: body.email
|
||||
});
|
||||
} else {
|
||||
reply(new AppError.oauthError('email field missing from oauth response'));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -54,11 +54,13 @@ exports.create = function createServer() {
|
|||
request.post({
|
||||
url: url,
|
||||
json: {
|
||||
token: token
|
||||
token: token,
|
||||
email: false // disables email fetching of oauth server
|
||||
}
|
||||
}, function(err, resp, body) {
|
||||
if (err || resp.statusCode >= 500) {
|
||||
err = err || resp.statusMessage || 'unknown';
|
||||
logger.error('oauth.error', err);
|
||||
return reply(AppError.oauthError(err));
|
||||
}
|
||||
if (body.code >= 400) {
|
||||
|
@ -67,7 +69,8 @@ exports.create = function createServer() {
|
|||
}
|
||||
logger.debug('auth.valid', body);
|
||||
reply(null, {
|
||||
credentials: body
|
||||
credentials: body,
|
||||
token: token
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -42,7 +42,7 @@
|
|||
"load-grunt-tasks": "^1.0.0",
|
||||
"mkdirp": "^0.5.0",
|
||||
"mocha-text-cov": "^0.1.0",
|
||||
"nock": "^0.48.0",
|
||||
"nock": "^2.17.0",
|
||||
"pngparse": "2.0.1",
|
||||
"rimraf": "^2.4.3",
|
||||
"through": "^2.3.4",
|
||||
|
|
47
test/api.js
47
test/api.js
|
@ -61,6 +61,7 @@ describe('/profile', function() {
|
|||
|
||||
it('should return all of a profile', function() {
|
||||
mock.tokenGood();
|
||||
mock.email('user@example.domain');
|
||||
return Server.api.get({
|
||||
url: '/profile',
|
||||
headers: {
|
||||
|
@ -74,12 +75,12 @@ describe('/profile', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should handle oauth errors', function() {
|
||||
it('should handle auth server errors', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
scope: ['profile:write']
|
||||
// intentionally left off email
|
||||
});
|
||||
mock.emailFailure();
|
||||
|
||||
mock.log('server', function(rec) {
|
||||
return rec.levelname === 'ERROR'
|
||||
|
@ -98,6 +99,11 @@ describe('/profile', function() {
|
|||
&& rec.args[1].path === '/v1/profile';
|
||||
});
|
||||
|
||||
mock.log('routes.email', function(rec) {
|
||||
return rec.levelname === 'ERROR'
|
||||
&& rec.args[0] === 'request.auth_server.fail';
|
||||
});
|
||||
|
||||
return Server.api.get({
|
||||
url: '/profile',
|
||||
headers: {
|
||||
|
@ -105,7 +111,7 @@ describe('/profile', function() {
|
|||
}
|
||||
}).then(function(res) {
|
||||
assert.equal(res.statusCode, 503);
|
||||
assert.equal(res.result.errno, 104);
|
||||
assert.equal(res.result.errno, 105);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -132,9 +138,9 @@ describe('/profile', function() {
|
|||
it('should return an avatar if selected', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile']
|
||||
});
|
||||
mock.email('user@example.domain');
|
||||
var aid = avatarId();
|
||||
var PROVIDER = 'gravatar';
|
||||
return db.addAvatar(aid, user, GRAVATAR, PROVIDER, true)
|
||||
|
@ -154,9 +160,9 @@ describe('/profile', function() {
|
|||
it('should return a display name if set', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile']
|
||||
});
|
||||
mock.email('user@example.domain');
|
||||
return db.setDisplayName(user, 'Spock')
|
||||
.then(function() {
|
||||
return Server.api.get({
|
||||
|
@ -174,9 +180,9 @@ describe('/profile', function() {
|
|||
it('should return filtered profile if smaller scope', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:email']
|
||||
});
|
||||
mock.email('user@example.domain');
|
||||
return Server.api.get({
|
||||
url: '/profile',
|
||||
headers: {
|
||||
|
@ -192,7 +198,6 @@ describe('/profile', function() {
|
|||
it('should require a profile:* scope', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['some:other:scope']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -208,9 +213,9 @@ describe('/profile', function() {
|
|||
it('should include an etag in the http response', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile']
|
||||
});
|
||||
mock.email('user@example.domain');
|
||||
return db.setDisplayName(user, 'Spock')
|
||||
.then(function() {
|
||||
return Server.api.get({
|
||||
|
@ -233,6 +238,7 @@ describe('/email', function() {
|
|||
|
||||
it('should return an email', function() {
|
||||
mock.tokenGood();
|
||||
mock.email('user@example.domain');
|
||||
return Server.api.get({
|
||||
url: '/email',
|
||||
headers: {
|
||||
|
@ -247,7 +253,6 @@ describe('/email', function() {
|
|||
it('should NOT return email if wrong scope', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:uid']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -280,7 +285,6 @@ describe('/uid', function() {
|
|||
it('should NOT return a uid if wrong scope', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:email']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -317,7 +321,6 @@ describe('/avatar', function() {
|
|||
it('should return selected avatar', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -334,7 +337,6 @@ describe('/avatar', function() {
|
|||
it('should include an etag in the http response', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -355,7 +357,6 @@ describe('/avatar', function() {
|
|||
it('should log an avatar.get activity event', function(done) {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar']
|
||||
});
|
||||
|
||||
|
@ -381,7 +382,6 @@ describe('/avatar', function() {
|
|||
it('should post a new avatar url', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
return Server.api.post({
|
||||
|
@ -401,7 +401,6 @@ describe('/avatar', function() {
|
|||
it('should log the avatar.post activity event', function(done) {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
|
||||
|
@ -429,7 +428,6 @@ describe('/avatar', function() {
|
|||
it('should check url matches a provider', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
return Server.api.post({
|
||||
|
@ -455,7 +453,6 @@ describe('/avatar', function() {
|
|||
this.timeout(3000);
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
mock.image(imageData.length);
|
||||
|
@ -486,7 +483,6 @@ describe('/avatar', function() {
|
|||
it('should gracefully handle and report upload failures', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
mock.workerFailure('post', imageData.length);
|
||||
|
@ -531,7 +527,6 @@ describe('/avatar', function() {
|
|||
it('should fail if not owned by user', function() {
|
||||
mock.token({
|
||||
user: uid(),
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
return Server.api.delete({
|
||||
|
@ -547,7 +542,6 @@ describe('/avatar', function() {
|
|||
it('should remove avatar from user', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
return Server.api.delete({
|
||||
|
@ -570,7 +564,6 @@ describe('/avatar', function() {
|
|||
before(function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
mock.image(imageData.length);
|
||||
|
@ -591,7 +584,6 @@ describe('/avatar', function() {
|
|||
it('should remove avatar from db and s3', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
mock.deleteImage();
|
||||
|
@ -642,7 +634,6 @@ describe('/avatars', function() {
|
|||
it('should return a list of avatars', function() {
|
||||
mock.token({
|
||||
user: user,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:avatar:write']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -675,7 +666,6 @@ describe('/display_name', function() {
|
|||
it('should return a displayName', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name']
|
||||
});
|
||||
|
||||
|
@ -697,7 +687,6 @@ describe('/display_name', function() {
|
|||
var userId = uid();
|
||||
mock.token({
|
||||
user: userId,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name']
|
||||
});
|
||||
|
||||
|
@ -715,7 +704,6 @@ describe('/display_name', function() {
|
|||
it('should NOT return a display_name if wrong scope', function() {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:email']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -734,7 +722,6 @@ describe('/display_name', function() {
|
|||
var NAME = 'Spock';
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name:write']
|
||||
});
|
||||
return Server.api.post({
|
||||
|
@ -757,7 +744,6 @@ describe('/display_name', function() {
|
|||
var NAME = 'Spock';
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name:write']
|
||||
});
|
||||
return Server.api.post({
|
||||
|
@ -772,7 +758,6 @@ describe('/display_name', function() {
|
|||
assert.equal(res.statusCode, 200);
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name:write']
|
||||
});
|
||||
return Server.api.post({
|
||||
|
@ -788,7 +773,6 @@ describe('/display_name', function() {
|
|||
assert.equal(res.statusCode, 200);
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -811,7 +795,6 @@ describe('/display_name', function() {
|
|||
return P.resolve(NAMES).each(function(NAME) {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name:write']
|
||||
});
|
||||
return Server.api.post({
|
||||
|
@ -826,7 +809,6 @@ describe('/display_name', function() {
|
|||
assert.equal(res.statusCode, 200);
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name']
|
||||
});
|
||||
return Server.api.get({
|
||||
|
@ -858,7 +840,6 @@ describe('/display_name', function() {
|
|||
return P.resolve(NAMES).each(function(NAME) {
|
||||
mock.token({
|
||||
user: USERID,
|
||||
email: 'user@example.domain',
|
||||
scope: ['profile:display_name:write']
|
||||
});
|
||||
return Server.api.post({
|
||||
|
|
|
@ -24,7 +24,6 @@ module.exports = function mock(options) {
|
|||
const TOKEN_GOOD = JSON.stringify({
|
||||
user: options.userid,
|
||||
scope: ['profile'],
|
||||
email: 'user@example.domain'
|
||||
});
|
||||
|
||||
const MOCK_ID = new Array(33).join('f');
|
||||
|
@ -118,14 +117,18 @@ module.exports = function mock(options) {
|
|||
tokenGood: function tokenGood() {
|
||||
var parts = url.parse(config.get('oauth.url'));
|
||||
return nock(parts.protocol + '//' + parts.host)
|
||||
.post(parts.path + '/verify')
|
||||
.post(parts.path + '/verify', function(body) {
|
||||
return body.email === false;
|
||||
})
|
||||
.reply(200, TOKEN_GOOD);
|
||||
},
|
||||
|
||||
token: function token(tok) {
|
||||
var parts = url.parse(config.get('oauth.url'));
|
||||
return nock(parts.protocol + '//' + parts.host)
|
||||
.post(parts.path + '/verify')
|
||||
.post(parts.path + '/verify', function(body) {
|
||||
return body.email === false;
|
||||
})
|
||||
.reply(200, JSON.stringify(tok));
|
||||
},
|
||||
|
||||
|
@ -137,6 +140,22 @@ module.exports = function mock(options) {
|
|||
|
||||
},
|
||||
|
||||
email: function mockEmail(email) {
|
||||
var parts = url.parse(config.get('authServer.url'));
|
||||
return nock(parts.protocol + '//' + parts.host)
|
||||
.get(parts.path + '/account/profile')
|
||||
.reply(200, {
|
||||
email: email
|
||||
});
|
||||
},
|
||||
|
||||
emailFailure: function mockEmailFailure() {
|
||||
var parts = url.parse(config.get('authServer.url'));
|
||||
return nock(parts.protocol + '//' + parts.host)
|
||||
.get(parts.path + '/account/profile')
|
||||
.reply(500);
|
||||
},
|
||||
|
||||
workerFailure: function workerFailure(action, bytes) {
|
||||
if (action !== 'post' && action !== 'delete') {
|
||||
throw new Error('failure must be post or delete');
|
||||
|
|
Загрузка…
Ссылка в новой задаче