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.
@tkrotoff/stub-server
Advanced tools
Stub/mock server for REST APIs
For each route, decide what will happen: a JSON stub, a piece of JS or redirect to a real server
npm install --save-dev @tkrotoff/stub-server
Example: https://github.com/tkrotoff/MarvelHeroes
stubs/routes/my_api1_GET_200_OK.json
my_api2_GET_200_OK.jpg
my_api3_POST_400_BadRequest-invalidField.ts
my_api4_POST_400_BadRequest-invalidField.js
my_api5_DELETE_500_InternalServerError.html
my_api7_GET_200_OK.json
my_api7_POST_200_OK.json
my_api8_GET.ts
my_api9_GET.js
my_api10_GET_200_OK-param1.json
my_api10_GET_200_OK-param2.json
stubs/config.ts
webpack.config.ts
import path from 'path';
import { StubServerConfig } from '@tkrotoff/stub-server';
const prod = 'https://myapp.com';
const stubsPath = path.resolve(__dirname, 'routes');
const config: StubServerConfig = {
delay: { min: 500, max: 3000 },
routes: {
'/my/api1': { GET: `${stubsPath}/my_api1_GET_200_OK.json` },
'/my/api2': { GET: `${stubsPath}/my_api2_GET_200_OK.jpg` },
'/my/api3': { POST: `${stubsPath}/my_api3_POST_400_BadRequest-invalidField.ts` },
'/my/api4': { POST: `${stubsPath}/my_api4_POST_400_BadRequest-invalidField.js` },
'/my/api5': { DELETE: `${stubsPath}/my_api5_DELETE_500_InternalServerError.html` },
'/my/api6/:id': {
// Here stub-server works as a proxy,
// example of request sent: PUT https://myapp.com/my/api6/132379
PUT: prod
},
'/my/api7': {
delay: { min: 1000, max: 1000 },
GET: `${stubsPath}/my_api7_GET_200_OK.json`,
POST: {
delay: { min: 0, max: 0 },
response: req => {
req.headers.origin = prod;
return `${stubsPath}/my_api7_POST_200_OK.json`;
}
}
},
'/my/api8': { GET: `${stubsPath}/my_api8_GET.ts`},
'/my/api9': { GET: `${stubsPath}/my_api9_GET.js`},
'/my/api10/:id': { GET: req => `${stubsPath}/my_api10_GET_200_OK-${req.params.id}.json` }
}
};
const rootApiPath = 'https://myapp.com/client/:clientApi';
config.routes[`${rootApiPath}/my/api7`] = { GET: `${stubsPath}/my_api7_GET_200_OK.json` };
export default config; // Or "exports.default = config"
Note: stubs/config.ts
written in TypeScript instead of JavaScript requires ts-node
Configuration with webpack-dev-server
import { stubServer } from '@tkrotoff/stub-server';
...
devServer: {
// With webpack-dev-server >= v4.7.0
setupMiddlewares: (middlewares, devServer) => {
const configPath = path.resolve(__dirname, 'stubs/config');
stubServer(configPath, devServer.app!);
return middlewares;
}
// With webpack-dev-server from v4.0.0 to v4.6.0
onBeforeSetupMiddleware: (devServer) => {
const configPath = path.resolve(__dirname, 'stubs/config');
stubServer(configPath, devServer.app!);
}
// With webpack-dev-server < v4.0.0
before: app => {
const configPath = path.resolve(__dirname, 'stubs/config');
stubServer(configPath, app);
}
...
},
{
"foo": "bar"
}
export default {
error: 'Invalid field'
};
module.exports = {
error: 'Invalid field'
};
import express from 'express';
export default function stub(req: express.Request, res: express.Response) {
res.send('Hello, World!');
}
module.exports = (req, res) => {
res.send('Hello, World!');
};
Usage: stub-server [options] <config>
Arguments:
config path to the config file
Options:
--port <port> stub server port (default: "12345")
--no-delay ignore any delay specified in the config
-h, --help display help for command
// stubServer.js
const { stubServer } = require('@tkrotoff/stub-server');
const cors = require('cors');
const express = require('express');
const next = require('next');
const Log = require('next/dist/build/output/log');
const path = require('path');
const app = next({ dev: process.env.NODE_ENV !== 'production' });
const nextjsHandler = app.getRequestHandler();
const configPath = path.resolve(__dirname, 'stubs/config');
const port = 3000;
app.prepare().then(() => {
const server = express();
server.use(express.json());
server.use(cors());
stubServer(configPath, server);
// Next.js only processes GET requests unless you are using [API Routes](https://nextjs.org/docs/api-routes/introduction)
server.get('*', (req, res) => nextjsHandler(req, res));
server.all('*', req => {
throw new Error(`'${req.method} ${req.url}' should be declared in stubs/config.ts`);
});
server.listen(port, () => {
Log.ready(`ready on port ${port}`);
});
});
// package.json
"scripts": {
"dev": "node stubServer.js", // Instead of "next dev"
"build": "next build",
"start": "next start"
...
},
To "connect" your app to an environment (prod, staging, integration...), you can use stub-server as a proxy (intermediary between your app requesting a resource and the server providing that resource).
Why? To configure delays for the HTTP requests (helps find bugs and possible improvements to your app), access to request & response objects...
// package.json
"scripts": {
"start": "...",
"start:staging": "ENVIRONMENT_NAME=staging npm run start",
"start:prod": "ENVIRONMENT_NAME=prod npm run start"
...
},
// stubs/config.ts
import path from 'path';
import express from 'express';
import { GetStubFilenameOrUrl, StubServerConfig } from '@tkrotoff/stub-server';
const stubsPath = path.resolve(__dirname, 'routes');
type Environments = { [name: string]: { target: string; origin: string } | undefined };
const environments: Environments = {
staging: {
target: 'https://api.staging.myapp.com',
origin: 'https://staging.myapp.com'
},
prod: {
target: 'https://api.myapp.com',
origin: 'https://myapp.com'
}
};
const { target, origin } =
environments[process.env.ENVIRONMENT_NAME ?? 'No environment specified'] ?? {};
function configureRequest(stubOrUrl: string): GetStubFilenameOrUrl {
return (req: express.Request) => {
// You can rewrite the request URL if needed
req.url = req.url.replace('/prefix', '');
if (origin !== undefined) {
// May be required for some APIs
req.headers.origin = origin;
}
return stubOrUrl;
};
}
const config: StubServerConfig = {
delay: { min: 500, max: 3000 },
routes: {
'/prefix/my/api1': {
GET: configureRequest(
// Here stub-server works as a proxy,
// example of request sent: GET https://api.staging.myapp.com/my/api1
target ??
// ...or use a stub if no target specified
`${stubsPath}/my_api1_GET_200_OK.json`
)
},
...
}
};
export default config;
Examples of output (stdout) for requests processed by stub-server:
GET /account/payment-types?imagesWithUrl=true => stubs/routes/payment-types_200_OK.ts, delay: 442 ms
GET /account/captcha/1662973203224 => https://api.myapp.com, delay: 0 ms
GET /account/captcha/1663061235576 => stubs/routes/captcha_200_OK-242674.jpg, delay: 4 ms
POST /account/create => stubs/routes/account_create_201_Created-no-appro.json, delay: 169 ms
POST /auth/session?withNotification=true => https://api.myapp.com, delay: 34 ms
If the stub is missing or the target is unknown, stub-server returns a 500 (Internal Server Error) response with the error in HTML format and also displays the error in the console.
Examples of errors in the console:
ENOENT: no such file or directory, open 'stubs/routes/captcha_200_OK-242674.jpg'
Error: getaddrinfo ENOTFOUND api.myapp.com
If you request an unknown route, stub-server does not process it and therefore won't display anything in the console. It's up to you to handle this case with a catch-all route:
function missingStubHandler(req: express.Request) {
throw new Error(`Missing stub for '${req.method} ${req.url}'`);
}
...
'/prefix/*': {
GET: missingStubHandler,
POST: missingStubHandler,
PUT: missingStubHandler,
PATCH: missingStubHandler,
DELETE: missingStubHandler
}
0.13.0 (2023/03/11)
FAQs
Stub server for REST APIs
We found that @tkrotoff/stub-server 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.