bbot 2.4.2__py3-none-any.whl → 2.4.2.6590rc0__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 bbot might be problematic. Click here for more details.

Files changed (64) hide show
  1. bbot/__init__.py +1 -1
  2. bbot/core/event/base.py +64 -4
  3. bbot/core/helpers/diff.py +10 -7
  4. bbot/core/helpers/helper.py +5 -1
  5. bbot/core/helpers/misc.py +48 -11
  6. bbot/core/helpers/regex.py +4 -0
  7. bbot/core/helpers/regexes.py +45 -8
  8. bbot/core/helpers/url.py +21 -5
  9. bbot/core/helpers/web/client.py +25 -5
  10. bbot/core/helpers/web/engine.py +9 -1
  11. bbot/core/helpers/web/envelopes.py +352 -0
  12. bbot/core/helpers/web/web.py +10 -2
  13. bbot/core/helpers/yara_helper.py +50 -0
  14. bbot/core/modules.py +23 -7
  15. bbot/defaults.yml +26 -1
  16. bbot/modules/base.py +4 -2
  17. bbot/modules/{deadly/dastardly.py → dastardly.py} +1 -1
  18. bbot/modules/{deadly/ffuf.py → ffuf.py} +1 -1
  19. bbot/modules/ffuf_shortnames.py +1 -1
  20. bbot/modules/httpx.py +14 -0
  21. bbot/modules/hunt.py +24 -6
  22. bbot/modules/internal/aggregate.py +1 -0
  23. bbot/modules/internal/excavate.py +356 -197
  24. bbot/modules/lightfuzz/lightfuzz.py +203 -0
  25. bbot/modules/lightfuzz/submodules/__init__.py +0 -0
  26. bbot/modules/lightfuzz/submodules/base.py +312 -0
  27. bbot/modules/lightfuzz/submodules/cmdi.py +106 -0
  28. bbot/modules/lightfuzz/submodules/crypto.py +474 -0
  29. bbot/modules/lightfuzz/submodules/nosqli.py +183 -0
  30. bbot/modules/lightfuzz/submodules/path.py +154 -0
  31. bbot/modules/lightfuzz/submodules/serial.py +179 -0
  32. bbot/modules/lightfuzz/submodules/sqli.py +187 -0
  33. bbot/modules/lightfuzz/submodules/ssti.py +39 -0
  34. bbot/modules/lightfuzz/submodules/xss.py +191 -0
  35. bbot/modules/{deadly/nuclei.py → nuclei.py} +1 -1
  36. bbot/modules/paramminer_headers.py +2 -0
  37. bbot/modules/reflected_parameters.py +80 -0
  38. bbot/modules/{deadly/vhost.py → vhost.py} +2 -2
  39. bbot/presets/web/lightfuzz-heavy.yml +16 -0
  40. bbot/presets/web/lightfuzz-light.yml +20 -0
  41. bbot/presets/web/lightfuzz-medium.yml +14 -0
  42. bbot/presets/web/lightfuzz-superheavy.yml +13 -0
  43. bbot/presets/web/lightfuzz-xss.yml +21 -0
  44. bbot/presets/web/paramminer.yml +8 -5
  45. bbot/scanner/preset/args.py +26 -0
  46. bbot/scanner/scanner.py +6 -0
  47. bbot/test/test_step_1/test__module__tests.py +1 -1
  48. bbot/test/test_step_1/test_helpers.py +7 -0
  49. bbot/test/test_step_1/test_presets.py +2 -2
  50. bbot/test/test_step_1/test_web.py +20 -0
  51. bbot/test/test_step_1/test_web_envelopes.py +343 -0
  52. bbot/test/test_step_2/module_tests/test_module_excavate.py +404 -29
  53. bbot/test/test_step_2/module_tests/test_module_httpx.py +29 -0
  54. bbot/test/test_step_2/module_tests/test_module_hunt.py +18 -1
  55. bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +1947 -0
  56. bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +4 -1
  57. bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +46 -2
  58. bbot/test/test_step_2/module_tests/test_module_reflected_parameters.py +226 -0
  59. bbot/wordlists/paramminer_parameters.txt +0 -8
  60. {bbot-2.4.2.dist-info → bbot-2.4.2.6590rc0.dist-info}/METADATA +2 -1
  61. {bbot-2.4.2.dist-info → bbot-2.4.2.6590rc0.dist-info}/RECORD +64 -42
  62. {bbot-2.4.2.dist-info → bbot-2.4.2.6590rc0.dist-info}/LICENSE +0 -0
  63. {bbot-2.4.2.dist-info → bbot-2.4.2.6590rc0.dist-info}/WHEEL +0 -0
  64. {bbot-2.4.2.dist-info → bbot-2.4.2.6590rc0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,343 @@
1
+ import pytest
2
+
3
+
4
+ async def test_web_envelopes():
5
+ from bbot.core.helpers.web.envelopes import (
6
+ BaseEnvelope,
7
+ TextEnvelope,
8
+ HexEnvelope,
9
+ B64Envelope,
10
+ JSONEnvelope,
11
+ XMLEnvelope,
12
+ URLEnvelope,
13
+ )
14
+
15
+ # simple text
16
+ text_envelope = BaseEnvelope.detect("foo")
17
+ assert isinstance(text_envelope, TextEnvelope)
18
+ assert text_envelope.unpacked_data() == "foo"
19
+ assert text_envelope.subparams == {"__default__": "foo"}
20
+ expected_subparams = [([], "foo")]
21
+ assert list(text_envelope.get_subparams()) == expected_subparams
22
+ for subparam, value in expected_subparams:
23
+ assert text_envelope.get_subparam(subparam) == value
24
+ assert text_envelope.pack() == "foo"
25
+ assert text_envelope.num_envelopes == 0
26
+ assert text_envelope.get_subparam() == "foo"
27
+ text_envelope.set_subparam(value="bar")
28
+ assert text_envelope.get_subparam() == "bar"
29
+ assert text_envelope.unpacked_data() == "bar"
30
+
31
+ # simple binary
32
+ # binary_envelope = BaseEnvelope.detect("foo\x00")
33
+ # assert isinstance(binary_envelope, BinaryEnvelope)
34
+ # assert binary_envelope.unpacked_data == "foo\x00"
35
+ # assert binary_envelope.packed_data == "foo\x00"
36
+ # assert binary_envelope.subparams == {"__default__": "foo\x00"}
37
+
38
+ # text encoded as hex
39
+ hex_envelope = BaseEnvelope.detect("706172616d")
40
+ assert isinstance(hex_envelope, HexEnvelope)
41
+ assert hex_envelope.unpacked_data(recursive=True) == "param"
42
+ hex_inner_envelope = hex_envelope.unpacked_data(recursive=False)
43
+ assert isinstance(hex_inner_envelope, TextEnvelope)
44
+ assert hex_inner_envelope.unpacked_data(recursive=False) == "param"
45
+ assert hex_inner_envelope.unpacked_data(recursive=True) == "param"
46
+ assert list(hex_envelope.get_subparams(recursive=False)) == [([], hex_inner_envelope)]
47
+ assert list(hex_envelope.get_subparams(recursive=True)) == [([], "param")]
48
+ assert hex_inner_envelope.unpacked_data() == "param"
49
+ assert hex_inner_envelope.subparams == {"__default__": "param"}
50
+ expected_subparams = [([], "param")]
51
+ assert list(hex_inner_envelope.get_subparams()) == expected_subparams
52
+ for subparam, value in expected_subparams:
53
+ assert hex_inner_envelope.get_subparam(subparam) == value
54
+ assert hex_envelope.pack() == "706172616d"
55
+ assert hex_envelope.num_envelopes == 1
56
+ assert hex_envelope.get_subparam() == "param"
57
+ hex_envelope.set_subparam(value="asdf")
58
+ assert hex_envelope.get_subparam() == "asdf"
59
+ assert hex_envelope.unpacked_data() == "asdf"
60
+ assert hex_envelope.pack() == "61736466"
61
+
62
+ # text encoded as base64
63
+ base64_envelope = BaseEnvelope.detect("cGFyYW0=")
64
+ assert isinstance(base64_envelope, B64Envelope)
65
+ assert base64_envelope.unpacked_data() == "param"
66
+ base64_inner_envelope = base64_envelope.unpacked_data(recursive=False)
67
+ assert isinstance(base64_inner_envelope, TextEnvelope)
68
+ assert list(base64_envelope.get_subparams(recursive=False)) == [([], base64_inner_envelope)]
69
+ assert list(base64_envelope.get_subparams()) == [([], "param")]
70
+ assert base64_inner_envelope.pack() == "param"
71
+ assert base64_inner_envelope.unpacked_data() == "param"
72
+ assert base64_inner_envelope.subparams == {"__default__": "param"}
73
+ expected_subparams = [([], "param")]
74
+ assert list(base64_inner_envelope.get_subparams()) == expected_subparams
75
+ for subparam, value in expected_subparams:
76
+ assert base64_inner_envelope.get_subparam(subparam) == value
77
+ assert base64_envelope.num_envelopes == 1
78
+ base64_envelope.set_subparam(value="asdf")
79
+ assert base64_envelope.get_subparam() == "asdf"
80
+ assert base64_envelope.unpacked_data() == "asdf"
81
+ assert base64_envelope.pack() == "YXNkZg=="
82
+
83
+ # test inside hex inside base64
84
+ hex_envelope = BaseEnvelope.detect("634746795957303d")
85
+ assert isinstance(hex_envelope, HexEnvelope)
86
+ assert hex_envelope.get_subparam() == "param"
87
+ assert hex_envelope.unpacked_data() == "param"
88
+ base64_envelope = hex_envelope.unpacked_data(recursive=False)
89
+ assert isinstance(base64_envelope, B64Envelope)
90
+ assert base64_envelope.get_subparam() == "param"
91
+ assert base64_envelope.unpacked_data() == "param"
92
+ text_envelope = base64_envelope.unpacked_data(recursive=False)
93
+ assert isinstance(text_envelope, TextEnvelope)
94
+ assert text_envelope.get_subparam() == "param"
95
+ assert text_envelope.unpacked_data() == "param"
96
+ hex_envelope.set_subparam(value="asdf")
97
+ assert hex_envelope.get_subparam() == "asdf"
98
+ assert hex_envelope.unpacked_data() == "asdf"
99
+ assert text_envelope.get_subparam() == "asdf"
100
+ assert text_envelope.unpacked_data() == "asdf"
101
+ assert base64_envelope.get_subparam() == "asdf"
102
+ assert base64_envelope.unpacked_data() == "asdf"
103
+
104
+ # URL-encoded text
105
+ url_encoded_envelope = BaseEnvelope.detect("a%20b%20c")
106
+ assert isinstance(url_encoded_envelope, URLEnvelope)
107
+ assert url_encoded_envelope.pack() == "a%20b%20c"
108
+ assert url_encoded_envelope.unpacked_data() == "a b c"
109
+ url_inner_envelope = url_encoded_envelope.unpacked_data(recursive=False)
110
+ assert isinstance(url_inner_envelope, TextEnvelope)
111
+ assert url_inner_envelope.unpacked_data(recursive=False) == "a b c"
112
+ assert url_inner_envelope.unpacked_data(recursive=True) == "a b c"
113
+ assert list(url_encoded_envelope.get_subparams(recursive=False)) == [([], url_inner_envelope)]
114
+ assert list(url_encoded_envelope.get_subparams(recursive=True)) == [([], "a b c")]
115
+ assert url_inner_envelope.pack() == "a b c"
116
+ assert url_inner_envelope.unpacked_data() == "a b c"
117
+ assert url_inner_envelope.subparams == {"__default__": "a b c"}
118
+ expected_subparams = [([], "a b c")]
119
+ assert list(url_inner_envelope.get_subparams()) == expected_subparams
120
+ for subparam, value in expected_subparams:
121
+ assert url_inner_envelope.get_subparam(subparam) == value
122
+ assert url_encoded_envelope.num_envelopes == 1
123
+ url_encoded_envelope.set_subparam(value="a s d f")
124
+ assert url_encoded_envelope.get_subparam() == "a s d f"
125
+ assert url_encoded_envelope.unpacked_data() == "a s d f"
126
+ assert url_encoded_envelope.pack() == "a%20s%20d%20f"
127
+
128
+ # json
129
+ json_envelope = BaseEnvelope.detect('{"param1": "val1", "param2": {"param3": "val3"}}')
130
+ assert isinstance(json_envelope, JSONEnvelope)
131
+ assert json_envelope.pack() == '{"param1": "val1", "param2": {"param3": "val3"}}'
132
+ assert json_envelope.unpacked_data() == {"param1": "val1", "param2": {"param3": "val3"}}
133
+ assert json_envelope.unpacked_data(recursive=False) == {"param1": "val1", "param2": {"param3": "val3"}}
134
+ assert json_envelope.unpacked_data(recursive=True) == {"param1": "val1", "param2": {"param3": "val3"}}
135
+ assert json_envelope.subparams == {"param1": "val1", "param2": {"param3": "val3"}}
136
+ expected_subparams = [
137
+ (["param1"], "val1"),
138
+ (["param2", "param3"], "val3"),
139
+ ]
140
+ assert list(json_envelope.get_subparams()) == expected_subparams
141
+ for subparam, value in expected_subparams:
142
+ assert json_envelope.get_subparam(subparam) == value
143
+ json_envelope.selected_subparam = ["param2", "param3"]
144
+ assert json_envelope.get_subparam() == "val3"
145
+ assert json_envelope.num_envelopes == 1
146
+
147
+ # prevent json over-detection
148
+ just_a_string = BaseEnvelope.detect("10")
149
+ assert not isinstance(just_a_string, JSONEnvelope)
150
+
151
+ # xml
152
+ xml_envelope = BaseEnvelope.detect(
153
+ '<root><param1 attr="attr1">val1</param1><param2><param3>val3</param3></param2></root>'
154
+ )
155
+ assert isinstance(xml_envelope, XMLEnvelope)
156
+ assert (
157
+ xml_envelope.pack()
158
+ == '<?xml version="1.0" encoding="utf-8"?>\n<root><param1 attr="attr1">val1</param1><param2><param3>val3</param3></param2></root>'
159
+ )
160
+ assert xml_envelope.unpacked_data() == {
161
+ "root": {"param1": {"@attr": "attr1", "#text": "val1"}, "param2": {"param3": "val3"}}
162
+ }
163
+ assert xml_envelope.unpacked_data(recursive=False) == {
164
+ "root": {"param1": {"@attr": "attr1", "#text": "val1"}, "param2": {"param3": "val3"}}
165
+ }
166
+ assert xml_envelope.unpacked_data(recursive=True) == {
167
+ "root": {"param1": {"@attr": "attr1", "#text": "val1"}, "param2": {"param3": "val3"}}
168
+ }
169
+ assert xml_envelope.subparams == {
170
+ "root": {"param1": {"@attr": "attr1", "#text": "val1"}, "param2": {"param3": "val3"}}
171
+ }
172
+ expected_subparams = [
173
+ (["root", "param1", "@attr"], "attr1"),
174
+ (["root", "param1", "#text"], "val1"),
175
+ (["root", "param2", "param3"], "val3"),
176
+ ]
177
+ assert list(xml_envelope.get_subparams()) == expected_subparams
178
+ for subparam, value in expected_subparams:
179
+ assert xml_envelope.get_subparam(subparam) == value
180
+ assert xml_envelope.num_envelopes == 1
181
+
182
+ # json inside base64
183
+ base64_json_envelope = BaseEnvelope.detect("eyJwYXJhbTEiOiAidmFsMSIsICJwYXJhbTIiOiB7InBhcmFtMyI6ICJ2YWwzIn19")
184
+ assert isinstance(base64_json_envelope, B64Envelope)
185
+ assert base64_json_envelope.pack() == "eyJwYXJhbTEiOiAidmFsMSIsICJwYXJhbTIiOiB7InBhcmFtMyI6ICJ2YWwzIn19"
186
+ assert base64_json_envelope.unpacked_data() == {"param1": "val1", "param2": {"param3": "val3"}}
187
+ base64_inner_envelope = base64_json_envelope.unpacked_data(recursive=False)
188
+ assert isinstance(base64_inner_envelope, JSONEnvelope)
189
+ assert base64_inner_envelope.pack() == '{"param1": "val1", "param2": {"param3": "val3"}}'
190
+ assert base64_inner_envelope.unpacked_data() == {"param1": "val1", "param2": {"param3": "val3"}}
191
+ assert base64_inner_envelope.subparams == {"param1": "val1", "param2": {"param3": "val3"}}
192
+ expected_subparams = [
193
+ (["param1"], "val1"),
194
+ (["param2", "param3"], "val3"),
195
+ ]
196
+ assert list(base64_json_envelope.get_subparams()) == expected_subparams
197
+ for subparam, value in expected_subparams:
198
+ assert base64_json_envelope.get_subparam(subparam) == value
199
+ assert base64_json_envelope.num_envelopes == 2
200
+ with pytest.raises(ValueError):
201
+ assert base64_json_envelope.get_subparam()
202
+ base64_json_envelope.selected_subparam = ["param2", "param3"]
203
+ assert base64_json_envelope.get_subparam() == "val3"
204
+
205
+ # xml inside url inside hex inside base64
206
+ nested_xml_envelope = BaseEnvelope.detect(
207
+ "MjUzMzYzMjUzNzMyMjUzNjY2MjUzNjY2MjUzNzM0MjUzMzY1MjUzMzYzMjUzNzMwMjUzNjMxMjUzNzMyMjUzNjMxMjUzNjY0MjUzMzMxMjUzMjMwMjUzNjMxMjUzNzM0MjUzNzM0MjUzNzMyMjUzMzY0MjUzMjMyMjUzNzM2MjUzNjMxMjUzNjYzMjUzMzMxMjUzMjMyMjUzMzY1MjUzNzM2MjUzNjMxMjUzNjYzMjUzMzMxMjUzMzYzMjUzMjY2MjUzNzMwMjUzNjMxMjUzNzMyMjUzNjMxMjUzNjY0MjUzMzMxMjUzMzY1MjUzMzYzMjUzNzMwMjUzNjMxMjUzNzMyMjUzNjMxMjUzNjY0MjUzMzMyMjUzMzY1MjUzMzYzMjUzNzMwMjUzNjMxMjUzNzMyMjUzNjMxMjUzNjY0MjUzMzMzMjUzMzY1MjUzNzM2MjUzNjMxMjUzNjYzMjUzMzMzMjUzMzYzMjUzMjY2MjUzNzMwMjUzNjMxMjUzNzMyMjUzNjMxMjUzNjY0MjUzMzMzMjUzMzY1MjUzMzYzMjUzMjY2MjUzNzMwMjUzNjMxMjUzNzMyMjUzNjMxMjUzNjY0MjUzMzMyMjUzMzY1MjUzMzYzMjUzMjY2MjUzNzMyMjUzNjY2MjUzNjY2MjUzNzM0MjUzMzY1"
208
+ )
209
+ assert isinstance(nested_xml_envelope, B64Envelope)
210
+ assert nested_xml_envelope.unpacked_data() == {
211
+ "root": {"param1": {"@attr": "val1", "#text": "val1"}, "param2": {"param3": "val3"}}
212
+ }
213
+ assert (
214
+ nested_xml_envelope.pack()
215
+ == "MjUzMzQzMjUzMzQ2Nzg2ZDZjMjUzMjMwNzY2NTcyNzM2OTZmNmUyNTMzNDQyNTMyMzIzMTJlMzAyNTMyMzIyNTMyMzA2NTZlNjM2ZjY0Njk2ZTY3MjUzMzQ0MjUzMjMyNzU3NDY2MmQzODI1MzIzMjI1MzM0NjI1MzM0NTI1MzA0MTI1MzM0MzcyNmY2Zjc0MjUzMzQ1MjUzMzQzNzA2MTcyNjE2ZDMxMjUzMjMwNjE3NDc0NzIyNTMzNDQyNTMyMzI3NjYxNmMzMTI1MzIzMjI1MzM0NTc2NjE2YzMxMjUzMzQzMmY3MDYxNzI2MTZkMzEyNTMzNDUyNTMzNDM3MDYxNzI2MTZkMzIyNTMzNDUyNTMzNDM3MDYxNzI2MTZkMzMyNTMzNDU3NjYxNmMzMzI1MzM0MzJmNzA2MTcyNjE2ZDMzMjUzMzQ1MjUzMzQzMmY3MDYxNzI2MTZkMzIyNTMzNDUyNTMzNDMyZjcyNmY2Zjc0MjUzMzQ1"
216
+ )
217
+ inner_hex_envelope = nested_xml_envelope.unpacked_data(recursive=False)
218
+ assert isinstance(inner_hex_envelope, HexEnvelope)
219
+ assert (
220
+ inner_hex_envelope.pack()
221
+ == "253343253346786d6c25323076657273696f6e253344253232312e30253232253230656e636f64696e672533442532327574662d38253232253346253345253041253343726f6f74253345253343706172616d312532306174747225334425323276616c3125323225334576616c312533432f706172616d31253345253343706172616d32253345253343706172616d3325334576616c332533432f706172616d332533452533432f706172616d322533452533432f726f6f74253345"
222
+ )
223
+ inner_url_envelope = inner_hex_envelope.unpacked_data(recursive=False)
224
+ assert isinstance(inner_url_envelope, URLEnvelope)
225
+ assert (
226
+ inner_url_envelope.pack()
227
+ == r"%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0A%3Croot%3E%3Cparam1%20attr%3D%22val1%22%3Eval1%3C/param1%3E%3Cparam2%3E%3Cparam3%3Eval3%3C/param3%3E%3C/param2%3E%3C/root%3E"
228
+ )
229
+ inner_xml_envelope = inner_url_envelope.unpacked_data(recursive=False)
230
+ assert isinstance(inner_xml_envelope, XMLEnvelope)
231
+ assert (
232
+ inner_xml_envelope.pack()
233
+ == '<?xml version="1.0" encoding="utf-8"?>\n<root><param1 attr="val1">val1</param1><param2><param3>val3</param3></param2></root>'
234
+ )
235
+ assert inner_xml_envelope.unpacked_data() == {
236
+ "root": {"param1": {"@attr": "val1", "#text": "val1"}, "param2": {"param3": "val3"}}
237
+ }
238
+ assert inner_xml_envelope.subparams == {
239
+ "root": {"param1": {"@attr": "val1", "#text": "val1"}, "param2": {"param3": "val3"}}
240
+ }
241
+ expected_subparams = [
242
+ (["root", "param1", "@attr"], "val1"),
243
+ (["root", "param1", "#text"], "val1"),
244
+ (["root", "param2", "param3"], "val3"),
245
+ ]
246
+ assert list(nested_xml_envelope.get_subparams()) == expected_subparams
247
+ for subparam, value in expected_subparams:
248
+ assert nested_xml_envelope.get_subparam(subparam) == value
249
+ assert nested_xml_envelope.num_envelopes == 4
250
+
251
+ # manipulating text inside hex
252
+ hex_envelope = BaseEnvelope.detect("706172616d")
253
+ expected_subparams = [([], "param")]
254
+ assert list(hex_envelope.get_subparams()) == expected_subparams
255
+ for subparam, value in expected_subparams:
256
+ assert hex_envelope.get_subparam(subparam) == value
257
+ hex_envelope.set_subparam([], "asdf")
258
+ expected_subparams = [([], "asdf")]
259
+ assert list(hex_envelope.get_subparams()) == expected_subparams
260
+ for subparam, value in expected_subparams:
261
+ assert hex_envelope.get_subparam(subparam) == value
262
+ assert hex_envelope.unpacked_data() == "asdf"
263
+
264
+ # manipulating json inside base64
265
+ base64_json_envelope = BaseEnvelope.detect("eyJwYXJhbTEiOiAidmFsMSIsICJwYXJhbTIiOiB7InBhcmFtMyI6ICJ2YWwzIn19")
266
+ expected_subparams = [
267
+ (["param1"], "val1"),
268
+ (["param2", "param3"], "val3"),
269
+ ]
270
+ assert list(base64_json_envelope.get_subparams()) == expected_subparams
271
+ for subparam, value in expected_subparams:
272
+ assert base64_json_envelope.get_subparam(subparam) == value
273
+ base64_json_envelope.set_subparam(["param1"], {"asdf": [None], "fdsa": 1.0})
274
+ expected_subparams = [
275
+ (["param1", "asdf"], [None]),
276
+ (["param1", "fdsa"], 1.0),
277
+ (["param2", "param3"], "val3"),
278
+ ]
279
+ assert list(base64_json_envelope.get_subparams()) == expected_subparams
280
+ for subparam, value in expected_subparams:
281
+ assert base64_json_envelope.get_subparam(subparam) == value
282
+ base64_json_envelope.set_subparam(["param2", "param3"], {"1234": [None], "4321": 1.0})
283
+ expected_subparams = [
284
+ (["param1", "asdf"], [None]),
285
+ (["param1", "fdsa"], 1.0),
286
+ (["param2", "param3", "1234"], [None]),
287
+ (["param2", "param3", "4321"], 1.0),
288
+ ]
289
+ assert list(base64_json_envelope.get_subparams()) == expected_subparams
290
+ base64_json_envelope.set_subparam(["param2"], None)
291
+ expected_subparams = [
292
+ (["param1", "asdf"], [None]),
293
+ (["param1", "fdsa"], 1.0),
294
+ (["param2"], None),
295
+ ]
296
+ assert list(base64_json_envelope.get_subparams()) == expected_subparams
297
+
298
+ # xml inside url inside base64
299
+ xml_envelope = BaseEnvelope.detect(
300
+ "JTNDP3htbCUyMHZlcnNpb249JTIyMS4wJTIyJTIwZW5jb2Rpbmc9JTIydXRmLTglMjI/JTNFJTBBJTNDcm9vdCUzRSUzQ3BhcmFtMSUyMGF0dHI9JTIydmFsMSUyMiUzRXZhbDElM0MvcGFyYW0xJTNFJTNDcGFyYW0yJTNFJTNDcGFyYW0zJTNFdmFsMyUzQy9wYXJhbTMlM0UlM0MvcGFyYW0yJTNFJTNDL3Jvb3QlM0U="
301
+ )
302
+ assert (
303
+ xml_envelope.pack()
304
+ == "JTNDJTNGeG1sJTIwdmVyc2lvbiUzRCUyMjEuMCUyMiUyMGVuY29kaW5nJTNEJTIydXRmLTglMjIlM0YlM0UlMEElM0Nyb290JTNFJTNDcGFyYW0xJTIwYXR0ciUzRCUyMnZhbDElMjIlM0V2YWwxJTNDL3BhcmFtMSUzRSUzQ3BhcmFtMiUzRSUzQ3BhcmFtMyUzRXZhbDMlM0MvcGFyYW0zJTNFJTNDL3BhcmFtMiUzRSUzQy9yb290JTNF"
305
+ )
306
+ expected_subparams = [
307
+ (["root", "param1", "@attr"], "val1"),
308
+ (["root", "param1", "#text"], "val1"),
309
+ (["root", "param2", "param3"], "val3"),
310
+ ]
311
+ assert list(xml_envelope.get_subparams()) == expected_subparams
312
+ xml_envelope.set_subparam(["root", "param1", "@attr"], "asdf")
313
+ expected_subparams = [
314
+ (["root", "param1", "@attr"], "asdf"),
315
+ (["root", "param1", "#text"], "val1"),
316
+ (["root", "param2", "param3"], "val3"),
317
+ ]
318
+ assert list(xml_envelope.get_subparams()) == expected_subparams
319
+ assert (
320
+ xml_envelope.pack()
321
+ == "JTNDJTNGeG1sJTIwdmVyc2lvbiUzRCUyMjEuMCUyMiUyMGVuY29kaW5nJTNEJTIydXRmLTglMjIlM0YlM0UlMEElM0Nyb290JTNFJTNDcGFyYW0xJTIwYXR0ciUzRCUyMmFzZGYlMjIlM0V2YWwxJTNDL3BhcmFtMSUzRSUzQ3BhcmFtMiUzRSUzQ3BhcmFtMyUzRXZhbDMlM0MvcGFyYW0zJTNFJTNDL3BhcmFtMiUzRSUzQy9yb290JTNF"
322
+ )
323
+ xml_envelope.set_subparam(["root", "param2", "param3"], {"1234": [None], "4321": 1.0})
324
+ expected_subparams = [
325
+ (["root", "param1", "@attr"], "asdf"),
326
+ (["root", "param1", "#text"], "val1"),
327
+ (["root", "param2", "param3", "1234"], [None]),
328
+ (["root", "param2", "param3", "4321"], 1.0),
329
+ ]
330
+ assert list(xml_envelope.get_subparams()) == expected_subparams
331
+
332
+ # null
333
+ null_envelope = BaseEnvelope.detect("null")
334
+ assert isinstance(null_envelope, JSONEnvelope)
335
+ assert null_envelope.unpacked_data() is None
336
+ assert null_envelope.pack() == "null"
337
+ expected_subparams = [([], None)]
338
+ assert list(null_envelope.get_subparams()) == expected_subparams
339
+ for subparam, value in expected_subparams:
340
+ assert null_envelope.get_subparam(subparam) == value
341
+
342
+ tiny_base64 = BaseEnvelope.detect("YWJi")
343
+ assert isinstance(tiny_base64, TextEnvelope)