mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-22 07:08:10 +00:00
Merge branch 'main' of https://github.com/gorogoroumaru/mitmproxy into hover-menu
This commit is contained in:
commit
96d6804f5a
@ -67,6 +67,7 @@ If you depend on these features, please raise your voice in
|
||||
* Customize markers with emoji, and filters: The `flow.mark` command may be used to mark a flow with either the default
|
||||
"red ball" marker, a single character, or an emoji like `:grapes:`. Use the `~marker` filter to filter on marker characters. (@rbdixon)
|
||||
* New `flow.comment` command to add a comment to the flow. Add `~comment <regex>` filter syntax to search flow comments. (@rbdixon)
|
||||
* Fix multipart forms losing `boundary` values on edit (@roytu)
|
||||
* --- TODO: add new PRs above this line ---
|
||||
* ... and various other fixes, documentation improvements, dependency version bumps, etc.
|
||||
|
||||
|
@ -2,20 +2,13 @@
|
||||
|
||||
This directory houses the mitmproxy documentation available at <https://docs.mitmproxy.org/>.
|
||||
|
||||
## Quick Start
|
||||
## Prerequisites
|
||||
|
||||
1. Install [hugo "extended"](https://gohugo.io/getting-started/installing/).
|
||||
2. Windows users: Depending on your git settings, you may need to manually create a symlink from
|
||||
/docs/src/examples to /examples.
|
||||
3. Make sure the mitmproxy Python package is installed and the virtual python environment was activated. See [CONTRIBUTING.md](../CONTRIBUTING.md#development-setup) for details.
|
||||
4. Run `./build.py` to generate additional documentation source files.
|
||||
2. Windows users: Depending on your git settings, you may need to manually create a symlink from `/docs/src/examples` to `/examples`.
|
||||
|
||||
Now you can run `hugo server -D` in ./src.
|
||||
## Editing docs locally
|
||||
|
||||
## Extended Install
|
||||
|
||||
This is required to modify CSS files.
|
||||
|
||||
1. Install "extended" hugo version.
|
||||
|
||||
You can now run `modd` in this directory instead of running hugo directly.
|
||||
1. Make sure the mitmproxy Python package is installed and the virtual python environment was activated. See [CONTRIBUTING.md](../CONTRIBUTING.md#development-setup) for details.
|
||||
2. Run `./build.py` to generate additional documentation source files.
|
||||
3. Now you can change your working directory to `./src` and run `hugo server -D`.
|
||||
|
@ -169,18 +169,19 @@ class TlsConfig:
|
||||
if not server.alpn_offers:
|
||||
if client.alpn_offers:
|
||||
if ctx.options.http2:
|
||||
# We would perfectly support HTTP/1 -> HTTP/2, but we want to keep things on the same protocol
|
||||
# version. There are some edge cases where we want to mirror the regular server's behavior
|
||||
# accurately, for example header capitalization.
|
||||
server.alpn_offers = tuple(client.alpn_offers)
|
||||
else:
|
||||
server.alpn_offers = tuple(x for x in client.alpn_offers if x != b"h2")
|
||||
elif client.tls_established:
|
||||
# We would perfectly support HTTP/1 -> HTTP/2, but we want to keep things on the same protocol version.
|
||||
# There are some edge cases where we want to mirror the regular server's behavior accurately,
|
||||
# for example header capitalization.
|
||||
server.alpn_offers = []
|
||||
elif ctx.options.http2:
|
||||
server.alpn_offers = tls.HTTP_ALPNS
|
||||
else:
|
||||
server.alpn_offers = tls.HTTP1_ALPNS
|
||||
# We either have no client TLS or a client without ALPN.
|
||||
# - If the client does use TLS but did not send an ALPN extension, we want to mirror that upstream.
|
||||
# - If the client does not use TLS, there's no clear-cut answer. As a pragmatic approach, we also do
|
||||
# not send any ALPN extension in this case, which defaults to whatever protocol we are speaking
|
||||
# or falls back to HTTP.
|
||||
server.alpn_offers = []
|
||||
|
||||
if not server.cipher_list and ctx.options.ciphers_server:
|
||||
server.cipher_list = ctx.options.ciphers_server.split(":")
|
||||
|
@ -1,3 +1,5 @@
|
||||
import binascii
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import urllib.parse
|
||||
@ -86,7 +88,7 @@ class Headers(multidict.MultiDict): # type: ignore
|
||||
>>> h.fields
|
||||
|
||||
Caveats:
|
||||
- For use with the "Set-Cookie" header, either use `Response.cookies` or see `Headers.get_all`.
|
||||
- For use with the "Set-Cookie" and "Cookie" headers, either use `Response.cookies` or see `Headers.get_all`.
|
||||
"""
|
||||
|
||||
def __init__(self, fields: Iterable[Tuple[bytes, bytes]] = (), **headers):
|
||||
@ -142,9 +144,12 @@ class Headers(multidict.MultiDict): # type: ignore
|
||||
def get_all(self, name: Union[str, bytes]) -> List[str]:
|
||||
"""
|
||||
Like `Headers.get`, but does not fold multiple headers into a single one.
|
||||
This is useful for Set-Cookie headers, which do not support folding.
|
||||
This is useful for Set-Cookie and Cookie headers, which do not support folding.
|
||||
|
||||
*See also:* <https://tools.ietf.org/html/rfc7230#section-3.2.2>
|
||||
*See also:*
|
||||
- <https://tools.ietf.org/html/rfc7230#section-3.2.2>
|
||||
- <https://datatracker.ietf.org/doc/html/rfc6265#section-5.4>
|
||||
- <https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.5>
|
||||
"""
|
||||
name = _always_bytes(name)
|
||||
return [
|
||||
@ -940,8 +945,17 @@ class Request(Message):
|
||||
return ()
|
||||
|
||||
def _set_multipart_form(self, value):
|
||||
is_valid_content_type = self.headers.get("content-type", "").lower().startswith("multipart/form-data")
|
||||
if not is_valid_content_type:
|
||||
"""
|
||||
Generate a random boundary here.
|
||||
|
||||
See <https://datatracker.ietf.org/doc/html/rfc2046#section-5.1.1> for specifications
|
||||
on generating the boundary.
|
||||
"""
|
||||
boundary = "-" * 20 + binascii.hexlify(os.urandom(16)).decode()
|
||||
self.headers["content-type"] = f"multipart/form-data; boundary={boundary}"
|
||||
self.content = multipart.encode(self.headers, value)
|
||||
self.headers["content-type"] = "multipart/form-data"
|
||||
|
||||
@property
|
||||
def multipart_form(self) -> multidict.MultiDictView[bytes, bytes]:
|
||||
|
2
setup.py
2
setup.py
@ -84,7 +84,7 @@ setup(
|
||||
"pyOpenSSL>=20.0,<20.1",
|
||||
"pyparsing>=2.4.2,<2.5",
|
||||
"pyperclip>=1.6.0,<1.9",
|
||||
"ruamel.yaml>=0.16,<0.18",
|
||||
"ruamel.yaml>=0.16,<0.17",
|
||||
"sortedcontainers>=2.3,<2.5",
|
||||
"tornado>=4.3,<7",
|
||||
"urwid>=2.1.1,<2.2",
|
||||
|
@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import fileinput
|
||||
import sys
|
||||
import re
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
@ -10,7 +11,7 @@ if __name__ == "__main__":
|
||||
port = sys.argv[1]
|
||||
matches = False
|
||||
for line in fileinput.input(sys.argv[2:]):
|
||||
if line.startswith("["):
|
||||
if re.match(r"^\[|(\d+\.){3}", line):
|
||||
matches = port in line
|
||||
if matches:
|
||||
print(line, end="")
|
||||
|
@ -190,8 +190,8 @@ class TestTlsConfig:
|
||||
|
||||
assert_alpn(True, tls.HTTP_ALPNS + (b"foo",), tls.HTTP_ALPNS + (b"foo",))
|
||||
assert_alpn(False, tls.HTTP_ALPNS + (b"foo",), tls.HTTP1_ALPNS + (b"foo",))
|
||||
assert_alpn(True, [], tls.HTTP_ALPNS)
|
||||
assert_alpn(False, [], tls.HTTP1_ALPNS)
|
||||
assert_alpn(True, [], [])
|
||||
assert_alpn(False, [], [])
|
||||
ctx.client.timestamp_tls_setup = time.time()
|
||||
# make sure that we don't upgrade h1 to h2,
|
||||
# see comment in tlsconfig.py
|
||||
|
@ -429,9 +429,9 @@ class TestRequestUtils:
|
||||
|
||||
def test_set_multipart_form(self):
|
||||
request = treq()
|
||||
request.multipart_form = [("file", "shell.jpg"), ("file_size", "1000")]
|
||||
assert request.headers["Content-Type"] == 'multipart/form-data'
|
||||
assert request.content is None
|
||||
request.multipart_form = [(b"file", b"shell.jpg"), (b"file_size", b"1000")]
|
||||
assert request.headers["Content-Type"].startswith('multipart/form-data')
|
||||
assert list(request.multipart_form.items()) == [(b"file", b"shell.jpg"), (b"file_size", b"1000")]
|
||||
|
||||
|
||||
class TestResponse:
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"presets": ["es2015", "react"],
|
||||
"plugins": ["transform-class-properties", "transform-object-rest-spread"]
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ and activate your virtualenv environment before proceeding.**
|
||||
|
||||
## Testing
|
||||
|
||||
- Run `yarn run test` to run the testsuite.
|
||||
- Run `yarn test` to run the test suite.
|
||||
|
||||
## Architecture
|
||||
|
||||
|
4
web/babel.config.js
Normal file
4
web/babel.config.js
Normal file
@ -0,0 +1,4 @@
|
||||
/* This currently is only used for jest. We use esbuild for actual bundling. */
|
||||
module.exports = {
|
||||
presets: ['@babel/preset-react', '@babel/preset-env', '@babel/preset-typescript'],
|
||||
};
|
30
web/conf.js
30
web/conf.js
@ -1,30 +0,0 @@
|
||||
|
||||
var conf = {
|
||||
src: "src/",
|
||||
dist: "../mitmproxy/tools/web",
|
||||
static: "../mitmproxy/tools/web/static",
|
||||
js: {
|
||||
// Don't package these in the vendor distribution
|
||||
vendor_excludes: [
|
||||
"bootstrap" // We only use Bootstrap's CSS.
|
||||
],
|
||||
// Package these as well as the dependencies
|
||||
vendor_includes: [
|
||||
],
|
||||
app: 'src/js/app',
|
||||
eslint: ["src/js/**/*.js", "!src/js/filt/filt.js"]
|
||||
},
|
||||
css: {
|
||||
vendor: ["src/css/vendor.less"],
|
||||
app: ["src/css/app.less"]
|
||||
},
|
||||
copy: [
|
||||
"src/images/**", "src/fonts/fontawesome-webfont.*"
|
||||
],
|
||||
templates: [
|
||||
"src/templates/*"
|
||||
],
|
||||
peg: ["src/js/filt/filt.peg"]
|
||||
};
|
||||
|
||||
module.exports = conf;
|
300
web/gulpfile.js
300
web/gulpfile.js
@ -1,228 +1,118 @@
|
||||
var path = require('path');
|
||||
const gulp = require("gulp");
|
||||
const gulpEsbuild = require('gulp-esbuild');
|
||||
const less = require("gulp-less");
|
||||
const livereload = require("gulp-livereload");
|
||||
const cleanCSS = require('gulp-clean-css');
|
||||
const notify = require("gulp-notify");
|
||||
const compilePeg = require("gulp-peg");
|
||||
const plumber = require("gulp-plumber");
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
const through = require("through2");
|
||||
|
||||
var packagejs = require('./package.json');
|
||||
var conf = require('./conf.js');
|
||||
|
||||
// Sorted alphabetically!
|
||||
var babelify = require('babelify');
|
||||
var envify = require('envify/custom');
|
||||
var browserify = require('browserify');
|
||||
var gulp = require("gulp");
|
||||
var eslint = require('gulp-eslint');
|
||||
var less = require("gulp-less");
|
||||
var livereload = require("gulp-livereload");
|
||||
var cleanCSS = require('gulp-clean-css');
|
||||
var notify = require("gulp-notify");
|
||||
var peg = require("gulp-peg");
|
||||
var plumber = require("gulp-plumber");
|
||||
var rename = require("gulp-rename");
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
var gutil = require("gulp-util");
|
||||
var _ = require('lodash');
|
||||
var uglifyify = require('uglifyify');
|
||||
var buffer = require('vinyl-buffer');
|
||||
var source = require('vinyl-source-stream');
|
||||
var watchify = require('watchify');
|
||||
|
||||
var vendor_packages = _.difference(
|
||||
_.union(
|
||||
_.keys(packagejs.dependencies),
|
||||
conf.js.vendor_includes
|
||||
),
|
||||
conf.js.vendor_excludes
|
||||
);
|
||||
const noop = () => through.obj();
|
||||
|
||||
var handleError = {errorHandler: notify.onError("Error: <%= error.message %>")};
|
||||
|
||||
/*
|
||||
* Sourcemaps are a wonderful way to develop directly from the chrome devtools.
|
||||
* However, generating correct sourcemaps is a huge PITA, especially on Windows.
|
||||
* Fixing this upstream is tedious as apparently nobody really cares and
|
||||
* a single misbehaving transform breaks everything.
|
||||
* Thus, we just manually fix all paths.
|
||||
*/
|
||||
function fixSourceMaps(file) {
|
||||
file.sourceMap.sources = file.sourceMap.sources.map(function (x) {
|
||||
return path.relative(".", x).split(path.sep).join('/');
|
||||
});
|
||||
return "/";
|
||||
}
|
||||
// Browserify fails for paths starting with "..".
|
||||
function fixBrowserifySourceMaps(file) {
|
||||
file.sourceMap.sources = file.sourceMap.sources.map((x) => {
|
||||
return x.replace("src/js/node_modules", "node_modules");
|
||||
});
|
||||
return fixSourceMaps(file);
|
||||
}
|
||||
function fixLessSourceMaps(file) {
|
||||
file.sourceMap.sources = file.sourceMap.sources.map((x) => {
|
||||
if(!x.startsWith("..")){
|
||||
return "../src/css/" + x;
|
||||
}
|
||||
return x.replace("src/js/node_modules", "node_modules");
|
||||
});
|
||||
return fixSourceMaps(file);
|
||||
}
|
||||
|
||||
function styles(files, dev){
|
||||
function styles(files, dev) {
|
||||
return gulp.src(files)
|
||||
.pipe(dev ? plumber(handleError) : gutil.noop())
|
||||
.pipe(dev ? plumber(handleError) : noop())
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(less())
|
||||
.pipe(dev ? gutil.noop() : cleanCSS())
|
||||
.pipe(sourcemaps.write(".", {sourceRoot: fixLessSourceMaps}))
|
||||
.pipe(gulp.dest(conf.static))
|
||||
.pipe(dev ? noop() : cleanCSS())
|
||||
.pipe(sourcemaps.write(".", {sourceRoot: '/src/css'}))
|
||||
.pipe(gulp.dest("../mitmproxy/tools/web/static"))
|
||||
.pipe(livereload({auto: false}));
|
||||
}
|
||||
gulp.task("styles-app-dev", function () {
|
||||
return styles(conf.css.app, true);
|
||||
});
|
||||
gulp.task("styles-vendor-dev", function () {
|
||||
return styles(conf.css.vendor, true);
|
||||
});
|
||||
gulp.task("styles-app-prod", function () {
|
||||
return styles(conf.css.app, false);
|
||||
});
|
||||
gulp.task("styles-vendor-prod", function () {
|
||||
return styles(conf.css.vendor, false);
|
||||
});
|
||||
|
||||
|
||||
function buildScript(bundler, filename, dev) {
|
||||
if (dev) {
|
||||
bundler = watchify(bundler);
|
||||
} else {
|
||||
bundler = bundler.transform(envify({ _: 'purge', NODE_ENV: 'production' }), { global: true });
|
||||
bundler = bundler.transform({global: true}, uglifyify);
|
||||
}
|
||||
|
||||
function rebundle() {
|
||||
return bundler.bundle()
|
||||
.on('error', function(error) {
|
||||
gutil.log(error + '\n' + error.codeFrame);
|
||||
this.emit('end');
|
||||
})
|
||||
.pipe(dev ? plumber(handleError) : gutil.noop())
|
||||
.pipe(source('bundle.js'))
|
||||
.pipe(buffer())
|
||||
.pipe(sourcemaps.init({loadMaps: true}))
|
||||
.pipe(rename(filename))
|
||||
.pipe(sourcemaps.write('.', {sourceRoot: fixBrowserifySourceMaps}))
|
||||
.pipe(gulp.dest(conf.static))
|
||||
.pipe(livereload({auto: false}));
|
||||
}
|
||||
|
||||
// listen for an update and run rebundle
|
||||
bundler.on('update', rebundle);
|
||||
bundler.on('log', gutil.log);
|
||||
bundler.on('error', gutil.log);
|
||||
|
||||
// run it once the first time buildScript is called
|
||||
return rebundle();
|
||||
function styles_vendor_prod() {
|
||||
return styles("src/css/vendor.less", false)
|
||||
}
|
||||
|
||||
function vendor_stream(dev) {
|
||||
var bundler = browserify({
|
||||
entries: [],
|
||||
debug: true,
|
||||
cache: {}, // required for watchify
|
||||
packageCache: {} // required for watchify
|
||||
});
|
||||
for (var vp of vendor_packages) {
|
||||
bundler.require(vp);
|
||||
}
|
||||
return buildScript(bundler, "vendor.js", dev);
|
||||
function styles_vendor_dev() {
|
||||
return styles("src/css/vendor.less", true)
|
||||
}
|
||||
gulp.task("scripts-vendor-dev", function () {
|
||||
return vendor_stream(true);
|
||||
});
|
||||
gulp.task("scripts-vendor-prod", function () {
|
||||
return vendor_stream(false);
|
||||
});
|
||||
|
||||
function app_stream(dev) {
|
||||
var bundler = browserify({
|
||||
entries: [conf.js.app],
|
||||
debug: true,
|
||||
extensions: ['.jsx'],
|
||||
cache: {}, // required for watchify
|
||||
packageCache: {} // required for watchify
|
||||
});
|
||||
for (var vp of vendor_packages) {
|
||||
bundler.external(vp);
|
||||
}
|
||||
bundler = bundler.transform(babelify);
|
||||
return buildScript(bundler, "app.js", dev);
|
||||
function styles_app_prod() {
|
||||
return styles("src/css/app.less", false)
|
||||
}
|
||||
|
||||
function styles_app_dev() {
|
||||
return styles("src/css/app.less", true)
|
||||
}
|
||||
gulp.task('scripts-app-dev', function () {
|
||||
return app_stream(true);
|
||||
});
|
||||
gulp.task('scripts-app-prod', function () {
|
||||
return app_stream(false);
|
||||
});
|
||||
|
||||
|
||||
gulp.task("eslint", function () {
|
||||
return gulp.src(conf.js.eslint)
|
||||
function esbuild(dev) {
|
||||
return gulp.src('src/js/app.jsx').pipe(
|
||||
gulpEsbuild({
|
||||
outfile: 'app.js',
|
||||
sourcemap: true,
|
||||
sourceRoot: "/",
|
||||
minify: !dev,
|
||||
keepNames: true,
|
||||
bundle: true,
|
||||
}))
|
||||
.pipe(gulp.dest("../mitmproxy/tools/web/static"))
|
||||
.pipe(livereload({auto: false}));
|
||||
}
|
||||
|
||||
function scripts_dev() {
|
||||
return esbuild(true);
|
||||
}
|
||||
|
||||
function scripts_prod() {
|
||||
return esbuild(false);
|
||||
}
|
||||
|
||||
const copy_src = ["src/images/**", "src/fonts/fontawesome-webfont.*"];
|
||||
|
||||
function copy() {
|
||||
return gulp.src(copy_src, {base: "src/"})
|
||||
.pipe(gulp.dest("../mitmproxy/tools/web/static"));
|
||||
}
|
||||
|
||||
const template_src = "src/templates/*";
|
||||
|
||||
function templates() {
|
||||
return gulp.src(template_src, {base: "src/"})
|
||||
.pipe(gulp.dest("../mitmproxy/tools/web"));
|
||||
}
|
||||
|
||||
const peg_src = "src/js/filt/filt.peg";
|
||||
|
||||
function peg() {
|
||||
return gulp.src(peg_src, {base: "src/"})
|
||||
.pipe(plumber(handleError))
|
||||
.pipe(eslint())
|
||||
.pipe(eslint.format())
|
||||
});
|
||||
|
||||
gulp.task("copy", function () {
|
||||
return gulp.src(conf.copy, {base: conf.src})
|
||||
.pipe(gulp.dest(conf.static));
|
||||
});
|
||||
|
||||
|
||||
gulp.task('templates', function(){
|
||||
return gulp.src(conf.templates, {base: conf.src})
|
||||
.pipe(gulp.dest(conf.dist));
|
||||
});
|
||||
|
||||
gulp.task("peg", function () {
|
||||
return gulp.src(conf.peg, {base: conf.src})
|
||||
.pipe(plumber(handleError))
|
||||
.pipe(peg())
|
||||
.pipe(compilePeg())
|
||||
.pipe(gulp.dest("src/"));
|
||||
});
|
||||
}
|
||||
|
||||
gulp.task(
|
||||
"dev",
|
||||
gulp.series(
|
||||
"copy",
|
||||
"styles-vendor-dev",
|
||||
"styles-app-dev",
|
||||
"scripts-vendor-dev",
|
||||
"peg",
|
||||
"scripts-app-dev",
|
||||
"templates"
|
||||
)
|
||||
);
|
||||
gulp.task(
|
||||
"prod",
|
||||
gulp.series(
|
||||
"copy",
|
||||
"styles-vendor-prod",
|
||||
"styles-app-prod",
|
||||
"scripts-vendor-prod",
|
||||
"peg",
|
||||
"scripts-app-prod",
|
||||
"templates"
|
||||
)
|
||||
const dev = gulp.parallel(
|
||||
copy,
|
||||
styles_vendor_dev,
|
||||
styles_app_dev,
|
||||
peg,
|
||||
scripts_dev,
|
||||
templates
|
||||
);
|
||||
|
||||
gulp.task("default", gulp.series(
|
||||
"dev",
|
||||
function watch() {
|
||||
livereload.listen({auto: true});
|
||||
gulp.watch(["src/css/vendor*"], gulp.series("styles-vendor-dev"));
|
||||
gulp.watch(["src/css/**"], gulp.series("styles-app-dev"));
|
||||
|
||||
gulp.watch(conf.templates, gulp.series("templates"));
|
||||
gulp.watch(conf.peg, gulp.series("peg"));
|
||||
gulp.watch(["src/js/**"], gulp.series("eslint"));
|
||||
// other JS is handled by watchify.
|
||||
gulp.watch(conf.copy, gulp.series("copy"));
|
||||
})
|
||||
const prod = gulp.parallel(
|
||||
copy,
|
||||
styles_vendor_prod,
|
||||
styles_app_prod,
|
||||
peg,
|
||||
scripts_prod,
|
||||
templates
|
||||
);
|
||||
|
||||
exports.dev = dev;
|
||||
exports.prod = prod;
|
||||
exports.default = function watch() {
|
||||
const opts = {ignoreInitial: false};
|
||||
livereload.listen({auto: true});
|
||||
gulp.watch(["src/css/vendor*"], opts, styles_vendor_dev);
|
||||
gulp.watch(["src/css/**"], opts, styles_app_dev);
|
||||
gulp.watch(["src/js/**"], opts, scripts_dev);
|
||||
gulp.watch(template_src, opts, templates);
|
||||
gulp.watch(peg_src, opts, peg);
|
||||
gulp.watch(copy_src, opts, copy);
|
||||
}
|
||||
|
19
web/jest.config.js
Normal file
19
web/jest.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
process.env.TZ = 'UTC';
|
||||
|
||||
module.exports = {
|
||||
"testEnvironment": "jsdom",
|
||||
"testRegex": "__tests__/.*Spec.(js|ts)x?$",
|
||||
"roots": [
|
||||
"<rootDir>/src/js"
|
||||
],
|
||||
"unmockedModulePathPatterns": [
|
||||
"react"
|
||||
],
|
||||
"coverageDirectory": "./coverage",
|
||||
"coveragePathIgnorePatterns": [
|
||||
"<rootDir>/src/js/filt/filt.js"
|
||||
],
|
||||
"collectCoverageFrom": [
|
||||
"src/js/**/*.{js,jsx,ts,tsx}"
|
||||
]
|
||||
};
|
115
web/package.json
115
web/package.json
@ -1,72 +1,47 @@
|
||||
{
|
||||
"name": "mitmproxy",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "TZ=UTC jest --coverage",
|
||||
"build": "gulp prod",
|
||||
"start": "gulp"
|
||||
},
|
||||
"jest": {
|
||||
"testRegex": "__tests__/.*Spec.js$",
|
||||
"roots": [
|
||||
"<rootDir>/src/js"
|
||||
],
|
||||
"unmockedModulePathPatterns": [
|
||||
"react"
|
||||
],
|
||||
"coverageDirectory": "./coverage",
|
||||
"coveragePathIgnorePatterns": [
|
||||
"<rootDir>/src/js/filt/filt.js"
|
||||
],
|
||||
"collectCoverageFrom": [
|
||||
"src/js/**/*.{js,jsx}"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^3.3.7",
|
||||
"classnames": "^2.2.5",
|
||||
"lodash": "^4.17.4",
|
||||
"mock-xmlhttprequest": "^1.1.0",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "16.0.0",
|
||||
"react-codemirror": "^1.0.0",
|
||||
"react-dom": "16.0.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-test-renderer": "16.0.0",
|
||||
"redux": "^3.7.2",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-mock-store": "^1.3.0",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"shallowequal": "^1.0.2",
|
||||
"stable": "^0.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^8.0.1",
|
||||
"babel-jest": "^21.2.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babelify": "^8.0.0",
|
||||
"browserify": "^14.5.0",
|
||||
"envify": "^4.1.0",
|
||||
"eslint": "^4.9.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-clean-css": "^4.2.0",
|
||||
"gulp-eslint": "^6.0.0",
|
||||
"gulp-less": "^4.0.1",
|
||||
"gulp-livereload": "^4.0.2",
|
||||
"gulp-notify": "^3.2.0",
|
||||
"gulp-peg": "^0.2.0",
|
||||
"gulp-plumber": "^1.2.1",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-sourcemaps": "^2.6.5",
|
||||
"gulp-util": "^3.0.8",
|
||||
"jest": "^21.2.1",
|
||||
"uglifyify": "^4.0.4",
|
||||
"vinyl-buffer": "^1.0.1",
|
||||
"vinyl-source-stream": "^2.0.0",
|
||||
"watchify": "^3.11.1"
|
||||
}
|
||||
"name": "mitmproxy",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "jest --coverage",
|
||||
"build": "gulp prod",
|
||||
"start": "gulp"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^3.3.7",
|
||||
"classnames": "^2.3.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mock-xmlhttprequest": "^1.1.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
"react-codemirror": "^1.0.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"redux": "^4.1.0",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"shallowequal": "^1.1.0",
|
||||
"stable": "^0.1.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.3",
|
||||
"@babel/preset-env": "^7.14.4",
|
||||
"@babel/preset-react": "^7.13.13",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"babel-jest": "^27.0.2",
|
||||
"esbuild": "^0.12.8",
|
||||
"esbuild-jest": "^0.5.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-clean-css": "^4.3.0",
|
||||
"gulp-esbuild": "^0.8.1",
|
||||
"gulp-less": "^4.0.1",
|
||||
"gulp-livereload": "^4.0.2",
|
||||
"gulp-notify": "^4.0.0",
|
||||
"gulp-peg": "^0.2.0",
|
||||
"gulp-plumber": "^1.2.1",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"jest": "^27.0.4",
|
||||
"through2": "^4.0.2"
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { ViewServer, ViewImage, PureViewServer, Edit } from '../../../components
|
||||
import { TFlow, TStore } from '../../ducks/tutils'
|
||||
import mockXMLHttpRequest from 'mock-xmlhttprequest'
|
||||
|
||||
global.XMLHttpRequest = mockXMLHttpRequest
|
||||
window.XMLHttpRequest = mockXMLHttpRequest
|
||||
let tflow = new TFlow()
|
||||
|
||||
describe('ViewImage Component', () => {
|
||||
|
@ -26,7 +26,7 @@ exports[`ContentTooLarge Components should render correctly 1`] = `
|
||||
>
|
||||
<button
|
||||
className="btn btn-xs btn-warning pull-right"
|
||||
onClick={[Function]}
|
||||
onClick={[MockFunction]}
|
||||
>
|
||||
Display anyway
|
||||
</button>
|
||||
|
@ -6,9 +6,7 @@ exports[`ShowFullContentButton Component should render correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="view-all-content-btn btn-xs btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title={undefined}
|
||||
>
|
||||
Show full content
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@ import { TStore, TFlow } from '../ducks/tutils'
|
||||
import { Provider } from 'react-redux'
|
||||
import mockXMLHttpRequest from 'mock-xmlhttprequest'
|
||||
|
||||
global.XMLHttpRequest = mockXMLHttpRequest
|
||||
window.XMLHttpRequest = mockXMLHttpRequest
|
||||
|
||||
describe('ContentView Component', () => {
|
||||
let store = TStore()
|
||||
|
@ -2,10 +2,9 @@ jest.mock('../../components/EventLog/EventList')
|
||||
|
||||
import React from 'react'
|
||||
import renderer from 'react-test-renderer'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import EventLog, { PureEventLog } from '../../components/EventLog'
|
||||
import { Provider } from 'react-redux'
|
||||
import { TStore } from '../ducks/tutils'
|
||||
import EventLog, {PureEventLog} from '../../components/EventLog'
|
||||
import {Provider} from 'react-redux'
|
||||
import {TStore} from '../ducks/tutils'
|
||||
|
||||
window.addEventListener = jest.fn()
|
||||
window.removeEventListener = jest.fn()
|
||||
@ -13,9 +12,9 @@ window.removeEventListener = jest.fn()
|
||||
describe('EventLog Component', () => {
|
||||
let store = TStore(),
|
||||
provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<EventLog/>
|
||||
</Provider>),
|
||||
<Provider store={store}>
|
||||
<EventLog/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
|
||||
it('should connect to state and render correctly', () => {
|
||||
@ -27,31 +26,31 @@ describe('EventLog Component', () => {
|
||||
debugToggleButton.props.onClick()
|
||||
})
|
||||
|
||||
provider = TestUtils.renderIntoDocument(
|
||||
provider = renderer.create(
|
||||
<Provider store={store}><EventLog/></Provider>)
|
||||
let eventLog = TestUtils.findRenderedComponentWithType(provider, PureEventLog),
|
||||
mockEvent = { preventDefault: jest.fn() }
|
||||
let eventLog = provider.root.findByType(PureEventLog),
|
||||
mockEvent = {preventDefault: jest.fn()}
|
||||
|
||||
it('should handle DragStart', () => {
|
||||
eventLog.onDragStart(mockEvent)
|
||||
eventLog.instance.onDragStart(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
expect(window.addEventListener).toBeCalledWith('mousemove', eventLog.onDragMove)
|
||||
expect(window.addEventListener).toBeCalledWith('mouseup', eventLog.onDragStop)
|
||||
expect(window.addEventListener).toBeCalledWith('dragend', eventLog.onDragStop)
|
||||
expect(window.addEventListener).toBeCalledWith('mousemove', eventLog.instance.onDragMove)
|
||||
expect(window.addEventListener).toBeCalledWith('mouseup', eventLog.instance.onDragStop)
|
||||
expect(window.addEventListener).toBeCalledWith('dragend', eventLog.instance.onDragStop)
|
||||
mockEvent.preventDefault.mockClear()
|
||||
})
|
||||
|
||||
it('should handle DragMove', () => {
|
||||
eventLog.onDragMove(mockEvent)
|
||||
eventLog.instance.onDragMove(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
mockEvent.preventDefault.mockClear()
|
||||
})
|
||||
|
||||
console.error = jest.fn() // silent the error.
|
||||
it('should handle DragStop', () => {
|
||||
eventLog.onDragStop(mockEvent)
|
||||
eventLog.instance.onDragStop(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
expect(window.removeEventListener).toBeCalledWith('mousemove', eventLog.onDragMove)
|
||||
expect(window.removeEventListener).toBeCalledWith('mousemove', eventLog.instance.onDragMove)
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -15,36 +15,36 @@ describe('FlowTable Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<FlowTable onSelect={selectFn} flows={[tflow]}/>
|
||||
<FlowTable selectFlow={selectFn} flows={[tflow]}/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let provider = TestUtils.renderIntoDocument(
|
||||
let provider = renderer.create(
|
||||
<Provider store={store} >
|
||||
<FlowTable onSelect={selectFn} flows={[tflow]}/>
|
||||
<FlowTable selectFlow={selectFn} flows={[tflow]}/>
|
||||
</Provider>),
|
||||
flowTable = TestUtils.findRenderedComponentWithType(provider, FlowTable)
|
||||
flowTable = provider.root.findByType(FlowTable)
|
||||
|
||||
it('should handle componentWillUnmount', () => {
|
||||
flowTable.componentWillUnmount()
|
||||
expect(window.addEventListener).toBeCalledWith('resize', flowTable.onViewportUpdate)
|
||||
flowTable.instance.UNSAFE_componentWillUnmount()
|
||||
expect(window.addEventListener).toBeCalledWith('resize', flowTable.instance.onViewportUpdate)
|
||||
})
|
||||
|
||||
it('should handle componentDidUpdate', () => {
|
||||
// flowTable.shouldScrollIntoView == false
|
||||
expect(flowTable.componentDidUpdate()).toEqual(undefined)
|
||||
expect(flowTable.instance.componentDidUpdate()).toEqual(undefined)
|
||||
// rowTop - headHeight < viewportTop
|
||||
flowTable.shouldScrollIntoView = true
|
||||
flowTable.componentDidUpdate()
|
||||
flowTable.instance.shouldScrollIntoView = true
|
||||
flowTable.instance.componentDidUpdate()
|
||||
// rowBottom > viewportTop + viewportHeight
|
||||
flowTable.shouldScrollIntoView = true
|
||||
flowTable.componentDidUpdate()
|
||||
flowTable.instance.shouldScrollIntoView = true
|
||||
flowTable.instance.componentDidUpdate()
|
||||
})
|
||||
|
||||
it('should handle componentWillReceiveProps', () => {
|
||||
flowTable.componentWillReceiveProps({selected: tflow})
|
||||
expect(flowTable.shouldScrollIntoView).toBeTruthy()
|
||||
flowTable.instance.UNSAFE_componentWillReceiveProps({selected: tflow})
|
||||
expect(flowTable.instance.shouldScrollIntoView).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
@ -1,12 +1,11 @@
|
||||
jest.mock('../../../components/ContentView')
|
||||
jest.mock('../../../components/ContentView', () => () => null)
|
||||
import React from 'react'
|
||||
import renderer from 'react-test-renderer'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import { Request, Response, ErrorView } from '../../../components/FlowView/Messages'
|
||||
import { Provider } from 'react-redux'
|
||||
import { TFlow, TStore } from '../../ducks/tutils'
|
||||
import { updateEdit } from '../../../ducks/ui/flow'
|
||||
import { parseUrl } from '../../../flow/utils'
|
||||
import {ErrorView, Request, Response} from '../../../components/FlowView/Messages'
|
||||
import {Provider} from 'react-redux'
|
||||
import {TFlow, TStore} from '../../ducks/tutils'
|
||||
import {updateEdit} from '../../../ducks/ui/flow'
|
||||
import {parseUrl} from '../../../flow/utils'
|
||||
import ContentView from '../../../components/ContentView'
|
||||
import ContentViewOptions from '../../../components/ContentView/ContentViewOptions'
|
||||
import Headers from '../../../components/FlowView/Headers'
|
||||
@ -20,7 +19,9 @@ store.getState().ui.flow.modifiedFlow = false
|
||||
|
||||
describe('Request Component', () => {
|
||||
|
||||
afterEach(() => {store.clearActions()})
|
||||
afterEach(() => {
|
||||
store.clearActions()
|
||||
})
|
||||
|
||||
it('should render correctly', () => {
|
||||
let provider = renderer.create(
|
||||
@ -32,45 +33,47 @@ describe('Request Component', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let provider = TestUtils.renderIntoDocument(
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<Request/>
|
||||
</Provider>),
|
||||
valueEditors = TestUtils.scryRenderedComponentsWithType(provider, ValueEditor)
|
||||
valueEditors = provider.root.findAllByType(ValueEditor)
|
||||
|
||||
it('should handle done on flow request method', () => {
|
||||
let valueEditor = valueEditors[0]
|
||||
valueEditor.props.onDone('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({ request: { method: 'foo' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {method: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow request url', () => {
|
||||
let valueEditor = valueEditors[1],
|
||||
url = 'http://foo/bar'
|
||||
valueEditor.props.onDone(url)
|
||||
expect(store.getActions()).toEqual([updateEdit({ request: { path: '', ...parseUrl(url)}})])
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {path: '', ...parseUrl(url)}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow request http version', () => {
|
||||
let valueEditor = valueEditors[2]
|
||||
valueEditor.props.onDone('HTTP/9.9')
|
||||
expect(store.getActions()).toEqual([updateEdit({ request: { http_version: 'HTTP/9.9' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {http_version: 'HTTP/9.9'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow request header', () => {
|
||||
let headers = TestUtils.scryRenderedComponentsWithType(provider, Headers).filter(headers => headers.props.type === 'headers')[0]
|
||||
let headers = provider.root.findAllByType(Headers).filter(headers => headers.props.type === 'headers')[0]
|
||||
headers.props.onChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({ request: { headers: 'foo' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {headers: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow request contentView', () => {
|
||||
let contentView = TestUtils.findRenderedComponentWithType(provider, ContentView)
|
||||
let contentView = provider.root.findByType(ContentView)
|
||||
contentView.props.onContentChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({ request: { content: 'foo' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {content: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle uploadContent on flow request ContentViewOptions', () => {
|
||||
let contentViewOptions = TestUtils.findRenderedComponentWithType(provider, ContentViewOptions)
|
||||
// The line below shouldn't have .type, this is a workaround for https://github.com/facebook/react/issues/17301.
|
||||
// If this test breaks, just remove it.
|
||||
let contentViewOptions = provider.root.findByType(ContentViewOptions.type)
|
||||
contentViewOptions.props.uploadContent('foo')
|
||||
expect(fetch).toBeCalled()
|
||||
fetch.mockClear()
|
||||
@ -78,56 +81,60 @@ describe('Request Component', () => {
|
||||
})
|
||||
|
||||
describe('Response Component', () => {
|
||||
afterEach(() => {store.clearActions()})
|
||||
afterEach(() => {
|
||||
store.clearActions()
|
||||
})
|
||||
|
||||
it('should render correctly', () => {
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<Response/>
|
||||
</Provider>
|
||||
),
|
||||
),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let provider = TestUtils.renderIntoDocument(
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<Response/>
|
||||
</Provider>),
|
||||
valueEditors = TestUtils.scryRenderedComponentsWithType(provider, ValueEditor)
|
||||
valueEditors = provider.root.findAllByType(ValueEditor)
|
||||
|
||||
it('should handle done on flow response http version', () => {
|
||||
let valueEditor = valueEditors[0]
|
||||
valueEditor.props.onDone('HTTP/9.9')
|
||||
expect(store.getActions()).toEqual([updateEdit({ response: { http_version: 'HTTP/9.9' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {http_version: 'HTTP/9.9'}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow response status code', () => {
|
||||
let valueEditor = valueEditors[1]
|
||||
valueEditor.props.onDone('404')
|
||||
expect(store.getActions()).toEqual([updateEdit({ response: { code: parseInt('404') }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {code: parseInt('404')}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow response reason', () => {
|
||||
let valueEdiotr = valueEditors[2]
|
||||
valueEdiotr.props.onDone('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit( { response: { msg: 'foo' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {msg: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow response headers', () => {
|
||||
let headers = TestUtils.scryRenderedComponentsWithType(provider, Headers).filter(headers => headers.props.type === 'headers')[0]
|
||||
let headers = provider.root.findAllByType(Headers).filter(headers => headers.props.type === 'headers')[0]
|
||||
headers.props.onChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit( { response: { headers: 'foo' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {headers: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow response ContentView', () => {
|
||||
let contentView = TestUtils.findRenderedComponentWithType(provider, ContentView)
|
||||
let contentView = provider.root.findByType(ContentView)
|
||||
contentView.props.onContentChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit( { response: { content: 'foo' }})])
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {content: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle updateContent on flow response ContentViewOptions', () => {
|
||||
let contentViewOptions = TestUtils.findRenderedComponentWithType(provider, ContentViewOptions)
|
||||
// The line below shouldn't have .type, this is a workaround for https://github.com/facebook/react/issues/17301.
|
||||
// If this test breaks, just remove it.
|
||||
let contentViewOptions = provider.root.findByType(ContentViewOptions.type)
|
||||
contentViewOptions.props.uploadContent('foo')
|
||||
expect(fetch).toBeCalled()
|
||||
fetch.mockClear()
|
||||
|
@ -3,7 +3,6 @@
|
||||
exports[`HeaderEditor Component should render correctly 1`] = `
|
||||
<div
|
||||
className="inline-input editable"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "foo",
|
||||
@ -31,7 +30,6 @@ exports[`Headers Component should handle correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "k1",
|
||||
@ -57,7 +55,6 @@ exports[`Headers Component should handle correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "v1",
|
||||
@ -80,7 +77,6 @@ exports[`Headers Component should handle correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "k2",
|
||||
@ -106,7 +102,6 @@ exports[`Headers Component should handle correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "",
|
||||
|
@ -41,7 +41,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "GET",
|
||||
@ -54,12 +53,10 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "http://address:22/path",
|
||||
@ -72,12 +69,10 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "HTTP/1.1",
|
||||
@ -90,7 +85,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -104,7 +98,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "header",
|
||||
@ -117,7 +110,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
@ -130,7 +122,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "qvalue",
|
||||
@ -143,7 +134,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@ -153,7 +143,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "content-length",
|
||||
@ -166,7 +155,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
@ -179,7 +167,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "7",
|
||||
@ -192,7 +179,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@ -210,7 +196,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "trailer",
|
||||
@ -223,7 +208,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
@ -236,7 +220,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "qvalue",
|
||||
@ -249,7 +232,6 @@ exports[`Request Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@ -361,7 +343,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "HTTP/1.1",
|
||||
@ -374,12 +355,10 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "200",
|
||||
@ -392,12 +371,10 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "OK",
|
||||
@ -410,7 +387,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</div>
|
||||
<table
|
||||
@ -423,7 +399,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "header-response",
|
||||
@ -436,7 +411,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
@ -449,7 +423,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "svalue",
|
||||
@ -462,7 +435,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@ -472,7 +444,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "content-length",
|
||||
@ -485,7 +456,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
@ -498,7 +468,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "7",
|
||||
@ -511,7 +480,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@ -529,7 +497,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "trailer",
|
||||
@ -542,7 +509,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
@ -555,7 +521,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "qvalue",
|
||||
@ -568,7 +533,6 @@ exports[`Response Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={undefined}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -31,10 +31,8 @@ exports[`FileMenu Component should render correctly 1`] = `
|
||||
<li>
|
||||
|
||||
<a
|
||||
className={undefined}
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title={undefined}
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-folder-open"
|
||||
|
@ -24,7 +24,6 @@ exports[`FilterInput Component should render correctly 1`] = `
|
||||
onKeyDown={[Function]}
|
||||
placeholder="bar"
|
||||
type="text"
|
||||
value={undefined}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
@ -10,7 +10,6 @@ exports[`FlowMenu Component should connect to state 1`] = `
|
||||
>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="[r]eplay flow"
|
||||
>
|
||||
@ -21,7 +20,6 @@ exports[`FlowMenu Component should connect to state 1`] = `
|
||||
</div>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="[D]uplicate flow"
|
||||
>
|
||||
@ -33,7 +31,6 @@ exports[`FlowMenu Component should connect to state 1`] = `
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={true}
|
||||
onClick={undefined}
|
||||
title="revert changes to flow [V]"
|
||||
>
|
||||
<i
|
||||
@ -43,7 +40,6 @@ exports[`FlowMenu Component should connect to state 1`] = `
|
||||
</div>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="[d]elete flow"
|
||||
>
|
||||
@ -67,7 +63,6 @@ exports[`FlowMenu Component should connect to state 1`] = `
|
||||
>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="download"
|
||||
>
|
||||
@ -92,7 +87,6 @@ exports[`FlowMenu Component should connect to state 1`] = `
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={true}
|
||||
onClick={undefined}
|
||||
title="[a]ccept intercepted flow"
|
||||
>
|
||||
<i
|
||||
@ -103,7 +97,6 @@ exports[`FlowMenu Component should connect to state 1`] = `
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={true}
|
||||
onClick={undefined}
|
||||
title="kill intercepted flow [x]"
|
||||
>
|
||||
<i
|
||||
@ -131,7 +124,6 @@ exports[`FlowMenu Component should render correctly with flow 1`] = `
|
||||
>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="[r]eplay flow"
|
||||
>
|
||||
@ -142,7 +134,6 @@ exports[`FlowMenu Component should render correctly with flow 1`] = `
|
||||
</div>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="[D]uplicate flow"
|
||||
>
|
||||
@ -164,7 +155,6 @@ exports[`FlowMenu Component should render correctly with flow 1`] = `
|
||||
</div>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="[d]elete flow"
|
||||
>
|
||||
@ -188,7 +178,6 @@ exports[`FlowMenu Component should render correctly with flow 1`] = `
|
||||
>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="download"
|
||||
>
|
||||
|
@ -22,7 +22,7 @@ exports[`MenuToggle Component should render correctly 1`] = `
|
||||
<label>
|
||||
<input
|
||||
checked={true}
|
||||
onChange={[Function]}
|
||||
onChange={[MockFunction]}
|
||||
type="checkbox"
|
||||
/>
|
||||
<p>
|
||||
|
@ -10,7 +10,6 @@ exports[`OptionMenu Component should render correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="Open Options"
|
||||
>
|
||||
|
@ -23,9 +23,9 @@ describe('ValidateEditor Component', () => {
|
||||
isValid: s => s.length == 3,
|
||||
content: "bar"
|
||||
}
|
||||
validateEditor.componentWillReceiveProps(mockProps)
|
||||
validateEditor.UNSAFE_componentWillReceiveProps(mockProps)
|
||||
expect(validateEditor.state.valid).toBeTruthy()
|
||||
validateEditor.componentWillReceiveProps({...mockProps, content: "bars"})
|
||||
validateEditor.UNSAFE_componentWillReceiveProps({...mockProps, content: "bars"})
|
||||
expect(validateEditor.state.valid).toBeFalsy()
|
||||
|
||||
})
|
||||
|
@ -3,7 +3,6 @@
|
||||
exports[`ValidateEditor Component should render correctly 1`] = `
|
||||
<div
|
||||
className="inline-input editable has-success"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "foo",
|
||||
|
@ -3,7 +3,6 @@
|
||||
exports[`ValueEditor Component should render correctly 1`] = `
|
||||
<div
|
||||
className="inline-input editable"
|
||||
contentEditable={undefined}
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "foo",
|
||||
|
@ -4,8 +4,6 @@ exports[`Button Component should be able to be disabled 1`] = `
|
||||
<div
|
||||
className="classname btn btn-default"
|
||||
disabled="true"
|
||||
onClick={undefined}
|
||||
title={undefined}
|
||||
>
|
||||
<a>
|
||||
foo
|
||||
@ -16,7 +14,6 @@ exports[`Button Component should be able to be disabled 1`] = `
|
||||
exports[`Button Component should render correctly 1`] = `
|
||||
<div
|
||||
className="classname btn btn-default"
|
||||
disabled={undefined}
|
||||
onClick={[Function]}
|
||||
title="title"
|
||||
>
|
||||
|
@ -3,7 +3,7 @@
|
||||
exports[`ToggleButton Component should render correctly 1`] = `
|
||||
<div
|
||||
className="btn btn-toggle btn-primary"
|
||||
onClick={[Function]}
|
||||
onClick={[MockFunction]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-check-square-o"
|
||||
|
@ -12,7 +12,7 @@ describe('Autoscroll', () => {
|
||||
this.state = { vScroll: calcVScroll() }
|
||||
}
|
||||
|
||||
componentWillUpdate() {
|
||||
UNSAFE_componentWillUpdate() {
|
||||
mockFn("foo")
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ describe('Autoscroll', () => {
|
||||
viewport = ReactDOM.findDOMNode(autoScroll)
|
||||
viewport.scrollTop = 10
|
||||
Object.defineProperty(viewport, "scrollHeight", { value: 10, writable: true })
|
||||
autoScroll.componentWillUpdate()
|
||||
autoScroll.UNSAFE_componentWillUpdate()
|
||||
expect(mockFn).toBeCalledWith("foo")
|
||||
|
||||
Object.defineProperty(viewport, "scrollHeight", { value: 0, writable: true })
|
||||
|
@ -26,7 +26,7 @@ const store = createStore(
|
||||
)
|
||||
|
||||
useUrlState(store)
|
||||
if (MITMWEB_STATIC) {
|
||||
if (window.MITMWEB_STATIC) {
|
||||
window.backend = new StaticBackend(store)
|
||||
} else {
|
||||
window.backend = new WebSocketBackend(store)
|
||||
|
@ -32,11 +32,11 @@ class FlowTable extends React.Component {
|
||||
this.onViewportUpdate = this.onViewportUpdate.bind(this)
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
UNSAFE_componentWillMount() {
|
||||
window.addEventListener('resize', this.onViewportUpdate)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
UNSAFE_componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.onViewportUpdate)
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ class FlowTable extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.selected && nextProps.selected !== this.props.selected) {
|
||||
this.shouldScrollIntoView = true
|
||||
}
|
||||
@ -77,11 +77,11 @@ class FlowTable extends React.Component {
|
||||
|
||||
onViewportUpdate() {
|
||||
const viewport = ReactDOM.findDOMNode(this)
|
||||
const viewportTop = viewport.scrollTop
|
||||
const viewportTop = viewport.scrollTop || 0
|
||||
|
||||
const vScroll = calcVScroll({
|
||||
viewportTop,
|
||||
viewportHeight: viewport.offsetHeight,
|
||||
viewportHeight: viewport.offsetHeight || 0,
|
||||
itemCount: this.props.flows.length,
|
||||
rowHeight: this.props.rowHeight,
|
||||
})
|
||||
@ -103,7 +103,7 @@ class FlowTable extends React.Component {
|
||||
<FlowTableHead />
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style={{ height: vScroll.paddingTop }}></tr>
|
||||
<tr style={{ height: vScroll.paddingTop }}/>
|
||||
{flows.slice(vScroll.start, vScroll.end).map(flow => (
|
||||
<FlowRow
|
||||
key={flow.id}
|
||||
@ -113,7 +113,7 @@ class FlowTable extends React.Component {
|
||||
onSelect={this.props.selectFlow}
|
||||
/>
|
||||
))}
|
||||
<tr style={{ height: vScroll.paddingBottom }}></tr>
|
||||
<tr style={{ height: vScroll.paddingBottom }}/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -20,14 +20,14 @@ export function TimeStamp({ t, deltaTo, title }) {
|
||||
)
|
||||
}
|
||||
|
||||
export function ConnectionInfo({ conn }) {
|
||||
export function ConnectionInfo({ conn }) {
|
||||
return (
|
||||
<table className="connection-table">
|
||||
<tbody>
|
||||
<tr key="address">
|
||||
<td>Address:</td>
|
||||
<td>{conn.address.join(':')}</td>
|
||||
</tr>
|
||||
</tr>
|
||||
{conn.sni && (
|
||||
<tr key="sni">
|
||||
<td><abbr title="TLS Server Name Indication">TLS SNI:</abbr></td>
|
||||
@ -148,13 +148,13 @@ export default function Details({ flow }) {
|
||||
<h4>Client Connection</h4>
|
||||
<ConnectionInfo conn={flow.client_conn}/>
|
||||
|
||||
{flow.server_conn.address &&
|
||||
{flow.server_conn.address &&
|
||||
[
|
||||
<h4>Server Connection</h4>,
|
||||
<ConnectionInfo conn={flow.server_conn}/>
|
||||
]
|
||||
<h4 key="sc">Server Connection</h4>,
|
||||
<ConnectionInfo key="sc-ci" conn={flow.server_conn}/>
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
<CertificateInfo flow={flow}/>
|
||||
|
||||
<Timing flow={flow}/>
|
||||
|
@ -105,7 +105,7 @@ export class Request extends Component {
|
||||
flow={flow}
|
||||
onContentChange={content => updateFlow({ request: {content}})}
|
||||
message={flow.request}/>
|
||||
|
||||
|
||||
<hr/>
|
||||
<Headers
|
||||
message={flow.request}
|
||||
|
@ -14,7 +14,7 @@ export default class FilterDocs extends Component {
|
||||
this.state = { doc: FilterDocs.doc }
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
componentDidMount() {
|
||||
if (!FilterDocs.xhr) {
|
||||
FilterDocs.xhr = fetchApi('/filter-help').then(response => response.json())
|
||||
FilterDocs.xhr.catch(() => {
|
||||
|
@ -106,7 +106,7 @@ export default class FilterInput extends Component {
|
||||
return (
|
||||
<div className={classnames('filter-input input-group', { 'has-error': !this.isValid() })}>
|
||||
<span className="input-group-addon">
|
||||
<i className={'fa fa-fw fa-' + type} style={{ color }}></i>
|
||||
<i className={'fa fa-fw fa-' + type} style={{ color }}/>
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
@ -123,7 +123,7 @@ export default class FilterInput extends Component {
|
||||
<div className="popover bottom"
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onMouseLeave={this.onMouseLeave}>
|
||||
<div className="arrow"></div>
|
||||
<div className="arrow"/>
|
||||
<div className="popover-content">
|
||||
{this.getDesc()}
|
||||
</div>
|
||||
|
@ -11,7 +11,7 @@ const stopPropagation = e => {
|
||||
}
|
||||
}
|
||||
|
||||
BooleanOption.PropTypes = {
|
||||
BooleanOption.propTypes = {
|
||||
value: PropTypes.bool.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
@ -30,7 +30,7 @@ function BooleanOption({ value, onChange, ...props }) {
|
||||
)
|
||||
}
|
||||
|
||||
StringOption.PropTypes = {
|
||||
StringOption.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
@ -52,7 +52,7 @@ function Optional(Component) {
|
||||
}
|
||||
}
|
||||
|
||||
NumberOption.PropTypes = {
|
||||
NumberOption.propTypes = {
|
||||
value: PropTypes.number.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
@ -66,7 +66,7 @@ function NumberOption({ value, onChange, ...props }) {
|
||||
)
|
||||
}
|
||||
|
||||
ChoicesOption.PropTypes = {
|
||||
ChoicesOption.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
@ -86,8 +86,8 @@ export function ChoicesOption({ value, onChange, choices, ...props }) {
|
||||
)
|
||||
}
|
||||
|
||||
StringSequenceOption.PropTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
StringSequenceOption.propTypes = {
|
||||
value: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
function StringSequenceOption({ value, onChange, ...props }) {
|
||||
|
@ -21,7 +21,7 @@ export default class ValidateEditor extends Component {
|
||||
this.onDone = this.onDone.bind(this)
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
this.setState({ valid: nextProps.isValid(nextProps.content) })
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function HideInStatic({ children }) {
|
||||
return global.MITMWEB_STATIC ? null : [children]
|
||||
return window.MITMWEB_STATIC ? null : [children]
|
||||
}
|
||||
|
@ -8,9 +8,10 @@ export default Component => Object.assign(class AutoScrollWrapper extends Compon
|
||||
|
||||
static displayName = Component.name;
|
||||
|
||||
componentWillUpdate() {
|
||||
UNSAFE_componentWillUpdate() {
|
||||
const viewport = ReactDOM.findDOMNode(this);
|
||||
this[symShouldStick] = viewport.scrollTop && isAtBottom(viewport);
|
||||
super.UNSAFE_componentWillUpdate && super.UNSAFE_componentWillUpdate();
|
||||
super.componentWillUpdate && super.componentWillUpdate();
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
<link rel="stylesheet" href="/static/app.css"/>
|
||||
<link rel="icon" href="/static/images/favicon.ico" type="image/x-icon"/>
|
||||
<script src="/static/static.js"></script>
|
||||
<script src="/static/vendor.js"></script>
|
||||
<script src="/static/app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
7269
web/yarn.lock
7269
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user