diff --git a/interface/src/forms/ManageUsersForm.js b/interface/src/forms/ManageUsersForm.js index 21c2d5d..996ed3a 100644 --- a/interface/src/forms/ManageUsersForm.js +++ b/interface/src/forms/ManageUsersForm.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { ValidatorForm } from 'react-material-ui-form-validator'; @@ -13,6 +13,8 @@ import TableCell from '@material-ui/core/TableCell'; import TableFooter from '@material-ui/core/TableFooter'; import TableHead from '@material-ui/core/TableHead'; import TableRow from '@material-ui/core/TableRow'; +import Box from '@material-ui/core/Box'; + import EditIcon from '@material-ui/icons/Edit'; import DeleteIcon from '@material-ui/icons/Delete'; @@ -80,6 +82,12 @@ class ManageUsersForm extends React.Component { return !this.props.userData.users.find(u => u.admin); } + removeUser = user => { + const { userData } = this.props; + const users = userData.users.filter(u => u.username !== user.username); + this.props.setData({ ...userData, users }); + } + startEditingUser = user => { this.setState({ creating: false, @@ -96,8 +104,7 @@ class ManageUsersForm extends React.Component { doneEditingUser = () => { const { user } = this.state; const { userData } = this.props; - let { users } = userData; - users = users.filter(u => u.username !== user.username); + const users = userData.users.filter(u => u.username !== user.username); users.push(user); this.props.setData({ ...userData, users }); this.setState({ @@ -125,7 +132,7 @@ class ManageUsersForm extends React.Component { onSubmit = () => { this.props.onSubmit(); - this.props.authenticationContex.refresh(); + this.props.authenticationContext.refresh(); } render() { @@ -143,17 +150,7 @@ class ManageUsersForm extends React.Component { : userData ? - user ? - - : + @@ -175,7 +172,7 @@ class ManageUsersForm extends React.Component { } - + this.removeUser(user)}> this.startEditingUser(user)}> @@ -187,22 +184,23 @@ class ManageUsersForm extends React.Component { - - { - this.noAdminConfigured() && - - You must have at least one admin user configured. - - } - + +
+ { + this.noAdminConfigured() && + + + You must have at least one admin user configured. + + + } @@ -210,6 +208,21 @@ class ManageUsersForm extends React.Component { Reset
+ { + user && + + + + } +
: @@ -227,7 +240,7 @@ class ManageUsersForm extends React.Component { } ManageUsersForm.propTypes = { - authenticationContex: PropTypes.object.isRequired, + authenticationContex: PropTypes.object.isRequired, classes: PropTypes.object.isRequired, userData: PropTypes.object, userDataFetched: PropTypes.bool.isRequired, diff --git a/interface/src/forms/UserForm.js b/interface/src/forms/UserForm.js index 45ce0fc..cca9370 100644 --- a/interface/src/forms/UserForm.js +++ b/interface/src/forms/UserForm.js @@ -1,79 +1,88 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; import { withStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; -import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; -import PasswordValidator from '../components/PasswordValidator'; - import FormControlLabel from '@material-ui/core/FormControlLabel'; import Switch from '@material-ui/core/Switch'; import FormGroup from '@material-ui/core/FormGroup'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import Dialog from '@material-ui/core/Dialog'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogActions from '@material-ui/core/DialogActions'; + +import PasswordValidator from '../components/PasswordValidator'; const styles = theme => ({ textField: { width: "100%" }, - checkboxControl: { - width: "100%" - }, - chips: { - display: 'flex', - flexWrap: 'wrap', - }, - chip: { - marginRight: theme.spacing.unit, - }, button: { - marginRight: theme.spacing.unit * 2, - marginTop: theme.spacing.unit * 2, + margin: theme.spacing.unit } }); class UserForm extends React.Component { + constructor(props) { + super(props); + this.formRef = React.createRef(); + } + componentWillMount() { ValidatorForm.addValidationRule('uniqueUsername', this.props.uniqueUsername); } + submit = () => { + this.formRef.current.submit(); + } + render() { const { classes, user, creating, handleValueChange, handleCheckboxChange, onDoneEditing, onCancelEditing } = this.props; return ( - - - - - } - label="Admin?" - /> - - - + + + Modify User + + + + + } + label="Admin?" + /> + + + + + + + ); } diff --git a/src/ArduinoJsonJWT.cpp b/src/ArduinoJsonJWT.cpp index b99a949..fddfc03 100644 --- a/src/ArduinoJsonJWT.cpp +++ b/src/ArduinoJsonJWT.cpp @@ -14,7 +14,7 @@ void ArduinoJsonJWT::setSecret(String secret){ * No need to pull in additional crypto libraries - lets use what we already have. */ String ArduinoJsonJWT::sign(String &payload) { - unsigned char hmacResult[33]; + unsigned char hmacResult[32]; { #if defined(ESP_PLATFORM) mbedtls_md_context_t ctx; @@ -34,15 +34,14 @@ String ArduinoJsonJWT::sign(String &payload) { br_hmac_out(&hmacCtx, hmacResult); #endif } - hmacResult[32] = 0; - return encode(String((char *) hmacResult)); + return encode((char *) hmacResult, 32); } String ArduinoJsonJWT::buildJWT(JsonObject &payload) { // serialize, then encode payload String jwt; serializeJson(payload, jwt); - jwt = encode(jwt); + jwt = encode(jwt.c_str(), jwt.length()); // add the header to payload jwt = JWT_HEADER + '.' + jwt; @@ -89,27 +88,27 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) { } } -String ArduinoJsonJWT::encode(String value) { +String ArduinoJsonJWT::encode(const char *cstr, int inputLen) { // prepare encoder base64_encodestate _state; #if defined(ESP8266) base64_init_encodestate_nonewlines(&_state); - size_t encodedLength = base64_encode_expected_len_nonewlines(value.length()) + 1; + size_t encodedLength = base64_encode_expected_len_nonewlines(inputLen) + 1; #elif defined(ESP_PLATFORM) base64_init_encodestate(&_state); - size_t encodedLength = base64_encode_expected_len(value.length()) + 1; + size_t encodedLength = base64_encode_expected_len(inputLen) + 1; #endif // prepare buffer of correct length char buffer[encodedLength]; // encode to buffer - int len = base64_encode_block(value.c_str(), value.length(), &buffer[0], &_state); + int len = base64_encode_block(cstr, inputLen, &buffer[0], &_state); len += base64_encode_blockend(&buffer[len], &_state); buffer[len] = 0; // convert to arduino string - value = String(buffer); + String value = String(buffer); // remove padding and convert to URL safe form while (value.charAt(value.length() - 1) == '='){ diff --git a/src/ArduinoJsonJWT.h b/src/ArduinoJsonJWT.h index 672c9fc..829041b 100644 --- a/src/ArduinoJsonJWT.h +++ b/src/ArduinoJsonJWT.h @@ -24,7 +24,7 @@ private: String sign(String &value); - static String encode(String value); + static String encode(const char *cstr, int len); static String decode(String value); public: diff --git a/src/SecurityManager.cpp b/src/SecurityManager.cpp index fd5a549..c36d013 100644 --- a/src/SecurityManager.cpp +++ b/src/SecurityManager.cpp @@ -43,9 +43,10 @@ Authentication SecurityManager::authenticateRequest(AsyncWebServerRequest *reque AsyncWebHeader* authorizationHeader = request->getHeader(AUTHORIZATION_HEADER); if (authorizationHeader) { String value = authorizationHeader->value(); - value.startsWith(AUTHORIZATION_HEADER_PREFIX); - value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN); - return authenticateJWT(value); + if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)){ + value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN); + return authenticateJWT(value); + } } return Authentication(); }