Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
ies-node-api-template
Advanced tools
Download ENV file from this [Box](https://ibm.ent.box.com/folder/115227224180), rename as `.env` and place at /api/env/
This is a node api template cloud native microservice.
To use this library in your react project, ensure the following:
First time setup:
fxo-cio-ies-npm-virtual
Standard setup:
@ies/node-api-template
If using as Backend For Fronted:
SERVE_STATIC=true
api/client/build
folder where it can be served from.NOTE: The SERVICE_TYPE
envirnment varible is set to BFF
by default. This value forces handleNotAuthenticatedResponse
middleware to redirect to a defined LOGIN
route. Otherwise, this middeware simply returns a HTTP401Error
.
Make sure to check for updates to the component library periodically.
The library provides a templateServer
that can be run with http or https
and encapsulates all the common middleware and other setup required (the template currently does not support injecting custom middleware at this time). See the src/start.ts
file for example usage.
The primary building block for template consumers is to build their business logic Services
around a RestRouter
, RestController
, and Model
, then pass these routes into the templateServer
. See the example services/
in this repo. For guidance on service architectural layers, see Restful APIs using MVCS Pattern.
Command | Description |
---|---|
start | Starts the app in production mode based off the the static build. |
start:dev | Starts the app in development mode, w/ auto-reload on file changes |
build | Builds the app for production |
build:dev | Builds the app for development |
build:lib | Builds the module to publish for production to the lib folder. |
clean | Cleans out build files and folder(s) |
lint | Lint fixes project src files |
test | Starts tests in CI mode |
test:unit | Starts tests in CI mode running tests with suffix ...unit.test.ts |
test:integration | Starts tests in CI mode running tests with suffix ...unit.integration.ts |
test:watch | Starts tests with file watcher for TDD mode |
test:coverage | Start tests in CI mode with code coverage reporting |
view:coverage | Starts server to serve code coverage report to interact with |
migrate:jest | Operation to attempt an auto update on jest config (new version) |
----------------------------- | ------------------------------------------------------------------------- |
NPM:
start: npm run start:dev
If the hot reload is buggy, run npm run clean && npm run build:dev
.
It commonly occurs when switching between branches and pulling in new changes.
To avoid using Docker when developing with a frontend when used as a BFF, create a symlink to the client build folder and use two tabs for development mode in both projects.
ln -s <client build path> <api local build path>
Docker:
Start: docker-compose up -d
Stop: docker-compose down
:: Notes ::
Redis is currently only for production.
Monitoring redis: docker exec -it redis redis-cli monitor
Troubleshooting - Disable VPN as Redis will throw a security error thinking same host is trying to compromise the box
Anything outside of the services folder is part of the 'template'.
The main template file to be aware of is src/templateServer.ts
.
All components you wish to export as part of the npm module should be
exposed in src/index.ts
Once your changes are in, to test your changes you can use npm link
locally
to test out the project OR you can publish a <packagename>-test
version. This should occur on a feature branch as part of the final review process.
Publishing is performed on a release
branch. Once you exposed or modified the template framework that is exposed to module consumers,the module version must be updated and the changes logged:
release/<VersionNum>
branch from dev
package.json
with the version number for the release using npm version <update_type>
. Please follow semantic versioning best practices.npm publish
to publish module to artifactory. This will also kickoff the prepublish
script.Notes: This will eventually be incorporated eventually in the CI / CD pipeline
Services are the foundations of building http based microservices with this template grounded on the principles of community NodeJS best practices such as file collocation and a central dedicated error handler.
src/services
named for the component you wish to create.<name>.router.ts
file<name>.router.test.ts
file.index.ts
file to export your <name>.router.ts
<name>.router.controller.ts
file<name>.model.ts
filesrc/services/index.ts
Builder pattern
Tests not just ensure your code functions as intended but acts as living documentation. The Test Pyramid exposes the trade-offs made between higher level integration tests vs. unit tests.
It is suggested to apply testing as follows:
routes
which expose all the endpoints to tap into the apps business logic capabilities. Nock should be used for stubbing outgoing http requests. Feel free to create an env flag to enable and disable nock to go between Integration and E2E level testing.This pattern is commonly found in enterprise application architecture and popularized by SpringBoot. It contains the following component layer types in bottom up order:
Model - comprises interface types and other abstract definitions that help model the business domain.
Example:
DAO / DAL - An abstraction that your service layer can call to get/update the data it needs. This layer is data-centric and will either call a Database or some other system (eg: LDAP server, web service, or NoSql-type DB). A few common libraries that provide these capabilities are:
You can use your models to cast the schemas and data access patterns in these libraries to conform to a independent implementation. Another variation of this is known as a 'Provider'.
Example:
TBD
Provider - encapsulates the interaction with external data providers aka. 3rd party APIs and other microservices. This component is preferred over DAOs / DAL for read-only access.
Example:
TBD
Repository - designed to separate your domain objects from data access logic (DAO/DAL) by acting as a domain specific Collection (aka. higher level interface). It can use DAO to restore the business objects that your application / API is responsibile for.
Example:
TBD
Controller - orchestrates the calls between the api layer and the service layer. A controller can call more than one service but only a single service call is demonstrated in the demo app. Usually if your controller is calling many services its one indication to use a different solution like GraphQL.
Example:
TBD
Services - encapsulates business logic as finalized output to be called by a controller - a layer commonly found in enterprise architecture. In this template we further suggest that each named service directory in the services/
folder acts as a internal "microservice" that can be more easily refactored out into their own service in the future.
Example:
TBD
View - option to serve static content such as a build of a frontend application to enable a BFF pattern
Example:
TBD
Follows the domain driven folder structure of services. It is reccommended to separate your .typedefs.ts
, .resolvers.ts
, .mutators.ts
, etc into their own file.
Benefits:
Cons:
The template implements the most critical parts of Error Handling Practices. It covers catching uncaughtException and unhandledRejection that can put your app into an undefined state as well as distinguishing between client and server errors. It handles catching both sync and async errors within the middleware, allowing us to free our controllers’ code with error handling.
We want to throw an exception and make sure our dedicated middleware will handle it for us. This template creates a dedicated ErrorHandler class available for unit-testing.
We have three different error handlers for each use case:
handle404Error
the way you handle 404 in express. By adding a fallback middleware if nothing else was found.handleClientErrors
catches client API errors like Bad request or Unauthorized.handleServerErrors
a place where we handle “Internal Server Error”.All of the template's router-level authentication middleware verify an authenticated request using Passport's Request interface. A request is authenticated when the isAuthenticated
method from the Request instance returns true.
There are five different authentication middleware within the template, each respond differently to a non authenticated request:
ensureAuthenticated
if request is not authenticated, request will be redirected to AUTH_ROUTES.LOGIN.ensureSessionAuthRedirectUrl
if request is not authenticated, request will be redirected to the requests originalUrl.ensureAuthUser
if request is not authenticated, HTTP401Error will be thrown.requirePolicy
if request is not authenticated, the request will be redirected to AUTH_ROUTES.LOGIN allow the user to login. Additionally, if the user making the request has not accepted the applications policy, validateUserWithServiceIdApi, the request will be redirected to the req.requestUrl.ensureAdminUser
if a requesting user does not have the configured admin blue group a HTTP403Error will be thrown.The app uses redis for its store because express-session
default in memory store is not designed for production use. Due to many circulating issues with the reccomended redis client, Alibaba and other top companies support a more performant and powerful one used in this project - ioredis.
For development you can use docker to spin up a local instance or you can setup tls by applying the cert in the env under redisCertFileName
to connect to the IBM IES Team's Cloud hosted instance.
This templates configuration can be modified to fit the needs of the consuming application.
Configuration must be modified within the start.ts
file just before the server.start()
invocation.
Below are methods that can be called on the ApplicationConfig class, modifying the application configuration:
bluegroups
property of the application's baseConfig
.baseConfig
.api
to the application's baseConfig
.basicAuth
to the application's baseConfig
.basicAuth
to the application's baseConfig
. Also adds common
with properties serviceId
and servicesApi
to baseConfig
. Does not overwrite information set in common
by usePolicies
.You can use swagger to document your REST routes from this template. To do so, simply pass in a swagger configuration object when instantiating the server from the IESTemplateServer
constructor. After passing in the swagger object, go ahead and start documenting your routes with comments so that swagger-jsdoc can pick it up! For details on what that configuration object should look like, or how to document your routes, please refer to the examples provided in the code.
Setting up an oAuth flow in Swagger can be a little tricky, and this template aims to make that a little easier for you. To add oAuth flow:
Provide a valid clientId and clientSecret via the env variables OPENID_CLIENT_ID
and OPENID_CLIENT_SECRET
Authorize provisioner to redirect to your application. In addition to the normal authorizations, you will need to add the special routes /oauth2-redirect.html*
and /oauth2-redirect.html
attached to the end of your base-url for auth flow to work. For example, your application may have the following in provisioner:
https://my-sample-app.prod.identity-services.intranet.ibm.com/oauth2-redirect.html*
https://my-sample-app.prod.identity-services.intranet.ibm.com/oauth2-redirect.html
https://my-sample-app.prod.identity-services.intranet.ibm.com
Note that your provisioner setup may differ than this. A helpful hint is that if you successfully authenticate with the authorization server, but can't redirect back to your application because of an error telling you that the redirect url is not valid, you probably haven't whitelisted the right url in provisioner. Try looking at where provisioner is trying to rediret you in the url to help troubleshoot this further.
Create a security scheme for oAuth. The name can be arbitrary, but the type must be oauth2
authorizationUrl
inside the authorizationCode
property. This is the url that swagger will attempt to authenticate against/api/proxy/oidc/endpoint/default/token
. When the authorizationUrl redirects successfully, it will send a nonce back to swagger-ui, which will then be redireted to the server. The server will then forward this request to the JWT server with the nonce and client_secret and receive a JWT back. (The actual flow is slightly more complicated, with the redirect first hitting a special html file before redirecting to the swagger-ui)Here's what our securityScheme looks like at this point:
const securitySchemes: SecuritySchemes = {
oAuth: {
type: "oauth2",
description: "OAUTH2 Login Flow",
flows: {
authorizationCode: {
authorizationUrl:
"https://preprod.login.w3.ibm.com/oidc/endpoint/default/authorize",
tokenUrl: "/api/proxy/oidc/endpoint/default/token",
scopes: { openid: "root access" }, // This can be omitted, only necessary if you want to apply scopes
},
},
},
};
Under swaggerUIOptions, add an oauth
property with a clientId
property that points to the appropriate clientId
And this is what our swaggerUIOptions object looks like at this step:
const swaggerUIOptions = {
swaggerOptions: {
oauth: { clientId: getStringEnvVar("OPENID_CLIENT_ID", "") }, // clientId is picked up via a utility function which reads it from our env variables
},
explorer: true,
};
Import the ProxyRoutes
object from the template somewhere in your project where you can add it to your base routes
object. A common pattern that the team uses is to add this route in the index file under the services folder.
That's it! Congratulations on making it this far, and now how you consume this login flow with swagger-jsdoc
is up to you. Its likely though that you'll want to add this flow everywhere.
Using comments for swagger-jsdoc
, apply your security:
/**
* @swagger
* security:
* - oAuth: []
*/
In this example, oAuth
references the arbitrary name that was specified earlier in our securitySchemes. If you named it something else like myLoginFlow
, you would replace oAuth
with myLoginFlow
. Our examples don't implement scope, but you should be able to add it to your securityScheme if desired.
To implement security at a route level, we just add the security property to our comments for swagger-jsdoc
to pick up:
/**
* ...more comments above
* security:
* - oAuth: []
* ...more comments below
*/
You can override your security on a route with a - []
under security, opening up the api route to everyone. Further reading
Please refer to the implementation in this project for a reference point if you get stuck or confused. As a friendly reminder, Swagger is based off of the OpenAPI specification.
This template offers the ability to run an application in maintenance mode. In this feature, the applications maintenanceStatus
will be checked by common-services before determining whether or not to serve the file index.html
or maintenance.html
. To enable this mode:
serveStatic
is set to trueSERVE_STATIC
set to trueENABLE_MAINTENANCE_MODE
set to trueSERVICES_API=https://ies-common-services-api.dev.identity-services.intranet.ibm.com/api/v1
)SERVICE_ID=ies-hsk-procurement
)BASIC_AUTH_USER=username
BASIC_AUTH_PASS=pass
)enableMaintenanceMode
method off of ApplicationConfig
index.html
and maintenance.html
fileThe consuming application decides how to structure their maintenance.html
file. However, an example has been provided as part of this template. The example provided will allow a user to show the login button by hitting the ENTER key five times. If an admin user logs in at this point, they will be able to see the application as normal. Regular users will still see the maintenance page.
Site notices are messages that developers want the application users to see. A notice will be returned from the api, api/site-notice
endpoint, if the notice's start and end date fall between the current day.
The consuming application must be on node template version 3.0.0
or greater
The projuct must contain a DASHBOARD_SERVICE_API
environment variable that points to https://ies-dashboard-service.`TARGET ENV`.identity-services.intranet.ibm.com/api/v1
Within /api/src
create a file titled applyConfig.js
(if this file does not exist already) and use the useDashboardNotice
method on the ApplicationConfig
object to specify which offering to pull notices from. Below is an example apply Config.ts
file.
import { ApplicationConfig, getStringEnvVar } from "@ies/node-api-template";
// note that this implementaion uses getStringEnvVar to get the value of TARGET_OFFERING_ID from process.env
ApplicationConfig.useDashboardNotice(getStringEnvVar("TARGET_OFFERING_ID"));
The TARGET_OFFERING_ID
is the offering id of the offering that your application will receive notices about.
/api/src/services
create a file index.ts
(if this file does not exisit already), import the SiteNoticeRoutes
from the node api template and add it to your exported routes. Below is an example index.ts file.import { RestRouter, SiteNoticeRoutes } from "@ies/node-api-template";
import { UserRoutes } from "./authUser"; // example project specific route
const routes: RestRouter[] = [UserRoutes, SiteNoticeRoutes];
const getRoutes = async (): Promise<RestRouter[]> => {
return routes;
};
export { getRoutes };
Provide a more expressive framework to dynamically generate routes and swagger similar to SpringBoot annotations. There are currently two popular npm modules for this: TSOA and Typescript-Rest. The team has explored both frameworks in the following branches:
TSOA Branch TypescriptRest Branch
The biggest hurdle in both frameworks was the lack of support and/or documentation for custom security middleware. TypescriptRest seems to have the most promise with PassportJs support as well as security middleware injection which is encouraging in order to try again in the future.
Add GraphQL...
FAQs
Download ENV file from this [Box](https://ibm.ent.box.com/folder/115227224180), rename as `.env` and place at /api/env/
The npm package ies-node-api-template receives a total of 3 weekly downloads. As such, ies-node-api-template popularity was classified as not popular.
We found that ies-node-api-template demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer 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
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.