gh-121650: Encode newlines in headers, and verify headers are sound (… · python/cpython@0976339 (original) (raw)

`@@ -6,6 +6,7 @@

`

6

6

`from email.generator import Generator, BytesGenerator

`

7

7

`from email.headerregistry import Address

`

8

8

`from email import policy

`

``

9

`+

import email.errors

`

9

10

`from test.test_email import TestEmailBase, parameterize

`

10

11

``

11

12

``

`@@ -249,6 +250,44 @@ def test_rfc2231_wrapping_switches_to_default_len_if_too_narrow(self):

`

249

250

`g.flatten(msg)

`

250

251

`self.assertEqual(s.getvalue(), self.typ(expected))

`

251

252

``

``

253

`+

def test_keep_encoded_newlines(self):

`

``

254

`+

msg = self.msgmaker(self.typ(textwrap.dedent("""\

`

``

255

`+

To: nobody

`

``

256

`+

Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com

`

``

257

+

``

258

`+

None

`

``

259

`+

""")))

`

``

260

`+

expected = textwrap.dedent("""\

`

``

261

`+

To: nobody

`

``

262

`+

Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com

`

``

263

+

``

264

`+

None

`

``

265

`+

""")

`

``

266

`+

s = self.ioclass()

`

``

267

`+

g = self.genclass(s, policy=self.policy.clone(max_line_length=80))

`

``

268

`+

g.flatten(msg)

`

``

269

`+

self.assertEqual(s.getvalue(), self.typ(expected))

`

``

270

+

``

271

`+

def test_keep_long_encoded_newlines(self):

`

``

272

`+

msg = self.msgmaker(self.typ(textwrap.dedent("""\

`

``

273

`+

To: nobody

`

``

274

`+

Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com

`

``

275

+

``

276

`+

None

`

``

277

`+

""")))

`

``

278

`+

expected = textwrap.dedent("""\

`

``

279

`+

To: nobody

`

``

280

`+

Subject: Bad subject

`

``

281

`+

=?utf-8?q?=0A?=Bcc:

`

``

282

`+

injection@example.com

`

``

283

+

``

284

`+

None

`

``

285

`+

""")

`

``

286

`+

s = self.ioclass()

`

``

287

`+

g = self.genclass(s, policy=self.policy.clone(max_line_length=30))

`

``

288

`+

g.flatten(msg)

`

``

289

`+

self.assertEqual(s.getvalue(), self.typ(expected))

`

``

290

+

252

291

``

253

292

`class TestGenerator(TestGeneratorBase, TestEmailBase):

`

254

293

``

`@@ -273,6 +312,29 @@ def test_flatten_unicode_linesep(self):

`

273

312

`g.flatten(msg)

`

274

313

`self.assertEqual(s.getvalue(), self.typ(expected))

`

275

314

``

``

315

`+

def test_verify_generated_headers(self):

`

``

316

`+

"""gh-121650: by default the generator prevents header injection"""

`

``

317

`+

class LiteralHeader(str):

`

``

318

`+

name = 'Header'

`

``

319

`+

def fold(self, **kwargs):

`

``

320

`+

return self

`

``

321

+

``

322

`+

for text in (

`

``

323

`+

'Value\r\nBad Injection\r\n',

`

``

324

`+

'NoNewLine'

`

``

325

`+

):

`

``

326

`+

with self.subTest(text=text):

`

``

327

`+

message = message_from_string(

`

``

328

`+

"Header: Value\r\n\r\nBody",

`

``

329

`+

policy=self.policy,

`

``

330

`+

)

`

``

331

+

``

332

`+

del message['Header']

`

``

333

`+

message['Header'] = LiteralHeader(text)

`

``

334

+

``

335

`+

with self.assertRaises(email.errors.HeaderWriteError):

`

``

336

`+

message.as_string()

`

``

337

+

276

338

``

277

339

`class TestBytesGenerator(TestGeneratorBase, TestEmailBase):

`

278

340

``