
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@condor-labs/health-middleware
Advanced tools
Middleware to check API healthchecks in CondorLabs
To ensure that developers handle a standard on the health check of their APIs, we have developed a library that will verify compliance with the response standard of the aPIs in @condor-labs, this library works as a middleware that will allow us to verify that it complies with company guidelines.
The minimum supported version of Node.js is v8.
To use the library you just need to follow the following steps Install the library with npm
npm i -S mongoose@">=6.11.4 <8.0.0"
npm install @condor-labs/health-middleware
Import the library
const health = require("@condor-labs/health-middleware");
// OR
const {
healthMonitor,
statusType,
dependencyServices,
} = require("@condor-labs/health-middleware");
The main method is healthMonitor, you can use it as default to show basic stats like cpu or memory.
const express = require("express");
const { healthMonitor } = require("@condor-labs/health-middleware");
var app = express();
//only need app as parameter
healthMonitor(app);
app.listen(process.env.PORT || 3000);
As default the route is /health, if you consume you get a response like
{
"status": "fail",
"version": "1.0",
"service": "health",
"description": "",
"instance": "Admins-Mac-mini.local",
"checks": {
"memory:utilization": [
{
"componentType": "system",
"status": "fail",
"observedValue": 96.9440221786499,
"observedUnit": "percent",
"time": "2021-09-14T17:08:48.477Z",
"componentId": "memory0"
}
],
"cpu:utilization": [
{
"componentType": "system",
"status": "pass",
"observedValue": 13.860444612381132,
"observedUnit": "percent",
"time": "2021-09-14T17:08:48.478Z",
"componentId": "cpu0"
}
],
"network:availability": [
{
"componentId": "network0",
"componentType": "system",
"status": "pass",
"observedValue": true,
"observedUnit": "availability",
"time": "2021-09-14T08:48:49.105Z"
}
]
}
}
As the health middleware knows you likely need customize your checks, you can use the following vars to change the behavior of the Health Middleware.
Some of the following vars are just to give a useful explaination about the service or application such as service and description.
const healthConfig = {
service: "custom service",
description: "my project",
checks: [],
dependencies: [],
urls: ["https://www.google.com", "https://www.opendns.com"],
path: "/custom",
version: "1.0",
alias: "machine0",
};
//use in the monitor
healthMonitor(app, healthConfig);
param | description | required |
---|---|---|
service | it's a unique identifier of the service, in the application scope | true |
description | It is a human-friendly description of the service. | true |
checks | Array of objects that provides detailed health statuses of additional downstream systems and endpoints which can affect the overall health of the main API. | false |
dependencies | Array of objects that provides detailed information about connection to databases, it works like checks but whitout callbacks, the connection is made from the connection parameters entered. | false |
urls | Urls for network availability test, the field is not required: default: "https://www.google.com", "https://www.opendns.com") | false |
path | its a route where your health will live. default: /health | false |
version | Public version of the service (default: 1.0) . | false |
alias | It is a short and human-friendly name for the instances | false |
When you need to add a custom check for example the one from your database, you can use the prepareCheck function to do the job.
{ prepareCheck } = require("@condor-labs/health-middleware");
const checks = [prepareCheck("mongo", dbConnectExample)];
Or use a object to define the params
const checks = [{
componentName: "oracle", //Object
componentType: statusType.DATASTORE,
callback: dbConnectExample,
cacheTTL: cacheExpirationTime, //optional(by default cacheTTL will be 10), time in seconds
},
],
A dependency is a connection with a database which can affect the overall health of the main API. When you need to add a dependency for example the one from your Redis database, use an object to define the connection params. It works like checks but whitout callbacks, the connection is verified from the connection params entered.
const dependencies = [{
service: dependencyServices.REDIS, // You can use REDIS, MONGODB, MYSQL or ELASTICSEARCH
componentName: 'myredis',
connection: {
prefix: 'prefix', //optional(by default prefix will be null)
host: '127.0.0.1',
port: 6379, //optional(by default port will be 6379)
password: 'password', //optional(by default password will be null)
},
},
{
service: dependencyServices.MONGODB,
componentName: 'MyMongoDB',
connection: {
host: 'clusterN-shard-00-00.3wetr.mongodb.net',
port: 27017, //optional(by default port will be 27017)
database: 'myDatabase',
user: 'user',
password: 'password',
replicaSet: 'atlas-xu7xxx-shard-0', //optional
ssl: true,
authSource: 'admin',
},
},
{
service: dependencyServices.MYSQL,
componentName: 'Mysql',
connection: {
host: 'localhost',
port: 3306, //optional(by default port will be 3306)
user: 'root',
password: 'example',
database: 'sample', //optional
multipleStatements: false, //optional
},
},
{
service: dependencyServices.ELASTICSEARCH,
componentName: 'MyElasticSearch',
connection: {
protocol: '', // optional(null, '', 'http', 'https')
user: '', // optional
password: '', // optional
host: 'localhost',
port: 9200,
ssl: {}, //optional
},
},
],
const {
healthMonitor,
getStatus,
statusType,
dependencyServices,
} = require("@condor-labs/health-middleware");
const yourDBConnectTesting = () => {
return true; //return a boolean
};
const newCheck = getStatus(yourDBConnectTesting, statusType.DATASTORE);
const healthConfig = {
//only need modify params that you need it
service: "service random",
description: "my service with some random check",
dependencies: [
{
service: dependencyServices.REDIS,
componentName: "MyRedis",
connection: {
prefix: "demo",
host: "127.0.0.1",
port: 6379,
password: "password",
},
},
{
service: dependencyServices.MONGODB,
componentName: "MyMongoDB",
connection: {
host: "clusterN-shard-00-00.3wetr.mongodb.net",
port: 27017,
database: "myDatabase",
user: "user",
password: "password",
replicaSet: "atlas-xu7xxx-shard-0",
ssl: true,
authSource: "admin",
},
},
{
service: dependencyServices.MYSQL,
componentName: "Mysql",
connection: {
host: "localhost",
port: 3306,
user: "root",
password: "password",
database: "test",
multipleStatements: false,
},
},
{
service: dependencyServices.ELASTICSEARCH,
componentName: "MyElasticSearch",
connection: {
protocol: "",
user: "",
password: "",
host: "localhost",
port: 9200,
},
},
],
checks: [
{
componentName: "oracle", //Object
componentType: statusType.DATASTORE,
callback: dbConnectExample,
cacheTTL: 20, //20 sec in cache, set in 0 if you don't want have cache
},
],
};
healthMonitor(app, healthConfig);
You will get something like this
{
"status": "fail",
"version": "1.1",
"releaseTag": "1.1.0",
"service": "custom service",
"description": "",
"instance": "Machine0|Admins-Mac-mini.local",
"checks": {
"memory:utilization": [
{
"componentId": "memory0",
"componentType": "system",
"status": "fail",
"observedValue": 99.59919452667236,
"observedUnit": "percent",
"time": "2021-09-15T16:06:40.252Z"
}
],
"cpu:utilization": [
{
"componentId": "cpu0",
"componentType": "system",
"status": "pass",
"observedValue": 14.022481829750083,
"observedUnit": "percent",
"time": "2021-09-15T16:06:40.255Z"
}
],
"network:availability": [
{
"componentId": "network0",
"componentType": "system",
"status": "pass",
"observedValue": true,
"observedUnit": "availability",
"time": "2021-09-15T16:06:42.415Z"
}
],
"myredis:responseTime": [
{
"componentId": "MyRedis0",
"componentType": "datastore",
"observedValue": 148.39368800073862,
"observedUnit": "ms",
"status": "pass",
"time": "2021-09-15T16:06:42.419Z",
"hostname": "127.0.0.1",
"resourceVersion": "6.2.7"
}
],
"mymongodb:responseTime": [
{
"componentId": "MyMongoDB0",
"componentType": "datastore",
"observedValue": 0.45793600007891655,
"observedUnit": "ms",
"status": "pass",
"time": "2021-09-15T16:06:42.421Z",
"hostname": "localhost",
"resourceVersion": "4.1.13"
}
],
"mysql:responseTime": [
{
"componentId": "Mysql0",
"componentType": "datastore",
"observedValue": 220.51974400132895,
"observedUnit": "ms",
"status": "pass",
"time": "2021-09-15T16:06:42.422Z",
"hostname": "localhost",
"resourceVersion": "5.7.38"
}
],
"myelasticsearch:responseTime": [
{
"componentId": "MyElasticSearch0",
"componentType": "datastore",
"observedValue": 56.33939500153065,
"observedUnit": "ms",
"status": "pass",
"time": "2021-09-15T16:06:42.424Z",
"hostname": "localhost",
"resourceVersion": "7.4.0"
}
],
"oracle:responseTime": [
{
"componentId": "oracle0",
"componentType": "datastore",
"observedValue": 0.03558000177145004,
"observedUnit": "ms",
"status": "pass",
"time": "2021-09-15T16:06:42.430Z"
}
]
}
}
If you need to report the status of your API to a external service such as a Apps Inventory repository, you must provide a new param into the healthConfig object, this gives the ability to report the health of your service. This internally will check the status of your application and then, report the metric to the external endpoint.
Note: This functionality requires an external API to receive the reports of the service. Also, this feature will send request every 30secs by default to the external service by instance running.
to Add this new functionality to your API add to the config the following object:
{
...defaultConfig,
"webhook": {
"enabled": true,
"url": "http://localhost:3000/dev/apps/test_api/sections/health",
"auth": "39KMqOATRgZBMZxEqsqk0cTQK",
"intervalMS": 10000,
},
}
If your applications its not a API and you also need to report health statuses, you must use the following Implementation for workers:
const { HealthMonitorPush } = require("../library/index");
const healthConfig = {
service: "",
checks: [],
dependencies: [],
description: "",
urls: [],
path: "",
version: "",
aliasMachine: "",
timeoutMS: 3000,
debug: true,
webhook: {
enabled: true,
url: "http://localhost:3000/dev/apps/test_api/sections/health",
auth: "39KMqOATRgZBMZxEqsqk0cTQK",
intervalMS: 10000,
},
};
HealthMonitorPush(healthConfig);
Notice in this case you dont need to send the Express application to the health middleware since we assume you're not working in a API. This feature is useful for workers and cron-tasks in NodeJS
const healthConfig = {
webhook: {
enabled: true,
url: "http://localhost/apps/test_api/sections/health",
auth: "39KMqOATRgZBMZxEqsqk0cTQK",
intervalMS: 10000,
},
};
param | description | required |
---|---|---|
webhook.enabled | This value indicates that the sending of health to the apps inventory api will be activated. | true |
webhook.url | URL for sending health to the api apps inventory. | true |
webhook.auth | Auth token for sending health api apps inventory. | true |
webhook.intervalMS | Interval of how often the health will be sent to the api apps inventory. Default value: 30000 || min: 10000 || max: 60000 | false |
Basic types have been implemented to allow the library to work with TypeScript.
Import the library
import healthCheck from "@condor-labs/health-middleware";
// OR
import {
healthMonitor,
statusType,
dependencyServices,
} from "@condor-labs/health-middleware";
Modify healthMonitor parameters
import { HealthConfig } from "@condor-labs/health-middleware";
const healthConfig: HealthConfig = {
service: "custom service",
description: "my project",
checks: [],
dependencies: [],
urls: ["https://www.google.com", "https://www.opendns.com"],
path: "/custom",
version: "1.0",
aliasMachine: "machine0",
};
//use in the monitor
healthMonitor(app, healthConfig);
The following parameter is an example of how you can customize the limit for memory usage and CPU usage of the system for the fail and warn state.
const healthConfig = {
...configs
rules: {
memory:{
warn: 85,
fail: 95,
},
cpu:{
warn: 70,
fail: 80,
},
}
};
param | description | required |
---|---|---|
memory | Object containing the limit values for the warn and fail states | false |
memory.warn | Number | false |
memory.fail | Number | false |
cpu | Object containing the limit values for the warn and fail states | false |
cpu.warn | Number | false |
cpu.fail | Number | false |
const express = require("express");
const { healthMonitor } = require("../library");
const port = process.env.PORT || 3000;
var app = express();
const healthConfig = {
service: "custom service",
description: "",
urls: ["https://www.google.com"],
path: "/health",
version: "1.0",
aliasMachine: "",
rules: {
memory: {
warn: 80,
fail: 90,
},
cpu: {
warn: 8,
fail: 9,
},
},
};
healthMonitor(app, healthConfig);
app.get("/", (req, res) => {
res.send("Hello Express");
});
app.listen(port, () => {
console.log(`Server on port ${port}`);
});
This library supports old and new versions of Api using:
const Hapi = require("hapi");
const { healthMonitorHapi } = require("../library");
const server = new Hapi.Server();
const serverConfig = {
host: "localhost",
port: 3000,
routes: {
cors: {
origin: ["*"],
exposedHeaders: ["x-total-count"],
credentials: true,
},
timeout: {
server: 90000,
},
validate: {
options: {
abortEarly: false,
},
},
},
};
const healthConfig = {
service: "custom service",
description: "",
checks: [],
dependencies: [],
urls: "https://www.google.com",
path: "/health",
version: "1.0",
aliasMachine: "",
rules: {
memory: {
warn: 80,
fail: 90,
},
cpu: {
warn: 85,
fail: 100,
},
},
};
server.connection(serverConfig);
healthMonitorHapi(server, healthConfig); // or healthMonitorHapiv17(...)
server.route({
method: ["GET", "POST"],
path: "/",
handler: (request, reply) => {
reply("Hello World!");
},
});
server.start();
console.log("Server running on %s", server.info.uri);
The following are the health library error codes.
CODE | Description |
---|---|
ERROR_PUSHING_HEALTH_TO_INVENTORY | Error response when sending health to inventory. |
ERROR_PUT_HEALTH_TO_INVENTORY | Error response when put health to inventory. |
CONFIGURATION_REQUIRED | Configuration is required to be able to publish the status of your application. |
ENABLED_REQUIRED | Enabled is required in true to be able to publish the health of your app. |
APP_REQUIRED | App is required. |
CALLBACK_EXPECTED | A callback function was expected for this check. |
The following are the health library success codes.
CODE | Description |
---|---|
SUCCESS_RESPONSE_FROM_INVENTORY | Successful response when sending health to inventory. |
releaseTag in response json will be used to indicate the release under which the healt-check is executed.
The release tag only works when the RELEASE_TAG variable is set as environment var in the machine where the process is running.
You will need to update the package.json
file placed in the root folder.
identify the property version
and increase the right number in plus one.
npm login
[Enter username]
[Enter password]
[Enter email]
If all is ok the console will show you something like this : Logged in as USERNAME on https://registry.npmjs.org/.
npm publish --access public
Ref: https://docs.npmjs.com/getting-started/publishing-npm-packages
Note: you will need to have a NPM account, if you don't have one create one here: https://www.npmjs.com/signup
The original author and current lead maintainer of this module is the @condor-labs development team.
More about Condorlabs Here.
FAQs
Middleware to check API healthchecks in CondorLabs
The npm package @condor-labs/health-middleware receives a total of 41 weekly downloads. As such, @condor-labs/health-middleware popularity was classified as not popular.
We found that @condor-labs/health-middleware demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 7 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.