Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
The 'birpc' npm package is a lightweight library for creating bidirectional RPC (Remote Procedure Call) communication between different contexts, such as between a web worker and the main thread, or between an iframe and its parent window. It simplifies the process of sending and receiving messages, handling responses, and managing errors.
Basic RPC Communication
This feature allows you to set up basic RPC communication between two contexts. In this example, the main thread defines an 'add' function that can be called from the worker.
const { createBirpc } = require('birpc');
// In the main thread
const rpc = createBirpc({
add: (a, b) => a + b
}, {
post: (msg) => worker.postMessage(msg),
on: (fn) => worker.onmessage = (e) => fn(e.data)
});
// In the worker
const rpc = createBirpc({}, {
post: (msg) => postMessage(msg),
on: (fn) => onmessage = (e) => fn(e.data)
});
// Call the 'add' function from the worker
rpc.add(1, 2).then(result => console.log(result)); // 3
Error Handling
This feature demonstrates how to handle errors in RPC communication. The main thread defines a function that throws an error, and the worker catches and logs the error message.
const { createBirpc } = require('birpc');
// In the main thread
const rpc = createBirpc({
throwError: () => { throw new Error('Something went wrong'); }
}, {
post: (msg) => worker.postMessage(msg),
on: (fn) => worker.onmessage = (e) => fn(e.data)
});
// In the worker
const rpc = createBirpc({}, {
post: (msg) => postMessage(msg),
on: (fn) => onmessage = (e) => fn(e.data)
});
// Call the 'throwError' function from the worker
rpc.throwError().catch(err => console.error(err.message)); // 'Something went wrong'
Bidirectional Communication
This feature shows how to set up bidirectional communication, where both the main thread and the worker can define and call functions on each other.
const { createBirpc } = require('birpc');
// In the main thread
const rpc = createBirpc({
mainFunction: () => 'Hello from main thread'
}, {
post: (msg) => worker.postMessage(msg),
on: (fn) => worker.onmessage = (e) => fn(e.data)
});
// In the worker
const rpc = createBirpc({
workerFunction: () => 'Hello from worker'
}, {
post: (msg) => postMessage(msg),
on: (fn) => onmessage = (e) => fn(e.data)
});
// Call the 'workerFunction' from the main thread
rpc.workerFunction().then(result => console.log(result)); // 'Hello from worker'
// Call the 'mainFunction' from the worker
rpc.mainFunction().then(result => console.log(result)); // 'Hello from main thread'
Comlink is a library that makes WebWorkers enjoyable. It allows you to use WebWorkers as if they were local objects. Compared to birpc, Comlink provides a more seamless and higher-level abstraction for working with WebWorkers, but it is primarily focused on WebWorkers and may not be as flexible for other contexts.
Postmate is a powerful, simple, promise-based library for cross-domain iframe communication. It allows you to easily communicate between an iframe and its parent window. While birpc can also handle iframe communication, Postmate is specifically designed for this purpose and provides a more specialized API.
rpc-websockets is a library for creating RPC servers and clients over WebSockets. It is more suitable for networked applications where WebSocket communication is required. Compared to birpc, rpc-websockets is more focused on network communication rather than inter-context communication within the same application.
Message-based two-way remote procedure call. Useful for WebSockets and Workers communication.
When using WebSocket, you need to pass your custom serializer and deserializer.
import type { ServerFunctions } from './types'
const ws = new WebSocket('ws://url')
const clientFunctions: ClientFunctions = {
hey(name: string) {
return `Hey ${name} from client`
}
}
const rpc = createBirpc<ServerFunctions>(
clientFunctions,
{
post: data => ws.send(data),
on: data => ws.on('message', data),
// these are required when using WebSocket
serialize: v => JSON.stringify(v),
deserialize: v => JSON.parse(v),
},
)
await rpc.hi('Client') // Hi Client from server
import { WebSocketServer } from 'ws'
import type { ClientFunctions } from './types'
const serverFunctions: ServerFunctions = {
hi(name: string) {
return `Hi ${name} from server`
}
}
const wss = new WebSocketServer()
wss.on('connection', (ws) => {
const rpc = createBirpc<ClientFunctions>(
serverFunctions,
{
post: data => ws.send(data),
on: data => ws.on('message', data),
serialize: v => JSON.stringify(v),
deserialize: v => JSON.parse(v),
},
)
await rpc.hey('Server') // Hey Server from client
})
As JSON.stringify
does not supporting circular references, we recommend using flatted
as the serializer when you expect to have circular references.
import { parse, stringify } from 'flatted'
const rpc = createBirpc<ServerFunctions>(
functions,
{
post: data => ws.send(data),
on: data => ws.on('message', data),
// use flatted as serializer
serialize: v => stringify(v),
deserialize: v => parse(v),
},
)
MessageChannel will automatically serialize the message and support circular references out-of-box.
export const channel = new MessageChannel()
import type { AliceFunctions } from './types'
import { channel } from './channel'
const Bob: BobFunctions = {
hey(name: string) {
return `Hey ${name}, I am Bob`
}
}
const rpc = createBirpc<AliceFunctions>(
Bob,
{
post: data => channel.port1.postMessage(data),
on: data => channel.port1.on('message', data),
},
)
await rpc.hi('Alice') // Hi Bob, I am Alice
import type { BobFunctions } from './types'
import { channel } from './channel'
const Alice: AliceFunctions = {
hi(name: string) {
return `Hi ${name}, I am Alice`
}
}
const rpc = createBirpc<BobFunctions>(
Alice,
{
post: data => channel.port2.postMessage(data),
on: data => channel.port2.on('message', data),
},
)
await rpc.hey('Alice') // Hey Alice, I am Bob
Refer to ./test/group.test.ts as an example.
MIT License © 2021 Anthony Fu
FAQs
Message based Two-way remote procedure call
We found that birpc demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 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
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.