Skip to content

Commit

Permalink
Reuse storage UI for config (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
msm-code authored Apr 29, 2020
1 parent dc7a28b commit 4275a9d
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
from schema import (
JobsSchema,
JobSchema,
RequestConfigEdit,
RequestQueryMethod,
QueryRequestSchema,
QueryResponseSchema,
ParseResponseSchema,
MatchesSchema,
StatusSchema,
ConfigSchema,
UserSettingsSchema,
UserInfoSchema,
UserAuthSchema,
Expand Down Expand Up @@ -118,6 +120,29 @@ def job_cancel(job_id: str) -> StatusSchema:
return StatusSchema(status="ok")


@app.get("/api/config", response_model=List[ConfigSchema])
def config_list() -> List[ConfigSchema]:
return [
ConfigSchema(
plugin="default",
key="mwdb_url",
value="http://mwdb.cert.pl",
description="URL of a a mwdb service.",
),
ConfigSchema(
plugin="default",
key="stuff",
value="1337",
description="Important configuration key.",
),
]


@app.post("/api/config/edit", response_model=StatusSchema)
def config_edit(data: RequestConfigEdit = Body(...)) -> StatusSchema:
return StatusSchema(status="ok")


@app.get("/api/user/settings", response_model=UserSettingsSchema)
def user_settings() -> UserSettingsSchema:
return UserSettingsSchema(can_register=True, plugin_name="Redis")
Expand Down
2 changes: 2 additions & 0 deletions src/mqueryfront/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Navigation from "./Navigation";
import QueryPage from "./QueryPage";
import RecentPage from "./RecentPage";
import StatusPage from "./StatusPage";
import ConfigPage from "./ConfigPage";
import "./App.css";

class App extends Component {
Expand All @@ -16,6 +17,7 @@ class App extends Component {
<Route exact path="/" component={QueryPage} />
<Route path="/query/:hash" component={QueryPage} />
<Route exact path="/recent" component={RecentPage} />
<Route exact path="/config" component={ConfigPage} />
<Route exact path="/status" component={StatusPage} />
</Switch>
</div>
Expand Down
162 changes: 162 additions & 0 deletions src/mqueryfront/src/ConfigEntries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import React, { Component } from "react";
import ErrorBoundary from "./ErrorBoundary";
import axios from "axios";
import { API_URL } from "./config";

class ConfigRow extends Component {
constructor(props) {
super(props);

this.state = {
edit: false,
value: this.props.value,
};

this.save = this.save.bind(this);
this.cancel = this.cancel.bind(this);
this.edit = this.edit.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}

save() {
this.setState({
edit: false,
});
axios.post(API_URL + "/config/edit", {
plugin: this.props.plugin,
key: this.props.keyName,
value: this.props.value,
});
}

cancel() {
this.setState({
edit: false,
value: this.props.value,
});
}

edit() {
this.setState({
edit: true,
});
}

handleEdit(event) {
this.setState({
value: event.value,
});
}

render() {
let valueControl;
let editToggle;
if (this.state.edit) {
valueControl = (
<input
type="text"
className="form-control"
defaultValue={this.state.value}
onChange={this.handleEdit}
placeholder="Enter new value"
/>
);
editToggle = (
<div>
<button
type="button"
className="btn btn-success"
data-toggle="tooltip"
title="Save your changes"
onClick={this.save}
>
save
</button>
<button
type="button"
className="btn btn-danger"
data-toggle="tooltip"
title="Discard changes"
onClick={this.cancel}
>
cancel
</button>
</div>
);
} else {
valueControl = <span>{this.props.value}</span>;
editToggle = (
<button
type="button"
className="btn btn-info"
data-toggle="tooltip"
title="Change value of this parameter"
onClick={this.edit}
>
edit
</button>
);
}

return (
<tr>
<td>
<code
data-toggle="tooltip"
title="Name of the plugin using this field"
>
{this.props.plugin}
</code>
</td>
<td>
<code data-toggle="tooltip" title="Configuration key">
{this.props.keyName}
</code>
</td>
<td className="w-25">
<div className="d-flex">
<div className="flex-grow-1">{valueControl}</div>
<div className="flex-shrink-1">{editToggle}</div>
</div>
</td>
<td>
<span>{this.props.description}</span>
</td>
</tr>
);
}
}

class ConfigEntryList extends Component {
render() {
const configRows = this.props.config.map((config) => (
<ConfigRow
key={config.plugin + ":" + config.key}
plugin={config.plugin}
keyName={config.key}
value={config.value}
description={config.description}
/>
));

return (
<ErrorBoundary error={this.props.error}>
<div className="table-responsive">
<table className="table table-striped table-bordered">
<thead>
<tr>
<th>plugin</th>
<th>key</th>
<th>value</th>
<th>description</th>
</tr>
</thead>
<tbody>{configRows}</tbody>
</table>
</div>
</ErrorBoundary>
);
}
}

export default ConfigEntryList;
41 changes: 41 additions & 0 deletions src/mqueryfront/src/ConfigPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { Component } from "react";
import ErrorBoundary from "./ErrorBoundary";
import ConfigEntryList from "./ConfigEntries";
import axios from "axios";
import { API_URL } from "./config";
import { Link } from "react-router-dom";

class ConfigPage extends Component {
constructor(props) {
super(props);

this.state = {
config: [],
error: null,
};
}

componentDidMount() {
axios
.get(API_URL + "/config")
.then((response) => {
this.setState({ config: response.data });
})
.catch((error) => {
this.setState({ error: error });
});
}

render() {
return (
<ErrorBoundary error={this.state.error}>
<div className="container-fluid">
<h1 className="text-center mq-bottom">Config</h1>
<ConfigEntryList config={this.state.config} />
</div>
</ErrorBoundary>
);
}
}

export default ConfigPage;
7 changes: 7 additions & 0 deletions src/mqueryfront/src/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ class Navigation extends Component {
Recent jobs
</Link>
</li>
{process.env.NODE_ENV == "development" ? (
<li className="nav-item">
<Link className="nav-link" to={"/config"}>
Config
</Link>
</li>
) : undefined}
<li className="nav-item">
<Link className="nav-link" to={"/status"}>
Status
Expand Down
13 changes: 13 additions & 0 deletions src/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ class JobsSchema(BaseModel):
jobs: List[JobSchema]


class ConfigSchema(BaseModel):
plugin: str
key: str
value: str
description: str


class TaskSchema(BaseModel):
connection_id: str
epoch_ms: int
Expand All @@ -37,6 +44,12 @@ class RequestQueryMethod(str, Enum):
parse = "parse"


class RequestConfigEdit(BaseModel):
plugin: str
key: str
value: str


class QueryRequestSchema(BaseModel):
raw_yara: str
taint: Optional[str]
Expand Down

0 comments on commit 4275a9d

Please sign in to comment.