diff --git a/Mailtrap.sln b/Mailtrap.sln index 89218e89..519e9c79 100644 --- a/Mailtrap.sln +++ b/Mailtrap.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.9.34728.123 @@ -57,7 +57,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{CD08E7CB-C CONTRIBUTING.md = CONTRIBUTING.md LICENSE.md = LICENSE.md README.md = README.md - UPGRADE-3.0.md = UPGRADE-3.0.md + UPGRADE-3.0.md = UPGRADE-3.0.md EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mailtrap.Example.DependencyInjection", "examples\Mailtrap.Example.DependencyInjection\Mailtrap.Example.DependencyInjection.csproj", "{4457969D-4981-4F27-A304-A242DEC9FD92}" @@ -116,136 +116,402 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mailtrap.Example.Webhooks", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mailtrap.Example.SubAccount", "examples\Mailtrap.Example.SubAccount\Mailtrap.Example.SubAccount.csproj", "{D5E6F7A8-1234-5678-9ABC-DEF012345603}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mailtrap.Example.WebhookSignature", "examples\Mailtrap.Example.WebhookSignature\Mailtrap.Example.WebhookSignature.csproj", "{E9478405-3D5D-439C-B0D5-753DC5F2F46D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Debug|x64.ActiveCfg = Debug|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Debug|x64.Build.0 = Debug|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Debug|x86.ActiveCfg = Debug|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Debug|x86.Build.0 = Debug|Any CPU {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Release|Any CPU.ActiveCfg = Release|Any CPU {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Release|Any CPU.Build.0 = Release|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Release|x64.ActiveCfg = Release|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Release|x64.Build.0 = Release|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Release|x86.ActiveCfg = Release|Any CPU + {D18E67B4-9179-45A5-94DE-83A8AD7CAA64}.Release|x86.Build.0 = Release|Any CPU {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Debug|x64.ActiveCfg = Debug|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Debug|x64.Build.0 = Debug|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Debug|x86.ActiveCfg = Debug|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Debug|x86.Build.0 = Debug|Any CPU {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Release|Any CPU.Build.0 = Release|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Release|x64.ActiveCfg = Release|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Release|x64.Build.0 = Release|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Release|x86.ActiveCfg = Release|Any CPU + {5CFBF4CD-D0DE-4901-815C-06317C0AECE8}.Release|x86.Build.0 = Release|Any CPU {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Debug|x64.ActiveCfg = Debug|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Debug|x64.Build.0 = Debug|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Debug|x86.ActiveCfg = Debug|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Debug|x86.Build.0 = Debug|Any CPU {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Release|Any CPU.Build.0 = Release|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Release|x64.ActiveCfg = Release|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Release|x64.Build.0 = Release|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Release|x86.ActiveCfg = Release|Any CPU + {D3695456-3359-4D97-AE3B-23E2212C8E5F}.Release|x86.Build.0 = Release|Any CPU {4457969D-4981-4F27-A304-A242DEC9FD92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4457969D-4981-4F27-A304-A242DEC9FD92}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Debug|x64.ActiveCfg = Debug|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Debug|x64.Build.0 = Debug|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Debug|x86.ActiveCfg = Debug|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Debug|x86.Build.0 = Debug|Any CPU {4457969D-4981-4F27-A304-A242DEC9FD92}.Release|Any CPU.ActiveCfg = Release|Any CPU {4457969D-4981-4F27-A304-A242DEC9FD92}.Release|Any CPU.Build.0 = Release|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Release|x64.ActiveCfg = Release|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Release|x64.Build.0 = Release|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Release|x86.ActiveCfg = Release|Any CPU + {4457969D-4981-4F27-A304-A242DEC9FD92}.Release|x86.Build.0 = Release|Any CPU {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Debug|x64.ActiveCfg = Debug|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Debug|x64.Build.0 = Debug|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Debug|x86.ActiveCfg = Debug|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Debug|x86.Build.0 = Debug|Any CPU {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Release|Any CPU.ActiveCfg = Release|Any CPU {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Release|Any CPU.Build.0 = Release|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Release|x64.ActiveCfg = Release|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Release|x64.Build.0 = Release|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Release|x86.ActiveCfg = Release|Any CPU + {B94183D6-5D5C-4EC4-8F58-7D0D803EA197}.Release|x86.Build.0 = Release|Any CPU {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Debug|x64.ActiveCfg = Debug|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Debug|x64.Build.0 = Debug|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Debug|x86.ActiveCfg = Debug|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Debug|x86.Build.0 = Debug|Any CPU {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Release|Any CPU.ActiveCfg = Release|Any CPU {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Release|Any CPU.Build.0 = Release|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Release|x64.ActiveCfg = Release|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Release|x64.Build.0 = Release|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Release|x86.ActiveCfg = Release|Any CPU + {02122FD2-9990-44CB-B9E1-1C5CDD388629}.Release|x86.Build.0 = Release|Any CPU {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Debug|x64.ActiveCfg = Debug|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Debug|x64.Build.0 = Debug|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Debug|x86.ActiveCfg = Debug|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Debug|x86.Build.0 = Debug|Any CPU {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Release|Any CPU.Build.0 = Release|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Release|x64.ActiveCfg = Release|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Release|x64.Build.0 = Release|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Release|x86.ActiveCfg = Release|Any CPU + {5CF5E1BC-D209-4EED-A34D-A96474D6189E}.Release|x86.Build.0 = Release|Any CPU {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Debug|x64.ActiveCfg = Debug|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Debug|x64.Build.0 = Debug|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Debug|x86.ActiveCfg = Debug|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Debug|x86.Build.0 = Debug|Any CPU {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Release|Any CPU.ActiveCfg = Release|Any CPU {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Release|Any CPU.Build.0 = Release|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Release|x64.ActiveCfg = Release|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Release|x64.Build.0 = Release|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Release|x86.ActiveCfg = Release|Any CPU + {EAF0B25B-9DE8-422D-855E-4D0A59DEF316}.Release|x86.Build.0 = Release|Any CPU {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Debug|x64.ActiveCfg = Debug|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Debug|x64.Build.0 = Debug|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Debug|x86.ActiveCfg = Debug|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Debug|x86.Build.0 = Debug|Any CPU {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Release|Any CPU.ActiveCfg = Release|Any CPU {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Release|Any CPU.Build.0 = Release|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Release|x64.ActiveCfg = Release|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Release|x64.Build.0 = Release|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Release|x86.ActiveCfg = Release|Any CPU + {14FDEACB-4933-423F-B6BA-7BF4E17E954A}.Release|x86.Build.0 = Release|Any CPU {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Debug|x64.ActiveCfg = Debug|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Debug|x64.Build.0 = Debug|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Debug|x86.ActiveCfg = Debug|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Debug|x86.Build.0 = Debug|Any CPU {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Release|Any CPU.Build.0 = Release|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Release|x64.ActiveCfg = Release|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Release|x64.Build.0 = Release|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Release|x86.ActiveCfg = Release|Any CPU + {AFAF16D5-6BEA-43AA-883D-A7B7B8B98D1B}.Release|x86.Build.0 = Release|Any CPU {B7957D47-EB36-405D-8899-50D208CEFA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B7957D47-EB36-405D-8899-50D208CEFA64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Debug|x64.ActiveCfg = Debug|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Debug|x64.Build.0 = Debug|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Debug|x86.ActiveCfg = Debug|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Debug|x86.Build.0 = Debug|Any CPU {B7957D47-EB36-405D-8899-50D208CEFA64}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7957D47-EB36-405D-8899-50D208CEFA64}.Release|Any CPU.Build.0 = Release|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Release|x64.ActiveCfg = Release|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Release|x64.Build.0 = Release|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Release|x86.ActiveCfg = Release|Any CPU + {B7957D47-EB36-405D-8899-50D208CEFA64}.Release|x86.Build.0 = Release|Any CPU {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Debug|x64.ActiveCfg = Debug|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Debug|x64.Build.0 = Debug|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Debug|x86.ActiveCfg = Debug|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Debug|x86.Build.0 = Debug|Any CPU {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Release|Any CPU.ActiveCfg = Release|Any CPU {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Release|Any CPU.Build.0 = Release|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Release|x64.ActiveCfg = Release|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Release|x64.Build.0 = Release|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Release|x86.ActiveCfg = Release|Any CPU + {45CBA5F5-DE15-4F1A-9078-949D91773D99}.Release|x86.Build.0 = Release|Any CPU {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Debug|x64.ActiveCfg = Debug|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Debug|x64.Build.0 = Debug|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Debug|x86.ActiveCfg = Debug|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Debug|x86.Build.0 = Debug|Any CPU {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Release|Any CPU.ActiveCfg = Release|Any CPU {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Release|Any CPU.Build.0 = Release|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Release|x64.ActiveCfg = Release|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Release|x64.Build.0 = Release|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Release|x86.ActiveCfg = Release|Any CPU + {5B624EB6-155E-419B-A42E-7C63BFAA80D2}.Release|x86.Build.0 = Release|Any CPU {8B147171-BECF-4693-8343-4F69E597386C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8B147171-BECF-4693-8343-4F69E597386C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Debug|x64.ActiveCfg = Debug|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Debug|x64.Build.0 = Debug|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Debug|x86.ActiveCfg = Debug|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Debug|x86.Build.0 = Debug|Any CPU {8B147171-BECF-4693-8343-4F69E597386C}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B147171-BECF-4693-8343-4F69E597386C}.Release|Any CPU.Build.0 = Release|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Release|x64.ActiveCfg = Release|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Release|x64.Build.0 = Release|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Release|x86.ActiveCfg = Release|Any CPU + {8B147171-BECF-4693-8343-4F69E597386C}.Release|x86.Build.0 = Release|Any CPU {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Debug|x64.ActiveCfg = Debug|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Debug|x64.Build.0 = Debug|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Debug|x86.ActiveCfg = Debug|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Debug|x86.Build.0 = Debug|Any CPU {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Release|Any CPU.Build.0 = Release|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Release|x64.ActiveCfg = Release|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Release|x64.Build.0 = Release|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Release|x86.ActiveCfg = Release|Any CPU + {AB9CF980-EAC5-4BC4-AC85-FFA0770FF7DA}.Release|x86.Build.0 = Release|Any CPU {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Debug|x64.Build.0 = Debug|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Debug|x86.ActiveCfg = Debug|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Debug|x86.Build.0 = Debug|Any CPU {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Release|Any CPU.Build.0 = Release|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Release|x64.ActiveCfg = Release|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Release|x64.Build.0 = Release|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Release|x86.ActiveCfg = Release|Any CPU + {F6357CAB-06C6-4603-99E7-1EDB79ACA8E8}.Release|x86.Build.0 = Release|Any CPU {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Debug|x64.ActiveCfg = Debug|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Debug|x64.Build.0 = Debug|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Debug|x86.ActiveCfg = Debug|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Debug|x86.Build.0 = Debug|Any CPU {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Release|Any CPU.Build.0 = Release|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Release|x64.ActiveCfg = Release|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Release|x64.Build.0 = Release|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Release|x86.ActiveCfg = Release|Any CPU + {AB1237F4-D074-4D3C-9AE4-6794BD30EA71}.Release|x86.Build.0 = Release|Any CPU {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Debug|x64.ActiveCfg = Debug|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Debug|x64.Build.0 = Debug|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Debug|x86.ActiveCfg = Debug|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Debug|x86.Build.0 = Debug|Any CPU {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Release|Any CPU.Build.0 = Release|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Release|x64.ActiveCfg = Release|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Release|x64.Build.0 = Release|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Release|x86.ActiveCfg = Release|Any CPU + {3F8D2B21-5C6E-4A9A-9C3B-9F1D2A7B8C64}.Release|x86.Build.0 = Release|Any CPU {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Debug|x64.ActiveCfg = Debug|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Debug|x64.Build.0 = Debug|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Debug|x86.ActiveCfg = Debug|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Debug|x86.Build.0 = Debug|Any CPU {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Release|Any CPU.Build.0 = Release|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Release|x64.ActiveCfg = Release|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Release|x64.Build.0 = Release|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Release|x86.ActiveCfg = Release|Any CPU + {E7B8C1F2-9A3D-4C2E-8B7A-6D2F3A1E4B5C}.Release|x86.Build.0 = Release|Any CPU {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Debug|x64.ActiveCfg = Debug|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Debug|x64.Build.0 = Debug|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Debug|x86.ActiveCfg = Debug|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Debug|x86.Build.0 = Debug|Any CPU {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Release|Any CPU.Build.0 = Release|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Release|x64.ActiveCfg = Release|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Release|x64.Build.0 = Release|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Release|x86.ActiveCfg = Release|Any CPU + {08B23D8C-7AAC-4CE7-830C-4DFF9F296BFB}.Release|x86.Build.0 = Release|Any CPU {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Debug|x64.ActiveCfg = Debug|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Debug|x64.Build.0 = Debug|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Debug|x86.ActiveCfg = Debug|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Debug|x86.Build.0 = Debug|Any CPU {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Release|Any CPU.Build.0 = Release|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Release|x64.ActiveCfg = Release|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Release|x64.Build.0 = Release|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Release|x86.ActiveCfg = Release|Any CPU + {5CEEEC08-7F1F-4F75-BC8D-6E80C54C21FD}.Release|x86.Build.0 = Release|Any CPU {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Debug|x64.ActiveCfg = Debug|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Debug|x64.Build.0 = Debug|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Debug|x86.ActiveCfg = Debug|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Debug|x86.Build.0 = Debug|Any CPU {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Release|Any CPU.Build.0 = Release|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Release|x64.ActiveCfg = Release|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Release|x64.Build.0 = Release|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Release|x86.ActiveCfg = Release|Any CPU + {AA91FC07-FE50-4DE1-A388-7AA0DB35C84A}.Release|x86.Build.0 = Release|Any CPU {A52169E1-8653-4B7D-9F14-84837E237E43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A52169E1-8653-4B7D-9F14-84837E237E43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Debug|x64.ActiveCfg = Debug|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Debug|x64.Build.0 = Debug|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Debug|x86.ActiveCfg = Debug|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Debug|x86.Build.0 = Debug|Any CPU {A52169E1-8653-4B7D-9F14-84837E237E43}.Release|Any CPU.ActiveCfg = Release|Any CPU {A52169E1-8653-4B7D-9F14-84837E237E43}.Release|Any CPU.Build.0 = Release|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Release|x64.ActiveCfg = Release|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Release|x64.Build.0 = Release|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Release|x86.ActiveCfg = Release|Any CPU + {A52169E1-8653-4B7D-9F14-84837E237E43}.Release|x86.Build.0 = Release|Any CPU {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Debug|x64.ActiveCfg = Debug|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Debug|x64.Build.0 = Debug|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Debug|x86.ActiveCfg = Debug|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Debug|x86.Build.0 = Debug|Any CPU {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Release|Any CPU.Build.0 = Release|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Release|x64.ActiveCfg = Release|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Release|x64.Build.0 = Release|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Release|x86.ActiveCfg = Release|Any CPU + {9922946A-03DA-4AC6-8AA6-ADEC5EF2E9EB}.Release|x86.Build.0 = Release|Any CPU {8791C343-7B1E-4206-A954-A0CFD573E460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8791C343-7B1E-4206-A954-A0CFD573E460}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Debug|x64.ActiveCfg = Debug|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Debug|x64.Build.0 = Debug|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Debug|x86.ActiveCfg = Debug|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Debug|x86.Build.0 = Debug|Any CPU {8791C343-7B1E-4206-A954-A0CFD573E460}.Release|Any CPU.ActiveCfg = Release|Any CPU {8791C343-7B1E-4206-A954-A0CFD573E460}.Release|Any CPU.Build.0 = Release|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Release|x64.ActiveCfg = Release|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Release|x64.Build.0 = Release|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Release|x86.ActiveCfg = Release|Any CPU + {8791C343-7B1E-4206-A954-A0CFD573E460}.Release|x86.Build.0 = Release|Any CPU {11894B20-F780-4FC9-8140-3601EBF54C10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {11894B20-F780-4FC9-8140-3601EBF54C10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Debug|x64.ActiveCfg = Debug|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Debug|x64.Build.0 = Debug|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Debug|x86.ActiveCfg = Debug|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Debug|x86.Build.0 = Debug|Any CPU {11894B20-F780-4FC9-8140-3601EBF54C10}.Release|Any CPU.ActiveCfg = Release|Any CPU {11894B20-F780-4FC9-8140-3601EBF54C10}.Release|Any CPU.Build.0 = Release|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Release|x64.ActiveCfg = Release|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Release|x64.Build.0 = Release|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Release|x86.ActiveCfg = Release|Any CPU + {11894B20-F780-4FC9-8140-3601EBF54C10}.Release|x86.Build.0 = Release|Any CPU {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Debug|x64.ActiveCfg = Debug|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Debug|x64.Build.0 = Debug|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Debug|x86.ActiveCfg = Debug|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Debug|x86.Build.0 = Debug|Any CPU {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Release|Any CPU.ActiveCfg = Release|Any CPU {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Release|Any CPU.Build.0 = Release|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Release|x64.ActiveCfg = Release|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Release|x64.Build.0 = Release|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Release|x86.ActiveCfg = Release|Any CPU + {B3E7A1C2-4D5F-6E8A-9B0C-1D2E3F4A5B6C}.Release|x86.Build.0 = Release|Any CPU {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Debug|x64.ActiveCfg = Debug|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Debug|x64.Build.0 = Debug|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Debug|x86.ActiveCfg = Debug|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Debug|x86.Build.0 = Debug|Any CPU {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Release|Any CPU.Build.0 = Release|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Release|x64.ActiveCfg = Release|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Release|x64.Build.0 = Release|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Release|x86.ActiveCfg = Release|Any CPU + {C4F8B2D3-5E6A-7F9B-0C1D-2E3F4A5B6C7D}.Release|x86.Build.0 = Release|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Debug|x64.ActiveCfg = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Debug|x64.Build.0 = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Debug|x86.ActiveCfg = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Debug|x86.Build.0 = Debug|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Release|Any CPU.Build.0 = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Release|x64.ActiveCfg = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Release|x64.Build.0 = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Release|x86.ActiveCfg = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345601}.Release|x86.Build.0 = Release|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Debug|x64.ActiveCfg = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Debug|x64.Build.0 = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Debug|x86.ActiveCfg = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Debug|x86.Build.0 = Debug|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Release|Any CPU.Build.0 = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Release|x64.ActiveCfg = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Release|x64.Build.0 = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Release|x86.ActiveCfg = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345602}.Release|x86.Build.0 = Release|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Debug|x64.ActiveCfg = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Debug|x64.Build.0 = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Debug|x86.ActiveCfg = Debug|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Debug|x86.Build.0 = Debug|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Release|Any CPU.Build.0 = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Release|x64.ActiveCfg = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Release|x64.Build.0 = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Release|x86.ActiveCfg = Release|Any CPU + {D5E6F7A8-1234-5678-9ABC-DEF012345603}.Release|x86.Build.0 = Release|Any CPU + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Debug|Any CPU.ActiveCfg = Debug|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Debug|Any CPU.Build.0 = Debug|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Debug|x64.ActiveCfg = Debug|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Debug|x64.Build.0 = Debug|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Debug|x86.ActiveCfg = Debug|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Debug|x86.Build.0 = Debug|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Release|Any CPU.ActiveCfg = Release|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Release|Any CPU.Build.0 = Release|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Release|x64.ActiveCfg = Release|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Release|x64.Build.0 = Release|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Release|x86.ActiveCfg = Release|anycpu + {E9478405-3D5D-439C-B0D5-753DC5F2F46D}.Release|x86.Build.0 = Release|anycpu EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -282,6 +548,7 @@ Global {D5E6F7A8-1234-5678-9ABC-DEF012345601} = {09E18837-1DDE-4EAF-80EC-DA55557C81EB} {D5E6F7A8-1234-5678-9ABC-DEF012345602} = {09E18837-1DDE-4EAF-80EC-DA55557C81EB} {D5E6F7A8-1234-5678-9ABC-DEF012345603} = {09E18837-1DDE-4EAF-80EC-DA55557C81EB} + {E9478405-3D5D-439C-B0D5-753DC5F2F46D} = {09E18837-1DDE-4EAF-80EC-DA55557C81EB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0FF614CC-FEBC-4C66-B3FC-FCB73EE511D7} diff --git a/README.md b/README.md index 67700dcb..34ddf6c9 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,7 @@ private static SendEmailRequest TemplateBasedRequest() - Email logs (list with filters and pagination; get message details with events) – [`examples/Mailtrap.Example.EmailLogs`](examples/Mailtrap.Example.EmailLogs/) - Email sending statistics – [`examples/Mailtrap.Example.Stats`](examples/Mailtrap.Example.Stats/) - Webhooks management – [`examples/Mailtrap.Example.Webhooks`](examples/Mailtrap.Example.Webhooks/) +- Verifying webhook signatures – [`examples/Mailtrap.Example.WebhookSignature`](examples/Mailtrap.Example.WebhookSignature/) ### Email Sandbox (Testing) @@ -314,6 +315,28 @@ private static SendEmailRequest TemplateBasedRequest() Each example includes detailed comments and demonstrates best practices for error handling, configuration, and resource management. +### Verifying webhook signatures + +Mailtrap signs every outbound webhook with HMAC-SHA256 and sends the lowercase hex digest in the `Mailtrap-Signature` header. Verify the signature against the raw request body using the `signing_secret` returned when you created the webhook: + +```csharp +using Mailtrap.Webhooks; + +// `payload` must be the unparsed request body — do NOT re-serialize the +// parsed JSON, as that may reorder keys and invalidate the signature. +var valid = WebhookSignature.Verify( + payload, + request.Headers["Mailtrap-Signature"].ToString(), + Environment.GetEnvironmentVariable("MAILTRAP_WEBHOOK_SIGNING_SECRET")!); + +if (!valid) +{ + return Results.Unauthorized(); +} +``` + +The helper performs a constant-time comparison and returns `false` (rather than throwing) for empty, missing, or malformed signatures. + --- ## Documentation diff --git a/examples/Mailtrap.Example.WebhookSignature/Mailtrap.Example.WebhookSignature.csproj b/examples/Mailtrap.Example.WebhookSignature/Mailtrap.Example.WebhookSignature.csproj new file mode 100644 index 00000000..6b512ec9 --- /dev/null +++ b/examples/Mailtrap.Example.WebhookSignature/Mailtrap.Example.WebhookSignature.csproj @@ -0,0 +1 @@ + diff --git a/examples/Mailtrap.Example.WebhookSignature/Program.cs b/examples/Mailtrap.Example.WebhookSignature/Program.cs new file mode 100644 index 00000000..90caa8fc --- /dev/null +++ b/examples/Mailtrap.Example.WebhookSignature/Program.cs @@ -0,0 +1,17 @@ +using System.Security.Cryptography; +using System.Text; +using Mailtrap.Webhooks; + +var payload = "{\"event\":\"delivery\",\"message_id\":\"abc-123\"}"; +var signingSecret = "8d9a3c0e7f5b2d4a6c1e9f8b3a7d5c2e"; + +string signature; +using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(signingSecret))) +{ + signature = Convert.ToHexStringLower(hmac.ComputeHash(Encoding.UTF8.GetBytes(payload))); +} + +if (!WebhookSignature.Verify(payload, signature, signingSecret)) +{ + throw new InvalidOperationException("Signature verification failed!"); +} diff --git a/examples/Mailtrap.Example.WebhookSignature/Properties/launchSettings.json b/examples/Mailtrap.Example.WebhookSignature/Properties/launchSettings.json new file mode 100644 index 00000000..b8daf491 --- /dev/null +++ b/examples/Mailtrap.Example.WebhookSignature/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "Project": { + "commandName": "Project", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + } + } +} diff --git a/examples/Mailtrap.Example.WebhookSignature/appsettings.json b/examples/Mailtrap.Example.WebhookSignature/appsettings.json new file mode 100644 index 00000000..a4e2270e --- /dev/null +++ b/examples/Mailtrap.Example.WebhookSignature/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "System": "Warning", + "Microsoft": "Warning" + } + } +} diff --git a/src/Mailtrap.Abstractions/Webhooks/WebhookSignature.cs b/src/Mailtrap.Abstractions/Webhooks/WebhookSignature.cs new file mode 100644 index 00000000..e2e4869d --- /dev/null +++ b/src/Mailtrap.Abstractions/Webhooks/WebhookSignature.cs @@ -0,0 +1,175 @@ +using System.Security.Cryptography; +using System.Text; + +namespace Mailtrap.Webhooks; + + +/// +/// Helpers for verifying inbound Mailtrap webhook signatures. +/// +/// +/// +/// +/// Mailtrap signs every outbound webhook by computing +/// HMAC-SHA256(signing_secret, raw_request_body) and sending the lowercase hex digest +/// in the Mailtrap-Signature HTTP header. To authenticate a webhook on the receiver +/// side, compute the same digest using the signing_secret returned when the webhook +/// was created and compare it to the value of the header in constant time. +/// +/// +/// The comparison is performed in constant time to avoid timing side-channels. +/// +/// +/// never throws on inputs that could plausibly +/// arrive over the wire ( / empty strings, wrong-length signatures, +/// non-hex characters, missing secret) — it simply returns . This +/// makes it safe to call directly from a request handler without wrapping in try/catch. +/// +/// +/// See the +/// +/// Mailtrap documentation — Verifying the signature. +/// +/// +public static class WebhookSignature +{ + /// + /// Hex-encoded HMAC-SHA256 signature length (SHA-256 produces 32 bytes / 64 hex chars). + /// + public const int SignatureHexLength = 64; + + /// + /// Verifies the HMAC-SHA256 signature of a Mailtrap webhook payload. + /// + /// + /// + /// The raw request body, exactly as received. Do not parse and + /// re-serialize the JSON — re-encoding may reorder keys or alter whitespace and + /// invalidate the signature. In ASP.NET Core, call + /// HttpRequest.EnableBuffering() and read the body via + /// new StreamReader(Request.Body).ReadToEndAsync(), or bind directly to a + /// byte[] / on the webhook endpoint so the + /// body is preserved verbatim. + /// + /// + /// The value of the Mailtrap-Signature HTTP header (lowercase hex string). + /// + /// + /// The webhook's signing_secret, returned by the Webhooks API on webhook creation. + /// + /// + /// + /// if is valid for the given + /// and ; + /// otherwise (including any / empty input, wrong-length or + /// non-hex signatures). + /// + public static bool Verify(string payload, string signature, string signingSecret) + { + if (string.IsNullOrEmpty(signature)) + { + return false; + } + if (string.IsNullOrEmpty(signingSecret)) + { + return false; + } + if (string.IsNullOrEmpty(payload)) + { + return false; + } + if (signature.Length != SignatureHexLength) + { + return false; + } + + if (!TryParseHex(signature, out var providedBytes)) + { + return false; + } + + byte[] expectedBytes; + using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(signingSecret))) + { + expectedBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload)); + } + + // Defensive: the hex-length check above already pins providedBytes to 32 bytes + // (= expectedBytes.Length), but reassert before the constant-time compare so a + // future change to SignatureHexLength can't accidentally introduce a timing leak. + if (expectedBytes.Length != providedBytes.Length) + { + return false; + } + + return FixedTimeEquals(expectedBytes, providedBytes); + } + + /// + /// Parses a lowercase/uppercase hex string into bytes without throwing on invalid input. + /// + private static bool TryParseHex(string hex, out byte[] bytes) + { + if ((hex.Length & 1) != 0) + { + bytes = []; + return false; + } + + var result = new byte[hex.Length / 2]; + for (var i = 0; i < result.Length; i++) + { + if (!TryParseHexDigit(hex[(i * 2) + 0], out var high) || + !TryParseHexDigit(hex[(i * 2) + 1], out var low)) + { + bytes = []; + return false; + } + + result[i] = (byte)((high << 4) | low); + } + + bytes = result; + return true; + } + + private static bool TryParseHexDigit(char c, out int value) + { + if (c is >= '0' and <= '9') + { + value = c - '0'; + return true; + } + if (c is >= 'a' and <= 'f') + { + value = c - 'a' + 10; + return true; + } + if (c is >= 'A' and <= 'F') + { + value = c - 'A' + 10; + return true; + } + + value = 0; + return false; + } + + /// + /// Constant-time byte-array equality. Equivalent to + /// CryptographicOperations.FixedTimeEquals, which is unavailable on + /// netstandard2.0. + /// + private static bool FixedTimeEquals(byte[] left, byte[] right) + { + // Lengths are checked up-front by the caller; equal-length guarantees a constant + // number of loop iterations and avoids leaking length information via timing. + var diff = 0; + for (var i = 0; i < left.Length; i++) + { + diff |= left[i] ^ right[i]; + } + + return diff == 0; + } +} diff --git a/tests/Mailtrap.UnitTests/GlobalUsings.cs b/tests/Mailtrap.UnitTests/GlobalUsings.cs index 10a9248e..1fd40eac 100644 --- a/tests/Mailtrap.UnitTests/GlobalUsings.cs +++ b/tests/Mailtrap.UnitTests/GlobalUsings.cs @@ -68,6 +68,7 @@ global using Mailtrap.TestingMessages; global using Mailtrap.TestingMessages.Requests; global using Mailtrap.UnitTests.TestConstants; +global using Mailtrap.Webhooks; global using Mailtrap.UnitTests.TestExtensions; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Mailtrap.UnitTests/Webhooks/WebhookSignatureTests.cs b/tests/Mailtrap.UnitTests/Webhooks/WebhookSignatureTests.cs new file mode 100644 index 00000000..4a892846 --- /dev/null +++ b/tests/Mailtrap.UnitTests/Webhooks/WebhookSignatureTests.cs @@ -0,0 +1,198 @@ +using System.Security.Cryptography; + +namespace Mailtrap.UnitTests.Webhooks; + + +[TestFixture] +internal sealed class WebhookSignatureTests +{ + // --------------------------------------------------------------------- + // Cross-SDK shared fixture — DO NOT CHANGE. + // + // The same (payload, signing_secret, expected_signature) triple is + // embedded verbatim in the test suites of every official Mailtrap SDK + // (Ruby, Python, PHP, Node.js, Java, .NET) to guarantee byte-for-byte + // compatibility of the verification algorithm across languages. Keep + // these three strings in sync with the other SDKs. + // --------------------------------------------------------------------- + private const string FixturePayload = + "{\"event\":\"delivery\",\"sending_stream\":\"transactional\",\"category\":\"welcome\"," + + "\"message_id\":\"a8b1d8f6-1f8d-4a3c-9b2e-1a2b3c4d5e6f\"," + + "\"email\":\"recipient@example.com\"," + + "\"event_id\":\"f1e2d3c4-b5a6-7890-1234-567890abcdef\"," + + "\"timestamp\":1716070000}"; + + private const string FixtureSigningSecret = "8d9a3c0e7f5b2d4a6c1e9f8b3a7d5c2e"; + + private const string FixtureExpectedSignature = + "6d262e2611cd09be1f948382b5c611d63b0e585c4c9c5e40139d6ac3876d5433"; + + + // --------------------------------------------------------------------- + // 1. Valid signature → true + // --------------------------------------------------------------------- + [Test] + public void Verify_WithValidSignature_ReturnsTrue() + { + WebhookSignature + .Verify(FixturePayload, FixtureExpectedSignature, FixtureSigningSecret) + .Should().BeTrue(); + } + + // --------------------------------------------------------------------- + // 2. Wrong secret → false + // --------------------------------------------------------------------- + [Test] + public void Verify_WithWrongSecret_ReturnsFalse() + { + WebhookSignature + .Verify(FixturePayload, FixtureExpectedSignature, "wrong_secret_value") + .Should().BeFalse(); + } + + // --------------------------------------------------------------------- + // 3. Payload tampered (one byte changed) → false + // --------------------------------------------------------------------- + [Test] + public void Verify_WithTamperedPayload_ReturnsFalse() + { + // Flip "delivery" to "delivere" — same length, different bytes. + var tampered = FixturePayload.Replace("\"delivery\"", "\"delivere\"", StringComparison.Ordinal); + + WebhookSignature + .Verify(tampered, FixtureExpectedSignature, FixtureSigningSecret) + .Should().BeFalse(); + } + + // --------------------------------------------------------------------- + // 4. Signature with wrong length → false (no throw) + // --------------------------------------------------------------------- + [Test] + public void Verify_WithSignatureOfWrongLength_ReturnsFalse() + { + var tooShort = FixtureExpectedSignature[..63]; + var tooLong = FixtureExpectedSignature + "a"; + + WebhookSignature + .Verify(FixturePayload, tooShort, FixtureSigningSecret) + .Should().BeFalse(); + + WebhookSignature + .Verify(FixturePayload, tooLong, FixtureSigningSecret) + .Should().BeFalse(); + } + + // --------------------------------------------------------------------- + // 5. Signature with non-hex characters → false (no throw) + // --------------------------------------------------------------------- + [Test] + public void Verify_WithNonHexCharactersInSignature_ReturnsFalse() + { + // Same length (64), but contains 'z' which is not a hex digit. + var nonHex = string.Concat("z", FixtureExpectedSignature.AsSpan(1)); + nonHex.Should().HaveLength(WebhookSignature.SignatureHexLength); + + WebhookSignature + .Verify(FixturePayload, nonHex, FixtureSigningSecret) + .Should().BeFalse(); + } + + // --------------------------------------------------------------------- + // 6. Empty signature string → false + // --------------------------------------------------------------------- + [Test] + public void Verify_WithEmptySignature_ReturnsFalse() + { + WebhookSignature + .Verify(FixturePayload, string.Empty, FixtureSigningSecret) + .Should().BeFalse(); + } + + // --------------------------------------------------------------------- + // 7. Empty signingSecret → false + // --------------------------------------------------------------------- + [Test] + public void Verify_WithEmptySigningSecret_ReturnsFalse() + { + WebhookSignature + .Verify(FixturePayload, FixtureExpectedSignature, string.Empty) + .Should().BeFalse(); + } + + // --------------------------------------------------------------------- + // 8. Empty payload with non-empty signature → false + // --------------------------------------------------------------------- + [Test] + public void Verify_WithEmptyPayload_ReturnsFalse() + { + WebhookSignature + .Verify(string.Empty, FixtureExpectedSignature, FixtureSigningSecret) + .Should().BeFalse(); + } + + // --------------------------------------------------------------------- + // 9. Known-good fixture round-trip — independently recompute the HMAC + // in the test (not via the helper) and assert it matches both the + // embedded expected signature AND the helper's verdict. + // --------------------------------------------------------------------- + [Test] + public void Verify_FixtureRoundTrip_MatchesIndependentlyComputedHmac() + { + // Recompute the HMAC-SHA256 independently of the helper, using BCL + // primitives directly. If this drifts from FixtureExpectedSignature, + // either the fixture is wrong or the algorithm/encoding has changed. + byte[] digest; + using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(FixtureSigningSecret))) + { + digest = hmac.ComputeHash(Encoding.UTF8.GetBytes(FixturePayload)); + } + + var computedHex = ToLowerHex(digest); + + computedHex.Should().Be( + FixtureExpectedSignature, + "independently computed HMAC must equal embedded fixture signature"); + + WebhookSignature + .Verify(FixturePayload, FixtureExpectedSignature, FixtureSigningSecret) + .Should().BeTrue("helper must agree the fixture is valid"); + } + + // --------------------------------------------------------------------- + // Bonus: null inputs → false (no NullReferenceException) + // --------------------------------------------------------------------- + [Test] + public void Verify_WithNullPayload_ReturnsFalse() + { + WebhookSignature + .Verify(null!, FixtureExpectedSignature, FixtureSigningSecret) + .Should().BeFalse(); + } + + [Test] + public void Verify_WithNullSignature_ReturnsFalse() + { + WebhookSignature + .Verify(FixturePayload, null!, FixtureSigningSecret) + .Should().BeFalse(); + } + + [Test] + public void Verify_WithNullSigningSecret_ReturnsFalse() + { + WebhookSignature + .Verify(FixturePayload, FixtureExpectedSignature, null!) + .Should().BeFalse(); + } + + + private static string ToLowerHex(byte[] bytes) + { + var sb = new StringBuilder(bytes.Length * 2); + foreach (var b in bytes) + { + sb.Append(b.ToString("x2", System.Globalization.CultureInfo.InvariantCulture)); + } + return sb.ToString(); + } +}