aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/net/tcp.py7
-rw-r--r--test/mitmproxy/net/data/server.crt33
-rw-r--r--test/mitmproxy/net/data/server.key43
-rw-r--r--test/mitmproxy/net/test_tcp.py7
-rw-r--r--web/src/js/__tests__/components/ContentView/CodeEditorSpec.js26
-rw-r--r--web/src/js/__tests__/components/ContentView/ContentViewOptionsSpec.js20
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/CodeEditorSpec.js.snap8
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewOptionsSpec.js.snap41
8 files changed, 157 insertions, 28 deletions
diff --git a/mitmproxy/net/tcp.py b/mitmproxy/net/tcp.py
index 12cf7337..fce0b744 100644
--- a/mitmproxy/net/tcp.py
+++ b/mitmproxy/net/tcp.py
@@ -634,7 +634,12 @@ class TCPClient(_Connection):
if self.cert.cn:
crt["subject"] = [[["commonName", self.cert.cn.decode("ascii", "strict")]]]
if sni:
- hostname = sni
+ # SNI hostnames allow support of IDN by using ASCII-Compatible Encoding
+ # Conversion algorithm is in RFC 3490 which is implemented by idna codec
+ # https://docs.python.org/3/library/codecs.html#text-encodings
+ # https://tools.ietf.org/html/rfc6066#section-3
+ # https://tools.ietf.org/html/rfc4985#section-3
+ hostname = sni.encode("idna").decode("ascii")
else:
hostname = "no-hostname"
match_hostname(crt, hostname)
diff --git a/test/mitmproxy/net/data/server.crt b/test/mitmproxy/net/data/server.crt
index 68f61bac..a459937f 100644
--- a/test/mitmproxy/net/data/server.crt
+++ b/test/mitmproxy/net/data/server.crt
@@ -1,14 +1,23 @@
-----BEGIN CERTIFICATE-----
-MIICOzCCAaQCCQDC7f5GsEpo9jANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJO
-WjEOMAwGA1UECBMFT3RhZ28xEDAOBgNVBAcTB0R1bmVkaW4xDzANBgNVBAoTBm5l
-dGxpYjEPMA0GA1UECxMGbmV0bGliMQ8wDQYDVQQDEwZuZXRsaWIwHhcNMTIwNjI0
-MjI0MTU0WhcNMjIwNjIyMjI0MTU0WjBiMQswCQYDVQQGEwJOWjEOMAwGA1UECBMF
-T3RhZ28xEDAOBgNVBAcTB0R1bmVkaW4xDzANBgNVBAoTBm5ldGxpYjEPMA0GA1UE
-CxMGbmV0bGliMQ8wDQYDVQQDEwZuZXRsaWIwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
-MIGJAoGBALJSVEl9y3QUSYuXTH0UjBOPQgS0nHmNWej9hjqnA0KWvEnGY+c6yQeP
-/rmwswlKw1iVV5o8kRK9Wej88YWQl/hl/xruyeJgGic0+yqY/FcueZxRudwBcWu2
-7+46aEftwLLRF0GwHZxX/HwWME+TcCXGpXGSG2qs921M4iVeBn5hAgMBAAEwDQYJ
-KoZIhvcNAQEFBQADgYEAODZCihEv2yr8zmmQZDrfqg2ChxAoOXWF5+W2F/0LAUBf
-2bHP+K4XE6BJWmadX1xKngj7SWrhmmTDp1gBAvXURoDaScOkB1iOCOHoIyalscTR
-0FvSHKqFF8fgSlfqS6eYaSbXU3zQolvwP+URzIVnGDqgQCWPtjMqLD3Kd5tuwos=
+MIID3zCCAsegAwIBAgIJAKA4XJuTgjSHMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYD
+VQQGEwJOWjEOMAwGA1UECAwFT3RhZ28xEDAOBgNVBAcMB0R1bmVkaW4xEjAQBgNV
+BAoMCU1pdG1wcm94eTESMBAGA1UECwwJTWl0bXByb3h5MSwwKgYDVQQDDCN4bi0t
+bWl0bXByb3h5c3MtdDhhOHU0Yy5leGFtcGxlLmNvbTAeFw0xNzA2MDExMTM4MTha
+Fw0yNzA1MzAxMTM4MThaMIGFMQswCQYDVQQGEwJOWjEOMAwGA1UECAwFT3RhZ28x
+EDAOBgNVBAcMB0R1bmVkaW4xEjAQBgNVBAoMCU1pdG1wcm94eTESMBAGA1UECwwJ
+TWl0bXByb3h5MSwwKgYDVQQDDCN4bi0tbWl0bXByb3h5c3MtdDhhOHU0Yy5leGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALkECdLZFqH8
+7JRpfdkUMew4qrric4WGM3UiLyQ8sgpCqeqK4m7Df2CAXGRze8JKjfIWSsva+y18
+xC2CCIBUFvvBgXxkvrBML+NddYNxPeV2zCjBMgjrhtKUqbHeV5Fz0WtGUoUds955
+uXeNK0d5wa4QmaRcPARTpW2UFvMrxlivI0/MQ8x3YfejAvUZaho8FvWKmB0kI6um
+396xtsrYqjevofSFwi+LYx6q4mYsQke6Ubglasv9naTHEiZmrKBrtBmxuMJQjh8Q
+aikeM6X/NyUC0zS6eEimjW1IPRI7hyeVPYcIBccSdkDuP5iJeuUdVa/Qx0vUp0U7
+YJoPTCyUn+ECAwEAAaNQME4wHQYDVR0OBBYEFHrTiFx1z6RP+EFK4I064u+3Jtd4
+MB8GA1UdIwQYMBaAFHrTiFx1z6RP+EFK4I064u+3Jtd4MAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQELBQADggEBAIYX5dEvO44idRwFJPoleOh+mjJVeIeW0qOEf14q
+pRRm3l7s+xTaxu0TnIZ2PZRmajFlmSAqoeUyowrmjMQWb63CWTz/aqDLxdS0ciD9
+/T26xYHGV5QtPsLY/O5r0LtmBXHWDIaON4vDbH72NVNUMeZAI0Mayewd6uWXgwOo
+2azncUS2PO89vgX1Xjxq45bVMauwOTq2j5/1ZLb1VJ8IwfsNsvvTXJyv5iSXnuJ5
+ACIwY3auSHqRL+3fjNRgfp/YuQfZ0rZJKvVujPSig9AMoWlQ+J0K5wHptGe76O/v
+PWWNho52eLHtAquwXfcyZ7RqD2qsosIJ++MnLEk+gHwmqn0=
-----END CERTIFICATE-----
diff --git a/test/mitmproxy/net/data/server.key b/test/mitmproxy/net/data/server.key
index b1b658ab..ecf432e8 100644
--- a/test/mitmproxy/net/data/server.key
+++ b/test/mitmproxy/net/data/server.key
@@ -1,15 +1,28 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQCyUlRJfct0FEmLl0x9FIwTj0IEtJx5jVno/YY6pwNClrxJxmPn
-OskHj/65sLMJSsNYlVeaPJESvVno/PGFkJf4Zf8a7sniYBonNPsqmPxXLnmcUbnc
-AXFrtu/uOmhH7cCy0RdBsB2cV/x8FjBPk3AlxqVxkhtqrPdtTOIlXgZ+YQIDAQAB
-AoGAQEpGcSiVTYhy64zk2sOprPOdTa0ALSK1I7cjycmk90D5KXAJXLho+f0ETVZT
-dioqO6m8J7NmamcyHznyqcDzyNRqD2hEBDGVRJWmpOjIER/JwWLNNbpeVjsMHV8I
-40P5rZMOhBPYlwECSC5NtMwaN472fyGNNze8u37IZKiER/ECQQDe1iY5AG3CgkP3
-tEZB3Vtzcn4PoOr3Utyn1YER34lPqAmeAsWUhmAVEfR3N1HDe1VFD9s2BidhBn1a
-/Bgqxz4DAkEAzNw0m+uO0WkD7aEYRBW7SbXCX+3xsbVToIWC1jXFG+XDzSWn++c1
-DMXEElzEJxPDA+FzQUvRTml4P92bTAbGywJAS9H7wWtm7Ubbj33UZfbGdhqfz/uF
-109naufXedhgZS0c0JnK1oV+Tc0FLEczV9swIUaK5O/lGDtYDcw3AN84NwJBAIw5
-/1jrOOtm8uVp6+5O4dBmthJsEZEPCZtLSG/Qhoe+EvUN3Zq0fL+tb7USAsKs6ERz
-wizj9PWzhDhTPMYhrVkCQGIponZHx6VqiFyLgYUH9+gDTjBhYyI+6yMTYzcRweyL
-9Suc2NkS3X2Lp+wCjvVZdwGtStp6Vo8z02b3giIsAIY=
------END RSA PRIVATE KEY-----
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5BAnS2Rah/OyU
+aX3ZFDHsOKq64nOFhjN1Ii8kPLIKQqnqiuJuw39ggFxkc3vCSo3yFkrL2vstfMQt
+ggiAVBb7wYF8ZL6wTC/jXXWDcT3ldswowTII64bSlKmx3leRc9FrRlKFHbPeebl3
+jStHecGuEJmkXDwEU6VtlBbzK8ZYryNPzEPMd2H3owL1GWoaPBb1ipgdJCOrpt/e
+sbbK2Ko3r6H0hcIvi2MequJmLEJHulG4JWrL/Z2kxxImZqyga7QZsbjCUI4fEGop
+HjOl/zclAtM0unhIpo1tSD0SO4cnlT2HCAXHEnZA7j+YiXrlHVWv0MdL1KdFO2Ca
+D0wslJ/hAgMBAAECggEARcfeJKY4QRRx7m/zRUK2qY+d5Sqvw3agRdeEzDgQNop6
+J7oGORyHGFCRiFl+HgOckegSgdyvy7I5E6jtp+kPWhjby5z7xuaVUT3YqqC1Zaxu
+yBhF1NNwYFAtyKZBhNyX6cv2J7rSMmDasNqPrj+f6xTbvgADquYZiMDH/yNNhfiz
+Hq6E2ojO0jjFBh/gooLo8ADk1bnpc/b5x6+DdYtjDOqioSujJbAxHTcZLpeBGBHm
++WBnxnSNpJHJQvscpry8eBMG8HSKNMgG3o5kHKdyOiJkWL5luz2xkmEnHBUBTZTI
+lB5v2J2SC+XGP4R1jbbfeLIx2P+zaDkzXeaiwr/2AQKBgQD0tJZmYLmZwZHWUcya
+01wJ07+K+zr8uKItI22TtjQ74svqtbP/Xg8GBjtRunf9evPEJ2tRuBqMR+3iwZXe
+wB/gn+llHkSjQguLuKhlVGfreURMchTS4dvLSy+BRGKTqjryFJnUPUeqaQbijFV9
+mSbXXWGmyJkW9VSZebFg2uC20QKBgQDBjiogBmnmAeoTJp2Aj5sEtno9GU6N0IaT
+TVNO66Qn0baV4LGcMb+8ogjM813FlMFtCBsrwKKrBo+slERJX1wtZ+69c5T+V1n2
+1X0B4odreH4E5Qty4nqrwv4kf7GUsqszWQEYVuzs7beTWHFVCbdYkMPRydRX6N2Q
+g4s2jre8EQKBgFcSy1GyqVhk4Jf6k2ukOePlTQsPSnYS3OJi8OLWus90bEsgTORZ
+e88Q+JqkV34C+iqaPD3f3NJ95dACQmn4w18Sh+JLWvEc1y7ojkNAPZo0lHD/Rxmi
+9KrqHgVJaCpTMJZjbjlvdMjWhnSmquT+UivgNpc6Wf8pXOkfvFZSjBOBAoGAPodi
+7H2l8Hxl1lH/R+0cs2UQEHUAf6gCEcxFQZW2rnZ9eeXg+wjHXHUsSqnEfXQVGNgp
+jvTomD/CYopzlRCNgs20vtd8Jr6pfahyfg1kmj+O1p34GOE5qAuSdtAZ2mPuEuSK
+Cgbq+4/AYoWL92DwLlh2Kmv9gXjlOy6D5tgsW0ECgYEAvr14NW1D+NTIEw41VWPj
+gzr1hsrWoTSXQs4oDJ1ng2yrRclEpVgzytGConfxiWOFwApxOfngRYz0VZKTShQx
+c6eA/948VBdveGWZcRnkD3iDyIzjXCCapHQMn8w3CxIyve4p1177WA8cPOdHfZrm
+BYSkZMxKTfrmGPULj5+De+E=
+-----END PRIVATE KEY-----
diff --git a/test/mitmproxy/net/test_tcp.py b/test/mitmproxy/net/test_tcp.py
index adf8701a..73de0879 100644
--- a/test/mitmproxy/net/test_tcp.py
+++ b/test/mitmproxy/net/test_tcp.py
@@ -387,6 +387,13 @@ class TestSNI(tservers.ServerTestBase):
assert c.sni == "foo.com"
assert c.rfile.readline() == b"foo.com"
+ def test_idn(self):
+ c = tcp.TCPClient(("127.0.0.1", self.port))
+ with c.connect():
+ c.convert_to_ssl(sni="mitmproxyäöüß.example.com")
+ assert c.ssl_established
+ assert "doesn't match" not in str(c.ssl_verification_error)
+
class TestServerCipherList(tservers.ServerTestBase):
handler = ClientCipherListHandler
diff --git a/web/src/js/__tests__/components/ContentView/CodeEditorSpec.js b/web/src/js/__tests__/components/ContentView/CodeEditorSpec.js
new file mode 100644
index 00000000..ba7acf07
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/CodeEditorSpec.js
@@ -0,0 +1,26 @@
+jest.mock('react-codemirror')
+import React from 'react'
+import renderer from 'react-test-renderer'
+import CodeEditor from '../../../components/ContentView/CodeEditor'
+
+describe('CodeEditor Component', () => {
+ let content = "foo content",
+ changeFn = jest.fn(),
+ codeEditor = renderer.create(
+ <CodeEditor content={content} onChange={changeFn}/>
+ ),
+ tree = codeEditor.toJSON()
+
+ it('should render correctly', () => {
+ // This actually does not render properly, but getting a full CodeMirror rendering
+ // is cumbersome. This is hopefully good enough.
+ // see: https://github.com/mitmproxy/mitmproxy/pull/2365#discussion_r119766850
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle key down', () => {
+ let mockEvent = { stopPropagation: jest.fn() }
+ tree.props.onKeyDown(mockEvent)
+ expect(mockEvent.stopPropagation).toBeCalled()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/ContentViewOptionsSpec.js b/web/src/js/__tests__/components/ContentView/ContentViewOptionsSpec.js
new file mode 100644
index 00000000..68afb4ec
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/ContentViewOptionsSpec.js
@@ -0,0 +1,20 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import ContentViewOptions from '../../../components/ContentView/ContentViewOptions'
+import { Provider } from 'react-redux'
+import { TFlow, TStore } from '../../ducks/tutils'
+import { uploadContent } from '../../../ducks/flows'
+
+let tflow = new TFlow()
+
+describe('ContentViewOptions Component', () => {
+ let store = TStore()
+ it('should render correctly', () => {
+ let provider = renderer.create(
+ <Provider store={store}>
+ <ContentViewOptions flow={tflow} message={tflow.response} uploadContent={uploadContent}/>
+ </Provider>),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/CodeEditorSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/CodeEditorSpec.js.snap
new file mode 100644
index 00000000..7e688a60
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/CodeEditorSpec.js.snap
@@ -0,0 +1,8 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CodeEditor Component should render correctly 1`] = `
+<div
+ className="codeeditor"
+ onKeyDown={[Function]}
+/>
+`;
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewOptionsSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewOptionsSpec.js.snap
new file mode 100644
index 00000000..e3561ec1
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewOptionsSpec.js.snap
@@ -0,0 +1,41 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ContentViewOptions Component should render correctly 1`] = `
+<div
+ className="view-options"
+>
+ <span>
+ <b>
+ View:
+ </b>
+ edit
+ </span>
+  
+ <a
+ className="btn btn-default btn-xs"
+ href="/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content"
+ title="Download the content of the flow."
+ >
+ <i
+ className="fa fa-download"
+ />
+ </a>
+  
+ <a
+ className="btn btn-default btn-xs"
+ href="#"
+ onClick={[Function]}
+ title="Upload a file to replace the content."
+ >
+ <i
+ className="fa fa-fw fa-upload"
+ />
+ <input
+ className="hidden"
+ onChange={[Function]}
+ type="file"
+ />
+ </a>
+  
+</div>
+`;