-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disable all remote methods and enable only selected ones (white-list) #651
Comments
@bajtos Can you please clarify which part of this is docs and which is an enhancement request. |
AFAIK, this is not possible at the moment. Let's keep this issue open to track your request for that. Note that the implementation will require changes in the strong-remoting module too.
You have to call
After a closer look, this is a pure enhancement. I am going to remove the "doc" label. |
I'm able to hide my remote methods from the explorer when using @voitau's function in 2.17.2. |
+1 |
great code @voitau, thanks! |
To hide ALL methods, I ended up doing this function disableAllMethodsBut(model, methodsToExpose)
{
if(model && model.sharedClass)
{
methodsToExpose = methodsToExpose || [];
var modelName = model.sharedClass.name;
var methods = model.sharedClass.methods();
var relationMethods = [];
var hiddenMethods = [];
try
{
Object.keys(model.definition.settings.relations).forEach(function(relation)
{
relationMethods.push({ name: '__findById__' + relation, isStatic: false });
relationMethods.push({ name: '__destroyById__' + relation, isStatic: false });
relationMethods.push({ name: '__updateById__' + relation, isStatic: false });
relationMethods.push({ name: '__exists__' + relation, isStatic: false });
relationMethods.push({ name: '__link__' + relation, isStatic: false });
relationMethods.push({ name: '__get__' + relation, isStatic: false });
relationMethods.push({ name: '__create__' + relation, isStatic: false });
relationMethods.push({ name: '__update__' + relation, isStatic: false });
relationMethods.push({ name: '__destroy__' + relation, isStatic: false });
relationMethods.push({ name: '__unlink__' + relation, isStatic: false });
relationMethods.push({ name: '__count__' + relation, isStatic: false });
relationMethods.push({ name: '__delete__' + relation, isStatic: false });
});
} catch(err) {}
methods.concat(relationMethods).forEach(function(method)
{
var methodName = method.name;
if(methodsToExpose.indexOf(methodName) < 0)
{
hiddenMethods.push(methodName);
model.disableRemoteMethod(methodName, method.isStatic);
}
});
if(hiddenMethods.length > 0)
{
console.log('\nRemote mehtods hidden for', modelName, ':', hiddenMethods.join(', '), '\n');
}
}
}; |
FYI, I am working on a feature that enables/disables sharedMethods using settings in |
@superkhau Is there any sprint planned for these features? |
@mrbatista Anything marked with a label is up for sprint planning. There is no guarantee when the issue will be pulled into the current sprint. See https://waffle.io/strongloop-internal/scrum-loopback. |
@EricPrieto In what file did you run that method? |
@devonatdomandtom in any file... Just pass the model that you want the methods to be hidden. I usually run that on the model implementation. |
@EricPrieto thanks! did you include the function definition there as well? |
This is what I'm doing to disable current methods:
|
@devonatdomandtom no, I store this function in some helpers library helpers.js module.exports.disableAllMethods = function disableAllMethods(model, methodsToExpose)
{
if(model && model.sharedClass)
{
methodsToExpose = methodsToExpose || [];
var modelName = model.sharedClass.name;
var methods = model.sharedClass.methods();
var relationMethods = [];
var hiddenMethods = [];
try
{
Object.keys(model.definition.settings.relations).forEach(function(relation)
{
relationMethods.push({ name: '__findById__' + relation, isStatic: false });
relationMethods.push({ name: '__destroyById__' + relation, isStatic: false });
relationMethods.push({ name: '__updateById__' + relation, isStatic: false });
relationMethods.push({ name: '__exists__' + relation, isStatic: false });
relationMethods.push({ name: '__link__' + relation, isStatic: false });
relationMethods.push({ name: '__get__' + relation, isStatic: false });
relationMethods.push({ name: '__create__' + relation, isStatic: false });
relationMethods.push({ name: '__update__' + relation, isStatic: false });
relationMethods.push({ name: '__destroy__' + relation, isStatic: false });
relationMethods.push({ name: '__unlink__' + relation, isStatic: false });
relationMethods.push({ name: '__count__' + relation, isStatic: false });
relationMethods.push({ name: '__delete__' + relation, isStatic: false });
});
} catch(err) {}
methods.concat(relationMethods).forEach(function(method)
{
var methodName = method.name;
if(methodsToExpose.indexOf(methodName) < 0)
{
hiddenMethods.push(methodName);
model.disableRemoteMethod(methodName, method.isStatic);
}
});
if(hiddenMethods.length > 0)
{
console.log('\nRemote mehtods hidden for', modelName, ':', hiddenMethods.join(', '), '\n');
}
}
}; models/SomeModel.js var disableAllMethods = require('../helpers.js').disableAllMethods;
module.exports = function(SomeModel)
{
disableAllMethods(SomeModel, [... methodsIDontWannaHide]);
...
}; |
@EricPrieto Amazing sir. That was exceedingly helpful |
@EricPrieto thanks! |
Anytime, guys :) |
@alFReD-NSH thanks, ur code is simple. |
@gunjpan Cool--please keep me posted. I added the |
I have refactored the code to be a little more DRY and also include a method for passing in an array of endpoints to disable. 'use strict';
const
relationMethodPrefixes = [
'prototype.__findById__',
'prototype.__destroyById__',
'prototype.__updateById__',
'prototype.__exists__',
'prototype.__link__',
'prototype.__get__',
'prototype.__create__',
'prototype.__update__',
'prototype.__destroy__',
'prototype.__unlink__',
'prototype.__count__',
'prototype.__delete__'
];
function reportDisabledMethod( model, methods ) {
const joinedMethods = methods.join( ', ' );
if ( methods.length ) {
console.log( '\nRemote methods hidden for', model.sharedClass.name, ':', joinedMethods, '\n' );
}
}
module.exports = {
disableAllExcept( model, methodsToExpose ) {
const
excludedMethods = methodsToExpose || [];
var hiddenMethods = [];
if ( model && model.sharedClass ) {
model.sharedClass.methods().forEach( disableMethod );
Object.keys( model.definition.settings.relations ).forEach( disableRelatedMethods );
reportDisabledMethod( model, hiddenMethods );
}
function disableRelatedMethods( relation ) {
relationMethodPrefixes.forEach( function( prefix ) {
var methodName = prefix + relation;
disableMethod({ name: methodName });
});
}
function disableMethod( method ) {
var methodName = method.name;
if ( excludedMethods.indexOf( methodName ) < 0 ) {
model.disableRemoteMethodByName( methodName );
hiddenMethods.push( methodName );
}
}
},
/**
* Options for methodsToDisable:
* create, upsert, replaceOrCreate, upsertWithWhere, exists, findById, replaceById,
* find, findOne, updateAll, deleteById, count, updateAttributes, createChangeStream
* -- can also specify related method using prefixes listed above
* and the related model name ex for Account: (prototype.__updateById__followers, prototype.__create__tags)
* @param model
* @param methodsToDisable array
*/
disableOnlyTheseMethods( model, methodsToDisable ) {
methodsToDisable.forEach( function( method ) {
model.disableRemoteMethodByName( method );
});
reportDisabledMethod( model, methodsToDisable );
}
}; |
@dancingshell could you turn this into a module, maybe even a mixin? Also, this does not hide |
@Discountrobot and @dancingshell --- converted to mixin: You can expose methods in your model.json file: {
"mixins":{
"DisableAllMethods":{
"expose":[
"find",
"findById"
]
}
}
} or hide specific methods: {
"mixins":{
"DisableAllMethods":{
"hide":[
"create"
]
}
}
} https://gist.github.com/drmikecrowe/7ec75265fda2788e1c08249ece505a44 |
hi, |
What I chose to do (I just updated the Gist) is to not hide any methods that had explicit ACL's. So, if you granted an allow permission, then expose that method or remote method (based on these comments #651 (comment)) |
@drmikecrowe , all, please see this gist I refactored bits and pieces to make the code more straightforward and compatible with any version of loopback including v3 where a number of function names change. Especially, i simplified the whole <is this a static or is this a related instance method?> logic. The reason why you only get static model methods from I also added an option for the mixin to work even if not specifying any method to explicitly hide or expose Also included is an index.js file to allow for mixin declaration Note: the code now uses the |
After all I bootstrapped a whole new mixin which is more compact (leveraging on lodash sugar): the option to enable methods from ACLs is now configurable with |
@ebarault Where did you spot |
@PaddyMann : it's from my own mixin code : here (although it's intended to bet set when expected false, as it defaults to true) |
ah great stuff (sorry I misread your previous comment!) I'll probably give your mixin a try in the next week or two :) |
@ebarault: what would be the differences between using your gist and this module https://github.com/Neil-UWA/loopback-remote-routing ? (Are there any differences?) If there are differences, I would recommend creating your code as a npm module. |
@c3s4r You meant your comment for someone else? (no gists from me?) |
Sorry, I meant @ebarault. I just edited my comment. |
@c3s4r thanks for bringing this mixin through yes, the idea is to port it as an npm module ultimately |
I just finished creating a module for this. I changed the names of the options a little bit, and added unit tests. I manually tested on loopback 2 and 3, and it seems to be working fine. https://www.npmjs.com/package/loopback-setup-remote-methods-mixin I'm also thinking on adding an option for defining new remote methods as well. (Which will be deprecated when the Methods section is implemented for Loopback 3, but can be useful for Loopback 2). Any comments or suggestions are welcome :) |
As I said: I will be pushing the mixin as an npm module soon. @c3s4r : although you most probably did this with all the best intentions :
|
@ebarault: Sorry, I did this on my best intentions, didn't want to steal the credit. I couldn't wait because I was needing it for a project, so I putted some effort on doing the unit tests, refactoring the code and publishing the module. Anyways,... let me know how you would like to proceed. I can mention you on the credits, or I can transfer you the project. |
-> no pb @c3s4r : not my full credit at all either. We can add a list of contributors from this thread. |
I just fixed the broken implementation but haven't pushed yet. (Can do it
tomorrow morning). Anyone that has contributed on the initial code please
let me know your usernames on npm so I can add you as contributors.
|
I just pushed the package to npm with the outstanding bug fixed. Also, I added @ebarault and @drmikecrowe as contributors and a credits section in the README file. https://www.npmjs.com/package/loopback-setup-remote-methods-mixin |
@ebarault I think it makes sense to create an issue for that at https://github.com/devsu/loopback-setup-remote-methods-mixin/issues |
@ebarault: I'm aware of the limitation, I didn't see it like a big issue, anyways, if you think it should be changed, please open an issue on the other repo and let's continue the conversation there. |
thanks all for the module, it is cool, but it is slow when you have many models and each of them has many relations. anything we can do about it? |
@go2smartphone Something to deal with |
@go2smartphone @HyperC0der Please open a new issue describing the problem you are facing in detail, ideally with a small app reproducing it (see http://loopback.io/doc/en/contrib/Reporting-issues.html#bug-report). |
There is a bunch of existing open/closed issues with questions how to hide the method of the model. My question is about how can all the methods be disabled first and then enabled only those which are necessary? (basically, duplicates this comment: #465 (comment))
Here is the simple function which hides all the methods of the model:
However, it doesn't hide two groups:
Could you please advise what would be the correct way to hide everything (without specific call for each method by its name explicitly) and allow only the methods which are necessary?
The text was updated successfully, but these errors were encountered: