Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Engineering
Bradley Meck Farias
August 16, 2023
Applications and libraries grow over time. In JavaScript and TypeScript these lead to large amounts of files over time due to various conventions and linting rules that may be held in a code base like separate files for tests, single component per file, etc. It is very easy to end up with lots of things having large import paths like:
import '../../../../components/customer-table.js'
There are a variety of workaround provided by other tools. TypeScript provides tsconfig.json's (and jsconfig.jsons's) paths field, webpack has resolve plugins and the resolve config, yarn has their link protocol and portal protocol, etc. These generally cause some level of interoperability problems since they are not supported everywhere. All of these have slight differences but the general usage is to alias some path local to the current package scope.
Some bundlers and tools have recently started to add support for tsconfig.json's paths field even if they do not necessarily utilize typescript. However, for most people developing JS/TS they actually have a solution already that they might not even know about.
Almost every tool supports package.json#imports since it is part of the default Node.js resolver standard. This feature is supported all the way back to Node version 12 as well!
If you are familiar with tsconfig.json you might add an alias using paths like the following:
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"compilerOptions": {
"paths": {
"#components/*": [ "./src/components/*" ]
}
}
}
With package.json imports it would look like the following:
{
"$schema": "https://json.schemastore.org/package.json",
"imports": {
"#components/*": "./src/components/*"
}
}
You might notice I started both aliases with "#" that is because for package.json imports must include that prefix when providing the alias name. Then we could have a much simpler import than above:
import '#components/customer-table.js'
These aliases though are much more dynamic due to the ability to have conditions associated with them. For example you can vary the destination for your alias depending on where it is going to be used:
{
"$schema": "https://json.schemastore.org/package.json",
"imports": {
"#components": {
"browser": "./src/components/client/*",
"default": "./src/components/server/*"
}
}
}
This allows for things like you to co-locate server & client code in the same repository without needing complex routing just for conditionally choosing which file to load when in a bundler's build for the browser or not.
There is a common gotcha here in which people need to know that imports is a key order dependent JSON field, it is not unordered! In the example above it will iterate and see "browser" and validate that condition before moving onto the next. It might be easier to think of it as a big if/else tree like follows:
// each tool has a default unordered set of conditions
// that set of conditions MUST include "default"
const DEFAULT_CONDITIONS = new Set(['browser', 'default'])
// each import resolves with a set of conditions that is a
// superset of DEFAULT_CONDITIONS that may context some context
// about what is being used for resolving: types, import, require()
function resolveImport(moduleSpecifier, conditions = DEFAULT_CONDITIONS) {}
if (moduleSpecifier.startsWith('#components/')) {
// get the value for the * in the template
const globValue = moduleSpecifier.slice('#components/'.length)
if (conditions.has('browser')) {
return './src/components/client/' + globValue
}
if (conditions.has('default')) {
return './src/components/server/' + globValue
}
}
// ... do normal resolution here ...
}
Hope this tiny blog post was helpful; keep on building amazing stuff!
Subscribe to our newsletter
Get notified when we publish new security blog posts!
Try it now
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.