Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Electrum simplifies framework-agnostic declaration of React components. It is used internally by Epsitec SA to bridge the gap with its Xcraft toolchain and with its Lydia framework.
Electrum is an alloy of gold and silver used to produce ancient Lydian coinage.
The first metal coins ever made, were of Electrum and date back to the end of the 7th century, beginning of the 6th century BC.
The implementation of electrum
is being modified radically.
Please wait until version has stabilized.
Let's say we want to display an article which contains the content and information about the author. The article data might be represented like this:
{ "article":
{ "content":
{ "title": "About typography"
, "text": "Lorem ipsum..."
, "date": "2015-12-02" }
, "author":
{ "name": "John"
, "mail": "john@doe.org" } } }
This can be loaded into a store
instance. The "article"
node will be
passed as state to the <Article>
component:
// In this example, the article is the root component
const state = store.select ('article');
return <Article state={state}/>;
The <Article>
can be implemented as a stateless function component:
import E from 'electrum';
function Article (props) {
return (
<div>
<Content {...E.link (props, 'content')} />
<Author {...E.link (props, 'author')} />
</div>
);
}
Components will very often need to read values from the store. To make life
easier for the developer, electrum
provides a read()
method, which takes
the props
of the component and an optional key
of the value to read:
import E from 'electrum';
function Content (props) {
return (
<div>
<h1>{E.read (props)}</h1>
<p>{E.read (props, 'details')}</p>
</div>
);
}
We decided to use radium
as the way to go to inject styles into components.
By using the E
instance provided by import Electrum from 'electrum'
),
components are automatically configured to use radium
when wrapped like
this:
import Electrum from 'electrum';
import _Button from './Button.component.js';
import _Button$styles from './Button.styles.js';
export const Button = Electrum.wrap ('Button', _Button, {styles: _Button$styles});
See electrum-theme
for an explanation of how style functions should be
defined. Style functions can have following signatures:
() => ...
→ a parameterless style function.(theme) => ...
→ a style function, based on the theme.(theme, props) => ...
→ a style function, based on the theme and on
the component properties. The component should implement a getter named
styleProps
which returns a hash with the meaningful properties.Multiple styles definitions can be exported as a hash of style functions.
A component linked with a style definition consisting of a single style function will expose following method and property:
styles
→ a styles object which can be set on DOM element style
properties; the styles object is compatible with Radium. It exposes a
with(s1, s2, ...)
function which can be used to obtain an updated
styles object into which additional styles have been merged.mergeStyles(s1, s2, ...)
→ a hash containing the merged styles.A component linked with a style definition consisting of a multiple style functions will expose following methods:
getStyles(key)
→ a styles object for the specified style definiton,
which can be set on DOM element style
properties; the styles object is
compatible with Radium. It exposes a with(s1, s2, ...)
function which
can be used to obtain an updated styles object into which additional
styles have been merged.mergeStyles(key, s1, s2, ...)
→ a hash containing the merged
styles for the specified style definition.Note that the signature of the methods are different from a component with a single style function.
Electrum.wrap()
returns a new component class
, which will be treated as a
pure component by React:
shouldComponentUpdate(nextProps, nextState)
→ pure component.It injects some additional functionality:
link(id)
→ shorthand for Electrum.link(this.props, id)
.link(id, overrides)
→ shorthand for Electrum.link(this.props, id, overrides)
.read()
→ shorthand for this.read('value')
.read(key)
→ returns named property if it exists on this.props
, otherwise
calls Electrum.read(this.props, key)
and reads the value from the state.theme
→ shorthand for this.props.theme
.styles
→ resolves the styles based on rules implemented by Styles
.The component is also extended by Radium
which will flatten styles
arrays injected in child components, and handle the
state required to handle browser states such as :hover
.
One more trick Electrum.wrap()
does is that it ensures that event handler
methods (e.g. onChange
or handleFoo
) get properly bound to the component
instance. Therefore, event handlers can be passed to React
in a natural
way:
render () {
return <div onClick={this.onClick}>Click me</div>;
}
whereas normally, you would have to write this:
render () {
return <div onClick={this.onClick.bind (this)}>Click me</div>;
}
or do the binding manually in the constructor:
constructor () {
super ();
this.onClick = this.onClick.bind (this);
}
render () {
return <div onClick={this.onClick}>Click me</div>;
}
Electrum's autobinding looks for methods starting with on
or handle
and using camel case (such as onClick
); other methods won't be
automatically bound to this
.
See also the explanation on autobinding on the React blog.
Electrum can use a bus to dispatch messages/commands and notify changes. The bus interface looks like this:
{
dispatch (props, message) {}
notify (props, source, value, ...states) {}
}
A bus can be attached with Electrum.useBus(bus)
.
The default Electrum
instance is configured to use electrum-events
,
which injects various event handlers into the wrapped components:
onChange
→ fires notification of type changeonKeyDown
, onKeyUp
, onKeyPress
→ fire notifications of
type key-down, key-up, key-pressonFocus
→ fires notification of type focusonSelect
→ fires notification of type selectNote: if the component provides its own event handlers, they will be called by the injected methods.
Events will automatically be sent to the bus, if one has been configured
(see Electrum.use
). The EventHandlers
class in electrum-events
is
in charge of the event forwarding. It will provide the value and the
states associated with the underlying component, usually by reading
the DOM:
source
← {type, event}
where type is the event namevalue
← event.target.value
states
← {begin:0, end:10}
for text fieldsWhen the defaults are not meaningful (e.g. for a checkbox
, where the
value does not exist per se), the component can provide the value
(method getValue()
) or the states (method getStates()
):
class MyCheckbox extends React.Component {
render () {
return <input type='checkbox' /* ... */ />;
}
getValue (target) {
// The value will be 'on' or 'off', depending on the checked state
// of the target DOM node:
return target.checked ? 'on' : 'off';
}
}
The easiest way to get all components of a module wrapped is to use the
electrum-require-components
module.
See electrum-require-components.
npm install electrum-require-components --save-dev
Edit package.json
to add a script that can be invoked with npm run regen
in order to regenerate the source file all.js
which includes, wraps and exports
all components.
"scripts": {
...
"regen": "electrum-require-components --wrap ./src components .component.js all.js"
}
To export all components found in your module, use:
export * from './all.js';
Electrum includes basic tracing functionality, which might come in handy when live debugging wrapped components.
Whenever React calls a wrapped component's shouldComponentUpdate()
, Electrum
will call the corresponding logging function:
import E from 'electrum';
E.configureLog ('shouldComponentUpdate', (component, nextProps, nextState, result) => { /* ... */ });
The arguments are:
component
→ component instance.nextProps
→ next properties, as provided to shouldComponentUpdate
.nextState
→ next state, as provided to shouldComponentUpdate
.result
→ result of the call to shouldComponentUpdate
, where true
means that the component should be rendered.Components may need to represent their internal state as a collection of simple state objects:
const fieldSelection = { from: 12, to: 17 }; // 'from,to'
const listSelection = { first: 5, active: 8 }; // 'active,first'
These state objects have fingerprints which are based on their sorted
property names ('from,to'
, 'active,first'
). It does not include the
optional id
property.
The FieldStates
class maintains an internal array of state objects.
It is implemented in electrum-field
and made available by electrum
as a convenience.
FieldStates.fingerprint (state)
→ the fingerprint of a state object.find (fingerprint)
→ the first state object which matches the
specified fingerprint, or undefined
if none can be found.get ()
→ an immutable array of immutable state objects.The instances are immutable. All methods which modify the internal array of state objects will return a new instance (or the unchanged instance if the update was a no-op). The original instance is never modified.
add (state)
→ a new instance where the internal array of states has
been updated by adding or replacing a state; matching is done based on the
state's fingerprint.add (state1, state2, ...)
→ same as add()
called multiple times.remove (fingerprint)
→ a new instance where the internal array of
states has been updated by removing the first state matching the specified
fingerprint.Electrum prescribes how actions represent their specific state and
provides the Action
class to inspect it:
Action.isEnabled (state)
→ true
if the state is enabled.Action.isDisabled (state)
→ true
if the state is disabled.FAQs
Electrum simplifies framework-agnostic declaration of React components.
The npm package electrum receives a total of 4 weekly downloads. As such, electrum popularity was classified as not popular.
We found that electrum demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 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.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.