[#8199] Adds CRLF line endings to 2FA recovery codes download for Windows UAs
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 7dc1532..537d545 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -812,9 +812,12 @@
         h.auditlog_user('Viewed multifactor recovery codes')
         provider = plugin.AuthenticationProvider.get(request)
 
+        windows_line_endings = "WINDOWS" in request.headers.get('USER_AGENT', '').upper()
+
         return dict(
             codes=codes,
             menu = provider.account_navigation(),
+            windows_line_endings=windows_line_endings
         )
 
     @expose()
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 572b6e6..c0fe667 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -1286,13 +1286,17 @@
                 raise exception()
 
 
-def base64uri(content_or_image, image_format='PNG', mimetype='image/png'):
+def base64uri(content_or_image, image_format='PNG', mimetype='image/png', windows_line_endings=False):
     if hasattr(content_or_image, 'save'):
         output = StringIO()
         content_or_image.save(output, format=image_format)
         content = output.getvalue()
     else:
         content = content_or_image
+
+    if windows_line_endings:
+        content = content.replace('\n', '\r\n')
+
     data = base64.b64encode(content)
     return 'data:{};base64,{}'.format(mimetype, data)
 
diff --git a/Allura/allura/templates/user_recovery_codes.html b/Allura/allura/templates/user_recovery_codes.html
index 5039dd0..bf4a63d 100644
--- a/Allura/allura/templates/user_recovery_codes.html
+++ b/Allura/allura/templates/user_recovery_codes.html
@@ -26,9 +26,9 @@
 
 
 {% macro plaintext(codes) %}
-{{ config['site_name'] }} Recovery Codes:
+{{- config['site_name'] }} Recovery Codes:
 {% for code in codes %}
-{{ code }}
+{{ code -}}
 {% endfor %}
 {% endmacro %}
 
@@ -38,7 +38,7 @@
     <h2 class="subtitle">Your {{ config['site_name'] }} Recovery Codes</h2>
     <p>
         <a href="#" class="print"><strong>Print</strong></a> these!
-        <a href="{{ h.base64uri(plaintext(codes), mimetype='text/plain') }}" download="{{ config['site_name'] }} recovery codes.txt" class="download"><strong>Download</strong></a> them!
+        <a href="{{ h.base64uri(plaintext(codes), mimetype='text/plain', windows_line_endings=windows_line_endings) }}" download="{{ config['site_name'] }} recovery codes.txt" class="download"><strong>Download</strong></a> them!
         Keep them safe.
     </p>
     <p>