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.
@catamphetamine/farce
Advanced tools
History repeats itself.
This is a fork of the original farce
package with some changes:
redux
is in peerDependencies
instead of dependencies
location
(BrowserProtocol
/ServerProtocol
):
origin
hostname
host
port
protocol
ServerProtocol
has a different constructor argument: { url, origin }
instead of url
.location.pathname
bug in createBasenameMiddleware.js
.Farce provides a Redux store enhancer that wraps a series of middlewares to allow controlling browser navigation by dispatching actions and to allow managing location state with the rest of your store state.
Table of Contents generated with DocToc
import {
Actions as FarceActions,
BrowserProtocol,
createHistoryEnhancer,
locationReducer,
queryMiddleware,
} from 'farce';
import { combineReducers, createStore } from 'redux';
const store = createStore(
combineReducers({
location: locationReducer,
}),
createHistoryEnhancer({
protocol: new BrowserProtocol(),
middlewares: [queryMiddleware],
}),
);
store.dispatch(FarceActions.init());
// To navigate to a new location:
store.dispatch(FarceActions.push('/new/path'));
// To get the current location:
const location = store.getState().location;
// -> { action: 'PUSH', pathname: '/new/path', ... }
$ npm i -S redux
$ npm i -S farce
Create a history enhancer with createHistoryEnhancer
. Configure it with an options object with a protocol
property to control how to interact with browser APIs and an optional middlewares
property to customize handling of location objects. Use this history enhancer to enhance your store.
Install locationReducer
to track the current location state in your store.
const store = createStore(
combineReducers({
location: locationReducer,
}),
createHistoryEnhancer({
protocol: new BrowserProtocol(),
middlewares: [queryMiddleware],
}),
);
Dispatch FarceActions.init()
to initialize up your store with the current browser state and to set up event listeners.
Dispatch FarceActions.push(location)
, FarceActions.replace(location)
, or FarceActions.go(delta)
to navigate.
// Add a /foo history entry.
store.dispatch(FarceActions.push('/foo'));
// Replace the current history entry with /bar.
store.dispatch(FarceActions.replace('/bar'));
// Go back one entry.
store.dispatch(FarceActions.go(-1));
If you want to tear down all event listeners, dispatch FarceActions.dispose()
.
store.dispatch(FarceActions.dispose());
BrowserProtocol
BrowserProtocol
uses the browser URL path and the HTML5 History API.
const protocol = new BrowserProtocol();
The examples here assume the use of a new BrowserProtocol()
.
HashProtocol
HashProtocol
uses the URL hash for navigation, and is intended for use in cases where server-side routing is not available, or in legacy environments where the HTML5 History API is not available. Prefer using BrowserProtocol
over HashProtocol
when possible.
const protocol = new HashProtocol();
ServerProtocol
ServerProtocol
uses a fixed, in-memory location for use in server-side rendering. It takes the path for the location to use. ServerProtocol
instances do not support location.state
and cannot navigate.
// Given a standard Node request object:
const protocol = new ServerProtocol({ url, origin });
MemoryProtocol
MemoryProtocol
tracks the current location and the location history in memory. It is intended for use in tests exercising navigation, and in cases where actual browser navigation is not possible or not desired, such as in browser plugins and in Electron apps. MemoryProtocol
requires an initial location.
const protocol = new MemoryProtocol(initialLocation);
MemoryProtocol
also supports persisting the location history state to session storage, which allows for use cases like preserving navigation state when refreshing in an Electron app.
const protocol = new MemoryProtocol(initialLocation, { persistent: true });
queryMiddleware
and createQueryMiddleware
The queryMiddleware
middleware adds support for the query
property, which enables the use of query objects to set the search string.
The createQueryMiddleware
middleware factory creates a custom query middleware. It takes a configuration object with parse
and stringify
functions as properties to configure parsing and stringifying queries.
import qs from 'qs';
const customQueryMiddleware = createQueryMiddleware({
parse: qs.parse,
stringify: qs.stringify,
});
The examples here assume the use of queryMiddleware
.
createBasenameMiddleware
The createBasenameMiddleware
middleware factory creates a middleware that implicitly prepends all paths with a base path. It takes a configuration object with a basename
string.
// With this middleware, dispatching FarceActions.push('/bar') will navigate to
// /foo/bar:
const basenameMiddleware = createBasenameMiddleware({ basename: '/foo' });
The locationReducer
reducer updates the store state with a location object. Location objects have the following properties:
action
: 'PUSH'
or 'REPLACE'
if the location was reached via FarceActions.push
or FarceActions.replace
respectively; 'POP'
on the initial location, or if the location was reached via the browser back or forward buttons or via FarceActions.go
pathname
: the path name; as on window.location
search
: the search string; as on window.location
hash
: the location hash; as on window.location
key
: if present, a unique key identifying the current history entryindex
: the current index of the history entry, starting at 0 for the initial entry; this increments on FarceActions.push
but not on FarceActions.replace
delta
: the difference between the current index
and the index
of the previous locationstate
: additional location state that is not part of the URLIf a queryMiddleware
is applied, the location object will also contain a query
property that is the parsed query object from the search string. If a basenameMiddleware
is applied, pathname
will be relative to the specified basename
.
FarceActions.push
and FarceActions.replace
take a location descriptor. A location descriptor can be an object with the shape of the location object. If it is an object, the action
, key
, index
, and delta
keys are ignored. A location descriptor can also be a string with the full path.
// Location descriptor string:
store.dispatch(FarceActions.push('/foo?bar=baz#qux'));
// Equivalent location descriptor object:
store.dispatch(
FarceActions.push({
pathname: '/foo',
search: '?bar=baz',
hash: '#qux',
}),
);
// Given a location object, you can override a subset of its properties:
store.dispatch(
FarceActions.replace({
...location,
query: { the: 'new-query' },
hash: '#new-hash',
}),
);
The history enhancer adds a farce
object as a property to the store that exposes createHref
and createLocation
methods. createHref
takes a location descriptor and returns a link href
. createLocation
takes a location descriptor and returns a fully-populated location descriptor object.
const href = store.farce.createHref({
pathname: '/foo',
query: { the: 'query' },
});
// -> '/foo?the=query'
const location = store.farce.createLocation('/foo?the=query');
// -> { pathname: '/foo', query: { the: 'query' }, ... }
The farce
object on the store also has an addNavigationListener
method. This method takes a navigation listener function and an optional options object and returns a function to remove the navigation listener.
const removeNavigationListener = store.farce.addNavigationListener(
(location) =>
location.pathname === '/bar'
? 'Are you sure you want to go to /bar?'
: true,
);
// To remove the navigation listener:
removeNavigationListener();
The navigation listener function receives the location to which the user is attempting to navigate. This function may return:
true
to allow navigationfalse
to block navigationWhen adding a navigation listener, you can set the beforeUnload
option to run the listener when the user attempts to leave the page entirely. If beforeUnload
is set, the navigation listener will be called with a null
location when the user attempts to leave the page. In this scenario, the navigation listener must return a non-promise value.
store.farce.addNavigationListener(
(location) => {
if (!location) {
return false;
}
return asyncConfirm(location);
},
{ beforeUnload: true },
);
The StateStorage
class provides transient storage associated with location objects. This can be used for tracking values like scroll position that should not be propagated when using a location object to build a new location descriptor. The StateStorage
constructor takes the farce
property from the store and a namespace
string to uniquely identify the state storage instance.
const stateStorage = new StateStorage(store.farce, 'my-transient-state');
The state storage object exposes read
and save
methods. The save
method takes a location object, an optional key to further qualify the saved property, and a JSON-serializable value; it saves the value to session storage. The read
method takes the location object and the key; it returns the saved value if retrievable or undefined
otherwise.
stateStorage.save(location, null, 1);
stateStorage.save(location, 'foo', [2, 3]);
const value1 = stateStorage.read(location);
// -> 1
const value2 = stateStorage.read(location, 'foo');
// -> [2, 3]
const value3 = stateStorage.read(location, 'bar');
// -> undefined
StateStorage
intentionally ignores errors. As such, it should be treated as unreliable. Do not use StateStorage
for managing state that is critical to the operation of your application.
The top-level farce
package exports everything available in this library. It is unlikely that any single application will use all the features available. As such, for real applications, you should import the modules you need directly, to pull in only the code that you use.
import BrowserProtocol from 'farce/BrowserProtocol';
import createHistoryEnhancer from 'farce/createHistoryEnhancer';
import queryMiddleware from 'farce/queryMiddleware';
// Instead of:
// import {
// BrowserProtocol,
// createHistoryEnhancer,
// queryMiddleware,
// } from 'farce';
FAQs
History repeats itself
The npm package @catamphetamine/farce receives a total of 172 weekly downloads. As such, @catamphetamine/farce popularity was classified as not popular.
We found that @catamphetamine/farce 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.