Last week I was given a task to research how to prevent certain files from being attached to Web Forms for Marketers (WFFM) forms: basically files that have certain extensions, or files that exceed a specified size.
I have not seen this done before in WFFM, so I did what comes naturally to me: I Googled! 🙂
After a few unsuccessful searches on the internet — if you have some examples on how others have accomplished this in WFFM, please share in a comment — I decided to dig into the WFFM assemblies to see what would be needed to accomplish this, and felt using custom WFFM field validators would be the way to go.
I thought having a custom validator to check the attached file’s MIME type would be a better solution over one that checks the file’s extension — thanks to Sitecore MVP Yogesh Patel for giving me the idea from his post on restricting certain files from being uploading into Sitecore by checking their MIME types — since a malefactor could attach a restricted file with a different extension to bypass the extension validation step.
That thought lead me to build the following custom WFFM field validator:
using System; using System.Collections.Generic; using System.Linq; using System.Web.UI.WebControls; using Sitecore.Form.Core.Validators; using Sitecore.Form.Web.UI.Controls; namespace Sitecore.Sandbox.Form.Core.Validators { public class RestrictedFileTypes : FormCustomValidator { public string MimeTypesNotAllowed { get { if (string.IsNullOrWhiteSpace(base.classAttributes["mimeTypesNotAllowed"])) { return string.Empty; } return base.classAttributes["mimeTypesNotAllowed"]; } set { base.classAttributes["mimeTypesNotAllowed"] = value; } } public RestrictedFileTypes() { } protected override bool OnServerValidate(string value) { IEnumerable<string> mimeTypesNotAllowed = GetMimeTypesNotAllowed(); FileUpload fileUpload = FindControl(ControlToValidate) as FileUpload; bool canProcess = mimeTypesNotAllowed.Any() && fileUpload != null && fileUpload.HasFile; if (!canProcess) { return true; } foreach(string mimeType in mimeTypesNotAllowed) { if (AreEqualIgnoreCase(mimeType, fileUpload.PostedFile.ContentType)) { return false; } } return true; } private IEnumerable<string> GetMimeTypesNotAllowed() { if (string.IsNullOrWhiteSpace(MimeTypesNotAllowed)) { return new List<string>(); } return MimeTypesNotAllowed.Split(new []{',', ';'}, StringSplitOptions.RemoveEmptyEntries); } private static bool AreEqualIgnoreCase(string stringOne, string stringTwo) { return string.Equals(stringOne, stringTwo, StringComparison.CurrentCultureIgnoreCase); } } }
Restricted MIME types are passed to the custom validator through a parameter named MimeTypesNotAllowed, and these are injected into a property of the same name.
The MIME types can be separated by commas or semicolons, and the code above splits the string along these delimiters into a collection, checks to see if the uploaded file — we get the uploaded file via the FileUpload control on the form for the field we are validating — has a restricted MIME type by iterating over the collection of restricted MIME types, and comparing each entry to its MIME type. If there is a match, we return “false”: basically the field is invalid.
If no MIME types were set for the validator, or no file was uploaded, we return “true”: the field is valid. We do this for the case where the field is not required, or there is a required field validator set for it, and we don’t want to interfere with its validation check.
I then mapped the above validator in Sitecore:
After saving the above validator Item in Sitecore, I built the following validator class to check to see if a file exceeds a certain size:
using System; using System.Collections.Generic; using System.Linq; using System.Web.UI.WebControls; using Sitecore.Form.Core.Validators; using Sitecore.Form.Web.UI.Controls; namespace Sitecore.Sandbox.Form.Core.Validators { public class RestrictedFileSize : FormCustomValidator { public int MaxFileSize { get { int maxSize; if (int.TryParse(base.classAttributes["mimeTypesNotAllowed"], out maxSize)) { return maxSize; } return 0; } set { base.classAttributes["mimeTypesNotAllowed"] = value.ToString(); } } public RestrictedFileSize() { } protected override bool OnServerValidate(string value) { FileUpload fileUpload = FindControl(ControlToValidate) as FileUpload; if (!fileUpload.HasFile) { return true; } return fileUpload.PostedFile.ContentLength <= MaxFileSize; } } }
Just as we had done in the other validator, we grab the FileUpload from the form, and see if there is a file attached. If there is no file attached, we return “true”: we don’t want to say the field is invalid when the field is not required.
We then return whether the uploaded file is less than or equal to the specified maximum size in bytes — this is set on a parameter named MaxFileSize which gets injected into the MaxFileSize property of the validator instance.
I then registered the above validator in Sitecore:
I then decided to create a custom WFFM field type for the purposes of mapping our validators above, so that we don’t enforce these restrictions on the “out of the box” WFFM “File Upload” field type:
I then set the new field type on a file field I added to a test WFFM form:
Let’s see how we did!
Let’s try to upload an executable that exceeds the maximum upload size limit:
As you can see both validators were triggered for this file:
How about a JavaScript file? Let’s try to attach one:
Nope, we can’t attach that file either:
How about an image that is larger than the size limit? Let’s try one:
Nope, we can’t upload that either:
Let’s try an image that is under 100KB:
Yes, we can attach that file since it’s not restricted, and the form did submit:
If you have any thoughts on this, or other ideas around preventing certain files from being attached to WFFM form submissions, please share in a comment.
This is great, Mike. At some point we should also discuss my experimentation with Sitecore Rocks and importing CSV data into Sitecore (for the purposes of a WFFM form). It “works”, but I saw some funky results which I can tell you about… Have you played around with importing list data into Sitecore?
Thanks Stephen!
I have built solutions that talk to Sitecore via the Sitecore Item Web API, PowerShell scripts using the Sitecore PowerShell Extensions module, and Web Forms to import content from Excel files and CSVs.
Find me at work so we can talk about the odd behavior you’ve encountered during your experimentation.
[…] (WFFM), and wondered whether I could create an alternative solution to the one I had shared in this post — I had built a custom WFFM field type to prevent certain files from being uploaded through […]
Mike this is great as has already been stated, and I have a version of it working on my local instance (my PC). I am wondering about the base.classAttributes[“mimeTypesNotAllowed”] in the C# code.
1) to what is it referring?
2) I see it in both the mimeTypes code and the MaxFileSize code. It makes sense in the mimeTypes code, but can’t figure out why it’s in the MaxFileSize code. Can you explain that to me?
Thank you so much!!
Larry
I added an “Allowed” file extension check to this, and have it working as well. The one thing I needed to do for some reason is put the “.doc,.docx,.txt,.pdf,.rtf,.png,.jpg” in the “Localized Parameters” field of my new Custom Validation item.
I also noticed that the MimeTypes check is merely checking the extension against the MimeType. Is it supposed to check the contents of the file? I ask because one of my tests was to copy and rename an exe so it had a .doc extension – – it allowed the upload. I suppose it did because .doc’s mimeType is not an executable mimetype.
Thanks again! Very good solution.
Hi Larry,
When I wrote this blog post, I wasn’t fully thinking. It would be best to check the actual mime type of the file being upload.
Sitecore MVP Yogesh Patel wrote a blog post that covers how to do that — check out http://sitecoreblog.patelyogesh.in/2013/11/block-files-by-mime-content-type-from-being-uploaded-in-sitecore.html. His post highlights how my solution above is limited.
Cheers,
Mike
Hi Larry,
Here are answers to your questions:
1) mimeTypesNotAllowed is a parameter set on the validator. Please see the Parameters field in the following image: https://sitecorejunkie.files.wordpress.com/2014/04/restricted-file-types-validator.png (this is the first image above in this blog post).
2) The RestrictedFileSize validator is just an example validator. The point of this post is to make people aware how easy it is to create WFFM field validators, and inject parameter values into them.
Cheers,
Mike