
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
react-jsonschema-form-manager
Advanced tools
Extension of react-jsonschema-form with conditional field support
This project is opinionated implementation of a manager for mozilla form or any of it's derivative projects, it provides a REST based api layer that handles form submission and update.
REST or LocalStorage api for testingPUT requestsREST form configuration supportInstall react-jsonschema-form-manager by running:
npm install --s react-jsonschema-form-manager
The simplest use case would be to load static properties and save them in localStorage,
this can be done like this:
import React from "react";
import ReactDOM from "react-dom";
import Form from "react-jsonschema-form";
import withManager, { LocalStorageFormManager, StaticConfigResolver, intervalUpdateStrategy } from "react-jsonschema-form-manager";
let config = {
schema: {
type: "object",
required: ["firstName", "lastName"],
properties: {
firstName: {
type: "string",
title: "First name",
},
lastName: {
type: "string",
title: "Last name",
}
}
}
};
let configResolver = new StaticConfigResolver(config);
let manager = new LocalStorageFormManager();
let updateStrategy = intervalUpdateStrategy(10000);
let FormToDisplay = withManager(manager, configResolver, updateStrategy)(Form);
ReactDOM.render(<FormToDisplay />, document.getElementById("app"));
Functional part of API consist of 3 parts
static or REST)localStorage or REST)imediate or interval)You can configure and extend them independently of one another, to get functionality you need.
UI workflow consists of 2 phases
LoadingScreen - display loading, while configuration is resolvedform with loaded configuration, or display an ErrorScreen screen in case configuration can't be resolvedYou can override default presentations, when you call withManager
import React, { Component } from "react";
import Form from "react-jsonschema-form";
import withManager from "react-jsonschema-form-manager";
class CustomLoadingScreen extends Component {
render() {
return (
<div className="container">
<h1>About to launch</h1>
</div>
);
}
}
class CustomErrorScreen extends Component {
render() {
return (
<div className="container">
<h4>Houston, we have a problem</h4>
<h2>
{this.props.error.message}
</h2>
</div>
);
}
}
...
export default withManager(manager, configResolver)(Form, CustomLoadingScreen, CustomErrorScreen);
Each mozilla form needs a configuration, which can be either pre configured or loaded from the server.
LoadingScreen will be displayed while configuration loads. ConfigResolver does not make any assumptions regarding the content
of the configuration, so except for schema and uiSchema you can return any configuration needed.
The simplest configuration for schema configuration load, would look like this:
import React, { Component } from "react";
import Form from "react-jsonschema-form";
import withManager, { StaticConfigResolver, LocalStorageFormManager } from "react-jsonschema-form-manager";
let config = {
schema: {
//...
},
uiSchema: {
//...
},
formData: {
//...
},
};
let configResolver = new StaticConfigResolver(config);
let localStorageManager = new LocalStorageFormManager();
let FormToDisplay = withManager(configResolver, localStorageManager)(Form);
class ResultForm extends Component {
render() {
return (
<FormToDisplay />
);
}
}
Here the config will be used as Form configuration and StaticConfigResolver is used to return it.
This is enough for forms to operate properly
There are 2 supported configuration resolvers:
config settingconfigurationYou can also specify your own configuration resolver.
StaticConfigResolver takes 2 parameters config and timeout,
config is the configuration to returntimeout delay before returning configuration, it was added primarily for testing purposesimport { StaticConfigResolver } from "react-jsonschema-form-manager";
let timeout = 10000;
let config = {
schema: {
//...
},
uiSchema: {
//...
},
formData: {
//...
},
};
let configResolver = new StaticConfigResolver(config, timeout);
Primary configuration option is by means of REST API, which you can configure with needed authentication
RESTConfigResolver takes 3 parameters
url configuration url to usecredentials authentication to use with urloutputHandler manipulate data returned by the HTTP call before resolving the promiseThe simplest RESTConfigResolver will look like this:
import { RESTConfigResolver } from "react-jsonschema-form-manager";
let configResolver = new RESTConfigResolver(`https://example.com/schema`);
In this case no authentication is needed and config resolver returnes json result of REST request
There are 3 options to specify credentials for the configuration endpoint
In this case no authentication will be provided for the request
import { RESTConfigResolver } from "react-jsonschema-form-manager";
let configResolver = new RESTConfigResolver(`https://example.com/schema`);
In case authentication can be done with domain Cookies, you can simply specify credentials object in accordance with fetch documentation. Refer to whatwg-fetch sending cookies documentation for more details.
import { RESTConfigResolver } from "react-jsonschema-form-manager";
let configResolver = new RESTConfigResolver(
`https://example.com/schema`,
{
credentials: 'same-origin'
});
or
import { RESTConfigResolver } from "react-jsonschema-form-manager";
let configResolver = new RESTConfigResolver(
`https://example.com/schema`,
{
credentials: 'include'
});
Transformation function, would sign fetch Request with any custom authentication logic needed.
For example to have a Basic authentication can be done like this:
import { RESTConfigResolver } from "react-jsonschema-form-manager";
let credentials = (req) => new Request(req, { headers: {
'Authorization': 'Basic '+ btoa(`${username}:${password}`),
}});
let configResolver = new RESTConfigResolver(
`https://example.com/schema`,
credentials);
Use this if your HTTP resource doesn't return the exact JSON data you want to pass to your Form's props. Also useful for adding/merging default values to the HTTP response.
import { RESTConfigResolver } from "react-jsonschema-form-manager";
let outputHandler = obj => {
let output = {
subSetOfData: obj.someProperty,
};
return output;
};
let configResolver = new RESTConfigResolver(
"http://localhost:3000/conf",
{},
outputHandler
);
// if origOutput = JSON response of REST call,
//configResolver resolves to: { subSetOfData: origOutput.someProperty };
If neither REST or Static configuration fits your needs, you can create your own configuration, by simply providing
resolve method with no params, that would return Promise with config result
For example GraphQL ConfigResolver can be defined something like this:
import { RESTConfigResolver } from "react-jsonschema-form-manager";
class GraphQLConfigResolver {
constructor(url, credentials) {
this.restResolver = new RESTConfigResolver(url, credentials);
}
resolve = () => {
return this.restResolver.resolve().then(({ data, error }) => {
return new Promise((resolve, reject) => {
if (error) {
reject(new Error(error));
} else {
resolve(data);
}
});
});
};
}
Besides schema configuration, you need to specify the way to save formData. System supports 2 ways of saving data
LocalStorage - using LocalStorage for storing submitted data, this is primarily for testing purposeREST - saving data in REST endpointThe simplest configuration can look like this
import React, { Component } from "react";
import Form from "react-jsonschema-form";
import withManager, { StaticConfigResolver, LocalStorageFormManager } from "react-jsonschema-form-manager";
let config = {
//...
};
let configResolver = new StaticConfigResolver(config);
let localStorageManager = new LocalStorageFormManager();
let FormToDisplay = withManager(configResolver, localStorageManager)(Form);
class ResultForm extends Component {
render() {
return (
<FormToDisplay onSubmit={() => onSuccessCallback}/>
);
}
}
In this case data is stored in LocalStorage and on successful submit, if there are no errors onSuccessCallback is called for further processing.
Implementation wraps onSubmit on original form and calls it only after formData was successfully saved with underlying FormManager.
LocalStorage store is there only for testing purposes and not supposed to be used in production.
You can specify a key under which provided form will be stored. By default form is used as a key and you are limited to single form.
As with schema configuration, this is primary option for storing your data.
RESTFormManager takes 2 parameters
url configuration url to usecredentials authentication to use with urlAuthentication logic is the same as for RESTConfigurationResolver, the only difference is that instead of the GET, we send a POST
with JSON of formData as a request.
As with ConfigurationResolver you can create your custom implementation for FormManager, which needs only 3 methods
submit called when form is submitted, should return Promise that will be resolved after successful submissionupdateIfChanged called when form needs to update it's transient stay to the server. It must return either a Promise, if manager
considers data changed and will trigger an update, or undefined if there is nothing to change.
updateIfChanged accepts force flag that will always result in update.onChange called whenever form data changes, it's needed to manage formData state inside a managerFor example FormManager using SessionStorage can look something like this:
class SessionStorageFormManager {
constructor(key = DEFAULT_KEY) {
this.key = key;
}
onChange = (state) => {
this.formData = state.formData;
}
submit = () => {
return new Promise(resolve => {
sessionStorage.setItem(this.key, JSON.stringify(this.formData));
resolve(formData);
});
}
updateIfChanged = () => {
return new Promise(resolve => {
sessionStorage.setItem(this.key, JSON.stringify(this.formData));
resolve(formData);
});
}
}
You can skip logic in update, if you are not planning to use any UpdateStrategy in your case.
UpdateStrategy is needed in case you want to save transient results of work.
For example
import React, { Component } from "react";
import Form from "react-jsonschema-form";
import { instantUpdateStrategy } from "react-jsonschema-form-manager";
...
let FormToDisplay = withManager(configResolver, manager, instantUpdateStrategy)(Form);
class ResultForm extends Component {
render() {
return (
<FormToDisplay/>
);
}
}
In this case all changes to the formData, will be instantly submitted by the FormManager to the underlying server.
As with FormManager, UpdateStrategy override embedded onChange mozilla-jsonschema functionality.
There are 2 kinds of UpdateStrategy currently supported
instantUpdateStrategy updates request on every change of the form. This is a lot of work for the server and not recommended.
import React, { Component } from "react";
import Form from "react-jsonschema-form";
import { instantUpdateStrategy } from "react-jsonschema-form-manager";
let FormToDisplay = withManager(configResolver, manager, instantUpdateStrategy)(Form);
class ResultForm extends Component {
render() {
return (
<FormToDisplay onChange={() => onSuccessChange}/>
);
}
}
intervalUpdateStrategy updates request in specified interval of time, it takes timeout as parameter.
For example, in order to update server every 100 seconds configuration would look something like this:
import React, { Component } from "react";
import Form from "react-jsonschema-form";
import { intervalUpdateStrategy } from "react-jsonschema-form-manager";
let updateStrategy = intervalUpdateStrategy(100000);
let FormToDisplay = withManager(configResolver, manager, updateStrategy)(Form);
class ResultForm extends Component {
render() {
return (
<FormToDisplay/>
);
}
}
As with other components you can easily override UpdateStrategy with custom implementation.
Construction of the object is done with a currying pattern, you can define any parameters you want on first call,
and you will get manager when updateStrategy is going to be used. Returned object needs 2 methods onChange and stop.
stop get called when component unMounts, or after successful submitonChange called when ever formData changes, in original FormFor example you want to update only on even dates, this would look something like this:
export function evenDaysUpdateStrategy() {
return (manager) => {
return {
onChange: () => {
if (new Date().getDate() % 2 == 0) {
manager.updateIfChanged();
}
},
stop: function() {};
};
};
}
If you want to track server data updates, you can do this by specifying onUpdate callback on rendered form
...
let FormToDisplay = withManager(configResolver, manager, updateStrategy)(Form);
class ResultForm extends Component {
render() {
return (
<FormToDisplay onUpdate={() => console.log("Data updated")}/>
);
}
}
If you are having issues, please let us know here or on StackOverflow.
The project is licensed under the Apache Licence 2.0.
FAQs
Extension of react-jsonschema-form with conditional field support
We found that react-jsonschema-form-manager demonstrated a not healthy version release cadence and project activity because the last version was released 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
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.

Research
A malicious package uses a QR code as steganography in an innovative technique.

Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.