addon-dailer
lqqyt2423 4 years ago
parent 4ee3534d93
commit 3f5dd4bd52

@ -0,0 +1,33 @@
env:
browser: true
es2021: true
extends:
- 'eslint:recommended'
- 'plugin:react/recommended'
- 'plugin:@typescript-eslint/recommended'
parser: '@typescript-eslint/parser'
parserOptions:
ecmaFeatures:
jsx: true
ecmaVersion: 12
sourceType: module
plugins:
- react
- '@typescript-eslint'
rules:
indent:
- error
- 2
linebreak-style:
- error
- unix
quotes:
- error
- single
semi:
- error
- never
'@typescript-eslint/explicit-module-boundary-types':
- 0
'@typescript-eslint/no-explicit-any':
- 0

@ -44,27 +44,3 @@ You dont have to ever use `eject`. The curated feature set is suitable for sm
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/). To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `yarn build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

@ -1,25 +1,25 @@
{ {
"files": { "files": {
"main.css": "/static/css/main.cb45a0e0.chunk.css", "main.css": "/static/css/main.451c1dcc.chunk.css",
"main.js": "/static/js/main.6b681f56.chunk.js", "main.js": "/static/js/main.5904c112.chunk.js",
"main.js.map": "/static/js/main.6b681f56.chunk.js.map", "main.js.map": "/static/js/main.5904c112.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.48e80cd2.js", "runtime-main.js": "/static/js/runtime-main.bcda7d85.js",
"runtime-main.js.map": "/static/js/runtime-main.48e80cd2.js.map", "runtime-main.js.map": "/static/js/runtime-main.bcda7d85.js.map",
"static/css/2.150d169a.chunk.css": "/static/css/2.150d169a.chunk.css", "static/css/2.150d169a.chunk.css": "/static/css/2.150d169a.chunk.css",
"static/js/2.68265363.chunk.js": "/static/js/2.68265363.chunk.js", "static/js/2.88d332b9.chunk.js": "/static/js/2.88d332b9.chunk.js",
"static/js/2.68265363.chunk.js.map": "/static/js/2.68265363.chunk.js.map", "static/js/2.88d332b9.chunk.js.map": "/static/js/2.88d332b9.chunk.js.map",
"static/js/3.f3a1fc42.chunk.js": "/static/js/3.f3a1fc42.chunk.js", "static/js/3.a88e738d.chunk.js": "/static/js/3.a88e738d.chunk.js",
"static/js/3.f3a1fc42.chunk.js.map": "/static/js/3.f3a1fc42.chunk.js.map", "static/js/3.a88e738d.chunk.js.map": "/static/js/3.a88e738d.chunk.js.map",
"index.html": "/index.html", "index.html": "/index.html",
"static/css/2.150d169a.chunk.css.map": "/static/css/2.150d169a.chunk.css.map", "static/css/2.150d169a.chunk.css.map": "/static/css/2.150d169a.chunk.css.map",
"static/css/main.cb45a0e0.chunk.css.map": "/static/css/main.cb45a0e0.chunk.css.map", "static/css/main.451c1dcc.chunk.css.map": "/static/css/main.451c1dcc.chunk.css.map",
"static/js/2.68265363.chunk.js.LICENSE.txt": "/static/js/2.68265363.chunk.js.LICENSE.txt" "static/js/2.88d332b9.chunk.js.LICENSE.txt": "/static/js/2.88d332b9.chunk.js.LICENSE.txt"
}, },
"entrypoints": [ "entrypoints": [
"static/js/runtime-main.48e80cd2.js", "static/js/runtime-main.bcda7d85.js",
"static/css/2.150d169a.chunk.css", "static/css/2.150d169a.chunk.css",
"static/js/2.68265363.chunk.js", "static/js/2.88d332b9.chunk.js",
"static/css/main.cb45a0e0.chunk.css", "static/css/main.451c1dcc.chunk.css",
"static/js/main.6b681f56.chunk.js" "static/js/main.5904c112.chunk.js"
] ]
} }

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>go-mitmproxy</title><link href="/static/css/2.150d169a.chunk.css" rel="stylesheet"><link href="/static/css/main.cb45a0e0.chunk.css" rel="stylesheet"></head><body><a href="https://github.com/lqqyt2423/go-mitmproxy" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#70b7fd;color:#fff;position:absolute;top:0;border:0;right:0" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin:130px 106px" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);p.length;)p.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"f3a1fc42"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpclient=this.webpackJsonpclient||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([])</script><script src="/static/js/2.68265363.chunk.js"></script><script src="/static/js/main.6b681f56.chunk.js"></script></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>go-mitmproxy</title><link href="/static/css/2.150d169a.chunk.css" rel="stylesheet"><link href="/static/css/main.451c1dcc.chunk.css" rel="stylesheet"></head><body><a href="https://github.com/lqqyt2423/go-mitmproxy" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#70b7fd;color:#fff;position:absolute;top:0;border:0;right:0" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin:130px 106px" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);s.length;)s.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"a88e738d"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this["webpackJsonpmitmproxy-client"]=this["webpackJsonpmitmproxy-client"]||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([])</script><script src="/static/js/2.88d332b9.chunk.js"></script><script src="/static/js/main.5904c112.chunk.js"></script></body></html>

@ -1,2 +1,2 @@
.main-table-wrap{font-family:Menlo,Monaco;font-size:.8rem}.top-control{display:flex;align-items:center}.top-control>div{margin-right:20px}.main-table-wrap tbody tr.tr-selected{background-color:#2376e5;color:#fff}.main-table-wrap tbody tr.tr-wait-intercept{background-color:#d86e53;color:#fff}.flow-detail{position:fixed;top:0;right:0;height:100vh;background-color:#fff;min-width:500px;width:50%;overflow-y:auto;word-break:break-all}.flow-detail .header-tabs{display:flex}.flow-detail .header-tabs span{display:inline-block;line-height:1;padding:8px;cursor:pointer}.flow-detail .header-tabs .selected{border-bottom:2px solid #2376e5}.flow-detail .header-tabs .flow-wait-area button{margin-left:10px}.flow-detail .header-block{margin-bottom:20px}.flow-detail .header-block>p{font-weight:700}.flow-detail .header-block .header-block-content p{margin:5px 0}.flow-detail .header-block .header-block-content{margin-left:20px;line-height:1.5} .main-table-wrap{font-family:Menlo,Monaco;font-size:.8rem}.top-control{display:flex;align-items:center}.top-control>div{margin-right:20px}.main-table-wrap tbody tr.tr-selected{background-color:#2376e5;color:#fff}.main-table-wrap tbody tr.tr-wait-intercept{background-color:#d86e53;color:#fff}.flow-detail{position:fixed;top:0;right:0;height:100vh;background-color:#fff;min-width:500px;width:50%;overflow-y:auto;word-break:break-all}.flow-detail .header-tabs{display:flex}.flow-detail .header-tabs span{display:inline-block;line-height:1;padding:8px;cursor:pointer}.flow-detail .header-tabs .selected{border-bottom:2px solid #2376e5}.flow-detail .header-tabs .flow-wait-area button{margin-left:10px}.flow-detail .header-block{margin-bottom:20px}.flow-detail .header-block>p{font-weight:700}.flow-detail .header-block .header-block-content p{margin:5px 0}.flow-detail .header-block .header-block-content{margin-left:20px;line-height:1.5}
/*# sourceMappingURL=main.cb45a0e0.chunk.css.map */ /*# sourceMappingURL=main.451c1dcc.chunk.css.map */

@ -0,0 +1 @@
{"version":3,"sources":["webpack://src/App.css"],"names":[],"mappings":"AAAA,iBACE,wBAAyB,CACzB,eACF,CAEA,aACE,YAAa,CACb,kBACF,CAEA,iBACE,iBACF,CAGA,sCACE,wBAAmC,CACnC,UACF,CAEA,4CACE,wBAAmC,CACnC,UACF,CAEA,aACE,cAAe,CACf,KAAM,CACN,OAAQ,CAER,YAAa,CACb,qBAAsB,CACtB,eAAgB,CAChB,SAAU,CACV,eAAgB,CAEhB,oBACF,CAEA,0BACE,YACF,CAEA,+BACE,oBAAqB,CACrB,aAAc,CACd,WAAY,CACZ,cACF,CAEA,oCACE,+BACF,CAEA,iDACE,gBACF,CAEA,2BACE,kBACF,CAEA,6BACE,eACF,CAEA,mDACE,YACF,CAEA,iDACE,gBAAiB,CACjB,eACF","file":"main.451c1dcc.chunk.css","sourcesContent":[".main-table-wrap {\n font-family: Menlo,Monaco;\n font-size: 0.8rem;\n}\n\n.top-control {\n display: flex;\n align-items: center;\n}\n\n.top-control > div {\n margin-right: 20px;\n}\n\n\n.main-table-wrap tbody tr.tr-selected {\n background-color: rgb(35, 118, 229);\n color: white;\n}\n\n.main-table-wrap tbody tr.tr-wait-intercept {\n background-color: rgb(216, 110, 83);\n color: white;\n}\n\n.flow-detail {\n position: fixed;\n top: 0;\n right: 0;\n\n height: 100vh;\n background-color: #fff;\n min-width: 500px;\n width: 50%;\n overflow-y: auto;\n\n word-break: break-all;\n}\n\n.flow-detail .header-tabs {\n display: flex;\n}\n\n.flow-detail .header-tabs span {\n display: inline-block;\n line-height: 1;\n padding: 8px;\n cursor: pointer;\n}\n\n.flow-detail .header-tabs .selected {\n border-bottom: 2px rgb(35, 118, 229) solid;\n}\n\n.flow-detail .header-tabs .flow-wait-area button {\n margin-left: 10px;\n}\n\n.flow-detail .header-block {\n margin-bottom: 20px;\n}\n\n.flow-detail .header-block > p {\n font-weight: bold;\n}\n\n.flow-detail .header-block .header-block-content p {\n margin: 5px 0;\n}\n\n.flow-detail .header-block .header-block-content {\n margin-left: 20px;\n line-height: 1.5;\n}\n"]}

@ -1 +0,0 @@
{"version":3,"sources":["webpack://src/App.css"],"names":[],"mappings":"AAAA,iBACI,wBAAyB,CACzB,eACJ,CAEA,aACI,YAAa,CACb,kBACJ,CAEA,iBACI,iBACJ,CAGA,sCACI,wBAAmC,CACnC,UACJ,CAEA,4CACI,wBAAmC,CACnC,UACJ,CAEA,aACI,cAAe,CACf,KAAM,CACN,OAAQ,CAER,YAAa,CACb,qBAAsB,CACtB,eAAgB,CAChB,SAAU,CACV,eAAgB,CAEhB,oBACJ,CAEA,0BACI,YACJ,CAEA,+BACI,oBAAqB,CACrB,aAAc,CACd,WAAY,CACZ,cACJ,CAEA,oCACI,+BACJ,CAEA,iDACI,gBACJ,CAEA,2BACI,kBACJ,CAEA,6BACI,eACJ,CAEA,mDACI,YACJ,CAEA,iDACI,gBAAiB,CACjB,eACJ","file":"main.cb45a0e0.chunk.css","sourcesContent":[".main-table-wrap {\n font-family: Menlo,Monaco;\n font-size: 0.8rem;\n}\n\n.top-control {\n display: flex;\n align-items: center;\n}\n\n.top-control > div {\n margin-right: 20px;\n}\n\n\n.main-table-wrap tbody tr.tr-selected {\n background-color: rgb(35, 118, 229);\n color: white;\n}\n\n.main-table-wrap tbody tr.tr-wait-intercept {\n background-color: rgb(216, 110, 83);\n color: white;\n}\n\n.flow-detail {\n position: fixed;\n top: 0;\n right: 0;\n\n height: 100vh;\n background-color: #fff;\n min-width: 500px;\n width: 50%;\n overflow-y: auto;\n\n word-break: break-all;\n}\n\n.flow-detail .header-tabs {\n display: flex;\n}\n\n.flow-detail .header-tabs span {\n display: inline-block;\n line-height: 1;\n padding: 8px;\n cursor: pointer;\n}\n\n.flow-detail .header-tabs .selected {\n border-bottom: 2px rgb(35, 118, 229) solid;\n}\n\n.flow-detail .header-tabs .flow-wait-area button {\n margin-left: 10px;\n}\n\n.flow-detail .header-block {\n margin-bottom: 20px;\n}\n\n.flow-detail .header-block > p {\n font-weight: bold;\n}\n\n.flow-detail .header-block .header-block-content p {\n margin: 5px 0;\n}\n\n.flow-detail .header-block .header-block-content {\n margin-left: 20px;\n line-height: 1.5;\n}"]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -5,12 +5,12 @@ object-assign
*/ */
/*! /*!
Copyright (c) 2017 Jed Watson. Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames http://jedwatson.github.io/classnames
*/ */
/** @license React v0.20.1 /** @license React v0.20.2
* scheduler.production.min.js * scheduler.production.min.js
* *
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
@ -19,7 +19,7 @@ object-assign
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
/** @license React v17.0.1 /** @license React v17.0.2
* react-dom.production.min.js * react-dom.production.min.js
* *
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
@ -28,7 +28,7 @@ object-assign
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
/** @license React v17.0.1 /** @license React v17.0.2
* react-jsx-runtime.production.min.js * react-jsx-runtime.production.min.js
* *
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
@ -37,7 +37,7 @@ object-assign
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
/** @license React v17.0.1 /** @license React v17.0.2
* react.production.min.js * react.production.min.js
* *
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.

File diff suppressed because one or more lines are too long

@ -0,0 +1,2 @@
(this["webpackJsonpmitmproxy-client"]=this["webpackJsonpmitmproxy-client"]||[]).push([[3],{55:function(t,e,n){"use strict";n.r(e),n.d(e,"getCLS",(function(){return d})),n.d(e,"getFCP",(function(){return y})),n.d(e,"getFID",(function(){return F})),n.d(e,"getLCP",(function(){return k})),n.d(e,"getTTFB",(function(){return C}));var i,a,r,o,c=function(t,e){return{name:t,value:void 0===e?-1:e,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},u=function(t,e){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var n=new PerformanceObserver((function(t){return t.getEntries().map(e)}));return n.observe({type:t,buffered:!0}),n}}catch(t){}},s=function(t,e){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(t(i),e&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},f=function(t){addEventListener("pageshow",(function(e){e.persisted&&t(e)}),!0)},m="function"==typeof WeakSet?new WeakSet:new Set,p=function(t,e,n){var i;return function(){e.value>=0&&(n||m.has(e)||"hidden"===document.visibilityState)&&(e.delta=e.value-(i||0),(e.delta||void 0===i)&&(i=e.value,t(e)))}},d=function(t,e){var n,i=c("CLS",0),a=function(t){t.hadRecentInput||(i.value+=t.value,i.entries.push(t),n())},r=u("layout-shift",a);r&&(n=p(t,i,e),s((function(){r.takeRecords().map(a),n()})),f((function(){i=c("CLS",0),n=p(t,i,e)})))},v=-1,l=function(){return"hidden"===document.visibilityState?0:1/0},h=function(){s((function(t){var e=t.timeStamp;v=e}),!0)},S=function(){return v<0&&(v=l(),h(),f((function(){setTimeout((function(){v=l(),h()}),0)}))),{get timeStamp(){return v}}},y=function(t,e){var n,i=S(),a=c("FCP"),r=u("paint",(function(t){"first-contentful-paint"===t.name&&(r&&r.disconnect(),t.startTime<i.timeStamp&&(a.value=t.startTime,a.entries.push(t),m.add(a),n()))}));r&&(n=p(t,a,e),f((function(i){a=c("FCP"),n=p(t,a,e),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),n()}))}))})))},g={passive:!0,capture:!0},w=new Date,E=function(t,e){i||(i=e,a=t,r=new Date,b(removeEventListener),L())},L=function(){if(a>=0&&a<r-w){var t={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+a};o.forEach((function(e){e(t)})),o=[]}},T=function(t){if(t.cancelable){var e=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,e){var n=function(){E(t,e),a()},i=function(){a()},a=function(){removeEventListener("pointerup",n,g),removeEventListener("pointercancel",i,g)};addEventListener("pointerup",n,g),addEventListener("pointercancel",i,g)}(e,t):E(e,t)}},b=function(t){["mousedown","keydown","touchstart","pointerdown"].forEach((function(e){return t(e,T,g)}))},F=function(t,e){var n,r=S(),d=c("FID"),v=function(t){t.startTime<r.timeStamp&&(d.value=t.processingStart-t.startTime,d.entries.push(t),m.add(d),n())},l=u("first-input",v);n=p(t,d,e),l&&s((function(){l.takeRecords().map(v),l.disconnect()}),!0),l&&f((function(){var r;d=c("FID"),n=p(t,d,e),o=[],a=-1,i=null,b(addEventListener),r=v,o.push(r),L()}))},k=function(t,e){var n,i=S(),a=c("LCP"),r=function(t){var e=t.startTime;e<i.timeStamp&&(a.value=e,a.entries.push(t)),n()},o=u("largest-contentful-paint",r);if(o){n=p(t,a,e);var d=function(){m.has(a)||(o.takeRecords().map(r),o.disconnect(),m.add(a),n())};["keydown","click"].forEach((function(t){addEventListener(t,d,{once:!0,capture:!0})})),s(d,!0),f((function(i){a=c("LCP"),n=p(t,a,e),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),n()}))}))}))}},C=function(t){var e,n=c("TTFB");e=function(){try{var e=performance.getEntriesByType("navigation")[0]||function(){var t=performance.timing,e={entryType:"navigation",startTime:0};for(var n in t)"navigationStart"!==n&&"toJSON"!==n&&(e[n]=Math.max(t[n]-t.navigationStart,0));return e}();n.value=n.delta=e.responseStart,n.entries=[e],t(n)}catch(t){}},"complete"===document.readyState?setTimeout(e,0):addEventListener("pageshow",e)}}}]);
//# sourceMappingURL=3.a88e738d.chunk.js.map

File diff suppressed because one or more lines are too long

@ -1,2 +0,0 @@
(this.webpackJsonpclient=this.webpackJsonpclient||[]).push([[3],{55:function(t,n,e){"use strict";e.r(n),e.d(n,"getCLS",(function(){return v})),e.d(n,"getFCP",(function(){return y})),e.d(n,"getFID",(function(){return k})),e.d(n,"getLCP",(function(){return C})),e.d(n,"getTTFB",(function(){return P}));var i,a,r,o,c=function(t,n){return{name:t,value:void 0===n?-1:n,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},u=function(t,n){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var e=new PerformanceObserver((function(t){return t.getEntries().map(n)}));return e.observe({type:t,buffered:!0}),e}}catch(t){}},f=!1,s=function(t,n){f||"undefined"!=typeof InstallTrigger||(addEventListener("beforeunload",(function(){})),f=!0),addEventListener("visibilitychange",(function e(i){"hidden"===document.visibilityState&&(t(i),n&&removeEventListener("visibilitychange",e,!0))}),!0)},d=function(t){addEventListener("pageshow",(function(n){n.persisted&&t(n)}),!0)},m="function"==typeof WeakSet?new WeakSet:new Set,p=function(t,n,e){var i;return function(){n.value>=0&&(e||m.has(n)||"hidden"===document.visibilityState)&&(n.delta=n.value-(i||0),(n.delta||void 0===i)&&(i=n.value,t(n)))}},v=function(t,n){var e,i=c("CLS",0),a=function(t){t.hadRecentInput||(i.value+=t.value,i.entries.push(t),e())},r=u("layout-shift",a);r&&(e=p(t,i,n),s((function(){r.takeRecords().map(a),e()})),d((function(){i=c("CLS",0),e=p(t,i,n)})))},l=-1,h=function(){return"hidden"===document.visibilityState?0:1/0},S=function(){s((function(t){var n=t.timeStamp;l=n}),!0)},g=function(){return l<0&&(l=h(),S(),d((function(){setTimeout((function(){l=h(),S()}),0)}))),{get timeStamp(){return l}}},y=function(t,n){var e,i=g(),a=c("FCP"),r=u("paint",(function(t){"first-contentful-paint"===t.name&&(r&&r.disconnect(),t.startTime<i.timeStamp&&(a.value=t.startTime,a.entries.push(t),m.add(a),e()))}));r&&(e=p(t,a,n),d((function(i){a=c("FCP"),e=p(t,a,n),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),e()}))}))})))},w={passive:!0,capture:!0},E=new Date,L=function(t,n){i||(i=n,a=t,r=new Date,F(removeEventListener),T())},T=function(){if(a>=0&&a<r-E){var t={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+a};o.forEach((function(n){n(t)})),o=[]}},b=function(t){if(t.cancelable){var n=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,n){var e=function(){L(t,n),a()},i=function(){a()},a=function(){removeEventListener("pointerup",e,w),removeEventListener("pointercancel",i,w)};addEventListener("pointerup",e,w),addEventListener("pointercancel",i,w)}(n,t):L(n,t)}},F=function(t){["mousedown","keydown","touchstart","pointerdown"].forEach((function(n){return t(n,b,w)}))},k=function(t,n){var e,r=g(),f=c("FID"),v=function(t){t.startTime<r.timeStamp&&(f.value=t.processingStart-t.startTime,f.entries.push(t),m.add(f),e())},l=u("first-input",v);e=p(t,f,n),l&&s((function(){l.takeRecords().map(v),l.disconnect()}),!0),l&&d((function(){var r;f=c("FID"),e=p(t,f,n),o=[],a=-1,i=null,F(addEventListener),r=v,o.push(r),T()}))},C=function(t,n){var e,i=g(),a=c("LCP"),r=function(t){var n=t.startTime;n<i.timeStamp&&(a.value=n,a.entries.push(t)),e()},o=u("largest-contentful-paint",r);if(o){e=p(t,a,n);var f=function(){m.has(a)||(o.takeRecords().map(r),o.disconnect(),m.add(a),e())};["keydown","click"].forEach((function(t){addEventListener(t,f,{once:!0,capture:!0})})),s(f,!0),d((function(i){a=c("LCP"),e=p(t,a,n),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),e()}))}))}))}},P=function(t){var n,e=c("TTFB");n=function(){try{var n=performance.getEntriesByType("navigation")[0]||function(){var t=performance.timing,n={entryType:"navigation",startTime:0};for(var e in t)"navigationStart"!==e&&"toJSON"!==e&&(n[e]=Math.max(t[e]-t.navigationStart,0));return n}();e.value=e.delta=n.responseStart,e.entries=[n],t(e)}catch(t){}},"complete"===document.readyState?setTimeout(n,0):addEventListener("pageshow",n)}}}]);
//# sourceMappingURL=3.f3a1fc42.chunk.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,2 +1,2 @@
!function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);p.length;)p.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"f3a1fc42"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpclient=this.webpackJsonpclient||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([]); !function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);s.length;)s.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"a88e738d"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this["webpackJsonpmitmproxy-client"]=this["webpackJsonpmitmproxy-client"]||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([]);
//# sourceMappingURL=runtime-main.48e80cd2.js.map //# sourceMappingURL=runtime-main.bcda7d85.js.map

File diff suppressed because it is too large Load Diff

@ -1,16 +1,21 @@
{ {
"name": "client", "name": "mitmproxy-client",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"bootstrap": "^4.6.0", "bootstrap": "^4.6.0",
"react": "^17.0.1", "react": "^17.0.2",
"react-bootstrap": "^1.4.3", "react-bootstrap": "^1.5.2",
"react-dom": "^17.0.1", "react-dom": "^17.0.2",
"react-scripts": "4.0.2", "react-scripts": "4.0.3",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1" "web-vitals": "^1.0.1"
}, },
"scripts": { "scripts": {
@ -36,5 +41,11 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"eslint": "^7.25.0",
"eslint-plugin-react": "^7.23.2"
} }
} }

@ -1,3 +1,4 @@
import React from 'react'
import { render, screen } from '@testing-library/react' import { render, screen } from '@testing-library/react'
import App from './App' import App from './App'

@ -9,11 +9,19 @@ import EditFlow from './components/EditFlow'
import { FlowManager } from './flow' import { FlowManager } from './flow'
import { isTextBody, getSize } from './utils' import { isTextBody, getSize } from './utils'
import { parseMessage, sendMessageEnum, buildMessageMeta } from './message' import { parseMessage, SendMessageType, buildMessageMeta, IFlow, MessageType, IRequest, IResponse } from './message'
class App extends React.Component { interface IState {
flows: IFlow[]
flow: IFlow | null
flowTab: 'Headers' | 'Preview' | 'Response'
}
class App extends React.Component<any, IState> {
private flowMgr: FlowManager
private ws: WebSocket | null
constructor(props) { constructor(props: any) {
super(props) super(props)
this.flowMgr = new FlowManager() this.flowMgr = new FlowManager()
@ -59,30 +67,30 @@ class App extends React.Component {
} }
// console.log('msg:', msg) // console.log('msg:', msg)
if (msg.type === 'request') { if (msg.type === MessageType.REQUEST) {
const flow = { id: msg.id, request: msg.content, waitIntercept: msg.waitIntercept } const flow = { id: msg.id, request: msg.content as IRequest, waitIntercept: msg.waitIntercept }
this.flowMgr.add(flow) this.flowMgr.add(flow)
this.setState({ flows: this.flowMgr.showList() }) this.setState({ flows: this.flowMgr.showList() })
} }
else if (msg.type === 'requestBody') { else if (msg.type === MessageType.REQUEST_BODY) {
const flow = this.flowMgr.get(msg.id) const flow = this.flowMgr.get(msg.id)
if (!flow) return if (!flow) return
flow.waitIntercept = msg.waitIntercept flow.waitIntercept = msg.waitIntercept
flow.request.body = msg.content flow.request.body = msg.content as ArrayBuffer
this.setState({ flows: this.state.flows }) this.setState({ flows: this.state.flows })
} }
else if (msg.type === 'response') { else if (msg.type === MessageType.RESPONSE) {
const flow = this.flowMgr.get(msg.id) const flow = this.flowMgr.get(msg.id)
if (!flow) return if (!flow) return
flow.waitIntercept = msg.waitIntercept flow.waitIntercept = msg.waitIntercept
flow.response = msg.content flow.response = msg.content as IResponse
this.setState({ flows: this.state.flows }) this.setState({ flows: this.state.flows })
} }
else if (msg.type === 'responseBody') { else if (msg.type === MessageType.RESPONSE_BODY) {
const flow = this.flowMgr.get(msg.id) const flow = this.flowMgr.get(msg.id)
if (!flow || !flow.response) return if (!flow || !flow.response) return
flow.waitIntercept = msg.waitIntercept flow.waitIntercept = msg.waitIntercept
flow.response.body = msg.content flow.response.body = msg.content as ArrayBuffer
this.setState({ flows: this.state.flows }) this.setState({ flows: this.state.flows })
} }
} }
@ -96,15 +104,15 @@ class App extends React.Component {
if (!flow) return null if (!flow) return null
const request = flow.request const request = flow.request
const response = flow.response || {} const response: IResponse = (flow.response || {}) as any
return ( return (
<div className="flow-detail"> <div className="flow-detail">
<div className="header-tabs"> <div className="header-tabs">
<span onClick={() => { this.setState({ flow: null }) }}>x</span> <span onClick={() => { this.setState({ flow: null }) }}>x</span>
<span className={flowTab === 'Headers' ? 'selected' : null} onClick={() => { this.setState({ flowTab: 'Headers' }) }}>Headers</span> <span className={flowTab === 'Headers' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Headers' }) }}>Headers</span>
<span className={flowTab === 'Preview' ? 'selected' : null} onClick={() => { this.setState({ flowTab: 'Preview' }) }}>Preview</span> <span className={flowTab === 'Preview' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Preview' }) }}>Preview</span>
<span className={flowTab === 'Response' ? 'selected' : null} onClick={() => { this.setState({ flowTab: 'Response' }) }}>Response</span> <span className={flowTab === 'Response' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Response' }) }}>Response</span>
<EditFlow <EditFlow
flow={flow} flow={flow}
@ -116,13 +124,15 @@ class App extends React.Component {
this.setState({ flows: this.state.flows }) this.setState({ flows: this.state.flows })
}} }}
onChangeResponse={response => { onChangeResponse={response => {
if (!flow.response) flow.response = {} as IResponse
flow.response.statusCode = response.statusCode flow.response.statusCode = response.statusCode
flow.response.header = response.header flow.response.header = response.header
if (isTextBody(flow.response)) flow.response.body = response.body if (isTextBody(flow.response)) flow.response.body = response.body
this.setState({ flows: this.state.flows }) this.setState({ flows: this.state.flows })
}} }}
onMessage={msg => { onMessage={msg => {
this.ws.send(msg) if (this.ws) this.ws.send(msg)
flow.waitIntercept = false flow.waitIntercept = false
this.setState({ flows: this.state.flows }) this.setState({ flows: this.state.flows })
}} }}
@ -180,7 +190,7 @@ class App extends React.Component {
<div className="header-block-content"> <div className="header-block-content">
<p> <p>
{ {
!(isTextBody(request)) ? "Not text" : !(isTextBody(request)) ? 'Not text' :
new TextDecoder().decode(request.body) new TextDecoder().decode(request.body)
} }
</p> </p>
@ -228,8 +238,8 @@ class App extends React.Component {
</div> </div>
<BreakPoint onSave={rules => { <BreakPoint onSave={rules => {
const msg = buildMessageMeta(sendMessageEnum.changeBreakPointRules, rules) const msg = buildMessageMeta(SendMessageType.CHANGE_BREAK_POINT_RULES, rules)
this.ws.send(msg) if (this.ws) this.ws.send(msg)
}} /> }} />
</div> </div>
@ -255,14 +265,14 @@ class App extends React.Component {
if (path.length > 65) path = path.slice(0, 65) + '...' if (path.length > 65) path = path.slice(0, 65) + '...'
const request = f.request const request = f.request
const response = f.response || {} const response: IResponse = (f.response || {}) as any
const classNames = [] const classNames = []
if (this.state.flow && this.state.flow.id === f.id) classNames.push('tr-selected') if (this.state.flow && this.state.flow.id === f.id) classNames.push('tr-selected')
if (f.waitIntercept) classNames.push('tr-wait-intercept') if (f.waitIntercept) classNames.push('tr-wait-intercept')
return ( return (
<tr className={classNames.length ? classNames.join(' ') : null} key={f.id} <tr className={classNames.length ? classNames.join(' ') : undefined} key={f.id}
onClick={() => { onClick={() => {
this.setState({ flow: f }) this.setState({ flow: f })
}} }}

@ -5,8 +5,26 @@ import Form from 'react-bootstrap/Form'
import Row from 'react-bootstrap/Row' import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col' import Col from 'react-bootstrap/Col'
class BreakPoint extends React.Component { type Method = 'ALL' | 'GET' | 'POST' | 'PUT' | 'DELETE' | ''
constructor(props) { type Action = 1 | 2 | 3
interface IRule {
method: Method
url: string
action: Action
}
interface IState {
show: boolean
rule: IRule
haveRules: boolean
}
interface IProps {
onSave: (rules: IRule[]) => void
}
class BreakPoint extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props) super(props)
this.state = { this.state = {
@ -15,7 +33,7 @@ class BreakPoint extends React.Component {
rule: { rule: {
method: 'ALL', method: 'ALL',
url: '', url: '',
action: '1', action: 1,
}, },
haveRules: false, haveRules: false,
@ -36,12 +54,12 @@ class BreakPoint extends React.Component {
handleSave() { handleSave() {
const { rule } = this.state const { rule } = this.state
const rules = [] const rules: IRule[] = []
if (rule.url) { if (rule.url) {
rules.push({ rules.push({
method: rule.method === 'ALL' ? '' : rule.method, method: rule.method === 'ALL' ? '' : rule.method,
url: rule.url, url: rule.url,
action: parseInt(rule.action) action: rule.action,
}) })
} }
@ -68,7 +86,7 @@ class BreakPoint extends React.Component {
<Form.Group as={Row}> <Form.Group as={Row}>
<Form.Label column sm={2}>Method</Form.Label> <Form.Label column sm={2}>Method</Form.Label>
<Col sm={10}> <Col sm={10}>
<Form.Control as="select" value={rule.method} onChange={e => { this.setState({ rule: { ...rule, method: e.target.value } }) }}> <Form.Control as="select" value={rule.method} onChange={e => { this.setState({ rule: { ...rule, method: e.target.value as Method } }) }}>
<option>ALL</option> <option>ALL</option>
<option>GET</option> <option>GET</option>
<option>POST</option> <option>POST</option>
@ -86,7 +104,7 @@ class BreakPoint extends React.Component {
<Form.Group as={Row}> <Form.Group as={Row}>
<Form.Label column sm={2}>Action</Form.Label> <Form.Label column sm={2}>Action</Form.Label>
<Col sm={10}> <Col sm={10}>
<Form.Control as="select" value={rule.action} onChange={e => { this.setState({ rule: { ...rule, action: e.target.value } }) }}> <Form.Control as="select" value={rule.action} onChange={e => { this.setState({ rule: { ...rule, action: parseInt(e.target.value) as Action } }) }}>
<option value="1">Request</option> <option value="1">Request</option>
<option value="2">Response</option> <option value="2">Response</option>
<option value="3">Both</option> <option value="3">Both</option>

@ -4,11 +4,11 @@ import Modal from 'react-bootstrap/Modal'
import Form from 'react-bootstrap/Form' import Form from 'react-bootstrap/Form'
import Alert from 'react-bootstrap/Alert' import Alert from 'react-bootstrap/Alert'
import { sendMessageEnum, buildMessageEdit } from '../message' import { SendMessageType, buildMessageEdit, IRequest, IResponse, Header, IFlow } from '../message'
import { isTextBody } from '../utils' import { isTextBody } from '../utils'
const stringifyRequest = request => { const stringifyRequest = (request: IRequest) => {
const firstLine = `${request.method} ${request.url}` const firstLine = `${request.method} ${request.url}`
const headerLines = Object.keys(request.header).map(key => { const headerLines = Object.keys(request.header).map(key => {
const valstr = request.header[key].join(' \t ') // for parse convenience const valstr = request.header[key].join(' \t ') // for parse convenience
@ -21,7 +21,7 @@ const stringifyRequest = request => {
return `${firstLine}\n\n${headerLines}\n\n${bodyLines}` return `${firstLine}\n\n${headerLines}\n\n${bodyLines}`
} }
const parseRequest = content => { const parseRequest = (content: string): IRequest | undefined => {
const sections = content.split('\n\n') const sections = content.split('\n\n')
if (sections.length !== 3) return if (sections.length !== 3) return
@ -29,25 +29,26 @@ const parseRequest = content => {
const [method, url] = firstLine.split(' ') const [method, url] = firstLine.split(' ')
if (!method || !url) return if (!method || !url) return
const header = {} const header: Header = {}
for (const line of headerLines.split('\n')) { for (const line of headerLines.split('\n')) {
const [key, vals] = line.split(': ') const [key, vals] = line.split(': ')
if (!key || !vals) return if (!key || !vals) return
header[key] = vals.split(' \t ') header[key] = vals.split(' \t ')
} }
let body = null let body: ArrayBuffer | undefined
if (bodyLines) body = new TextEncoder().encode(bodyLines) if (bodyLines) body = new TextEncoder().encode(bodyLines)
return { return {
method, method,
url, url,
proto: '',
header, header,
body, body,
} }
} }
const stringifyResponse = response => { const stringifyResponse = (response: IResponse) => {
const firstLine = `${response.statusCode}` const firstLine = `${response.statusCode}`
const headerLines = Object.keys(response.header).map(key => { const headerLines = Object.keys(response.header).map(key => {
const valstr = response.header[key].join(' \t ') // for parse convenience const valstr = response.header[key].join(' \t ') // for parse convenience
@ -60,7 +61,7 @@ const stringifyResponse = response => {
return `${firstLine}\n\n${headerLines}\n\n${bodyLines}` return `${firstLine}\n\n${headerLines}\n\n${bodyLines}`
} }
const parseResponse = content => { const parseResponse = (content: string): IResponse | undefined => {
const sections = content.split('\n\n') const sections = content.split('\n\n')
if (sections.length !== 3) return if (sections.length !== 3) return
@ -68,14 +69,14 @@ const parseResponse = content => {
const statusCode = parseInt(firstLine) const statusCode = parseInt(firstLine)
if (isNaN(statusCode)) return if (isNaN(statusCode)) return
const header = {} const header: Header = {}
for (const line of headerLines.split('\n')) { for (const line of headerLines.split('\n')) {
const [key, vals] = line.split(': ') const [key, vals] = line.split(': ')
if (!key || !vals) return if (!key || !vals) return
header[key] = vals.split(' \t ') header[key] = vals.split(' \t ')
} }
let body = null let body: ArrayBuffer | undefined
if (bodyLines) body = new TextEncoder().encode(bodyLines) if (bodyLines) body = new TextEncoder().encode(bodyLines)
return { return {
@ -86,8 +87,21 @@ const parseResponse = content => {
} }
class EditFlow extends React.Component { interface IProps {
constructor(props) { flow: IFlow
onChangeRequest: (request: IRequest) => void
onChangeResponse: (response: IResponse) => void
onMessage: (msg: ArrayBufferLike) => void
}
interface IState {
show: boolean
alertMsg: string
content: string
}
class EditFlow extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props) super(props)
this.state = { this.state = {
@ -101,7 +115,7 @@ class EditFlow extends React.Component {
this.handleSave = this.handleSave.bind(this) this.handleSave = this.handleSave.bind(this)
} }
showAlert(msg) { showAlert(msg: string) {
this.setState({ alertMsg: msg }) this.setState({ alertMsg: msg })
} }
@ -117,7 +131,7 @@ class EditFlow extends React.Component {
if (when === 'request') { if (when === 'request') {
content = stringifyRequest(flow.request) content = stringifyRequest(flow.request)
} else { } else {
content = stringifyResponse(flow.response) content = stringifyResponse(flow.response as IResponse)
} }
this.setState({ show: true, alertMsg: '', content }) this.setState({ show: true, alertMsg: '', content })
@ -164,13 +178,13 @@ class EditFlow extends React.Component {
<Button size="sm" onClick={this.handleShow}>Edit</Button> <Button size="sm" onClick={this.handleShow}>Edit</Button>
<Button size="sm" onClick={() => { <Button size="sm" onClick={() => {
const msgType = when === 'response' ? sendMessageEnum.changeResponse : sendMessageEnum.changeRequest const msgType = when === 'response' ? SendMessageType.CHANGE_RESPONSE : SendMessageType.CHANGE_REQUEST
const msg = buildMessageEdit(msgType, flow) const msg = buildMessageEdit(msgType, flow)
this.props.onMessage(msg) this.props.onMessage(msg)
}}>Continue</Button> }}>Continue</Button>
<Button size="sm" onClick={() => { <Button size="sm" onClick={() => {
const msgType = when === 'response' ? sendMessageEnum.dropResponse : sendMessageEnum.dropRequest const msgType = when === 'response' ? SendMessageType.DROP_RESPONSE : SendMessageType.DROP_REQUEST
const msg = buildMessageEdit(msgType, flow) const msg = buildMessageEdit(msgType, flow)
this.props.onMessage(msg) this.props.onMessage(msg)
}}>Drop</Button> }}>Drop</Button>

@ -1,4 +1,13 @@
import { IFlow } from './message'
export class FlowManager { export class FlowManager {
private items: IFlow[]
private _map: Map<string, IFlow>
private filterText: string
private filterTimer: number | null
private num: number
private max: number
constructor() { constructor() {
this.items = [] this.items = []
this._map = new Map() this._map = new Map()
@ -16,26 +25,26 @@ export class FlowManager {
}) })
} }
add(item) { add(item: IFlow) {
item.no = ++this.num item.no = ++this.num
this.items.push(item) this.items.push(item)
this._map.set(item.id, item) this._map.set(item.id, item)
if (this.items.length > this.max) { if (this.items.length > this.max) {
const oldest = this.items.shift() const oldest = this.items.shift()
this._map.delete(oldest.id) if (oldest) this._map.delete(oldest.id)
} }
} }
get(id) { get(id: string) {
return this._map.get(id) return this._map.get(id)
} }
changeFilter(text) { changeFilter(text: string) {
this.filterText = text this.filterText = text
} }
changeFilterLazy(text, callback) { changeFilterLazy(text: string, callback: () => void) {
if (this.filterTimer) { if (this.filterTimer) {
clearTimeout(this.filterTimer) clearTimeout(this.filterTimer)
this.filterTimer = null this.filterTimer = null
@ -44,7 +53,7 @@ export class FlowManager {
this.filterTimer = setTimeout(() => { this.filterTimer = setTimeout(() => {
this.filterText = text this.filterText = text
callback() callback()
}, 300) }, 300) as any
} }
clear() { clear() {

@ -1,45 +1,77 @@
const messageEnum = { export enum MessageType {
'request': 1, REQUEST = 1,
'requestBody': 2, REQUEST_BODY = 2,
'response': 3, RESPONSE = 3,
'responseBody': 4, RESPONSE_BODY = 4,
} }
const allMessageBytes = Object.keys(messageEnum).map(k => messageEnum[k]) export type Header = Record<string, string[]>
const messageByteMap = Object.keys(messageEnum).reduce((m, k) => { export interface IRequest {
m[messageEnum[k]] = k method: string
return m url: string
}, {}) proto: string
header: Header
body?: ArrayBuffer
}
export interface IResponse {
statusCode: number
header: Header
body?: ArrayBuffer
}
export interface IMessage {
type: MessageType
id: string
waitIntercept: boolean
content?: ArrayBuffer | IRequest | IResponse
}
export interface IFlow {
id: string
no?: number
waitIntercept: boolean
request: IRequest
response?: IResponse
}
const allMessageBytes = [
MessageType.REQUEST,
MessageType.REQUEST_BODY,
MessageType.RESPONSE,
MessageType.RESPONSE_BODY,
]
// type: 1/2/3/4 // type: 1/2/3/4
// messageFlow // messageFlow
// version 1 byte + type 1 byte + id 36 byte + waitIntercept 1 byte + content left bytes // version 1 byte + type 1 byte + id 36 byte + waitIntercept 1 byte + content left bytes
export const parseMessage = data => { export const parseMessage = (data: ArrayBuffer): IMessage | null => {
if (data.byteLength < 39) return null if (data.byteLength < 39) return null
const meta = new Int8Array(data.slice(0, 39)) const meta = new Int8Array(data.slice(0, 39))
const version = meta[0] const version = meta[0]
if (version !== 1) return null if (version !== 1) return null
const type = meta[1] const type = meta[1] as MessageType
if (!allMessageBytes.includes(type)) return null if (!allMessageBytes.includes(type)) return null
const id = new TextDecoder().decode(data.slice(2, 38)) const id = new TextDecoder().decode(data.slice(2, 38))
const waitIntercept = meta[38] === 1 const waitIntercept = meta[38] === 1
const resp = { const resp: IMessage = {
type: messageByteMap[type], type,
id, id,
waitIntercept, waitIntercept,
} }
if (data.byteLength === 39) return resp if (data.byteLength === 39) return resp
if (type === messageEnum['requestBody'] || type === messageEnum['responseBody']) { if (type === MessageType.REQUEST_BODY || type === MessageType.RESPONSE_BODY) {
resp.content = data.slice(39) resp.content = data.slice(39)
return resp return resp
} }
let content = new TextDecoder().decode(data.slice(39)) const contentStr = new TextDecoder().decode(data.slice(39))
let content: any
try { try {
content = JSON.parse(content) content = JSON.parse(contentStr)
} catch (err) { } catch (err) {
return null return null
} }
@ -49,19 +81,19 @@ export const parseMessage = data => {
} }
export const sendMessageEnum = { export enum SendMessageType {
'changeRequest': 11, CHANGE_REQUEST = 11,
'changeResponse': 12, CHANGE_RESPONSE = 12,
'dropRequest': 13, DROP_REQUEST = 13,
'dropResponse': 14, DROP_RESPONSE = 14,
'changeBreakPointRules': 21, CHANGE_BREAK_POINT_RULES = 21,
} }
// type: 11/12/13/14 // type: 11/12/13/14
// messageEdit // messageEdit
// version 1 byte + type 1 byte + id 36 byte + header len 4 byte + header content bytes + body len 4 byte + [body content bytes] // version 1 byte + type 1 byte + id 36 byte + header len 4 byte + header content bytes + body len 4 byte + [body content bytes]
export const buildMessageEdit = (messageType, flow) => { export const buildMessageEdit = (messageType: SendMessageType, flow: IFlow) => {
if (messageType === sendMessageEnum.dropRequest || messageType === sendMessageEnum.dropResponse) { if (messageType === SendMessageType.DROP_REQUEST || messageType === SendMessageType.DROP_RESPONSE) {
const view = new Uint8Array(38) const view = new Uint8Array(38)
view[0] = 1 view[0] = 1
view[1] = messageType view[1] = messageType
@ -69,12 +101,13 @@ export const buildMessageEdit = (messageType, flow) => {
return view return view
} }
let header, body let header: Omit<IRequest, 'body'> | Omit<IResponse, 'body'>
let body: ArrayBuffer | undefined
if (messageType === sendMessageEnum.changeRequest) { if (messageType === SendMessageType.CHANGE_REQUEST) {
({ body, ...header } = flow.request) ({ body, ...header } = flow.request)
} else if (messageType === sendMessageEnum.changeResponse) { } else if (messageType === SendMessageType.CHANGE_RESPONSE) {
({ body, ...header } = flow.response) ({ body, ...header } = flow.response as IResponse)
} else { } else {
throw new Error('invalid message type') throw new Error('invalid message type')
} }
@ -88,7 +121,7 @@ export const buildMessageEdit = (messageType, flow) => {
view[1] = messageType view[1] = messageType
view.set(new TextEncoder().encode(flow.id), 2) view.set(new TextEncoder().encode(flow.id), 2)
view.set(headerBytes, 2 + 36 + 4) view.set(headerBytes, 2 + 36 + 4)
if (bodyLen) view.set(body, 2 + 36 + 4 + headerBytes.byteLength + 4) if (bodyLen) view.set(body as any, 2 + 36 + 4 + headerBytes.byteLength + 4)
const view2 = new DataView(data) const view2 = new DataView(data)
view2.setUint32(2 + 36, headerBytes.byteLength) view2.setUint32(2 + 36, headerBytes.byteLength)
@ -101,8 +134,8 @@ export const buildMessageEdit = (messageType, flow) => {
// type: 21 // type: 21
// messageMeta // messageMeta
// version 1 byte + type 1 byte + content left bytes // version 1 byte + type 1 byte + content left bytes
export const buildMessageMeta = (messageType, rules) => { export const buildMessageMeta = (messageType: SendMessageType, rules: any) => {
if (messageType !== sendMessageEnum.changeBreakPointRules) { if (messageType !== SendMessageType.CHANGE_BREAK_POINT_RULES) {
throw new Error('invalid message type') throw new Error('invalid message type')
} }

@ -0,0 +1 @@
/// <reference types="react-scripts" />

@ -1,4 +1,6 @@
const reportWebVitals = onPerfEntry => { import { ReportHandler } from 'web-vitals'
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) { if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry) getCLS(onPerfEntry)

@ -1,4 +1,6 @@
export const isTextBody = payload => { import { IRequest, IResponse } from './message'
export const isTextBody = (payload: IRequest | IResponse) => {
if (!payload) return false if (!payload) return false
if (!payload.header) return false if (!payload.header) return false
if (!payload.header['Content-Type']) return false if (!payload.header['Content-Type']) return false
@ -6,7 +8,7 @@ export const isTextBody = payload => {
return /text|javascript|json/.test(payload.header['Content-Type'].join('')) return /text|javascript|json/.test(payload.header['Content-Type'].join(''))
} }
export const getSize = response => { export const getSize = (response: IResponse) => {
if (!response) return '0' if (!response) return '0'
if (!response.header) return '0' if (!response.header) return '0'

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save