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.
type-genius
Advanced tools
Type Genius is a library that can generate a Typescript file from any JSON object.
This generator can be useful for many reasons:
For example, the object returned from an HTTP request can be anything, but generally, it's going to be consistent in its return. It would be great to leverage Typescript to have intellisense for the response object. However, many APIs don't ship with a Typescript library, so you have to assume any
as its type, or type it by hand.
On the other hand, you can use this package to quickly generate an interface from an API response.
import { buildTypes } from "type-genius";
// Get some data
const res = await fetch("https://json.com");
const data = await res.json();
// Generate type file
buildTypes(data);
The buildTypes
function takes a second parameter where you can pass an options object. Below are the expected keys for that option object.
Option Name | Type | Default | Description |
---|---|---|---|
customTypes | Object? | js { string: "string", number: "number", boolean: "boolean", object: "object" } | Customize the types that get rendered. For objects, you can render a Record like this: js customTypes: { object: "Record<string, unknown>" |
forceOptional | Boolean? | false | Forces each value in every type to be optional. |
initialInterfaceName | String? | "Response" | The name given to the first generated interface. |
logSuccess | Boolean? | false | Should a success message get rendered after successfully generating the types. |
outputFilename | String? | "exported.d.ts" | File name to give the rendered types file. |
outputPath | String? | "../dist/" | Where to render the generated types. |
renderSemis | Boolean? | false | Render semicolons in the outputted file. |
skipFileWrite | Boolean? | false | Whether to write the file or not. |
useStore | TypeStore? | [] | Store of existing InterfaceConfiguration objects to use for this generation. |
useTypes | Boolean? | false | Whether to render "type"s instead of "interface"s. |
Before we can create our Typescript file, we have to run through a few steps to make sure things run correctly. Here is what happens under the hood:
We first parse our object to determine each value's type. For example, this object:
{
"key_name_1": "value",
"key_name_2": 1,
"key_name_3": {
"key_name_4": true
}
}
will become this:
{
"key_name_1": {
"type": "string",
"optional": false
},
"key_name_2": {
"type": "number",
"optional": false
},
"key_name_3": {
"type": "object",
"optional": false,
"object_keys": {
"key_name_4": {
"type": "boolean",
"optional": false
}
}
}
}
Soon we're going to create configuration objects that describe how to construct our interface. Before we do that, we need to save them somewhere so we can refer back to this list if we have to. We have to do this in order to remove duplicate interfaces.
const typesStore = [];
If you want to save interfaces generated in the past and refer back to them, you can use a populated array here. This is useful if you have recurring interfaces in multiple places. You don't always want to generate every interface from scratch.
An interface configuration is a set of instructions that outline how to create each interface. It includes the name of the interface, the various type configuration objects within, and the generated file string.
An interface configuration looks like this:
{
"string": "", // string that will get written to a file
"typesConfig": {}, // type configuration object
"interfaceName": "" // name of the interface
}
Here is how each interface configuration gets produced. First, let's assume our store is empty. The engine will go key-by-key through our type configuration object and generate the string necessary.
{
"key_name_1": {
"type": "string",
"optional": false
}
}
will produce the string:
export interface Response {
key_name_1: string;
}
At this point the interface configuration is saved and stored.
If one of the keys has a type of object
, the function will run recursively to determine an interface for the nested object. For example, when the engine reaches a key like the one below, the function is going to rerun on the object_keys
field:
{
"key_name_3": {
"type": "object",
"optional": false,
"object_keys": {
"key_name_4": {
"type": "boolean",
"optional": false
}
}
}
}
Each time the engine attempts to create an interface configuration, it will first do a deep comparison of its type configuration object against all existing interface configurations' type configuration objects already in the store. If it finds a match, it will return that interface and the key will now reference that interface.
At this stage, each interface configuration string is concatenated into a single string. This big string will get written to a file, and exported with the specified options.
FAQs
[Demo](https://type-genius.carbonology.in/)
We found that type-genius 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.