├── .gitignore
├── FileTypeChecker.Tests
├── FileTypeChecker.Tests.csproj
├── FileTypeCheckerTests.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── Resources
│ ├── LAND.BMP
│ └── advancedquantumthermodynamics.pdf
└── packages.config
├── FileTypeChecker.sln
├── FileTypeChecker
├── App.config
├── ExactFileTypeMatcher.cs
├── FileType.cs
├── FileTypeChecker.cs
├── FileTypeChecker.csproj
├── FileTypeChecker.nuspec
├── FileTypeMatcher.cs
├── FuzzyFileTypeMatcher.cs
├── IFileTypeChecker.cs
├── Properties
│ └── AssemblyInfo.cs
└── RangeFileTypeMatcher.cs
├── LICENSE.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 | bower_components/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 | # Node.js Tools for Visual Studio
190 | .ntvs_analysis.dat
191 |
192 | # Visual Studio 6 build log
193 | *.plg
194 |
195 | # Visual Studio 6 workspace options file
196 | *.opt
197 |
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/FileTypeChecker.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {716D0AB2-5088-4A22-A6E8-24B8D2F2039B}
8 | Library
9 | Properties
10 | FileTypeChecker.Tests
11 | FileTypeChecker.Tests
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\NUnit.2.6.4\lib\nunit.framework.dll
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | True
50 | True
51 | Resources.resx
52 |
53 |
54 |
55 |
56 | {0ae201d3-ce5b-404f-8c25-36bd929e1d19}
57 | FileTypeChecker
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | ResXFileCodeGenerator
67 | Resources.Designer.cs
68 |
69 |
70 |
71 |
72 |
73 |
74 |
81 |
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/FileTypeCheckerTests.cs:
--------------------------------------------------------------------------------
1 | namespace FileTypeChecker.Tests
2 | {
3 | using System.Drawing.Imaging;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Collections.Generic;
7 | using NUnit.Framework;
8 |
9 | using Properties;
10 |
11 | [TestFixture]
12 | public class FileTypeCheckerTests
13 | {
14 | [TestFixture]
15 | public class WhenTheFileIsKnown
16 | {
17 | private MemoryStream bitmap;
18 |
19 | private MemoryStream pdf;
20 |
21 | private FileTypeChecker checker;
22 |
23 | [TestFixtureSetUp]
24 | public void SetUp()
25 | {
26 | bitmap = new MemoryStream();
27 | // LAND.bmp is from http://www.fileformat.info/format/bmp/sample/
28 | Resources.LAND.Save(bitmap, ImageFormat.Bmp);
29 | // http://boingboing.net/2015/03/23/free-pdf-advanced-quantum-the.html
30 | pdf = new MemoryStream(Resources.advancedquantumthermodynamics);
31 | checker = new FileTypeChecker();
32 | }
33 |
34 | [Test]
35 | public void ItDetectsPDFs()
36 | {
37 | var fileTypes = checker.GetFileTypes(pdf);
38 | CollectionAssert.AreEquivalent(
39 | new[] { "Portable Document Format" },
40 | fileTypes.Select(fileType => fileType.Name));
41 | }
42 |
43 | [Test]
44 | public void ItDetectsBMPs()
45 | {
46 | var fileTypes = checker.GetFileTypes(bitmap);
47 | CollectionAssert.AreEquivalent(
48 | new[] { "Bitmap" },
49 | fileTypes.Select(fileType => fileType.Name));
50 | }
51 | }
52 |
53 | [TestFixture]
54 | public class WhenTheFileIsUnknown
55 | {
56 | private MemoryStream bitmap;
57 |
58 | private MemoryStream pdf;
59 |
60 | private FileTypeChecker checker;
61 |
62 | [TestFixtureSetUp]
63 | public void SetUp()
64 | {
65 | bitmap = new MemoryStream();
66 | // LAND.bmp is from http://www.fileformat.info/format/bmp/sample/
67 | Resources.LAND.Save(bitmap, ImageFormat.Bmp);
68 | // http://boingboing.net/2015/03/23/free-pdf-advanced-quantum-the.html
69 | pdf = new MemoryStream(Resources.advancedquantumthermodynamics);
70 | }
71 |
72 | [Test]
73 | public void ItDoesntDetectPDFs()
74 | {
75 | checker = new FileTypeChecker(new List
76 | {
77 | new FileType("Bitmap", ".bmp", new ExactFileTypeMatcher(new byte[] {0x42, 0x4d})),
78 | new FileType("Portable Network Graphic", ".png",
79 | new ExactFileTypeMatcher(new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})),
80 | new FileType("JPEG", ".jpg",
81 | new FuzzyFileTypeMatcher(new byte?[] {0xFF, 0xD, 0xFF, 0xE0, null, null, 0x4A, 0x46, 0x49, 0x46, 0x00})),
82 | new FileType("Graphics Interchange Format 87a", ".gif",
83 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x37, 0x61})),
84 | new FileType("Graphics Interchange Format 89a", ".gif",
85 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}))
86 | // ... Potentially more in future
87 | });
88 | var fileType = checker.GetFileType(pdf);
89 | Assert.AreEqual(
90 | "unknown",
91 | fileType.Name);
92 | }
93 |
94 | [Test]
95 | public void ItDoesntDetectBMPs()
96 | {
97 | checker = new FileTypeChecker(new List
98 | {
99 | new FileType("Portable Network Graphic", ".png",
100 | new ExactFileTypeMatcher(new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})),
101 | new FileType("JPEG", ".jpg",
102 | new FuzzyFileTypeMatcher(new byte?[] {0xFF, 0xD, 0xFF, 0xE0, null, null, 0x4A, 0x46, 0x49, 0x46, 0x00})),
103 | new FileType("Graphics Interchange Format 87a", ".gif",
104 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x37, 0x61})),
105 | new FileType("Graphics Interchange Format 89a", ".gif",
106 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x39, 0x61})),
107 | new FileType("Portable Document Format", ".pdf", new RangeFileTypeMatcher(new ExactFileTypeMatcher(new byte[] { 0x25, 0x50, 0x44, 0x46 }), 1019))
108 | // ... Potentially more in future
109 | });
110 | var fileType = checker.GetFileType(bitmap);
111 | Assert.AreEqual(
112 | "unknown",
113 | fileType.Name);
114 | }
115 |
116 | }
117 |
118 | [TestFixture]
119 | public class WhenTheFileIsUnknownList
120 | {
121 | private MemoryStream bitmap;
122 |
123 | private MemoryStream pdf;
124 |
125 | private FileTypeChecker checker;
126 |
127 | [TestFixtureSetUp]
128 | public void SetUp()
129 | {
130 | bitmap = new MemoryStream();
131 | // LAND.bmp is from http://www.fileformat.info/format/bmp/sample/
132 | Resources.LAND.Save(bitmap, ImageFormat.Bmp);
133 | // http://boingboing.net/2015/03/23/free-pdf-advanced-quantum-the.html
134 | pdf = new MemoryStream(Resources.advancedquantumthermodynamics);
135 | }
136 |
137 | [Test]
138 | public void ItDoesntDetectPDFs()
139 | {
140 | checker = new FileTypeChecker(new List
141 | {
142 | new FileType("Bitmap", ".bmp", new ExactFileTypeMatcher(new byte[] {0x42, 0x4d})),
143 | new FileType("Portable Network Graphic", ".png",
144 | new ExactFileTypeMatcher(new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})),
145 | new FileType("JPEG", ".jpg",
146 | new FuzzyFileTypeMatcher(new byte?[] {0xFF, 0xD, 0xFF, 0xE0, null, null, 0x4A, 0x46, 0x49, 0x46, 0x00})),
147 | new FileType("Graphics Interchange Format 87a", ".gif",
148 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x37, 0x61})),
149 | new FileType("Graphics Interchange Format 89a", ".gif",
150 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}))
151 | // ... Potentially more in future
152 | });
153 | var fileTypes = checker.GetFileTypes(pdf);
154 | Assert.AreEqual(0, fileTypes.Count());
155 | }
156 |
157 | [Test]
158 | public void ItDoesntDetectBMPs()
159 | {
160 | checker = new FileTypeChecker(new List
161 | {
162 | new FileType("Portable Network Graphic", ".png",
163 | new ExactFileTypeMatcher(new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})),
164 | new FileType("JPEG", ".jpg",
165 | new FuzzyFileTypeMatcher(new byte?[] {0xFF, 0xD, 0xFF, 0xE0, null, null, 0x4A, 0x46, 0x49, 0x46, 0x00})),
166 | new FileType("Graphics Interchange Format 87a", ".gif",
167 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x37, 0x61})),
168 | new FileType("Graphics Interchange Format 89a", ".gif",
169 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x39, 0x61})),
170 | new FileType("Portable Document Format", ".pdf", new RangeFileTypeMatcher(new ExactFileTypeMatcher(new byte[] { 0x25, 0x50, 0x44, 0x46 }), 1019))
171 | // ... Potentially more in future
172 | });
173 | var fileTypes = checker.GetFileTypes(bitmap);
174 | Assert.AreEqual(0, fileTypes.Count());
175 | }
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FileTypeChecker.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("HP")]
12 | [assembly: AssemblyProduct("FileTypeChecker.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © HP 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("da4da584-b4a8-4766-a0fc-81ba5b7ea1b6")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace FileTypeChecker.Tests.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FileTypeChecker.Tests.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Byte[].
65 | ///
66 | internal static byte[] advancedquantumthermodynamics {
67 | get {
68 | object obj = ResourceManager.GetObject("advancedquantumthermodynamics", resourceCulture);
69 | return ((byte[])(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Drawing.Bitmap.
75 | ///
76 | internal static System.Drawing.Bitmap LAND {
77 | get {
78 | object obj = ResourceManager.GetObject("LAND", resourceCulture);
79 | return ((System.Drawing.Bitmap)(obj));
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\advancedquantumthermodynamics.pdf;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
123 |
124 |
125 | ..\Resources\LAND.BMP;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
126 |
127 |
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/Resources/LAND.BMP:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xbrock/FileTypeChecker/65be0d72a4b388795f0fd31776d3747757918c56/FileTypeChecker.Tests/Resources/LAND.BMP
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/Resources/advancedquantumthermodynamics.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xbrock/FileTypeChecker/65be0d72a4b388795f0fd31776d3747757918c56/FileTypeChecker.Tests/Resources/advancedquantumthermodynamics.pdf
--------------------------------------------------------------------------------
/FileTypeChecker.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/FileTypeChecker.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27004.2005
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTypeChecker", "FileTypeChecker\FileTypeChecker.csproj", "{0AE201D3-CE5B-404F-8C25-36BD929E1D19}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTypeChecker.Tests", "FileTypeChecker.Tests\FileTypeChecker.Tests.csproj", "{716D0AB2-5088-4A22-A6E8-24B8D2F2039B}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1019EF17-64B8-4C70-BB39-A12DBFB30A16}"
11 | ProjectSection(SolutionItems) = preProject
12 | .gitignore = .gitignore
13 | README.md = README.md
14 | EndProjectSection
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {0AE201D3-CE5B-404F-8C25-36BD929E1D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {0AE201D3-CE5B-404F-8C25-36BD929E1D19}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {0AE201D3-CE5B-404F-8C25-36BD929E1D19}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {0AE201D3-CE5B-404F-8C25-36BD929E1D19}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {716D0AB2-5088-4A22-A6E8-24B8D2F2039B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {716D0AB2-5088-4A22-A6E8-24B8D2F2039B}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {716D0AB2-5088-4A22-A6E8-24B8D2F2039B}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {716D0AB2-5088-4A22-A6E8-24B8D2F2039B}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {113B3F98-0519-459D-91A6-EE74FABE92E6}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/FileTypeChecker/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/FileTypeChecker/ExactFileTypeMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace FileTypeChecker
2 | {
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 |
7 | public class ExactFileTypeMatcher : FileTypeMatcher
8 | {
9 | private readonly byte[] bytes;
10 |
11 | public ExactFileTypeMatcher(IEnumerable bytes)
12 | {
13 | this.bytes = bytes.ToArray();
14 | }
15 |
16 | protected override bool MatchesPrivate(Stream stream)
17 | {
18 | foreach (var b in bytes)
19 | {
20 | if (stream.ReadByte() != b)
21 | {
22 | return false;
23 | }
24 | }
25 |
26 | return true;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/FileTypeChecker/FileType.cs:
--------------------------------------------------------------------------------
1 | namespace FileTypeChecker
2 | {
3 | using System.IO;
4 |
5 | public class FileType
6 | {
7 | private static readonly FileType unknown = new FileType("unknown", string.Empty, null);
8 |
9 | private readonly string name;
10 |
11 | private readonly string extension;
12 |
13 | private readonly FileTypeMatcher fileTypeMatcher;
14 |
15 | public string Name { get { return name; } }
16 |
17 | public string Extension { get { return extension; } }
18 |
19 | public static FileType Unknown { get { return unknown; } }
20 |
21 | public FileType(string name, string extension, FileTypeMatcher matcher)
22 | {
23 | this.name = name;
24 | this.extension = extension;
25 | this.fileTypeMatcher = matcher;
26 | }
27 |
28 | public bool Matches(Stream stream)
29 | {
30 | return this.fileTypeMatcher == null || this.fileTypeMatcher.Matches(stream);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FileTypeChecker/FileTypeChecker.cs:
--------------------------------------------------------------------------------
1 | namespace FileTypeChecker
2 | {
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 |
7 | public class FileTypeChecker : IFileTypeChecker
8 | {
9 | private IList knownFileTypes;
10 |
11 | public FileTypeChecker()
12 | {
13 | this.knownFileTypes = new List
14 | {
15 | new FileType("Bitmap", ".bmp", new ExactFileTypeMatcher(new byte[] {0x42, 0x4d})),
16 | new FileType("Portable Network Graphic", ".png",
17 | new ExactFileTypeMatcher(new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})),
18 | new FileType("JPEG", ".jpg",
19 | new FuzzyFileTypeMatcher(new byte?[] {0xFF, 0xD, 0xFF, 0xE0, null, null, 0x4A, 0x46, 0x49, 0x46, 0x00})),
20 | new FileType("Graphics Interchange Format 87a", ".gif",
21 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x37, 0x61})),
22 | new FileType("Graphics Interchange Format 89a", ".gif",
23 | new ExactFileTypeMatcher(new byte[] {0x47, 0x49, 0x46, 0x38, 0x39, 0x61})),
24 | new FileType("Portable Document Format", ".pdf", new RangeFileTypeMatcher(new ExactFileTypeMatcher(new byte[] { 0x25, 0x50, 0x44, 0x46 }), 1019))
25 | // ... Potentially more in future
26 | };
27 | }
28 |
29 | public FileTypeChecker(IList knownFileTypes)
30 | {
31 | this.knownFileTypes = knownFileTypes;
32 | }
33 |
34 | public FileType GetFileType(Stream fileContent)
35 | {
36 | return GetFileTypes(fileContent).FirstOrDefault() ?? FileType.Unknown;
37 | }
38 |
39 | public IEnumerable GetFileTypes(Stream stream)
40 | {
41 | return knownFileTypes.Where(fileType => fileType.Matches(stream));
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/FileTypeChecker/FileTypeChecker.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {0AE201D3-CE5B-404F-8C25-36BD929E1D19}
8 | Library
9 | Properties
10 | FileTypeChecker
11 | FileTypeChecker
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
66 |
--------------------------------------------------------------------------------
/FileTypeChecker/FileTypeChecker.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FileTypeChecker
5 | 1.0.0
6 | File Type Checker
7 | 0xbrock
8 | https://github.com/0xbrock/FileTypeChecker
9 | false
10 | File type checker that checks the file's magic numbers/Identifying bytes. Useful for verifying uploaded files in web applications.
11 | NuGet package of code originally written by https://github.com/mjolka and extended to allow for dependency injecting the known file types.
12 | 2017
13 | File Type, Validator, Checker, Magic Numbers, Identifying Bytes
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/FileTypeChecker/FileTypeMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace FileTypeChecker
2 | {
3 | using System;
4 | using System.IO;
5 |
6 | public abstract class FileTypeMatcher
7 | {
8 | public bool Matches(Stream stream, bool resetPosition = true)
9 | {
10 | if (stream == null)
11 | {
12 | throw new ArgumentNullException("stream");
13 | }
14 | if (!stream.CanRead || (stream.Position != 0 && !stream.CanSeek))
15 | {
16 | throw new ArgumentException("File contents must be a readable stream", "stream");
17 | }
18 | if (stream.Position != 0 && resetPosition)
19 | {
20 | stream.Seek(0, SeekOrigin.Begin);
21 | }
22 |
23 | return MatchesPrivate(stream);
24 | }
25 |
26 | protected abstract bool MatchesPrivate(Stream stream);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/FileTypeChecker/FuzzyFileTypeMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace FileTypeChecker
2 | {
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 |
7 | public class FuzzyFileTypeMatcher : FileTypeMatcher
8 | {
9 | private readonly byte?[] bytes;
10 |
11 | public FuzzyFileTypeMatcher(IEnumerable bytes)
12 | {
13 | this.bytes = bytes.ToArray();
14 | }
15 |
16 | protected override bool MatchesPrivate(Stream stream)
17 | {
18 | foreach (var b in this.bytes)
19 | {
20 | var c = stream.ReadByte();
21 | if (c == -1 || (b.HasValue && c != b.Value))
22 | {
23 | return false;
24 | }
25 | }
26 |
27 | return true;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/FileTypeChecker/IFileTypeChecker.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 |
4 | namespace FileTypeChecker
5 | {
6 | public interface IFileTypeChecker
7 | {
8 | FileType GetFileType(Stream fileContent);
9 | IEnumerable GetFileTypes(Stream stream);
10 | }
11 | }
--------------------------------------------------------------------------------
/FileTypeChecker/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FileTypeChecker")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("HP")]
12 | [assembly: AssemblyProduct("FileTypeChecker")]
13 | [assembly: AssemblyCopyright("Copyright © HP 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("8f5ab3ff-cefb-4575-bbda-58ca0dc9b369")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/FileTypeChecker/RangeFileTypeMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace FileTypeChecker
2 | {
3 | using System.IO;
4 |
5 | public class RangeFileTypeMatcher : FileTypeMatcher
6 | {
7 | private readonly FileTypeMatcher matcher;
8 |
9 | private readonly int maximumStartLocation;
10 |
11 | public RangeFileTypeMatcher(FileTypeMatcher matcher, int maximumStartLocation)
12 | {
13 | this.matcher = matcher;
14 | this.maximumStartLocation = maximumStartLocation;
15 | }
16 |
17 | protected override bool MatchesPrivate(Stream stream)
18 | {
19 | for (var i = 0; i < this.maximumStartLocation; i++)
20 | {
21 | stream.Position = i;
22 | if (matcher.Matches(stream, resetPosition: false))
23 | {
24 | return true;
25 | }
26 | }
27 |
28 | return false;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-present Dan Abramov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # File Type Checker
2 |
3 | File Type Checker is a .Net file identification library allowing developers to verify the file's magic numbers/identifying bytes against a whitelist.
4 |
5 | The purpose of this code is to make it easier for people to add better file security functionality to their projects via a NuGet package.
6 |
7 | ## Installation
8 |
9 | Nuget package: [FileTypeChecker](https://www.nuget.org/packages/FileTypeChecker/)
10 |
11 | Via Package Manager:
12 |
13 | `Install-Package FileTypeChecker`
14 |
15 | ## Usage
16 |
17 | Using an IoC container, register the instance in the container
18 |
19 | ```C#
20 | new List
21 | {
22 | new FileType("Portable Network Graphic", ".png",
23 | new ExactFileTypeMatcher(new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})),
24 | new FileType("JPEG", ".jpg",
25 | new FuzzyFileTypeMatcher(new byte?[] {0xFF, 0xD, 0xFF, 0xE0, null, null, 0x4A, 0x46, 0x49, 0x46, 0x00})),
26 | new FileType("Portable Document Format", ".pdf", new RangeFileTypeMatcher(new ExactFileTypeMatcher(new byte[] { 0x25, 0x50, 0x44, 0x46 }), 1019))
27 | }
28 | ```
29 |
30 | Register the `FileTypeChecker` concrete implementation to the `IFileTypeChecker` interface. Wherever you need the checker, dependency inject it and use it like below.
31 | ```C#
32 | // pdf is a stream containing a PDF
33 | var fileType = checker.GetFileType(pdf);
34 | ```
35 |
36 |
37 | ## Background
38 |
39 | I have seen too many projects allow file uploads any the only validation that occurs is the filename extension. This project exists because there needs to be a plug and play library that facilites mitigating this security issue.
40 |
41 |
42 | ## File Magic Number Resources
43 |
44 | For a list of file magic numbers, I have found these sites to be useful.
45 |
46 | * [https://www.garykessler.net/library/file_sigs.html](https://www.garykessler.net/library/file_sigs.html)
47 | * [http://filext.com/](http://filext.com/)
48 | * [https://en.wikipedia.org/wiki/List_of_file_signatures](https://en.wikipedia.org/wiki/List_of_file_signatures)
49 | * [https://asecuritysite.com/forensics/magic](https://asecuritysite.com/forensics/magic)
50 |
51 |
52 | ## Credits
53 |
54 | Based on [mjolka](https://github.com/mjolka)'s answer to the Stack Overflow question [Guessing a file type based on its content](http://codereview.stackexchange.com/questions/85054/guessing-a-file-type-based-on-its-content).
55 |
56 | This repo is forked from [https://github.com/mjolka/filetypes](https://github.com/mjolka/filetypes) and the original code can be found in the "original" branch (preserving for posterity). I have changed the namespaces/project name to better describe the purpose.
57 |
--------------------------------------------------------------------------------