I am trying to use the ziti-sdk-nodejs, an opensource project, to secure a web application. I have a simple nodejs application that uses express. This application is a hello world demo that is deployed to Azure App Service. I'd like to use the ziti-nodejs sdk to secure my application.
I am trying to use the example shown here.
There is a part of the code that I need help understanding
const zitiHttpRequest = async (url, method, headers) => {
return new Promise((resolve) => {
ziti.Ziti_http_request(
url,
method,
headers,
(obj) => { // on_req callback
console.log('on_req callback: req is: %o', obj.req);
return resolve(obj.req);
},
(obj) => { // on_resp callback
console.log(`on_resp status: ${obj.code} ${obj.status}`);
if (obj.code != 200) {
core.setFailed(`on_resp failure: ${obj.status}`);
process.exit(-1);
}
process.exit(0);
},
(obj) => { // on_resp_body callback
// not expecting any body...
if (obj.len === UV_EOF) {
console.log('response complete')
process.exit(0);
} else if (obj.len < 0) {
core.setFailed(`on_resp failure: ${obj.len}`);
process.exit(-1);
}
if (obj.body) {
let str = Buffer.from(obj.body).toString();
console.log(`on_resp_body len: ${obj.len}, body: ${str}`);
} else {
console.log(`on_resp_body len: ${obj.len}`);
}
});
});
};
I'd like to understand what the arguments (url, method, headers, (obj)...) do. Can someone explain what these arguments mean? I would appreciate if someone could make a tag for open ziti. This is a popular opensource project that allows people to secure their application with a zero-trust network.
#evangertis the sample app you referenced uses an obsolete SDK, namely "ziti-sdk-nodejs": "^0.2.3".
The latest OpenZiti SDK for NodeJS is "#openziti/ziti-sdk-nodejs": "^0.13.3", and I encourage you to migrate to that since it is actively maintained.
Here is a link to the OpenZiti SDK for NodeJS API reference doc.
For more context on this SDK, you may be interested in this article I wrote concerning how to secure NodeJS applications.
Related
I am trying to write a caching function that returns cached elasticcache data or makes an api call to retrieve that data. However, the lambda function seems to be very unrealiable and timing out often.
It seems that the issue is having redis calls as well as public api calls causes the issue. I can confirm that I have setup aws correctly with a subnet with an internet gateway and a private subnet with a nat gateway. The function works, but lonly 10 % of the time.The remaining times exceution is stopped right before making the API call.
I have also noticed that the api calls fail after creating the redis client. If I make the external api call prior to making the redis check it seems the function is a lot more reliable and doesn't time out.
Not sure what to do. Is it best practice to seperate these 2 tasks or am I doing something wrong?
let data = null;
module.exports.handler = async (event) => {
//context.callbackWaitsForEmptyEventLoop = false;
let client;
try {
client = new Redis(
6379,
"redis://---.---.ng.0001.use1.cache.amazonaws.com"
);
client.get(event.token, async (err, result) => {
if (err) {
console.error(err);
} else {
data = result;
await client.quit();
}
});
if (data && new Date().getTime() / 1000 - eval(data).timestamp < 30) {
res.send(`({
"address": "${token}",
"price": "${eval(data).price}",
"timestamp": "${eval(data).timestamp}"
})`);
} else {
getPrice(event); //fetch api data
}
```
There a lot of misunderstand in your code. I'll try to guide you to fix it and understand how to do that correctly.
You are mixing asynchronous and synchronous code in your function.
You should use JSON.parse instead of eval to parse the data because eval allows arbitrary code to be executed in your function
You're using the res.send to return response to the client instead of callback. Remember the usage of res.send is only in express and you're using a lambda and to return the result to client you need to use callback function
To help you in this task, I completely rewrite your code solving these misundersand.
const Redis = require('ioredis');
module.exports.handler = async (event, context, callback) => {
// prefer to use lambda env instead of put directly in the code
const client = new Redis(
"REDIS_PORT_ENV",
"REDIS_HOST_ENV"
);
const data = await client.get(event.token);
client.quit();
const parsedData = JSON.parse(data);
if (parsedDate && new Date().getTime() / 1000 - parsedData.timestamp < 30) {
callback(null, {
address: event.token,
price: parsedData.price,
timestamp: parsedData.timestamp
});
} else {
const dataFromApi = await getPrice(event);
callback(null, dataFromApi);
}
};
There another usage with lambdas that return an object instead of pass a object inside callback, but I think you get the idea and understood your mistakes.
Follow the docs about correctly usage of lambda:
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-lambda-functions.html
To undestand more about async and sync in javascript:
https://www.freecodecamp.org/news/synchronous-vs-asynchronous-in-javascript/
JSON.parse x eval: JSON.parse vs. eval()
while developing the cloud function I got the following error.
i created a cloud action and used that action name inside the json response in watson assistance. then once the intent is matched it call the cloud function. I selected nodejs as developing language of the cloud function.
now my real requirement is to call a https get request from that cloud function. for that i need to use nodejs library called node-rest-client.
normally we need to install it by typing "npm install node-rest-client" in the terminal. since there is no terminal in IBM nodejs editor i got, could you please let me know how to do that.
As a substitute i used https library which is already in nodejs package. and wrote the following code in the editor
const https = require('https');
function main() {
https.get('https://f6054382.ngrok.io/webhook/testRequest', (resp) => {
resp.on('data', (d) => {
process.stdout.write(d);
});
});
}
main();
once I type "node init" in local folder and add the above code to index.js file and then run it using the command "node index.js" code works successfully by giving me the expected output from the webservice.
But I do not get that result in IBM nodejs editor
https://console.bluemix.net/openwhisk/details/action/dialogif.psi%2540gmail.com_dev/webhookCall/code
once i save the above code and invoke by clicking the button in right upper i get the successes response in green as follows.
Activation ID:
341d4e5bc81f4e489d4e5bc81f2e4888
Results:
{}
Logs:
[]
could you please help me to sort this out
Thank you
When executing an asynchronous operation, e.g. HTTP request, you need to return a Promise from the action handler. This ensures the platform will block on that asynchronous result before completing the invocation.
function main() {
return new Promise((resolve, reject) => {
https.get('https://f6054382.ngrok.io/webhook/testRequest', (resp) => {
resp.on('data', (d) => {
process.stdout.write(d);
resolve({})
});
});
})
}
The underlying issue is that your code runs asynchronously and does not return a Promise to indicate a result will be available in the future.
I'd suggest to use the request-promises, which comes pre-packaged with OpenWhisk's Node.js runtime.
const request = require('request-promise');
function main(params) {
return request("https://f6054382.ngrok.io/webhook/testRequest").then(response => {
process.stdout.write(response);
});
}
I am using a npm module to work with IBM's Watson to do speech to text. I'm using this package here: https://github.com/watson-developer-cloud/speech-javascript-sdk.
I can authenticate fine, but other than that nothing happens. I want to take the text from the response and insert it in the DOM. I tried the following just to try it out and I'm not getting any kind of feedback.
WatsonSpeech.SpeechToText.recognizeMicrophone({token: token, keepmic: true, ouputElement: "body"}).promise().then(function() {
console.log("talking");
})
The docs say the following for this method:
Other options passed to WritableElementStream if options.outputElement
is set.
And
Pipes results through a FormatStream by default, set options.format=false > to disable.
I would think that the
WatsonSpeech.SpeechToText.recognizeMicrophone
would take a callback function so I can handle the response and put insert it in my DOM, but I can't figure that out. Also, I'm not really a JS guy, so I don't know what the promise does.
Chapter 3 of "Zero to Cognitive" has exactly this code applied.
https://github.com/rddill-IBM/ZeroToCognitive
I recommend you to take a look at his lessons on youtube, but here is the code that I found.
function initPage ()
{
var _mic = $('#microphone'); var _stop = $("#stop");
_mic.addClass("mic_enabled");
_stop.addClass("mic_disabled");
_mic.on("click", function ()
{
var _className = this.className;
if(this.className == "mic_enabled")
{
_mic.addClass("mic_disabled");
_mic.removeClass("mic_enabled");
_stop.addClass("mic_enabled");
_stop.removeClass("mic_disabled");
$.when($.get('/api/speech-to-text/token')).done(
function (token) {
stream = WatsonSpeech.SpeechToText.recognizeMicrophone({
token: token,
outputElement: '#speech' // CSS selector or DOM Element
});
stream.on('error', function(err) { console.log(err); });
});
}
});
_stop.on("click", function() {
console.log("Stopping text-to-speech service...");
if (stream != undefined) {stream.stop(); }
_mic.addClass("mic_enabled");
_mic.removeClass("mic_disabled");
_stop.addClass("mic_disabled");
_stop.removeClass("mic_enabled");
});
}
I am writing an HTTP Promises package for nodeJS. I need it to be promises aplus compliant. I am using promises-aplus-tests - https://www.npmjs.com/package/promises-aplus-tests
I have created an adapter as follows:
var adapter = {
deferred: function() {
var d = {}
d.promise = new HTTPromise(new GETOptions('/path', DEFAULT_OPTIONS));
d.resolve = executorResponseFunc;
d.reject = executorRejectFunc;
return d;
}
}
promisesAplusTests(adapter, function (err) {
done(err);
});
My tests are failing on https://promisesaplus.com/#point-34 ...
with further help on https://promisesaplus.com/#point-67
2.2.4 onFulfilled or onRejected must not be called until the execution
context stack contains only platform code
3.1 Here “platform code” means engine, environment, and promise
implementation code. In practice, this requirement ensures that
onFulfilled and onRejected execute asynchronously, after the event
loop turn in which then is called, and with a fresh stack. This can be
implemented with either a “macro-task” mechanism such as setTimeout or
setImmediate, or with a “micro-task” mechanism such as
MutationObserver or process.nextTick. Since the promise implementation
is considered platform code, it may itself contain a task-scheduling
queue or “trampoline” in which the handlers are called.
But I can't get it passing this promises aplus test. I am using the bog standard JavaScript Promises library (which on its own passes the tests) documented at ...
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
new Promise(executor);
new Promise(function(resolve, reject) { ... });
In the executor I have tried ...
if (response.statusCode === 200) {
process.nextTick(() => {
resolve(finalResponse);
});
} else {
process.nextTick(() => {
reject(finalResponse);
});
}
and also ...
process.nextTick(() => {
if (response.statusCode === 200) {
resolve(finalResponse);
} else {
reject(finalResponse);
}
});
There seems to be a lot of talk on the Internet but not many code examples of how to comply. Is there a code sample on how to satisfy this test and how you would use nextTick or another suitable solution?
It's worthing mentioning I have another call to reject within an HTTP error handler within the executor function.
I would like to apologise to Bergi, I think I have the answer to my stupidity but I would appreciate confirmation that my thinking is now correct ...
My initial confusion came from ...
https://www.npmjs.com/package/request-promise
I am writing a similar but more powerful npm tool.
They have the "then" badge, so obviously I wanted it!
I thought I needed to pass your tests (they have made some kind of attempt at it).
So I tried to pass your promises-aplus-tests
with my library, which uses promises heavily but is NOT a promise implementation.
I see ...
https://www.npmjs.com/package/promises-aplus-tests
says
This suite tests compliance of a promise implementation with the
Promises/A+ specification.
So I realise now that my package does NOT need to pass your tests and I am not as clever as I might have hoped :)
However, I am running a test to ensure that the Promise library we are using passes your tests during the build process. If it does not the build will fail.
My code is now ...
class HTTPromise {
constructor(options) {
... blah blah blah
let executor = THE_REAL_EXECUTOR;
return AppPromise(executor);
}
}
class HTTPromiseCompliance {
constructor(executor) {
return AppPromise(executor);
}
}
AppPromise looks like ...
module.exports = executor => {
return new Promise(executor);
}
and finally the test suite ...
describe('HTTPromises', function () {
it('should use a Promises/A+ compliant Promise library', function (done) {
this.timeout(0);
var adapter = {
deferred: function() {
var d = {}
var executor = function(resolve, reject) {
d.resolve = resolve
d.reject = reject
};
d.promise = new HTTPromiseCompliance(executor);
return d
}
}
promisesAplusTests(adapter, function (err) {
if (err != null) {
console.log('promises Aplus Tests failed with ' + err.failures + ' failures');
} else {
console.log('promises Aplus Tests passed');
}
done(err);
});
});
});
A grunt task for this is fired during the build process.
If anyone has any thoughts on 'my new thinking' I would be appreciative.
Thanks
Our application consists of nodejs, express, reactjs, and newforms.
To make rest calls we are using :
var RestClient = require('superagent-ls')
And we are making rest calls like:
cleanBirthDate(callback) {
var {birthDate} = this.cleanedData
var formattedDob = moment (birthDate).format('DDMMYYYY')
RestClient.get(Global.getBirthDateServiceUrl() + '/' + formattedDob)
.end((err, res) => {
if (err) {
callback (err)
}
else if (res.clientError) {
var message = errorsMappingSwitch(res.body.error)
callback(null, forms.ValidationError(message))
}
else {
callback(null)
}
})
},
We want to move the RestClient related code to our own file say RestCleint.js and then require it and use it across the application. By doing so we can apply some generalised code(like error handling, logging, redirect to specific error pages depending on the error code) in one place.
Appreciate any help in this direction.
I did the exact same thing you require (even with using superagent). I created modules with the API code in a /utils folder and required them where applicable. For even more abstraction we're using CoffeeScript to create classes that inherit from a BaseAPIObject and invoke using something like API.Posts.getAll().end() etc.
This article was very helpful in understanding how to write your own modules: Export This: Interface Design Patterns for Node.js Modules.
you can always require it like
RestClient.js
export default function callApi(callback) {
//your rest code
// use the callback here in the callback of your call.
}
app.js
import {callApi} from './RestClient';
callApi((err, result) => {
if (err) console.log(err)
});