I'm writing a node.js based server that manages a range of devices. The node.js based server tells connected clients about its abilities. The abilities are defined by separate js files that define objects that are using inheritance via util.inherits().
The problem I have is that right now, I have to define a new js for a new ability and then update the main js program to require the new js, change the code to publish that the ability is available, and then utilise the new ability if requested to by the client.
I would like to make the main code more generic whereby it can
detect the new abilities,
automatically include them,
notify the clients, and
utilise the code.
The detection I can do via the various npm modules out there that support tree browsing, I can just nominate a subdirectory for all capabilities and discover what files are there. I presume that I can use require for step 2 (though not 100% certain), however I don't know how to do step 3 and 4 or use the results from step 2 with step 3 and 4.
I would value any feedback on how to solve this problem.
To clarify my problem. Right now my logic is as per the following:
var logicA = requires('./capabilities/a.js');
var logicB = requires('./capabilities/b.js');
var logicC = requires('./capabilities/c.js');
var Comms.CAPABILITY_A = 'a';
var Comms.CAPABILITY_B = 'b';
var Comms.CAPABILITY_C = 'c';
var Comms.MSG_CAPABILITY = 0;
var Comms.MSG_DO_LOGIC = 1;
function onMessageReceived(comms, msgId, body) {
switch (msgId) {
case(MSG_DO_LOGIC):
doLogic(body);
break;
...
}
}
function doLogic(flag) {
switch(flag) {
case(Comms.CAPABILITY_A):
logicA.doLogic();
break;
case(Comms.CAPABILITY_B):
logicB.doLogic();
break;
case(Comms.CAPABILITY_C):
logicC.doLogic();
break;
}
}
At the client side I have hard coded logic that presumes what is available. I can remove this by having the server send an array of the capabilities to the client, and then the client can choose one of the elements of the array and pass it back as the request to execute the logic. This is not my problem.
My problem is understanding how to cause the host program load all the logic dynamically and then evaluate which logic to execute on the dynamically loaded logic.
I should state that when I say dynamic, I mean that the code available is determined at runtime. However the evaluation is only ever performed when the server is first started.
I solved the problem by creating a register.js where all the protocols are kept. Each time I create a new protocol, I add it to the register.
Via the register I can get an array of all registered protocols. I can pass them back to the client, the client can choose a protocol and I can request an instance of the protocol via the register class.
While there is some hardcoding, it's restricted to the register class which is in the same directory as the protocols.
So in the register I have the following functions:
getList()
getText()
validateProtocolId()
getProtocol()
I use getList() to return an array of the protocol id's that are registered. I use getText() to provide a human readable list of supported protocols. I use validateProtocolId() to validate an id returned from the client to confirm that the id represents a registered protocol and then I use getProtocol() to generate an instance of the registered protocol.
In essence the getProtocol() just does a require('./<protocol file>.js') as appropriate.
It's not as elegant as auto discovery, but it allows tighter controls on what is registered without forcing custom file, etc.
Related
I'm developing my project with Blazor Server-side.
While I develop, I used javascript code to implement things that hard to implement by C#.
However, I'm facing something weird situation. (I guess it is problem for javascript)
Suppose there are 2 users(A, B). When 'A' user do some action that call javascript code, if 'B' user into same page, 'A' users action affects to 'B' user.
I implemented web page that have 3d scene with threejs. As I explained above, when User 'A' move some object with mouse event(mousemove, mousedown..), if User 'B' accesses the same page, 3d objects of B are moved to the location where User 'A' moved.
Originally, when user access to web page I developed, 3d objects's position should be 0,0,0.
My Guess
I don't use prototype or class(use variable and functions globally. I'm new to javascript.. )
Javascript runs on server-side(share resources??, If then, how can I solve it)
I'm guessing the javascript would be problem, but if you have any other opinions, would you please share?
Edited
I've solved this problem using DotNetObjectReference.Create(this);
C#
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//send created instance to javascript
var dotNetObjRef = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("SetObjectRef", dotNetObjRef);
}
await base.OnAfterRenderAsync(firstRender);
}
[JSInvokable]
public async Task enableSomething(bool bEnable)
{
var something = bEnable;
}
//== before edit
//[JSInvokable]
//public static async Task enableSomethingStatic(bool bEnable)
//{
// var something = bEnable;
//}
Javascript
var objectRef;
function SetObjectRef(ref) {
objectRef = ref;
}
//call c# function
objectRef.invokeMethodAsync("enableSomething", true);
It was problem of 'static' method as I guessed.
If you declare C# method called from javascript as 'static' and this method changes something of UI variable, this method can affect another users.
So I create instance of current page and send it javascript and when I need to call C# methods from javascript, I call methods using created instance.
Is there any problem or issue, please share it.
Sorry for my bad English.
JavaScript runs client side only. I don't see how two windows, let alone two users, would share data.
Almost for sure, the problem is that you are injecting a singleton service-- which means the server will use one instance for all users.
If so, you have two choices:
(1) add logic to your singleton service to incorporate users. (For example, a dictionary with UserID/Property name for key, and a column for Value)
(2) go to Startup.cs and change the suspect singleton service to .AddScoped(), which will create a new instance for each user.
For right now, I think the latter solution will solve your problem immediately. However, don't underestimate the value of Singletons-- they'll be very useful for other things.
I am rather confused with mechanics and hierarchy of things in javascript, reading few links and pages are adding to them.
There are various ways to create objects in Javascript. What I am getting confused is in following:
I have 3 websocket say WSServiceA, WSServiceB, WSServiceC : These are 3 different sockets and provide different data but data structure is same. Using a simple function I am updating 3 tables in web-page.
Each of these have onopen, onclose and onmessage function so I have simply copied same code 3 times, like this:
WSServiceA.onmessage(){}
WSServiceB.onmessage(){}
WSServiceC.onmessage(){}
If I create a something like this:
function CreateService(Service, WSAddress){
this.service=Service;
this.WSAddress = WSAddress;
this.websocket = new WebSocket(this.WSAddres);
this.onopen = function(event){ Send some message }
this.onmessage = function(event){ Update Table A}
}
After that I will create
ServiceA = CreateService("A", "ws://192.168.100.1.1:10001");
ServiceB = CreateService("B", "ws://192.168.100.1.2:10001");
ServiceC = CreateService("C", "ws://192.168.100.1.3:10001");
Then how and who will call ServiceA.onopen, Service.onmessage and other functions - when data comes to those sockets? Will it be called at all? Something created inside function should be visible only in that function - I am not able to understand flow and link. Probably I am missing some key concept or this should not work.
Background
There is ECMAScript, which is the language, and javascript, which is a generic name for an implementation of ECMAScript for a particular host (noting that JavaScriptâ„¢ is a trademark of Oracle Corporation).
ECMAScript by itself does very little, it doesn't even have a mechanism for input or output, it must be provided by the host. In regard to WebSockets, if the host supports them then it will implement the WebSockets API.
When you create a WebSocket through new WebSocket(...), then the host returns a host object that implements the interface. The object will have a state that changes in response to its environment (connecting, open, closing, closed) and it will dispatch events when certain things happen.
When the socket successfully makes a connection to the server, it will dispatch an open event on the socket, so that if there is an onopen listener, it will respond to the event by being called by the open handler. There are also events for error and close that have associated on* handlers.
Answer
Then how and who will call ServiceA.onopen, Service.onmessage and
other functions - when data comes to those sockets?
The host environment implementing the interface does all that.
Note: The context of this question is javascript, however is generic enough to not tie it as just as a javascript question.
We have a javascript library that needs to send a request using http or https. In order to decide which protocol to use, our library calls a method that decides which protocol should we use. That method is declared in the 'user side of our library' (as a callback?).
For the moment we have named it as isConnectionSecure but we are not asking that but instead the question is more like:
Should we use the secure protocol?
The library is working somehow like:
OurSuperLibrary.api = {
isConnectionSecure: function () {
// Do your checks
return true;
}
}
var ourLibrary = new OurSuperLibrary();
// Internally, our library will call the previously declared method:
ourLibrary.doRequest();
Thanks.
I have a similar problem to the person in this post; I'm trying to extend the cefsimple.exe app included with the chromium embedded framework binaries to include a V8 handler. I implemented the OnContextCreated() method and made sure to extend RenderProcessHandler in the SimpleHandler class. I'm trying to implement a simple window bound variable called test_string; here's what my code looks like;
void SimpleHandler::OnContextCreated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
CefRefPtr<CefV8Value> object = context->GetGlobal();
object->SetValue("test_string", CefV8Value::CreateString("this is a test"), V8_PROPERTY_ATTRIBUTE_NONE);
}
But the program never arrives at any breakpoints I add within the method, and the variable is undefined on any webpages I load within the app. I saw that one of the solutions in the other thread is to enable the settings.single_process flag, which i've done, but my code still doesn't reach the breakpoint.
To be clear, I'm accessing the variable on pages with window.test_string.
Make sure that you are sending that CefApp to CefExecuteProcess.
CefRefPtr<SimpleApp> app(new SimpleApp);
// CEF applications have multiple sub-processes (render, plugin, GPU, etc)
// that share the same executable. This function checks the command-line and,
// if this is a sub-process, executes the appropriate logic.
int exit_code = CefExecuteProcess(main_args, app, sandbox_info);
if (exit_code >= 0) {
// The sub-process has completed so return here.
return exit_code;
}
Found this solution here
Have you read through the General Usage guide? Some key points below
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-cefapp
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-processes
The single_process mode is not supported so I've never used it. In general I'd avoid it. The multi process architecture means you need to attach the debugger to the process. The Chromium guide is relevant to CEF in this instance.
https://www.chromium.org/developers/how-tos/debugging-on-windows#TOC-Attaching-to-the-renderer
you need to ensure your App is derived from CefRenderProcessHandler
not SimpleHandler!!!
class SimpleApp : public CefApp
, public CefRenderProcessHandler
{
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
valdemar-rudolfovich says you need to pass instance of SimpleApp in
CefExecuteProcess
I have a node js web app that is using handlebars. Users are asking me to let them register their own handlebars helpers.
I'm quite hesitant about letting them do it... but I'll give it a go if there is a secure way of doing it so.
var Handlebars = require("handlebars");
var fs = require("fs");
var content = fs.readFileSync("template.html", "utf8");
//This helper will be posted by the user
var userHandlebarsHelpers = "Handlebars.registerHelper('foo', function(value) { return 'Foo' + value; });"
//eval(userHandlebarsHelpers); This I do not like! Eval is evil
//Compile handlebars with user submitted Helpers
var template = Handlebars.compile(content);
var handleBarContent = template({ foo: bar });
//Save compiled template and some extra code.
Thank you in advance!
Because helpers are just Javascript code, the only way you could safely run arbitrary Javascript from the outside world on your server is if you either ran it an isolated sandbox process or you somehow sanitized the code before you ran it.
The former can be done with isolated VMs and external control over the process, but that makes it quite a pain to have helper code in some external process as you now have to develop ways to even call it and pass data back and forth.
Sanitizing Javascript to be safe from running exploits on your server is a pretty much impossible task when your API set is as large as node.js. The browser has a very tightly controlled set of things that Javascript can do to keep the underlying system safe from what browser Javascript can do. node.js has none of those safeguards. You could put code in one of these helpers to erase the entire hard drive of the server or install multiple viruses or pretty much whatever evil exploit you wanted to code. So, running arbitrary Javascript will simply not be safe.
Depending upon the exact problems that need to be solved, one can something develop a data driven approach where, instead of code, the user provides some higher level set of instructions (map this to that, substitute this with that, replace this with that, display from this set of data, etc...) that is not actually Javascript, but rather some non-executable meta data. That is much more feasible to make safe because you control all the code that acts on this meta data so you just have to make sure that the code that processes the meta data isn't capable of being tricked into doing something evil.
Following #jfriend00 input and after some serious testing I found a way to do it using nodejs vm module.
Users will input their helpers with this format:
[[HBHELPER 'customHelper' value]]
value.replace(/[0-9]/g, "");
[[/HBHELPER]]
[[HBHELPER 'modulus' index mod result block]]
if(parseInt(index) % mod === parseInt(result))
block.fn(this);
[[/HBHELPER]]
//This will throw an error when executed "Script execution timed out."
[[HBHELPER 'infiniteLoop' value]]
while(1){}
[[/HBHELPER]]
I translate that block into this and execute it:
Handlebars.registerHelper('customHelper', function(value) {
//All the code is executed inside the VM
return vm.runInNewContext('value.replace(/[0-9]/g, "");', {
value: value
}, {
timeout: 1000
});
});
Handlebars.registerHelper('modulus', function(index, mod, result, block) {
return vm.runInNewContext('if(parseInt(index) % mod === parseInt(result)) block.fn(this);', {
index: index,
mod: mod,
result: result,
block: block
}, {
timeout: 1000
});
});
Handlebars.registerHelper('infiniteLoop', function(value) {
//Error
return vm.runInNewContext('while(1){}', {
value: value
}, {
timeout: 1000
});
});
I made multiple tests so far, trying to delete files, require modules, infinite loops. Everything is going perfectly, all those operations failed.
Running the handlebar helper callback function in a VM is what made this work for me, because my main problem using VM's and running the whole code inside was adding those helpers to my global Handlebars object.
I'll update if I found a way to exploit it.