Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
},
"homepage": "https://github.com/makeomatic/ms-users#readme",
"dependencies": {
"@microfleet/core": "^12.0.0",
"@microfleet/core": "^13.2.1",
"@microfleet/transport-amqp": "^13.1.2",
"@microfleet/validation": "^8.0.0",
"@microfleet/validation": "^8.1.0",
"bell": "^9.3.1",
"bluebird": "^3.5.2",
"bunyan": "^1.8.12",
Expand All @@ -41,15 +41,16 @@
"dlock": "^8.1.0",
"flake-idgen": "^1.1.0",
"get-stdin": "^6.0.0",
"get-value": "^3.0.1",
"handlebars": "^4.0.12",
"hapi": "^17.6.0",
"ioredis": "^4.1.0",
"ioredis": "^4.2.0",
"is": "^3.2.1",
"jsonwebtoken": "^8.3.0",
"jwa": "^1.1.6",
"lodash": "^4.17.11",
"moment": "^2.22.2",
"ms-conf": "^3.3.0",
"ms-conf": "^3.3.1",
"ms-flakeless": "^4.1.0",
"ms-mailer-client": "^8.0.1",
"ms-mailer-templates": "^1.10.0",
Expand All @@ -75,10 +76,10 @@
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/plugin-transform-strict-mode": "^7.0.0",
"@babel/register": "^7.0.0",
"@makeomatic/deploy": "^8.0.1",
"@semantic-release/changelog": "^3.0.0",
"@semantic-release/exec": "^3.1.3",
"@semantic-release/git": "^7.0.4",
"@makeomatic/deploy": "^8.2.3",
"@semantic-release/changelog": "^3.0.1",
"@semantic-release/exec": "^3.3.0",
"@semantic-release/git": "^7.0.5",
"apidoc": "^0.17.6",
"apidoc-plugin-schema": "^0.1.8",
"babel-eslint": "^10.0.1",
Expand All @@ -87,7 +88,7 @@
"cheerio": "^1.0.0-rc.2",
"codecov": "^3.1.0",
"cross-env": "^5.2.0",
"eslint": "^5.7.0",
"eslint": "^5.8.0",
"eslint-config-makeomatic": "^3.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-mocha": "^5.2.0",
Expand All @@ -100,7 +101,7 @@
"nyc": "^13.1.0",
"puppeteer": "1.4.0",
"rimraf": "^2.6.1",
"sinon": "^7.0.0"
"sinon": "^7.1.0"
},
"engines": {
"node": ">= 8.9.0",
Expand Down
1 change: 0 additions & 1 deletion src/accounts/init-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ module.exports = function initAccounts() {
return Promise
.delay(config.initAdminAccountsDelay)
.return(accounts)
// @todo use router dispatch, because a schema can contains default params
.map((account) => {
const userData = {
audience,
Expand Down
2 changes: 1 addition & 1 deletion src/actions/_/me.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async function Me({ auth }) {
Me.auth = {
name: 'bearer',
strategy: 'required',
passError: true,
passAuthError: true,
};
Me.schema = 'me';
Me.transports = [ActionTransport.http, ActionTransport.amqp];
Expand Down
4 changes: 2 additions & 2 deletions src/actions/remove.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const { ActionTransport } = require('@microfleet/core');
const Promise = require('bluebird');
const Errors = require('common-errors');
const get = require('lodash/get');
const intersection = require('lodash/intersection');
const get = require('../utils/get-value');
const key = require('../utils/key');
const { getInternalData } = require('../utils/userData');
const getMetadata = require('../utils/getMetadata');
Expand Down Expand Up @@ -81,7 +81,7 @@ async function removeUser({ params }) {

// remove refs to SSO account
for (const provider of SSO_PROVIDERS) {
const uid = get(internal, `${provider}.uid`, false);
const uid = get(internal, `${provider}.uid`, { default: false });

if (uid) {
transaction.hdel(USERS_SSO_TO_ID, uid);
Expand Down
2 changes: 1 addition & 1 deletion src/auth/oauth/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const Promise = require('bluebird');
const Errors = require('common-errors');
const get = require('lodash/get');
const partial = require('lodash/partial');

const get = require('../../utils/get-value');
const getUid = require('./utils/uid');
const refresh = require('./utils/refresh');
const extractJWT = require('./utils/extractJWT');
Expand Down
17 changes: 8 additions & 9 deletions src/auth/oauth/strategies/facebook.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const Promise = require('bluebird');
const Crypto = require('crypto');
const differenceWith = require('lodash/differenceWith');
const get = require('lodash/get');
const defaults = require('lodash/defaults');
const Urls = require('../utils/fb-urls');
const get = require('../../../utils/get-value');

const FIELDS = [
'id',
Expand Down Expand Up @@ -46,7 +46,7 @@ function defaultProfileHandler(profile) {
credentials.raw = profile;

// if we have actual picture
if (get(profile, 'picture.data.is_silhouette', true) === false) {
if (get(profile, 'picture.data.is_silhouette', { default: true }) === false) {
credentials.profile.picture = profile.picture.data.url;
}

Expand Down Expand Up @@ -93,23 +93,22 @@ function verifyPermissions(permissions) {

function profileFactory(fields, profileHandler = defaultProfileHandler) {
return async function obtainProfile(credentials, params, getter) {
// eslint-disable-next-line camelcase
const appsecret_proof = Crypto.createHmac('sha256', this.clientSecret)
const ap = Crypto.createHmac('sha256', this.clientSecret)
.update(credentials.token)
.digest('hex');

const requiredPermissions = get(this, 'provider.scope', []);
const requiredPermissions = get(this, 'provider.scope', { default: [] });
const ctx = {
fields,
credentials,
requiredPermissions,
};

return Promise
.bind(ctx, [getter, { appsecret_proof }])
.bind(ctx, [getter, { appsecret_proof: ap }])
.spread(fetchPermissions)
.tap(verifyPermissions)
.return([getter, { appsecret_proof, fields }])
.return([getter, { appsecret_proof: ap, fields }])
.spread(fetchProfile)
.then(profileHandler);
};
Expand All @@ -132,8 +131,8 @@ exports.options = (options) => {
Urls.setVersion(apiVersion);
}

const fields = get(options, 'fields', FIELDS);
const profileHandler = get(options, 'profileHandler', defaultProfileHandler);
const fields = get(options, 'fields', { default: FIELDS });
const profileHandler = get(options, 'profileHandler', { default: defaultProfileHandler });

const configuredOptions = {
scope,
Expand Down
4 changes: 2 additions & 2 deletions src/auth/oauth/utils/detach.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const get = require('lodash/get');
const Errors = require('common-errors');

const get = require('../../../utils/get-value');
const redisKey = require('../../../utils/key');
const updateMetadata = require('../../../utils/updateMetadata');
const handlePipeline = require('../../../utils/pipelineError');
Expand All @@ -17,7 +17,7 @@ module.exports = function detach(provider, userData) {
const userDataKey = redisKey(userId, USERS_DATA);
const pipeline = redis.pipeline();

const uid = get(userData, [provider, 'uid'], false);
const uid = get(userData, [provider, 'uid'], { default: false });
if (!uid) {
throw Errors.HttpStatusError(412, `${provider} account not found`);
}
Expand Down
39 changes: 18 additions & 21 deletions src/users.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
const Mservice = require('@microfleet/core');
const { Microfleet, ConnectorsTypes } = require('@microfleet/core');
const Mailer = require('ms-mailer-client');
const merge = require('lodash/merge');
const assert = require('assert');
const fsort = require('redis-filtered-sort');
const TokenManager = require('ms-token');
const LockManager = require('dlock');
const get = require('lodash/get');
const RedisCluster = require('ioredis').Cluster;
const Flakeless = require('ms-flakeless');
const conf = require('./config');
const get = require('./utils/get-value');

/**
* @namespace Users
*/
module.exports = class Users extends Mservice {
module.exports = class Users extends Microfleet {
/**
* Configuration options for the service
* @type {Object}
Expand Down Expand Up @@ -63,11 +63,11 @@ module.exports = class Users extends Mservice {
this.flake = new Flakeless(config.flake);

this.on('plugin:connect:amqp', (amqp) => {
this._mailer = new Mailer(amqp, config.mailer);
this.mailer = new Mailer(amqp, config.mailer);
});

this.on('plugin:close:amqp', () => {
this._mailer = null;
this.mailer = null;
});

this.on(`plugin:connect:${this.redisType}`, (redis) => {
Expand All @@ -80,16 +80,16 @@ module.exports = class Users extends Mservice {

this.on('plugin:start:http', (server) => {
// if oAuth is enabled - initiate the strategy
if (get(config, 'oauth.enabled', false) === true) {
if (get(config, 'oauth.enabled', { default: false }) === true) {
assert.equal(config.http.server.handler, 'hapi', 'oAuth must be used with hapi.js webserver');

const OAuthStrategyHandler = require('./auth/oauth/hapi');
this._oauth = new OAuthStrategyHandler(server, config);
this.oauth = new OAuthStrategyHandler(server, config);
}
});

this.on('plugin:stop:http', () => {
this._oauth = null;
this.oauth = null;
});

// cleanup connections
Expand All @@ -100,42 +100,39 @@ module.exports = class Users extends Mservice {

// add migration connector
if (config.migrations.enabled === true) {
this.addConnector(Mservice.ConnectorsTypes.migration, () => (
this.addConnector(ConnectorsTypes.migration, () => (
this.migrate('redis', `${__dirname}/migrations`)
));
}

// adds mailer connector
this._defineGetter('mailer');

// ensure we close connection when needed
this.addDestructor(Mservice.ConnectorsTypes.database, () => (
this._pubsub.quit().reflect()
this.addDestructor(ConnectorsTypes.database, () => (
this.pubsub.quit().reflect()
));

// add lock manager
this.addConnector(Mservice.ConnectorsTypes.migration, async () => {
this._pubsub = redisDuplicate(this.redis);
await this._pubsub.connect();
this.addConnector(ConnectorsTypes.migration, async () => {
this.pubsub = redisDuplicate(this.redis);
await this.pubsub.connect();

this.dlock = new LockManager({
...config.lockManager,
client: this._redis,
pubsub: this._pubsub,
client: this.redis,
pubsub: this.pubsub,
log: this.log,
});

return this.dlock;
});

// init account seed
this.addConnector(Mservice.ConnectorsTypes.application, () => (
this.addConnector(ConnectorsTypes.application, () => (
this.initAdminAccounts()
));

// fake accounts for development
if (process.env.NODE_ENV === 'development') {
this.addConnector(Mservice.ConnectorsTypes.application, () => (
this.addConnector(ConnectorsTypes.application, () => (
this.initFakeAccounts()
));
}
Expand Down
8 changes: 8 additions & 0 deletions src/utils/get-value.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const get = require('get-value');

const { hasOwnProperty } = Object.prototype;
const isValid = (key, obj) => hasOwnProperty.call(obj, key) && obj[key] !== undefined;

module.exports = (target, path, options = {}) => {
return get(target, path, { ...options, isValid });
};
4 changes: 2 additions & 2 deletions test/docker-compose.sentinel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ services:
- rabbitmq
working_dir: /src
volumes:
- ${PWD}:/src
- ./configs:/configs
- ${PWD}:/src:cached
- ./configs:/configs:cached
extra_hosts:
- "ms-users.local:172.16.238.12"
environment:
Expand Down
4 changes: 2 additions & 2 deletions test/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ services:
- rabbitmq
working_dir: /src
volumes:
- ${PWD}:/src
- ./configs:/configs
- ${PWD}:/src:cached
- ./configs:/configs:cached
extra_hosts:
- "ms-users.local:172.16.238.12"
environment:
Expand Down
2 changes: 1 addition & 1 deletion test/suites/amqp.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('#AMQP', function AMQPSuite() {
afterEach(global.clearRedis);

it('should be able to make requests using AMQP transport', function test() {
const { defaultAudience: audience } = this.users._config.jwt;
const { defaultAudience: audience } = this.users.config.jwt;

return this.users.amqp.publishAndWait('users.verify', { token: 'invalid-token', audience })
.reflect()
Expand Down
2 changes: 1 addition & 1 deletion test/suites/bearer/strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('/_/me', function verifySuite() {

const {
hashingFunction: algorithm, secret, issuer, defaultAudience,
} = this.users._config.jwt;
} = this.users.config.jwt;

const token = jwt.sign({ username: 'vitaly' }, secret, { algorithm, audience: defaultAudience, issuer });

Expand Down
10 changes: 7 additions & 3 deletions test/suites/getMetadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('#getMetadata', function getMetadataSuite() {
afterEach(global.clearRedis);

it('must reject to return metadata on a non-existing username', function test() {
const { defaultAudience: audience } = this.users._config.jwt;
const { defaultAudience: audience } = this.users.config.jwt;

return this.dispatch('users.getMetadata', { username: 'noob', audience })
.reflect()
Expand All @@ -27,15 +27,19 @@ describe('#getMetadata', function getMetadataSuite() {
.dispatch('users.register', {
username, password: '123', audience, metadata: { name: { q: 'verynicedata' } },
})
.then(({ user }) => (this.firstUserId = user.id));
.then(({ user }) => {
this.firstUserId = user.id;
});
});

beforeEach(function pretest() {
return this
.dispatch('users.register', {
username: usernameB, password: '123', audience, metadata: { name: 'boredom' },
})
.then(({ user }) => (this.secondUserId = user.id));
.then(({ user }) => {
this.secondUserId = user.id;
});
});

beforeEach(function pretest() {
Expand Down
Loading