def test_get_cdn_domain_on_localhost(client, mocker): mocker.patch.dict('app.current_app.config', values={'ADMIN_BASE_URL': 'http://localhost:6012'}) domain = get_logo_cdn_domain() assert domain == "{}.{}".format( current_app.config['LOGO_UPLOAD_BUCKET_NAME'], current_app.config['ASSET_DOMAIN'])
def useful_headers_after_request(response): response.headers.add('X-Frame-Options', 'deny') response.headers.add('X-Content-Type-Options', 'nosniff') response.headers.add('X-XSS-Protection', '1; mode=block') response.headers.add( 'Content-Security-Policy', ( "default-src 'self' {asset_domain} 'unsafe-inline';" "script-src 'self' {asset_domain} *.google-analytics.com *.googletagmanager.com 'unsafe-inline' 'unsafe-eval' data:;" "connect-src 'self' *.google-analytics.com;" "object-src 'self';" "style-src 'self' *.googleapis.com 'unsafe-inline';" "font-src 'self' {asset_domain} *.googleapis.com *.gstatic.com data:;" "img-src 'self' {asset_domain} *.google-analytics.com *.notifications.service.gov.uk {logo_domain} notification-alpha-canada-ca-cdn.s3.amazonaws.com data:;" # noqa: E501 "frame-src 'self' www.youtube.com;".format( asset_domain=current_app.config['ASSET_DOMAIN'], logo_domain=get_logo_cdn_domain(), ))) if 'Cache-Control' in response.headers: del response.headers['Cache-Control'] response.headers.add('Cache-Control', 'no-store, no-cache, private, must-revalidate') for key, value in response.headers: response.headers[key] = SanitiseASCII.encode(value) return response
def useful_headers_after_request(response): response.headers.add('X-Frame-Options', 'deny') response.headers.add('X-Content-Type-Options', 'nosniff') response.headers.add('X-XSS-Protection', '1; mode=block') response.headers.add('Content-Security-Policy', ( "default-src 'self' {asset_domain} 'unsafe-inline';" "script-src 'self' {asset_domain} *.google-analytics.com 'unsafe-inline' 'unsafe-eval' data:;" "connect-src 'self' *.google-analytics.com;" "object-src 'self';" "font-src 'self' {asset_domain} data:;" "img-src 'self' {asset_domain} *.tile.openstreetmap.org *.google-analytics.com" " *.notifications.service.gov.uk {logo_domain} data:;" "frame-src 'self' www.youtube-nocookie.com;".format( asset_domain=current_app.config['ASSET_DOMAIN'], logo_domain=get_logo_cdn_domain(), ))) response.headers.add( 'Link', ('<{asset_url}>; rel=dns-prefetch, <{asset_url}>; rel=preconnect'. format(asset_url=f'https://{current_app.config["ASSET_DOMAIN"]}'))) if 'Cache-Control' in response.headers: del response.headers['Cache-Control'] response.headers.add('Cache-Control', 'no-store, no-cache, private, must-revalidate') for key, value in response.headers: response.headers[key] = SanitiseASCII.encode(value) return response
def update_email_branding(branding_id, logo=None): email_branding = email_branding_client.get_email_branding( branding_id)["email_branding"] form = ServiceUpdateEmailBranding( name=email_branding["name"], text=email_branding["text"], colour=email_branding["colour"], brand_type=email_branding["brand_type"], ) logo = logo if logo else email_branding.get( "logo") if email_branding else None if form.validate_on_submit(): if form.file.data: upload_filename = upload_email_logo( form.file.data.filename, form.file.data, current_app.config["AWS_REGION"], user_id=session["user_id"], ) if logo and logo.startswith( TEMP_TAG.format(user_id=session["user_id"])): delete_email_temp_file(logo) return redirect( url_for( ".update_email_branding", branding_id=branding_id, logo=upload_filename, )) updated_logo_name = permanent_email_logo_name( logo, session["user_id"]) if logo else None email_branding_client.update_email_branding( branding_id=branding_id, logo=updated_logo_name, name=form.name.data, text=form.text.data, colour=form.colour.data, brand_type=form.brand_type.data, ) if logo: persist_logo(logo, updated_logo_name) delete_email_temp_files_created_by(session["user_id"]) return redirect(url_for(".email_branding", branding_id=branding_id)) return render_template( "views/email-branding/manage-branding.html", form=form, email_branding=email_branding, cdn_url=get_logo_cdn_domain(), logo=logo, )
def create_letter_branding(logo=None): file_upload_form = SVGFileUpload() letter_branding_details_form = ServiceLetterBrandingDetails() file_upload_form_submitted = file_upload_form.file.data details_form_submitted = request.form.get( "operation") == "branding-details" if file_upload_form_submitted and file_upload_form.validate_on_submit(): upload_filename = upload_letter_temp_logo( file_upload_form.file.data.filename, file_upload_form.file.data, current_app.config["AWS_REGION"], user_id=session["user_id"], ) if logo and logo.startswith( LETTER_TEMP_TAG.format(user_id=session["user_id"])): delete_letter_temp_file(logo) return redirect( url_for(".create_letter_branding", logo=upload_filename)) if details_form_submitted and letter_branding_details_form.validate_on_submit( ): if logo: db_filename = letter_filename_for_db(logo, session["user_id"]) png_file = get_png_file_from_svg(logo) try: letter_branding_client.create_letter_branding( filename=db_filename, name=letter_branding_details_form.name.data, ) upload_letter_logos(logo, db_filename, png_file, session["user_id"]) return redirect(url_for("main.letter_branding")) except HTTPError as e: if "name" in e.message: letter_branding_details_form.name.errors.append( e.message["name"][0]) else: raise e else: # Show error on upload form if trying to submit with no logo file_upload_form.validate() return render_template( "views/letter-branding/manage-letter-branding.html", file_upload_form=file_upload_form, letter_branding_details_form=letter_branding_details_form, cdn_url=get_logo_cdn_domain(), logo=logo, )
def test_update_existing_branding( platform_admin_client, mocker, fake_uuid, mock_get_email_branding, mock_update_email_branding, ): with platform_admin_client.session_transaction() as session: user_id = session["user_id"] data = { "logo": "test.png", "colour": "#0000ff", "text": "new text", "name": "new name", "brand_type": "both_english", } temp_filename = EMAIL_LOGO_LOCATION_STRUCTURE.format( temp=TEMP_TAG.format(user_id=user_id), unique_id=fake_uuid, filename=data["logo"], ) mocker.patch("app.main.views.email_branding.persist_logo") mocker.patch( "app.main.views.email_branding.delete_email_temp_files_created_by") platform_admin_client.post( url_for(".update_email_branding", logo=temp_filename, branding_id=fake_uuid), content_type="multipart/form-data", data={ "colour": data["colour"], "name": data["name"], "text": data["text"], "cdn_url": get_logo_cdn_domain(), "brand_type": data["brand_type"], }, ) updated_logo_name = "{}-{}".format(fake_uuid, data["logo"]) assert mock_update_email_branding.called assert mock_update_email_branding.call_args == call( branding_id=fake_uuid, logo=updated_logo_name, name=data["name"], text=data["text"], colour=data["colour"], brand_type=data["brand_type"], )
def test_update_existing_branding(platform_admin_client, mocker, fake_uuid, mock_get_email_branding, mock_update_email_branding): with platform_admin_client.session_transaction() as session: user_id = session["user_id"] data = { 'logo': 'test.png', 'colour': '#0000ff', 'text': 'new text', 'name': 'new name', 'brand_type': 'both' } temp_filename = EMAIL_LOGO_LOCATION_STRUCTURE.format( temp=TEMP_TAG.format(user_id=user_id), unique_id=fake_uuid, filename=data['logo']) mocker.patch('app.main.views.email_branding.persist_logo') mocker.patch( 'app.main.views.email_branding.delete_email_temp_files_created_by') platform_admin_client.post(url_for('.update_email_branding', logo=temp_filename, branding_id=fake_uuid), content_type='multipart/form-data', data={ 'colour': data['colour'], 'name': data['name'], 'text': data['text'], 'cdn_url': get_logo_cdn_domain(), 'brand_type': data['brand_type'] }) updated_logo_name = '{}-{}'.format(fake_uuid, data['logo']) assert mock_update_email_branding.called assert mock_update_email_branding.call_args == call( branding_id=fake_uuid, logo=updated_logo_name, name=data['name'], text=data['text'], colour=data['colour'], brand_type=data['brand_type'])
def create_email_branding(logo=None): form = ServiceUpdateEmailBranding(brand_type='org') if form.validate_on_submit(): if form.file.data: upload_filename = upload_email_logo( form.file.data.filename, form.file.data, current_app.config['AWS_REGION'], user_id=session["user_id"] ) if logo and logo.startswith(TEMP_TAG.format(user_id=session['user_id'])): delete_email_temp_file(logo) return redirect(url_for('.create_email_branding', logo=upload_filename)) updated_logo_name = permanent_email_logo_name(logo, session["user_id"]) if logo else None email_branding_client.create_email_branding( logo=updated_logo_name, name=form.name.data, text=form.text.data, colour=form.colour.data, brand_type=form.brand_type.data, ) if logo: persist_logo(logo, updated_logo_name) delete_email_temp_files_created_by(session["user_id"]) return redirect(url_for('.email_branding')) return render_template( 'views/email-branding/manage-branding.html', form=form, cdn_url=get_logo_cdn_domain(), logo=logo )
def branding_request(service_id, logo=None): file_upload_form = SVGFileUpload() file_upload_form_submitted = file_upload_form.file.data logo = logo if logo else "d512ab4f-3060-44e5-816f-59b5c54c67db-cds-logo-en-fr-5.png" upload_filename = None if file_upload_form_submitted: upload_filename = upload_email_logo( file_upload_form.file.data.filename, file_upload_form.file.data, current_app.config['AWS_REGION'], user_id=session["user_id"]) current_user.send_branding_request(current_service.id, current_service.name, upload_filename) return render_template( 'views/service-settings/branding/manage-email-branding.html', file_upload_form=file_upload_form, cdn_url=get_logo_cdn_domain(), upload_filename=upload_filename, logo=logo)
def test_get_cdn_domain_on_localhost(client, mocker): mocker.patch.dict('app.current_app.config', values={'ADMIN_BASE_URL': 'http://localhost:6012'}) domain = get_logo_cdn_domain() assert domain == 'static-logos.notify.tools'
def update_letter_branding(branding_id, logo=None): letter_branding = letter_branding_client.get_letter_branding(branding_id) file_upload_form = SVGFileUpload() letter_branding_details_form = ServiceLetterBrandingDetails( name=letter_branding['name'], ) file_upload_form_submitted = file_upload_form.file.data details_form_submitted = request.form.get( 'operation') == 'branding-details' logo = logo if logo else permanent_letter_logo_name( letter_branding['filename'], 'svg') if file_upload_form_submitted and file_upload_form.validate_on_submit(): upload_filename = upload_letter_temp_logo( file_upload_form.file.data.filename, file_upload_form.file.data, current_app.config['AWS_REGION'], user_id=session["user_id"]) if logo.startswith(LETTER_TEMP_TAG.format(user_id=session['user_id'])): delete_letter_temp_file(logo) return redirect( url_for('.update_letter_branding', branding_id=branding_id, logo=upload_filename)) if details_form_submitted and letter_branding_details_form.validate_on_submit( ): db_filename = letter_filename_for_db(logo, session['user_id']) try: if db_filename == letter_branding['filename']: letter_branding_client.update_letter_branding( branding_id=branding_id, filename=db_filename, name=letter_branding_details_form.name.data, ) return redirect(url_for('main.letter_branding')) else: letter_branding_client.update_letter_branding( branding_id=branding_id, filename=db_filename, name=letter_branding_details_form.name.data, ) upload_letter_svg_logo(logo, db_filename, session['user_id']) return redirect(url_for('main.letter_branding')) except HTTPError as e: if 'name' in e.message: letter_branding_details_form.name.errors.append( e.message['name'][0]) else: raise e except BotoClientError: # we had a problem saving the file - rollback the db changes letter_branding_client.update_letter_branding( branding_id=branding_id, filename=letter_branding['filename'], name=letter_branding['name'], ) file_upload_form.file.errors = [ 'Error saving uploaded file - try uploading again' ] return render_template( 'views/letter-branding/manage-letter-branding.html', file_upload_form=file_upload_form, letter_branding_details_form=letter_branding_details_form, cdn_url=get_logo_cdn_domain(), logo=logo, is_update=True)
def test_get_cdn_domain_on_localhost(client, mocker): mocker.patch.dict("app.current_app.config", values={"ADMIN_BASE_URL": "http://localhost:6012"}) domain = get_logo_cdn_domain() assert domain == current_app.config["ASSET_DOMAIN"]
def update_letter_branding(branding_id, logo=None): letter_branding = letter_branding_client.get_letter_branding(branding_id) file_upload_form = SVGFileUpload() letter_branding_details_form = ServiceLetterBrandingDetails( name=letter_branding["name"], ) file_upload_form_submitted = file_upload_form.file.data details_form_submitted = request.form.get( "operation") == "branding-details" logo = logo if logo else permanent_letter_logo_name( letter_branding["filename"], "svg") if file_upload_form_submitted and file_upload_form.validate_on_submit(): upload_filename = upload_letter_temp_logo( file_upload_form.file.data.filename, file_upload_form.file.data, current_app.config["AWS_REGION"], user_id=session["user_id"], ) if logo.startswith(LETTER_TEMP_TAG.format(user_id=session["user_id"])): delete_letter_temp_file(logo) return redirect( url_for(".update_letter_branding", branding_id=branding_id, logo=upload_filename)) if details_form_submitted and letter_branding_details_form.validate_on_submit( ): db_filename = letter_filename_for_db(logo, session["user_id"]) try: if db_filename == letter_branding["filename"]: letter_branding_client.update_letter_branding( branding_id=branding_id, filename=db_filename, name=letter_branding_details_form.name.data, ) return redirect(url_for("main.letter_branding")) else: png_file = get_png_file_from_svg(logo) letter_branding_client.update_letter_branding( branding_id=branding_id, filename=db_filename, name=letter_branding_details_form.name.data, ) upload_letter_logos(logo, db_filename, png_file, session["user_id"]) return redirect(url_for("main.letter_branding")) except HTTPError as e: if "name" in e.message: letter_branding_details_form.name.errors.append( e.message["name"][0]) else: raise e except BotoClientError: # we had a problem saving the file - rollback the db changes letter_branding_client.update_letter_branding( branding_id=branding_id, filename=letter_branding["filename"], name=letter_branding["name"], ) file_upload_form.file.errors = [ "Error saving uploaded file - try uploading again" ] return render_template( "views/letter-branding/manage-letter-branding.html", file_upload_form=file_upload_form, letter_branding_details_form=letter_branding_details_form, cdn_url=get_logo_cdn_domain(), logo=logo, is_update=True, )
def email_template(): branding_type = "fip_english" branding_style = request.args.get("branding_style", None) if ( branding_style == FieldWithLanguageOptions.ENGLISH_OPTION_VALUE or branding_style == FieldWithLanguageOptions.FRENCH_OPTION_VALUE ): if branding_style == FieldWithLanguageOptions.FRENCH_OPTION_VALUE: branding_type = "fip_french" branding_style = None if branding_style is not None: email_branding = email_branding_client.get_email_branding(branding_style)["email_branding"] branding_type = email_branding["brand_type"] if branding_type == "fip_english": brand_text = None brand_colour = None brand_logo = None fip_banner_english = True fip_banner_french = False logo_with_background_colour = False brand_name = None elif branding_type == "fip_french": brand_text = None brand_colour = None brand_logo = None fip_banner_english = False fip_banner_french = True logo_with_background_colour = False brand_name = None else: colour = email_branding["colour"] brand_text = email_branding["text"] brand_colour = colour brand_logo = "https://{}/{}".format(get_logo_cdn_domain(), email_branding["logo"]) if email_branding["logo"] else None fip_banner_english = branding_type in ["fip_english", "both_english"] fip_banner_french = branding_type in ["fip_french", "both_french"] logo_with_background_colour = branding_type == "custom_logo_with_background_colour" brand_name = email_branding["name"] template = { "subject": "foo", "content": ( "Lorem Ipsum is simply dummy text of the printing and typesetting " "industry.\n\nLorem Ipsum has been the industry’s standard dummy " "text ever since the 1500s, when an unknown printer took a galley " "of type and scrambled it to make a type specimen book. " "\n\n" "# History" "\n\n" "It has " "survived not only" "\n\n" "* five centuries" "\n" "* but also the leap into electronic typesetting" "\n\n" "It was " "popularised in the 1960s with the release of Letraset sheets " "containing Lorem Ipsum passages, and more recently with desktop " "publishing software like Aldus PageMaker including versions of " "Lorem Ipsum." "\n\n" "^ It is a long established fact that a reader will be distracted " "by the readable content of a page when looking at its layout." "\n\n" "The point of using Lorem Ipsum is that it has a more-or-less " "normal distribution of letters, as opposed to using ‘Content " "here, content here’, making it look like readable English." "\n\n\n" "1. One" "\n" "2. Two" "\n" "10. Three" "\n\n" "This is an example of an email sent using Notification." "\n\n" "https://www.notifications.service.gov.uk" ), } if not bool(request.args): resp = make_response(str(HTMLEmailTemplate(template))) else: resp = make_response( str( HTMLEmailTemplate( template, fip_banner_english=fip_banner_english, fip_banner_french=fip_banner_french, brand_text=brand_text, brand_colour=brand_colour, brand_logo=brand_logo, logo_with_background_colour=logo_with_background_colour, brand_name=brand_name, ) ) ) resp.headers["X-Frame-Options"] = "SAMEORIGIN" return resp
def test_get_cdn_domain_on_non_localhost(client, mocker): mocker.patch.dict('app.current_app.config', values={'ADMIN_BASE_URL': 'https://some.admintest.com'}) domain = get_logo_cdn_domain() assert domain == 'static-logos.admintest.com'
def email_template(): branding_type = 'govuk' branding_style = request.args.get('branding_style', None) if branding_style == FieldWithNoneOption.NONE_OPTION_VALUE: branding_style = None if branding_style is not None: email_branding = email_branding_client.get_email_branding( branding_style)['email_branding'] branding_type = email_branding['brand_type'] if branding_type == 'govuk': brand_text = None brand_colour = None brand_logo = None govuk_banner = True brand_banner = False brand_name = None else: colour = email_branding['colour'] brand_text = email_branding['text'] brand_colour = colour brand_logo = ('https://{}/{}'.format(get_logo_cdn_domain(), email_branding['logo']) if email_branding['logo'] else None) govuk_banner = branding_type in ['govuk', 'both'] brand_banner = branding_type == 'org_banner' brand_name = email_branding['name'] template = { 'template_type': 'email', 'subject': 'foo', 'content': ('Lorem Ipsum is simply dummy text of the printing and typesetting ' 'industry.\n\nLorem Ipsum has been the industry’s standard dummy ' 'text ever since the 1500s, when an unknown printer took a galley ' 'of type and scrambled it to make a type specimen book. ' '\n\n' '# History' '\n\n' 'It has ' 'survived not only' '\n\n' '* five centuries' '\n' '* but also the leap into electronic typesetting' '\n\n' 'It was ' 'popularised in the 1960s with the release of Letraset sheets ' 'containing Lorem Ipsum passages, and more recently with desktop ' 'publishing software like Aldus PageMaker including versions of ' 'Lorem Ipsum.' '\n\n' '^ It is a long established fact that a reader will be distracted ' 'by the readable content of a page when looking at its layout.' '\n\n' 'The point of using Lorem Ipsum is that it has a more-or-less ' 'normal distribution of letters, as opposed to using ‘Content ' 'here, content here’, making it look like readable English.' '\n\n\n' '1. One' '\n' '2. Two' '\n' '10. Three' '\n\n' 'This is an example of an email sent using GOV.UK Notify.' '\n\n' 'https://www.notifications.service.gov.uk') } if not bool(request.args): resp = make_response(str(HTMLEmailTemplate(template))) else: resp = make_response( str( HTMLEmailTemplate( template, govuk_banner=govuk_banner, brand_text=brand_text, brand_colour=brand_colour, brand_logo=brand_logo, brand_banner=brand_banner, brand_name=brand_name, ))) resp.headers['X-Frame-Options'] = 'SAMEORIGIN' return resp
def branding_request(service_id): current_branding = current_service.email_branding_id cdn_url = get_logo_cdn_domain() default_en_filename = "https://{}/gov-canada-en.svg".format(cdn_url) default_fr_filename = "https://{}/gov-canada-fr.svg".format(cdn_url) choices = [ ('__FIP-EN__', _('English GC logo') + '||' + default_en_filename), ('__FIP-FR__', _('French GC logo') + '||' + default_fr_filename), ] if current_branding is None: current_branding = (FieldWithLanguageOptions.FRENCH_OPTION_VALUE if current_service.default_branding_is_french is True else FieldWithLanguageOptions.ENGLISH_OPTION_VALUE) branding_style = current_branding else: current_branding_filename = "https://{}/{}".format( cdn_url, current_service.email_branding['logo']) branding_style = 'custom' choices.append( ('custom', _('Custom {} logo').format(current_service.name) + '||' + current_branding_filename)) form = SelectLogoForm( label=_('Type of logo'), choices=choices, branding_style=branding_style, ) upload_filename = None if form.validate_on_submit(): file_submitted = form.file.data if file_submitted: upload_filename = upload_email_logo( file_submitted.filename, file_submitted, current_app.config['AWS_REGION'], user_id=session["user_id"]) current_user.send_branding_request(current_service.id, current_service.name, upload_filename) default_branding_is_french = None branding_choice = form.branding_style.data if branding_choice == 'custom' or file_submitted: default_branding_is_french = None else: default_branding_is_french = ( branding_choice == FieldWithLanguageOptions.FRENCH_OPTION_VALUE ) if default_branding_is_french is not None: current_service.update( email_branding=None, default_branding_is_french=default_branding_is_french) return redirect(url_for('.service_settings', service_id=service_id)) return render_template( 'views/service-settings/branding/manage-email-branding.html', form=form, using_custom_branding=current_service.email_branding_id is not None, cdn_url=cdn_url, upload_filename=upload_filename, )