prelude-sdk 2.6.39__py3-none-any.whl → 2.6.41__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.
@@ -14,38 +14,33 @@ class BuildController(HttpController):
14
14
  def clone_test(self, source_test_id):
15
15
  """Clone a test"""
16
16
  res = self.post(
17
- f"{self.account.hq}/build/tests",
18
- json=dict(source_test_id=source_test_id),
19
- headers=self.account.headers,
20
- timeout=10,
17
+ f"{self.account.hq}/build/tests", json=dict(source_test_id=source_test_id)
21
18
  )
22
19
  return res.json()
23
20
 
24
21
  @verify_credentials
25
- def create_test(self, name, unit, technique=None, test_id=None):
22
+ def create_test(self, name, unit, schedulable=None, technique=None, test_id=None):
26
23
  """Create or update a test"""
27
24
  body = dict(name=name, unit=unit)
25
+ if schedulable is not None:
26
+ body["schedulable"] = schedulable
28
27
  if technique:
29
28
  body["technique"] = technique
30
29
  if test_id:
31
30
  body["id"] = test_id
32
31
 
33
- res = self.post(
34
- f"{self.account.hq}/build/tests",
35
- json=body,
36
- headers=self.account.headers,
37
- timeout=10,
38
- )
32
+ res = self.post(f"{self.account.hq}/build/tests", json=body)
39
33
  return res.json()
40
34
 
41
35
  @verify_credentials
42
36
  def update_test(
43
37
  self,
44
38
  test_id,
39
+ crowdstrike_expected_outcome: EDRResponse = None,
45
40
  name=None,
46
- unit=None,
41
+ schedulable=None,
47
42
  technique=None,
48
- crowdstrike_expected_outcome: EDRResponse = None,
43
+ unit=None,
49
44
  ):
50
45
  """Update a test"""
51
46
  body = dict()
@@ -53,38 +48,28 @@ class BuildController(HttpController):
53
48
  body["expected"] = dict(crowdstrike=crowdstrike_expected_outcome.value)
54
49
  if name:
55
50
  body["name"] = name
56
- if unit:
57
- body["unit"] = unit
51
+ if schedulable is not None:
52
+ body["schedulable"] = schedulable
58
53
  if technique is not None:
59
54
  body["technique"] = technique
55
+ if unit:
56
+ body["unit"] = unit
60
57
 
61
- res = self.post(
62
- f"{self.account.hq}/build/tests/{test_id}",
63
- json=body,
64
- headers=self.account.headers,
65
- timeout=10,
66
- )
58
+ res = self.post(f"{self.account.hq}/build/tests/{test_id}", json=body)
67
59
  return res.json()
68
60
 
69
61
  @verify_credentials
70
62
  def delete_test(self, test_id, purge):
71
63
  """Delete an existing test"""
72
64
  res = self.delete(
73
- f"{self.account.hq}/build/tests/{test_id}",
74
- json=dict(purge=purge),
75
- headers=self.account.headers,
76
- timeout=10,
65
+ f"{self.account.hq}/build/tests/{test_id}", json=dict(purge=purge)
77
66
  )
78
67
  return res.json()
79
68
 
80
69
  @verify_credentials
81
70
  def undelete_test(self, test_id):
82
71
  """Undelete a tombstoned test"""
83
- res = self.post(
84
- f"{self.account.hq}/build/tests/{test_id}/undelete",
85
- headers=self.account.headers,
86
- timeout=10,
87
- )
72
+ res = self.post(f"{self.account.hq}/build/tests/{test_id}/undelete")
88
73
  return res.json()
89
74
 
90
75
  @verify_credentials
@@ -97,11 +82,11 @@ class BuildController(HttpController):
97
82
  query_params = ""
98
83
  if skip_compile:
99
84
  query_params = "?" + urllib.parse.urlencode(dict(skip_compile=True))
85
+
100
86
  res = self.post(
101
87
  f"{self.account.hq}/build/tests/{test_id}/{filename}{query_params}",
102
88
  data=data,
103
89
  headers=h,
104
- timeout=10,
105
90
  )
106
91
  return res.json()
107
92
 
@@ -111,41 +96,39 @@ class BuildController(HttpController):
111
96
  res = self.post(
112
97
  f"{self.account.hq}/build/compile",
113
98
  json=dict(code=code, source_test_id=source_test_id),
114
- headers=self.account.headers,
115
- timeout=10,
116
99
  )
117
100
  return res.json()
118
101
 
119
102
  @verify_credentials
120
103
  def get_compile_status(self, job_id):
121
- res = self.get(
122
- f"{self.account.hq}/build/compile/{job_id}",
123
- headers=self.account.headers,
124
- timeout=10,
125
- )
104
+ res = self.get(f"{self.account.hq}/build/compile/{job_id}")
126
105
  return res.json()
127
106
 
128
107
  @verify_credentials
129
108
  def create_threat(
130
- self, name, published, threat_id=None, source_id=None, source=None, tests=None
109
+ self,
110
+ name,
111
+ published,
112
+ schedulable=None,
113
+ source=None,
114
+ source_id=None,
115
+ tests=None,
116
+ threat_id=None,
131
117
  ):
132
118
  """Create a threat"""
133
119
  body = dict(name=name, published=published)
134
- if threat_id:
135
- body["id"] = threat_id
136
- if source_id:
137
- body["source_id"] = source_id
120
+ if schedulable is not None:
121
+ body["schedulable"] = schedulable
138
122
  if source:
139
123
  body["source"] = source
124
+ if source_id:
125
+ body["source_id"] = source_id
140
126
  if tests:
141
127
  body["tests"] = tests
128
+ if threat_id:
129
+ body["id"] = threat_id
142
130
 
143
- res = self.post(
144
- f"{self.account.hq}/build/threats",
145
- json=body,
146
- headers=self.account.headers,
147
- timeout=10,
148
- )
131
+ res = self.post(f"{self.account.hq}/build/threats", json=body)
149
132
  return res.json()
150
133
 
151
134
  @verify_credentials
@@ -153,30 +136,28 @@ class BuildController(HttpController):
153
136
  self,
154
137
  threat_id,
155
138
  name=None,
156
- source_id=None,
157
- source=None,
158
139
  published=None,
140
+ schedulable=None,
141
+ source=None,
142
+ source_id=None,
159
143
  tests=None,
160
144
  ):
161
145
  """Update a threat"""
162
146
  body = dict()
163
147
  if name:
164
148
  body["name"] = name
165
- if source_id is not None:
166
- body["source_id"] = source_id
167
- if source is not None:
168
- body["source"] = source
169
149
  if published is not None:
170
150
  body["published"] = published
151
+ if schedulable is not None:
152
+ body["schedulable"] = schedulable
153
+ if source is not None:
154
+ body["source"] = source
155
+ if source_id is not None:
156
+ body["source_id"] = source_id
171
157
  if tests is not None:
172
158
  body["tests"] = tests
173
159
 
174
- res = self.post(
175
- f"{self.account.hq}/build/threats/{threat_id}",
176
- json=body,
177
- headers=self.account.headers,
178
- timeout=10,
179
- )
160
+ res = self.post(f"{self.account.hq}/build/threats/{threat_id}", json=body)
180
161
  return res.json()
181
162
 
182
163
  @verify_credentials
@@ -185,19 +166,13 @@ class BuildController(HttpController):
185
166
  res = self.delete(
186
167
  f"{self.account.hq}/build/threats/{threat_id}",
187
168
  json=dict(purge=purge),
188
- headers=self.account.headers,
189
- timeout=10,
190
169
  )
191
170
  return res.json()
192
171
 
193
172
  @verify_credentials
194
173
  def undelete_threat(self, threat_id):
195
174
  """Undelete a tombstoned threat"""
196
- res = self.post(
197
- f"{self.account.hq}/build/threats/{threat_id}/undelete",
198
- headers=self.account.headers,
199
- timeout=10,
200
- )
175
+ res = self.post(f"{self.account.hq}/build/threats/{threat_id}/undelete")
201
176
  return res.json()
202
177
 
203
178
  @verify_credentials
@@ -211,12 +186,7 @@ class BuildController(HttpController):
211
186
  if rule_id:
212
187
  body["rule_id"] = rule_id
213
188
 
214
- res = self.post(
215
- f"{self.account.hq}/build/detections",
216
- json=body,
217
- headers=self.account.headers,
218
- timeout=10,
219
- )
189
+ res = self.post(f"{self.account.hq}/build/detections", json=body)
220
190
  return res.json()
221
191
 
222
192
  @verify_credentials
@@ -228,22 +198,13 @@ class BuildController(HttpController):
228
198
  if test_id:
229
199
  body["test_id"] = test_id
230
200
 
231
- res = self.post(
232
- f"{self.account.hq}/build/detections/{detection_id}",
233
- json=body,
234
- headers=self.account.headers,
235
- timeout=10,
236
- )
201
+ res = self.post(f"{self.account.hq}/build/detections/{detection_id}", json=body)
237
202
  return res.json()
238
203
 
239
204
  @verify_credentials
240
205
  def delete_detection(self, detection_id: str):
241
206
  """Delete an existing detection"""
242
- res = self.delete(
243
- f"{self.account.hq}/build/detections/{detection_id}",
244
- headers=self.account.headers,
245
- timeout=10,
246
- )
207
+ res = self.delete(f"{self.account.hq}/build/detections/{detection_id}")
247
208
  return res.json()
248
209
 
249
210
  @verify_credentials
@@ -265,12 +226,7 @@ class BuildController(HttpController):
265
226
  if threat_hunt_id:
266
227
  body["id"] = threat_hunt_id
267
228
 
268
- res = self.post(
269
- f"{self.account.hq}/build/threat_hunts",
270
- json=body,
271
- headers=self.account.headers,
272
- timeout=10,
273
- )
229
+ res = self.post(f"{self.account.hq}/build/threat_hunts", json=body)
274
230
  threat_hunt = res.json()
275
231
  if self.account.resolve_enums:
276
232
  self.resolve_enums(threat_hunt, [(Control, "control")])
@@ -294,10 +250,7 @@ class BuildController(HttpController):
294
250
  body["test_id"] = test_id
295
251
 
296
252
  res = self.post(
297
- f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}",
298
- json=body,
299
- headers=self.account.headers,
300
- timeout=10,
253
+ f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}", json=body
301
254
  )
302
255
  threat_hunt = res.json()
303
256
  if self.account.resolve_enums:
@@ -307,9 +260,5 @@ class BuildController(HttpController):
307
260
  @verify_credentials
308
261
  def delete_threat_hunt(self, threat_hunt_id: str):
309
262
  """Delete an existing threat hunt"""
310
- res = self.delete(
311
- f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}",
312
- headers=self.account.headers,
313
- timeout=10,
314
- )
263
+ res = self.delete(f"{self.account.hq}/build/threat_hunts/{threat_hunt_id}")
315
264
  return res.json()
@@ -19,7 +19,6 @@ class DetectController(HttpController):
19
19
  f"{self.account.hq}/detect/endpoint",
20
20
  headers=dict(account=account, token=token, _product="py-sdk"),
21
21
  json=body,
22
- timeout=10,
23
22
  )
24
23
  return res.text
25
24
 
@@ -30,36 +29,23 @@ class DetectController(HttpController):
30
29
  if tags is not None:
31
30
  body["tags"] = tags
32
31
 
33
- res = self.post(
34
- f"{self.account.hq}/detect/endpoint/{endpoint_id}",
35
- headers=self.account.headers,
36
- json=body,
37
- timeout=10,
38
- )
32
+ res = self.post(f"{self.account.hq}/detect/endpoint/{endpoint_id}", json=body)
39
33
  return res.json()
40
34
 
41
35
  @verify_credentials
42
36
  def delete_endpoint(self, ident: str):
43
37
  """Delete an endpoint from your account"""
44
38
  params = dict(id=ident)
45
- res = self.delete(
46
- f"{self.account.hq}/detect/endpoint",
47
- headers=self.account.headers,
48
- json=params,
49
- timeout=10,
50
- )
39
+
40
+ res = self.delete(f"{self.account.hq}/detect/endpoint", json=params)
51
41
  return res.json()
52
42
 
53
43
  @verify_credentials
54
44
  def list_endpoints(self, days: int = 90):
55
45
  """List all endpoints on your account"""
56
46
  params = dict(days=days)
57
- res = self.get(
58
- f"{self.account.hq}/detect/endpoint",
59
- headers=self.account.headers,
60
- params=params,
61
- timeout=10,
62
- )
47
+
48
+ res = self.get(f"{self.account.hq}/detect/endpoint", params=params)
63
49
  endpoints = res.json()
64
50
  if self.account.resolve_enums:
65
51
  self.resolve_enums(endpoints, [(Control, "control")])
@@ -69,57 +55,38 @@ class DetectController(HttpController):
69
55
  def describe_activity(self, filters: dict, view: str = "protected"):
70
56
  """Get report for an Account"""
71
57
  params = dict(view=view, **filters)
72
- res = self.get(
73
- f"{self.account.hq}/detect/activity",
74
- headers=self.account.headers,
75
- params=params,
76
- timeout=10,
77
- )
58
+
59
+ res = self.get(f"{self.account.hq}/detect/activity", params=params)
78
60
  return res.json()
79
61
 
80
62
  @verify_credentials
81
63
  def threat_hunt_activity(self, threat_hunt_id=None, test_id=None, threat_id=None):
82
64
  """Get threat hunt activity"""
83
- filters = dict(
65
+ params = dict(
84
66
  threat_hunt_id=threat_hunt_id, test_id=test_id, threat_id=threat_id
85
67
  )
86
- res = self.get(
87
- f"{self.account.hq}/detect/threat_hunt_activity",
88
- headers=self.account.headers,
89
- params=filters,
90
- timeout=10,
91
- )
68
+
69
+ res = self.get(f"{self.account.hq}/detect/threat_hunt_activity", params=params)
92
70
  return res.json()
93
71
 
94
72
  @verify_credentials
95
73
  def list_tests(self, filters: dict = None):
96
74
  """List all tests available to an account"""
97
75
  res = self.get(
98
- f"{self.account.hq}/detect/tests",
99
- headers=self.account.headers,
100
- params=filters if filters else {},
101
- timeout=10,
76
+ f"{self.account.hq}/detect/tests", params=filters if filters else {}
102
77
  )
103
78
  return res.json()
104
79
 
105
80
  @verify_credentials
106
81
  def get_test(self, test_id):
107
82
  """Get properties of an existing test"""
108
- res = self.get(
109
- f"{self.account.hq}/detect/tests/{test_id}",
110
- headers=self.account.headers,
111
- timeout=10,
112
- )
83
+ res = self.get(f"{self.account.hq}/detect/tests/{test_id}")
113
84
  return res.json()
114
85
 
115
86
  @verify_credentials
116
87
  def list_techniques(self):
117
88
  """List techniques"""
118
- res = self.get(
119
- f"{self.account.hq}/detect/techniques",
120
- headers=self.account.headers,
121
- timeout=10,
122
- )
89
+ res = self.get(f"{self.account.hq}/detect/techniques")
123
90
  return res.json()
124
91
 
125
92
  @verify_credentials
@@ -127,51 +94,32 @@ class DetectController(HttpController):
127
94
  """List threats"""
128
95
  res = self.get(
129
96
  f"{self.account.hq}/detect/threats",
130
- headers=self.account.headers,
131
- params={},
132
- timeout=10,
133
97
  )
134
98
  return res.json()
135
99
 
136
100
  @verify_credentials
137
101
  def get_threat(self, threat_id):
138
102
  """Get properties of an existing threat"""
139
- res = self.get(
140
- f"{self.account.hq}/detect/threats/{threat_id}",
141
- headers=self.account.headers,
142
- timeout=10,
143
- )
103
+ res = self.get(f"{self.account.hq}/detect/threats/{threat_id}")
144
104
  return res.json()
145
105
 
146
106
  @verify_credentials
147
107
  def list_detections(self):
148
108
  """List detections"""
149
- res = self.get(
150
- f"{self.account.hq}/detect/detections",
151
- headers=self.account.headers,
152
- params={},
153
- timeout=10,
154
- )
109
+ res = self.get(f"{self.account.hq}/detect/detections")
155
110
  return res.json()
156
111
 
157
112
  @verify_credentials
158
113
  def get_detection(self, detection_id):
159
114
  """Get properties of an existing detection"""
160
- res = self.get(
161
- f"{self.account.hq}/detect/detections/{detection_id}",
162
- headers=self.account.headers,
163
- timeout=10,
164
- )
115
+ res = self.get(f"{self.account.hq}/detect/detections/{detection_id}")
165
116
  return res.json()
166
117
 
167
118
  @verify_credentials
168
119
  def list_threat_hunts(self, filters: dict = None):
169
120
  """List threat hunts"""
170
121
  res = self.get(
171
- f"{self.account.hq}/detect/threat_hunts",
172
- headers=self.account.headers,
173
- params=filters if filters else {},
174
- timeout=10,
122
+ f"{self.account.hq}/detect/threat_hunts", params=filters if filters else {}
175
123
  )
176
124
  threat_hunts = res.json()
177
125
  if self.account.resolve_enums:
@@ -181,11 +129,7 @@ class DetectController(HttpController):
181
129
  @verify_credentials
182
130
  def get_threat_hunt(self, threat_hunt_id):
183
131
  """Get properties of an existing threat hunt"""
184
- res = self.get(
185
- f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}",
186
- headers=self.account.headers,
187
- timeout=10,
188
- )
132
+ res = self.get(f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}")
189
133
  threat_hunt = res.json()
190
134
  if self.account.resolve_enums:
191
135
  self.resolve_enums(threat_hunt, [(Control, "control")])
@@ -195,35 +139,27 @@ class DetectController(HttpController):
195
139
  def do_threat_hunt(self, threat_hunt_id):
196
140
  """Run a threat hunt"""
197
141
  res = self.post(
198
- f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}",
199
- headers=self.account.headers,
200
- timeout=30,
142
+ f"{self.account.hq}/detect/threat_hunts/{threat_hunt_id}", timeout=30
201
143
  )
202
144
  return res.json()
203
145
 
204
146
  @verify_credentials
205
147
  def download(self, test_id, filename):
206
148
  """Clone a test file or attachment"""
207
- res = self.get(
208
- f"{self.account.hq}/detect/tests/{test_id}/{filename}",
209
- headers=self.account.headers,
210
- timeout=10,
211
- )
149
+ res = self.get(f"{self.account.hq}/detect/tests/{test_id}/{filename}")
212
150
  return res.content
213
151
 
214
152
  @verify_credentials
215
153
  def schedule(self, items: list):
216
- """Schedule tests and threats so endpoints will start running them
154
+ """
155
+ Schedule tests and threats so endpoints will start running them
217
156
 
218
157
  Example: items=[dict(run_code='DAILY', tags='grp-1,grp2', test_id='123-123-123'),
219
158
  dict(run_code='DAILY', tags='grp-1', threat_id='abc-def-ghi')]
220
159
  """
221
- res = self.post(
222
- url=f"{self.account.hq}/detect/queue",
223
- headers=self.account.headers,
224
- json=dict(items=items),
225
- timeout=10,
226
- )
160
+ body = dict(items=items)
161
+
162
+ res = self.post(url=f"{self.account.hq}/detect/queue", json=body)
227
163
  schedule = res.json()
228
164
  if self.account.resolve_enums:
229
165
  self.resolve_enums(schedule, [(RunCode, "run_code")])
@@ -231,26 +167,21 @@ class DetectController(HttpController):
231
167
 
232
168
  @verify_credentials
233
169
  def unschedule(self, items: list):
234
- """Unschedule tests and threats so endpoints will stop running them
170
+ """
171
+ Unschedule tests and threats so endpoints will stop running them
235
172
 
236
173
  Example: items=[dict(tags='grp-1,grp2', test_id='123-123-123'),
237
174
  dict(tags='grp-1', threat_id='abc-def-ghi')]
238
175
  """
239
- res = self.delete(
240
- f"{self.account.hq}/detect/queue",
241
- headers=self.account.headers,
242
- json=dict(items=items),
243
- timeout=10,
244
- )
176
+ body = dict(items=items)
177
+
178
+ res = self.delete(f"{self.account.hq}/detect/queue", json=body)
245
179
  return res.json()
246
180
 
247
181
  @verify_credentials
248
182
  def accept_terms(self, name, version):
249
183
  """Accept terms and conditions"""
250
- res = self.post(
251
- f"{self.account.hq}/iam/terms",
252
- headers=self.account.headers,
253
- json=dict(name=name, version=version),
254
- timeout=10,
255
- )
184
+ body = dict(name=name, version=version)
185
+
186
+ res = self.post(f"{self.account.hq}/iam/terms", json=body)
256
187
  return res.json()
@@ -17,15 +17,11 @@ class ExportController(HttpController):
17
17
  top: int = None,
18
18
  ):
19
19
  """Download partner data as a CSV"""
20
- params = {
20
+ body = {
21
21
  "$filter": filter,
22
22
  "$orderby": orderby,
23
23
  "$top": top,
24
24
  }
25
- res = self.post(
26
- f"{self.account.hq}/export/scm/{export_type.name}",
27
- params=params,
28
- headers=self.account.headers,
29
- timeout=10,
30
- )
25
+
26
+ res = self.post(f"{self.account.hq}/export/scm/{export_type.name}", json=body)
31
27
  return res.json()
@@ -11,6 +11,7 @@ class GenerateController(HttpController):
11
11
  def upload_threat_intel(self, file: str):
12
12
  with open(file, "rb") as f:
13
13
  body = f.read()
14
+
14
15
  res = self.post(
15
16
  f"{self.account.hq}/generate/threat-intel",
16
17
  data=body,
@@ -21,19 +22,15 @@ class GenerateController(HttpController):
21
22
 
22
23
  @verify_credentials
23
24
  def get_threat_intel(self, job_id: str):
24
- res = self.get(
25
- f"{self.account.hq}/generate/threat-intel/{job_id}",
26
- headers=self.account.headers,
27
- timeout=10,
28
- )
25
+ res = self.get(f"{self.account.hq}/generate/threat-intel/{job_id}")
29
26
  return res.json()
30
27
 
31
28
  @verify_credentials
32
29
  def generate_from_partner_advisory(self, partner: Control, advisory_id: str):
33
30
  params = dict(advisory_id=advisory_id)
31
+
34
32
  res = self.post(
35
33
  f"{self.account.hq}/generate/partner-advisories/{partner.name}",
36
- headers=self.account.headers,
37
34
  json=params,
38
35
  timeout=30,
39
36
  )
@@ -42,42 +42,58 @@ class HttpController(object):
42
42
  elif isinstance(v, dict) or isinstance(v, list):
43
43
  self._resolve_enum(v, enum_class, key)
44
44
 
45
- def get(self, url, retry=True, **kwargs):
46
- res = self._session.get(url, **kwargs)
45
+ def get(self, url, retry=True, timeout=10, headers=None, **kwargs):
46
+ res = self._session.get(
47
+ url, timeout=timeout, headers=headers or self.account.headers, **kwargs
48
+ )
47
49
  if res.status_code == 200:
48
50
  return res
49
51
  if res.status_code == 401 and retry and self.account.token_location:
50
52
  self.account.refresh_tokens()
51
53
  self.account.update_auth_header()
52
- return self.get(url, retry=False, **kwargs)
54
+ return self.get(
55
+ url, retry=False, timeout=timeout, headers=headers, **kwargs
56
+ )
53
57
  raise Exception(res.text)
54
58
 
55
- def post(self, url, retry=True, **kwargs):
56
- res = self._session.post(url, **kwargs)
59
+ def post(self, url, retry=True, timeout=10, headers=None, **kwargs):
60
+ res = self._session.post(
61
+ url, timeout=timeout, headers=headers or self.account.headers, **kwargs
62
+ )
57
63
  if res.status_code == 200:
58
64
  return res
59
65
  if res.status_code == 401 and retry and self.account.token_location:
60
66
  self.account.refresh_tokens()
61
67
  self.account.update_auth_header()
62
- return self.post(url, retry=False, **kwargs)
68
+ return self.post(
69
+ url, retry=False, timeout=timeout, headers=headers, **kwargs
70
+ )
63
71
  raise Exception(res.text)
64
72
 
65
- def delete(self, url, retry=True, **kwargs):
66
- res = self._session.delete(url, **kwargs)
73
+ def delete(self, url, retry=True, timeout=10, headers=None, **kwargs):
74
+ res = self._session.delete(
75
+ url, timeout=timeout, headers=headers or self.account.headers, **kwargs
76
+ )
67
77
  if res.status_code == 200:
68
78
  return res
69
79
  if res.status_code == 401 and retry and self.account.token_location:
70
80
  self.account.refresh_tokens()
71
81
  self.account.update_auth_header()
72
- return self.delete(url, retry=False, **kwargs)
82
+ return self.delete(
83
+ url, retry=False, timeout=timeout, headers=headers, **kwargs
84
+ )
73
85
  raise Exception(res.text)
74
86
 
75
- def put(self, url, retry=True, **kwargs):
76
- res = self._session.put(url, **kwargs)
87
+ def put(self, url, retry=True, timeout=10, headers=None, **kwargs):
88
+ res = self._session.put(
89
+ url, timeout=timeout, headers=headers or self.account.headers, **kwargs
90
+ )
77
91
  if res.status_code == 200:
78
92
  return res
79
93
  if res.status_code == 401 and retry and self.account.token_location:
80
94
  self.account.refresh_tokens()
81
95
  self.account.update_auth_header()
82
- return self.put(url, retry=False, **kwargs)
96
+ return self.put(
97
+ url, retry=False, timeout=timeout, headers=headers, **kwargs
98
+ )
83
99
  raise Exception(res.text)