matlab-proxy 0.25.0__py3-none-any.whl → 0.26.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of matlab-proxy might be problematic. Click here for more details.
- matlab_proxy/app.py +66 -12
- matlab_proxy/constants.py +1 -0
- matlab_proxy/gui/index.html +1 -1
- matlab_proxy/gui/static/js/{index.qK3VCGVb.js → index.CZgGkMCD.js} +15 -15
- matlab_proxy/settings.py +22 -1
- matlab_proxy/util/cookie_jar.py +72 -0
- matlab_proxy/util/mwi/environment_variables.py +10 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/METADATA +4 -1
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/RECORD +24 -21
- matlab_proxy_manager/lib/api.py +156 -114
- matlab_proxy_manager/storage/server.py +5 -2
- matlab_proxy_manager/utils/constants.py +2 -1
- matlab_proxy_manager/utils/environment_variables.py +6 -1
- matlab_proxy_manager/utils/exceptions.py +45 -0
- matlab_proxy_manager/utils/helpers.py +2 -2
- matlab_proxy_manager/utils/logger.py +4 -1
- matlab_proxy_manager/web/app.py +71 -19
- tests/unit/test_app.py +116 -17
- tests/unit/test_settings.py +26 -6
- tests/unit/util/test_cookie_jar.py +252 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/LICENSE.md +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/WHEEL +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/entry_points.txt +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Copyright 2025 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
from http.cookies import Morsel, SimpleCookie
|
|
4
|
+
|
|
5
|
+
from multidict import CIMultiDict
|
|
6
|
+
|
|
7
|
+
from matlab_proxy.util.cookie_jar import HttpOnlyCookieJar
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_simple_cookie_jar_initialization():
|
|
11
|
+
"""Test SimpleCookieJar initialization."""
|
|
12
|
+
# Arrange
|
|
13
|
+
# Nothing to arrange
|
|
14
|
+
|
|
15
|
+
# Act
|
|
16
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
17
|
+
|
|
18
|
+
# Assert
|
|
19
|
+
assert cookie_jar._cookie_jar == {}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_get_cookie_name():
|
|
23
|
+
"""Test getting cookie name from SimpleCookie."""
|
|
24
|
+
# Arrange
|
|
25
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
26
|
+
cookie = SimpleCookie()
|
|
27
|
+
cookie["test_cookie"] = "test_value"
|
|
28
|
+
|
|
29
|
+
# Act
|
|
30
|
+
cookie_name = cookie_jar._get_cookie_name(cookie)
|
|
31
|
+
|
|
32
|
+
# Assert
|
|
33
|
+
assert cookie_name == "test_cookie"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_get_cookie_name_with_multiple_cookies():
|
|
37
|
+
"""Test getting cookie name from SimpleCookie with multiple cookies."""
|
|
38
|
+
# Arrange
|
|
39
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
40
|
+
cookie_1, cookie_2 = SimpleCookie(), SimpleCookie()
|
|
41
|
+
cookie_1["first_cookie"] = "first_value"
|
|
42
|
+
cookie_2["second_cookie"] = "second_value"
|
|
43
|
+
|
|
44
|
+
# Act
|
|
45
|
+
cookie_name_1 = cookie_jar._get_cookie_name(cookie_1)
|
|
46
|
+
cookie_name_2 = cookie_jar._get_cookie_name(cookie_2)
|
|
47
|
+
|
|
48
|
+
# Assert
|
|
49
|
+
assert cookie_name_1 == "first_cookie"
|
|
50
|
+
assert cookie_name_2 == "second_cookie"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_update_from_response_headers_single_cookie():
|
|
54
|
+
"""Test updating cookie jar from response headers with single cookie."""
|
|
55
|
+
# Arrange
|
|
56
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
57
|
+
headers = CIMultiDict()
|
|
58
|
+
headers.add("Set-Cookie", "JSESSIONID=abc123; Path=/; HttpOnly")
|
|
59
|
+
|
|
60
|
+
# Act
|
|
61
|
+
cookie_jar.update_from_response_headers(headers)
|
|
62
|
+
|
|
63
|
+
# Assert
|
|
64
|
+
assert "JSESSIONID" in cookie_jar._cookie_jar
|
|
65
|
+
assert cookie_jar._cookie_jar["JSESSIONID"].value == "abc123"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_update_from_response_headers_multiple_cookies():
|
|
69
|
+
"""Test updating cookie jar from response headers with multiple cookies."""
|
|
70
|
+
# Arrange
|
|
71
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
72
|
+
headers = CIMultiDict()
|
|
73
|
+
headers.add("Set-Cookie", "JSESSIONID=abc123; Path=/; HttpOnly")
|
|
74
|
+
headers.add("Set-Cookie", "snc=1234; Path=/; Secure HttpOnly")
|
|
75
|
+
|
|
76
|
+
# Act
|
|
77
|
+
cookie_jar.update_from_response_headers(headers)
|
|
78
|
+
|
|
79
|
+
# Assert
|
|
80
|
+
assert "JSESSIONID" in cookie_jar._cookie_jar
|
|
81
|
+
assert "snc" in cookie_jar._cookie_jar
|
|
82
|
+
assert cookie_jar._cookie_jar["JSESSIONID"].value == "abc123"
|
|
83
|
+
assert cookie_jar._cookie_jar["snc"].value == "1234"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_update_from_response_headers_no_set_cookie():
|
|
87
|
+
"""Test updating cookie jar when no Set-Cookie headers present."""
|
|
88
|
+
# Arrange
|
|
89
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
90
|
+
headers = CIMultiDict()
|
|
91
|
+
headers.add("Content-Type", "application/json")
|
|
92
|
+
|
|
93
|
+
# Act
|
|
94
|
+
cookie_jar.update_from_response_headers(headers)
|
|
95
|
+
|
|
96
|
+
# Assert
|
|
97
|
+
assert len(cookie_jar._cookie_jar) == 0
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_update_from_response_headers_overwrite_existing():
|
|
101
|
+
"""Test that updating cookie jar overwrites existing cookies with same name."""
|
|
102
|
+
# Arrange
|
|
103
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
104
|
+
headers1 = CIMultiDict()
|
|
105
|
+
headers1.add("Set-Cookie", "JSESSIONID=old_value; Path=/ HttpOnly")
|
|
106
|
+
headers2 = CIMultiDict()
|
|
107
|
+
headers2.add("Set-Cookie", "JSESSIONID=new_value; Path=/ HttpOnly")
|
|
108
|
+
|
|
109
|
+
# Act
|
|
110
|
+
cookie_jar.update_from_response_headers(headers1)
|
|
111
|
+
cookie_jar.update_from_response_headers(headers2)
|
|
112
|
+
|
|
113
|
+
# Assert
|
|
114
|
+
assert cookie_jar._cookie_jar["JSESSIONID"].value == "new_value"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_get_cookies():
|
|
118
|
+
"""Test getting all cookies as list of Morsel objects."""
|
|
119
|
+
# Arrange
|
|
120
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
121
|
+
headers = CIMultiDict()
|
|
122
|
+
headers.add("Set-Cookie", "JSESSIONID=abc123; Path=/ HttpOnly")
|
|
123
|
+
headers.add("Set-Cookie", "snc=1234; Path=/ HttpOnly")
|
|
124
|
+
cookie_jar.update_from_response_headers(headers)
|
|
125
|
+
|
|
126
|
+
# Act
|
|
127
|
+
cookies = cookie_jar.get_cookies()
|
|
128
|
+
|
|
129
|
+
# Assert
|
|
130
|
+
assert len(cookies) == 2
|
|
131
|
+
assert all(isinstance(cookie, Morsel) for cookie in cookies)
|
|
132
|
+
values = [cookie.value for cookie in cookies]
|
|
133
|
+
assert "abc123" in values
|
|
134
|
+
assert "1234" in values
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_get_cookies_empty_jar():
|
|
138
|
+
"""Test getting cookies from empty jar."""
|
|
139
|
+
# Arrange
|
|
140
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
141
|
+
|
|
142
|
+
# Act
|
|
143
|
+
cookies = cookie_jar.get_cookies()
|
|
144
|
+
|
|
145
|
+
# Assert
|
|
146
|
+
assert cookies == []
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_get_dict():
|
|
150
|
+
"""Test getting cookies as dictionary."""
|
|
151
|
+
# Arrange
|
|
152
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
153
|
+
headers = CIMultiDict()
|
|
154
|
+
headers.add("Set-Cookie", "JSESSIONID=abc123; Path=/ HttpOnly")
|
|
155
|
+
headers.add("Set-Cookie", "snc=1234; Path=/ HttpOnly")
|
|
156
|
+
cookie_jar.update_from_response_headers(headers)
|
|
157
|
+
|
|
158
|
+
# Act
|
|
159
|
+
cookie_dict = cookie_jar.get_dict()
|
|
160
|
+
|
|
161
|
+
# Assert
|
|
162
|
+
assert isinstance(cookie_dict, dict)
|
|
163
|
+
assert cookie_dict["JSESSIONID"] == "abc123"
|
|
164
|
+
assert cookie_dict["snc"] == "1234"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_get_dict_empty_jar():
|
|
168
|
+
"""Test getting dictionary from empty jar."""
|
|
169
|
+
# Arrange
|
|
170
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
171
|
+
|
|
172
|
+
# Act
|
|
173
|
+
cookie_dict = cookie_jar.get_dict()
|
|
174
|
+
|
|
175
|
+
# Assert
|
|
176
|
+
assert cookie_dict == {}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_clear():
|
|
180
|
+
"""Test clearing all cookies from jar."""
|
|
181
|
+
# Arrange
|
|
182
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
183
|
+
headers = CIMultiDict()
|
|
184
|
+
headers.add("Set-Cookie", "JSESSIONID=abc123; Path=/ HttpOnly")
|
|
185
|
+
headers.add("Set-Cookie", "snc=1234; Path=/ HttpOnly")
|
|
186
|
+
cookie_jar.update_from_response_headers(headers)
|
|
187
|
+
|
|
188
|
+
# Act
|
|
189
|
+
cookie_jar.clear()
|
|
190
|
+
|
|
191
|
+
# Assert
|
|
192
|
+
assert len(cookie_jar._cookie_jar) == 0
|
|
193
|
+
assert cookie_jar.get_dict() == {}
|
|
194
|
+
assert cookie_jar.get_cookies() == []
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_clear_empty_jar():
|
|
198
|
+
"""Test clearing already empty jar."""
|
|
199
|
+
# Arrange
|
|
200
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
201
|
+
|
|
202
|
+
# Act
|
|
203
|
+
cookie_jar.clear()
|
|
204
|
+
|
|
205
|
+
# Assert
|
|
206
|
+
assert len(cookie_jar._cookie_jar) == 0
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def test_cookie_attributes_preserved():
|
|
210
|
+
"""Test that cookie attributes are preserved when stored."""
|
|
211
|
+
# Arrange
|
|
212
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
213
|
+
headers = CIMultiDict()
|
|
214
|
+
headers.add(
|
|
215
|
+
"Set-Cookie", "JSESSIONID=abc123; Path=/; HttpOnly; Secure; Max-Age=3600"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Act
|
|
219
|
+
cookie_jar.update_from_response_headers(headers)
|
|
220
|
+
|
|
221
|
+
# Assert
|
|
222
|
+
morsel = cookie_jar._cookie_jar["JSESSIONID"]
|
|
223
|
+
assert morsel.value == "abc123"
|
|
224
|
+
assert morsel["path"] == "/"
|
|
225
|
+
assert morsel["httponly"] is True
|
|
226
|
+
assert morsel["secure"] is True
|
|
227
|
+
assert morsel["max-age"] == "3600"
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def test_cookie_jar_insert_httponly_cookies():
|
|
231
|
+
"""Test that only HttpOnly cookies are added to the cookie jar."""
|
|
232
|
+
# Arrange
|
|
233
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
234
|
+
headers = CIMultiDict()
|
|
235
|
+
# JSessionID cookie with HttpOnly flag. This cookie should be added to the cookie jar.
|
|
236
|
+
headers.add(
|
|
237
|
+
"Set-Cookie", "JSESSIONID=abc123; Path=/; HttpOnly; Secure; Max-Age=3600"
|
|
238
|
+
)
|
|
239
|
+
# SNC cookie without HttpOnly. This cookie should not be added to the cookie jar
|
|
240
|
+
headers.add("Set-Cookie", "SNC=abc123; Path=/; Secure; Max-Age=3600")
|
|
241
|
+
|
|
242
|
+
# Act
|
|
243
|
+
cookie_jar.update_from_response_headers(headers)
|
|
244
|
+
|
|
245
|
+
# Assert
|
|
246
|
+
assert len(cookie_jar._cookie_jar) == 1
|
|
247
|
+
morsel = cookie_jar._cookie_jar["JSESSIONID"]
|
|
248
|
+
assert morsel.value == "abc123"
|
|
249
|
+
assert morsel["path"] == "/"
|
|
250
|
+
assert morsel["httponly"] is True
|
|
251
|
+
assert morsel["secure"] is True
|
|
252
|
+
assert morsel["max-age"] == "3600"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|