Merge pull request #1190 from mitmproxy/file_menu_save_open

File menu save open
This commit is contained in:
Maximilian Hils 2016-06-02 23:42:35 -07:00
commit 65fde7f554
7 changed files with 2073 additions and 1546 deletions

View File

@ -8,6 +8,8 @@ import re
import six import six
import tornado.websocket import tornado.websocket
from io import BytesIO
from mitmproxy.flow import FlowWriter, FlowReader
from mitmproxy import filt from mitmproxy import filt
from mitmproxy import version from mitmproxy import version
@ -159,6 +161,26 @@ class Flows(RequestHandler):
data=[_strip_content(f.get_state()) for f in self.state.flows] data=[_strip_content(f.get_state()) for f in self.state.flows]
)) ))
class DumpFlows(RequestHandler):
def get(self):
self.set_header("Content-Disposition", "attachment; filename=flows")
self.set_header("Content-Type", "application/octet-stream")
bio = BytesIO()
fw = FlowWriter(bio)
for f in self.state.flows:
fw.add(f)
self.write(bio.getvalue())
bio.close()
def post(self):
self.state.clear()
content = self.request.files.values()[0][0]["body"]
bio = BytesIO(content)
self.state.load_flows(FlowReader(bio).stream())
bio.close()
class ClearAll(RequestHandler): class ClearAll(RequestHandler):
@ -356,6 +378,7 @@ class Application(tornado.web.Application):
(r"/updates", ClientConnection), (r"/updates", ClientConnection),
(r"/events", Events), (r"/events", Events),
(r"/flows", Flows), (r"/flows", Flows),
(r"/flows/dump", DumpFlows),
(r"/flows/accept", AcceptFlows), (r"/flows/accept", AcceptFlows),
(r"/flows/(?P<flow_id>[0-9a-f\-]+)", FlowHandler), (r"/flows/(?P<flow_id>[0-9a-f\-]+)", FlowHandler),
(r"/flows/(?P<flow_id>[0-9a-f\-]+)/accept", AcceptFlow), (r"/flows/(?P<flow_id>[0-9a-f\-]+)/accept", AcceptFlow),

View File

@ -310,12 +310,10 @@ var _jquery = require("jquery");
var _jquery2 = _interopRequireDefault(_jquery); var _jquery2 = _interopRequireDefault(_jquery);
var _lodash = require("lodash");
var _lodash2 = _interopRequireDefault(_lodash);
var _dispatcher = require("./dispatcher.js"); var _dispatcher = require("./dispatcher.js");
var _utils = require("./utils.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ActionTypes = exports.ActionTypes = { var ActionTypes = exports.ActionTypes = {
@ -433,6 +431,18 @@ var FlowActions = exports.FlowActions = {
}, },
clear: function clear() { clear: function clear() {
_jquery2.default.post("/clear"); _jquery2.default.post("/clear");
},
download: function download() {
return window.location = "/flows/dump";
},
upload: function upload(file) {
var data = new FormData();
data.append('file', file);
(0, _utils.fetchApi)("/flows/dump", {
method: 'post',
body: data
});
} }
}; };
@ -442,7 +452,7 @@ var Query = exports.Query = {
SHOW_EVENTLOG: "e" SHOW_EVENTLOG: "e"
}; };
},{"./dispatcher.js":22,"jquery":"jquery","lodash":"lodash"}],3:[function(require,module,exports){ },{"./dispatcher.js":22,"./utils.js":27,"jquery":"jquery"}],3:[function(require,module,exports){
"use strict"; "use strict";
var _react = require("react"); var _react = require("react");
@ -3513,18 +3523,27 @@ var FileMenu = _react2.default.createClass({
} }
}, },
handleOpenClick: function handleOpenClick(e) { handleOpenClick: function handleOpenClick(e) {
this.fileInput.click();
e.preventDefault();
},
handleOpenFile: function handleOpenFile(e) {
if (e.target.files.length > 0) {
_actions.FlowActions.upload(e.target.files[0]);
this.fileInput.value = "";
}
e.preventDefault(); e.preventDefault();
console.error("unimplemented: handleOpenClick");
}, },
handleSaveClick: function handleSaveClick(e) { handleSaveClick: function handleSaveClick(e) {
e.preventDefault(); e.preventDefault();
console.error("unimplemented: handleSaveClick"); _actions.FlowActions.download();
}, },
handleShutdownClick: function handleShutdownClick(e) { handleShutdownClick: function handleShutdownClick(e) {
e.preventDefault(); e.preventDefault();
console.error("unimplemented: handleShutdownClick"); console.error("unimplemented: handleShutdownClick");
}, },
render: function render() { render: function render() {
var _this = this;
var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : ""); var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : "");
return _react2.default.createElement( return _react2.default.createElement(
@ -3548,6 +3567,29 @@ var FileMenu = _react2.default.createClass({
"New" "New"
) )
), ),
_react2.default.createElement(
"li",
null,
_react2.default.createElement(
"a",
{ href: "#", onClick: this.handleOpenClick },
_react2.default.createElement("i", { className: "fa fa-fw fa-folder-open" }),
"Open..."
),
_react2.default.createElement("input", { ref: function ref(_ref) {
return _this.fileInput = _ref;
}, className: "hidden", type: "file", onChange: this.handleOpenFile })
),
_react2.default.createElement(
"li",
null,
_react2.default.createElement(
"a",
{ href: "#", onClick: this.handleSaveClick },
_react2.default.createElement("i", { className: "fa fa-fw fa-floppy-o" }),
"Save..."
)
),
_react2.default.createElement("li", { role: "presentation", className: "divider" }), _react2.default.createElement("li", { role: "presentation", className: "divider" }),
_react2.default.createElement( _react2.default.createElement(
"li", "li",
@ -6602,7 +6644,7 @@ _lodash2.default.extend(LiveStoreMixin.prototype, {
this._fetchxhr = _jquery2.default.getJSON("/" + this.type).done(function (message) { this._fetchxhr = _jquery2.default.getJSON("/" + this.type).done(function (message) {
this.handle_fetch(message.data); this.handle_fetch(message.data);
}.bind(this)).fail(function () { }.bind(this)).fail(function () {
EventLogActions.add_event("Could not fetch " + this.type); _actions.EventLogActions.add_event("Could not fetch " + this.type);
}.bind(this)); }.bind(this));
} }
}, },
@ -6792,7 +6834,11 @@ Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
exports.formatTimeStamp = exports.formatTimeDelta = exports.formatSize = exports.Key = undefined; exports.formatTimeStamp = exports.formatTimeDelta = exports.formatSize = exports.Key = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.reverseString = reverseString; exports.reverseString = reverseString;
exports.fetchApi = fetchApi;
var _jquery = require("jquery"); var _jquery = require("jquery");
@ -6877,7 +6923,7 @@ function getCookie(name) {
var r = document.cookie.match(new RegExp("\\b" + name + "=([^;]*)\\b")); var r = document.cookie.match(new RegExp("\\b" + name + "=([^;]*)\\b"));
return r ? r[1] : undefined; return r ? r[1] : undefined;
} }
var xsrf = _jquery2.default.param({ _xsrf: getCookie("_xsrf") }); var xsrf = "_xsrf=" + getCookie("_xsrf");
//Tornado XSRF Protection. //Tornado XSRF Protection.
_jquery2.default.ajaxPrefilter(function (options) { _jquery2.default.ajaxPrefilter(function (options) {
@ -6900,6 +6946,17 @@ _jquery2.default.ajaxPrefilter(function (options) {
alert(message); alert(message);
}); });
function fetchApi(url, options) {
if (url.indexOf("?") === -1) {
url += "?" + xsrf;
} else {
url += "&" + xsrf;
}
return fetch(url, _extends({}, options, {
credentials: 'same-origin'
}));
}
},{"./actions.js":2,"jquery":"jquery","lodash":"lodash","react":"react"}]},{},[3]) },{"./actions.js":2,"jquery":"jquery","lodash":"lodash","react":"react"}]},{},[3])

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
import $ from "jquery"; import $ from "jquery";
import _ from "lodash";
import {AppDispatcher} from "./dispatcher.js"; import {AppDispatcher} from "./dispatcher.js";
import {fetchApi} from "./utils.js";
export var ActionTypes = { export var ActionTypes = {
// Connection // Connection
@ -117,6 +117,16 @@ export var FlowActions = {
}, },
clear: function(){ clear: function(){
$.post("/clear"); $.post("/clear");
},
download: () => window.location = "/flows/dump",
upload: (file) => {
let data = new FormData();
data.append('file', file);
fetchApi("/flows/dump", {
method: 'post',
body: data
})
} }
}; };

View File

@ -344,12 +344,19 @@ var FileMenu = React.createClass({
} }
}, },
handleOpenClick: function (e) { handleOpenClick: function (e) {
this.fileInput.click();
e.preventDefault();
},
handleOpenFile: function (e) {
if (e.target.files.length > 0) {
FlowActions.upload(e.target.files[0]);
this.fileInput.value = "";
}
e.preventDefault(); e.preventDefault();
console.error("unimplemented: handleOpenClick");
}, },
handleSaveClick: function (e) { handleSaveClick: function (e) {
e.preventDefault(); e.preventDefault();
console.error("unimplemented: handleSaveClick"); FlowActions.download();
}, },
handleShutdownClick: function (e) { handleShutdownClick: function (e) {
e.preventDefault(); e.preventDefault();
@ -368,6 +375,20 @@ var FileMenu = React.createClass({
New New
</a> </a>
</li> </li>
<li>
<a href="#" onClick={this.handleOpenClick}>
<i className="fa fa-fw fa-folder-open"></i>
Open...
</a>
<input ref={(ref) => this.fileInput = ref} className="hidden" type="file" onChange={this.handleOpenFile}/>
</li>
<li>
<a href="#" onClick={this.handleSaveClick}>
<i className="fa fa-fw fa-floppy-o"></i>
Save...
</a>
</li>
<li role="presentation" className="divider"></li> <li role="presentation" className="divider"></li>
<li> <li>
<a href="http://mitm.it/" target="_blank"> <a href="http://mitm.it/" target="_blank">
@ -376,18 +397,6 @@ var FileMenu = React.createClass({
</a> </a>
</li> </li>
{/* {/*
<li>
<a href="#" onClick={this.handleOpenClick}>
<i className="fa fa-fw fa-folder-open"></i>
Open
</a>
</li>
<li>
<a href="#" onClick={this.handleSaveClick}>
<i className="fa fa-fw fa-save"></i>
Save
</a>
</li>
<li role="presentation" className="divider"></li> <li role="presentation" className="divider"></li>
<li> <li>
<a href="#" onClick={this.handleShutdownClick}> <a href="#" onClick={this.handleShutdownClick}>

View File

@ -2,7 +2,7 @@
import _ from "lodash"; import _ from "lodash";
import $ from "jquery"; import $ from "jquery";
import {EventEmitter} from 'events'; import {EventEmitter} from 'events';
import { EventLogActions } from "../actions.js"
import {ActionTypes, StoreCmds} from "../actions.js"; import {ActionTypes, StoreCmds} from "../actions.js";
import {AppDispatcher} from "../dispatcher.js"; import {AppDispatcher} from "../dispatcher.js";

View File

@ -80,7 +80,7 @@ function getCookie(name) {
var r = document.cookie.match(new RegExp("\\b" + name + "=([^;]*)\\b")); var r = document.cookie.match(new RegExp("\\b" + name + "=([^;]*)\\b"));
return r ? r[1] : undefined; return r ? r[1] : undefined;
} }
var xsrf = $.param({_xsrf: getCookie("_xsrf")}); const xsrf = `_xsrf=${getCookie("_xsrf")}`;
//Tornado XSRF Protection. //Tornado XSRF Protection.
$.ajaxPrefilter(function (options) { $.ajaxPrefilter(function (options) {
@ -101,4 +101,16 @@ $(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
console.error(thrownError, message, arguments); console.error(thrownError, message, arguments);
actions.EventLogActions.add_event(thrownError + ": " + message); actions.EventLogActions.add_event(thrownError + ": " + message);
alert(message); alert(message);
}); });
export function fetchApi(url, options) {
if(url.indexOf("?") === -1){
url += "?" + xsrf;
} else {
url += "&" + xsrf;
}
return fetch(url, {
...options,
credentials: 'same-origin'
});
}