Skip to content

Commit

Permalink
Merge pull request #402 from kuzzleio/6.1.2-proposal
Browse files Browse the repository at this point in the history
Release 6.1.2

Bug fixes

    [ #398 ] Fix bulk return (Aschen)
    [ #394 ] Add default values for from/size to document:search (Aschen)
    [ #384 ] Fix search API: "sort" and "search_after" must be in the requests body (scottinet)

Enhancements

    [ #390 ] Add authenticated property on Kuzzle object (Aschen)
    [ #395 ] Proxify kuzzle to avoid mistyping error (thomasarbona)
    [ #389 ] Remove usage of _meta (Aschen)
    [ #391 ] Add isConnected (Aschen)
    [ #388 ] Use BaseController class for controllers (Aschen)
    [ #385 ] Add Security.createRestrictedUser method (Aschen)

Others

    [ #400 ] Fix large document search using scroll (stafyniaksacha)
    [ #387 ] SearchResult.next returns a new instance (Aschen)
  • Loading branch information
Aschen authored Jun 14, 2019
2 parents ff49bb5 + 357ddba commit 5b9a181
Show file tree
Hide file tree
Showing 37 changed files with 722 additions and 181 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"yoda": [2, "never"]
},
"parserOptions": {
"ecmaVersion": 2017
"ecmaVersion": 2018
},
"extends": "eslint:recommended"
}
2 changes: 1 addition & 1 deletion features/steps/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Then('the mapping of {string} should be updated', async function (collection) {
const mapping = await this.kuzzle.collection.getMapping(this.index, collection);

should(mapping[this.index].mappings[collection]).eql({
dynamic: 'true',
properties: {
gordon: {type: 'keyword'}
}
Expand All @@ -129,7 +130,6 @@ Then('the specifications of {string} must not exist', async function (collection
catch (error) {
should(error.status).eql(404);
}

});

Then('they should be validated', function () {
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kuzzle-sdk",
"version": "6.1.1",
"version": "6.1.2",
"description": "Official Javascript SDK for Kuzzle",
"author": "The Kuzzle Team <[email protected]>",
"repository": {
Expand Down
86 changes: 44 additions & 42 deletions src/Kuzzle.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const
SecurityController = require('./controllers/security'),
MemoryStorageController = require('./controllers/memoryStorage'),
BaseController = require('./controllers/base'),
uuidv4 = require('./uuidv4');
uuidv4 = require('./uuidv4'),
proxify = require('./proxify');

const
events = [
Expand Down Expand Up @@ -87,6 +88,14 @@ class Kuzzle extends KuzzleEventEmitter {
}
this.queuing = false;
this.replayInterval = 10;

this._jwt = undefined;

return proxify(this, {
seal: true,
name: 'kuzzle',
exposeApi: true
});
}

get autoQueue () {
Expand Down Expand Up @@ -116,28 +125,6 @@ class Kuzzle extends KuzzleEventEmitter {
this._autoReplay = value;
}

get jwt () {
return this._jwt;
}

set jwt (token) {
if (token === undefined || token === null) {
this._jwt = undefined;
}
else if (typeof token === 'string') {
this._jwt = token;
}
else if (typeof token === 'object'
&& token.result
&& token.result.jwt
&& typeof token.result.jwt === 'string'
) {
this._jwt = token.result.jwt;
} else {
throw new Error(`Invalid token argument: ${token}`);
}
}

get host () {
return this.protocol.host;
}
Expand Down Expand Up @@ -203,6 +190,26 @@ class Kuzzle extends KuzzleEventEmitter {
return this.protocol.sslConnection;
}

get authenticated () {
return this.auth.authenticationToken && !this.auth.authenticationToken.expired;
}

get jwt () {
if (!this.auth.authenticationToken) {
return null;
}

return this.auth.authenticationToken.encodedJwt;
}

set jwt (encodedJwt) {
this.auth.authenticationToken = encodedJwt;
}

get connected () {
return this.protocol.connected;
}

/**
* Emit an event to all registered listeners
* An event cannot be emitted multiple times before a timeout has been reached.
Expand Down Expand Up @@ -238,7 +245,7 @@ class Kuzzle extends KuzzleEventEmitter {
this.protocol.addListener('queryError', (err, query) => this.emit('queryError', err, query));

this.protocol.addListener('tokenExpired', () => {
this.jwt = undefined;
this.auth.authenticationToken = null;
this.emit('tokenExpired');
});

Expand Down Expand Up @@ -274,16 +281,17 @@ class Kuzzle extends KuzzleEventEmitter {
this.playQueue();
}

if (this.jwt) {
return this.auth.checkToken(this.jwt)
if (this.auth.authenticationToken) {
return this.auth.checkToken()
.then(res => {

// shouldn't obtain an error but let's invalidate the token anyway
if (!res.valid) {
this.jwt = undefined;
this.auth.authenticationToken = null;
}
})
.catch(() => {
this.jwt = undefined;
this.auth.authenticationToken = null;
})
.then(() => this.emit('reconnected'));
}
Expand Down Expand Up @@ -371,16 +379,7 @@ class Kuzzle extends KuzzleEventEmitter {
request.volatile.sdkInstanceId = this.protocol.id;
request.volatile.sdkVersion = this.sdkVersion;

/*
* Do not add the token for the checkToken route, to avoid getting a token error when
* a developer simply wish to verify his token
*/
if (this.jwt !== undefined
&& !(request.controller === 'auth'
&& (request.action === 'checkToken' || request.action === 'login'))
) {
request.jwt = this.jwt;
}
this.auth.authenticateRequest(request);

let queuable = true;
if (options && options.queuable === false) {
Expand Down Expand Up @@ -456,20 +455,23 @@ Discarded request: ${JSON.stringify(request)}`));
throw new Error('You must provide a valid accessor.');
}

if (this[accessor]) {
if (this.__proxy__ ? this.__proxy__.hasProp(accessor) : this[accessor]) {
throw new Error(`There is already a controller with the accessor '${accessor}'. Please use another one.`);
}

const controller = new ControllerClass(this);

if (!(controller.name && controller.name.length > 0)) {
throw new Error('Controllers must have a name.');
}

if (controller.kuzzle !== this) {
throw new Error('You must pass the Kuzzle SDK instance to the parent constructor.');
}


if (this.__proxy__) {
this.__proxy__.registerProp(accessor);
}
this[accessor] = controller;

return this;
Expand Down
67 changes: 53 additions & 14 deletions src/controllers/auth.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const
Jwt = require('../core/Jwt'),
BaseController = require('./base'),
User = require('./security/user');

Expand All @@ -16,6 +17,39 @@ class AuthController extends BaseController {
*/
constructor (kuzzle) {
super(kuzzle, 'auth');

this._authenticationToken = null;
}

get authenticationToken () {
return this._authenticationToken;
}

set authenticationToken (encodedJwt) {
if (encodedJwt === undefined || encodedJwt === null) {
this._authenticationToken = null;
} else if (typeof encodedJwt === 'string') {
this._authenticationToken = new Jwt(encodedJwt);
} else {
throw new Error(`Invalid token argument: ${encodedJwt}`);
}
}

/**
* Do not add the token for the checkToken route, to avoid getting a token error when
* a developer simply wish to verify his token
*
* @param {object} request
*/
authenticateRequest (request) {
if (!this.authenticationToken
|| (request.controller === 'auth'
&& (request.action === 'checkToken' || request.action === 'login'))
) {
return;
}

request.jwt = this.authenticationToken.encodedJwt;
}

/**
Expand All @@ -25,10 +59,14 @@ class AuthController extends BaseController {
* @return {Promise|*|PromiseLike<T>|Promise<T>}
*/
checkToken (token) {
if (token === undefined && this.authenticationToken) {
token = this.authenticationToken.encodedJwt;
}

return this.query({
action: 'checkToken',
body: {token}
}, {queuable: false})
body: { token }
}, { queuable: false })
.then(response => response.result);
}

Expand Down Expand Up @@ -87,7 +125,7 @@ class AuthController extends BaseController {
return this.query({
action: 'getCurrentUser'
}, options)
.then(response => new User(this.kuzzle, response.result._id, response.result._source, response.result._meta));
.then(response => new User(this.kuzzle, response.result._id, response.result._source));
}

/**
Expand Down Expand Up @@ -144,23 +182,24 @@ class AuthController extends BaseController {
throw new Error('Kuzzle.auth.login: strategy is required');
}

const
request = {
strategy,
expiresIn,
body: credentials,
action: 'login'
};
const request = {
strategy,
expiresIn,
body: credentials,
action: 'login'
};

return this.query(request, {queuable: false})
.then(response => {
try {
this.kuzzle.jwt = response.result.jwt;
this._authenticationToken = new Jwt(response.result.jwt);

this.kuzzle.emit('loginAttempt', {success: true});
}
catch (err) {
return Promise.reject(err);
}

return response.result.jwt;
})
.catch(err => {
Expand All @@ -179,7 +218,7 @@ class AuthController extends BaseController {
action: 'logout'
}, {queuable: false})
.then(() => {
this.kuzzle.jwt = undefined;
this._authenticationToken = null;
});
}

Expand Down Expand Up @@ -212,7 +251,7 @@ class AuthController extends BaseController {
body,
action: 'updateSelf'
}, options)
.then(response => new User(this.kuzzle, response.result._id, response.result._source, response.result._meta));
.then(response => new User(this.kuzzle, response.result._id, response.result._source));
}

/**
Expand Down Expand Up @@ -246,7 +285,7 @@ class AuthController extends BaseController {

return this.query(query, options)
.then(response => {
this.kuzzle.jwt = response.result.jwt;
this._authenticationToken = new Jwt(response.result.jwt);

return response.result;
});
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/bulk.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class BulkController extends BaseController {
bulkData: data
}
}, options)
.then(response => response.result.items);
.then(response => response.result);
}

}
Expand Down
6 changes: 6 additions & 0 deletions src/controllers/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,17 @@ class DocumentController extends BaseController {
body,
action: 'search',
};

for (const opt of ['from', 'size', 'scroll', 'includeTrash']) {
request[opt] = options[opt];
delete options[opt];
}

request.size = request.size || 10;
if (!request.scroll && !request.body.sort && !request.from) {
request.from = 0;
}

return this.query(request, options)
.then(response => new DocumentSearchResult(this.kuzzle, request, options, response.result));
}
Expand Down
3 changes: 2 additions & 1 deletion src/controllers/realtime/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ class RealTimeController extends BaseController {
}

this.subscriptions = {};
this.kuzzle.jwt = undefined;
this.kuzzle.auth.authenticationToken = null;

const now = Date.now();

if ((now - this.lastExpirationTimestamp) > expirationThrottleDelay) {
this.lastExpirationTimestamp = now;
this.kuzzle.emit('tokenExpired');
Expand Down
1 change: 1 addition & 0 deletions src/controllers/searchResult/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class SearchResultBase {
return this._kuzzle.query({
controller: this._request.controller,
action: this._scrollAction,
scroll: this._request.scroll,
scrollId: this._response.scrollId
}, this._options)
.then(response => this._buildNextSearchResult(response));
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/searchResult/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class UserSearchResult extends SearchResultBase {

this._searchAction = 'searchUsers';
this._scrollAction = 'scrollUsers';
this.hits = this._response.hits.map(hit => new User(this._kuzzle, hit._id, hit._source, hit._meta));
this.hits = this._response.hits.map(hit => new User(this._kuzzle, hit._id, hit._source));
}

next () {
Expand All @@ -19,7 +19,7 @@ class UserSearchResult extends SearchResultBase {
return null;
}

nextSearchResult.hits = nextSearchResult._response.hits.map(hit => new User(nextSearchResult._kuzzle, hit._id, hit._source, hit._meta));
nextSearchResult.hits = nextSearchResult._response.hits.map(hit => new User(nextSearchResult._kuzzle, hit._id, hit._source));
return nextSearchResult;
});
}
Expand Down
Loading

0 comments on commit 5b9a181

Please sign in to comment.