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.
A library to facilitate communication between windows (iframe, worker, popup, ...)
post-me
is a library that facilitates two way communication between windows, for example between a parent and an iframe, a worker, a tab, or a popup.
Under the hood post-me
uses the low level postMessage
API.
post-me
was inspired by postmate
, and it provides several major improvements:
typescript
support to allow strong typings of method calls and event payloads during development.In this live demo a parent window achieves two-way communication with its 5 children (4 iframes and 1 web worker).
To establish a connection between two windows follow the steps below:
ParentHandshake()
and ChildHandshake()
methods respectively.methods
parameter contain the methods that each window will expose to the other.Promise<Connection>
to the two windows.connection.getRemoteHandle()
method.
remoteHandle.call(methodName, ...args)
to call methods on the other window. It returns a Promise
of the result.remoteHandle.addEventListener(eventName, callback)
to listen to specific events dispatched by the other window.remoteHandle.removeEventListener(eventName, callback)
to remove listeners.connection.getLocalHandle()
method.
localHandle.emit(eventName, payload)
to emit a specific event with the given payload.Refer to the code snippet below as an example of these steps.
import { ParentHandshake } from 'post-me';
// Create the child window any way you like (iframe here, but could be popup or tab too)
const childFrame = document.createElement('iframe');
childFrame.src = './child.html';
const childWindow = childFrame.contentWindow;
// Define the methods you want to expose to the other window.
// Methods can either return values or Promises
const methods = {
foo: (s, x) => s.length * x,
bar: (x) => Promise.resolve(x * 2),
}
// Start the handshake
ParentHandshake(methods, childWindow, childWindow.origin);
.then((connection) => {
const localHandle = connection.localHandle();
const remoteHandle = connection.remoteHandle();
// Call a method on the child
remoteHandle.call('baz', 3)
.then((value) => {
console.log(value); // 9
})
// Listen for an event emitted by the child
remoteHandle.addEventListener('some-child-event', (payload) => {
console.log(payload) // 'Hi from child'
});
// Emit an evevent
localHandle.emit('some-parent-event', 'Hi from parent');
})
import { ChildHandshake } from 'post-me';
// Define the methods you want to expose to the other window.
// Methods can either return values or Promises
const methods = {
baz: (x) => x * 3,
}
// Start the handshake
// For safety it is strongly adviced to pass the explicit parent origin instead of '*'
const parentOrigin = '*';
ChildHandshake(methods, parentOrigin)
.then((connection) => {
const localHandle = connection.localHandle();
const remoteHandle = connection.remoteHandle();
// Call a method on the parent
remoteHandle.call('foo', 'ciao', 2)
.then((value) => {
console.log(value); // 8
})
// Listen for an event emitted by the child
remoteHandle.addEventListener('some-parent-event', (payload) => {
console.log(payload) // 'Hi from parent'
});
// Emit an evevent
localHandle.emit('some-child-event', 'Hi from child');
})
Thanks to post-me
typescript support, the correctness of the methods call arguments and event payloads can be statically enforced during development.
Ideally methods and events types should be defined in a third package that will be imported by both the parent and the child. This way, it will be ensured that both applications are working with up to date type definition.
Below a modified version of the previous example using typescript.
// common.ts
export type ParentMethods = {
foo: (s: string, x: number) => number;
bar: (x: number) => Promise<number>;
};
export type ParentEvents = {
'some-parent-event': string;
}
export type ChildMethods = {
baz: (x: number) => number;
};
export type ChildEvents = {
'some-child-event': string;
}
import { ParentHandshake, Connection } from 'post-me';
import { ParentMethods, ParentEvents, ChildMethods, ChildEvents} from '/path/to/common';
// Create the child window any way you like (iframe here, but could be popup or tab too)
const childFrame = document.createElement('iframe');
childFrame.src = './child.html';
const childWindow = childFrame.contentWindow;
// Define the methods you want to expose to the other window.
// Methods can either return values or Promises
const methods: ParentMethods = {
foo: (s, x) => s.length * x,
bar: (x) => Promise.resolve(x * 2),
}
// Start the handshake
ParentHandshake(methods, childWindow, childWindow.origin);
.then((connection: Connection<ParentEvents, ChildMethods, ChildEvents>) => {
const localHandle = connection.localHandle();
const remoteHandle = connection.remoteHandle();
// Call a method on the child
remoteHandle.call('baz', 3)
.then((value) => {
console.log(value); // 9
})
// Listen for an event emitted by the child
remoteHandle.addEventListener('some-child-event', (payload) => {
console.log(payload) // 'Hi from child'
});
// Emit an evevent
localHandle.emit('some-parent-event', 'Hi from parent');
})
import { ChildHandshake, Connection } from 'post-me';
import { ParentMethods, ParentEvents, ChildMethods, ChildEvents} from '/path/to/common';
// Define the methods you want to expose to the other window.
// Methods can either return values or Promises
const methods: ChildMethods = {
baz: (x) => x * 3,
}
// Start the handshake
// For safety it is strongly adviced to pass the explicit parent origin instead of '*'
const parentOrigin = '*';
ChildHandshake(methods, parentOrigin)
.then((connection: Connection<ChildEvents, ParentMethods, ParentEvents>) => {
const localHandle = connection.localHandle();
const remoteHandle = connection.remoteHandle();
// Call a method on the parent
remoteHandle.call('foo', 'ciao', 2)
.then((value) => {
console.log(value); // 8
})
// Listen for an event emitted by the child
remoteHandle.addEventListener('some-parent-event', (payload) => {
console.log(payload) // 'Hi from parent'
});
// Emit an evevent
localHandle.emit('some-child-event', 'Hi from child');
})
A minimal example of using post-me
with a web worker can be found in the demo source code.
FAQs
Use web Workers and other Windows through a simple Promise API
The npm package post-me receives a total of 1,741 weekly downloads. As such, post-me popularity was classified as popular.
We found that post-me 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 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.