1+ using System . Reflection ;
2+ using System . Security . Cryptography . X509Certificates ;
3+ using Titanium . Web . Proxy . Helpers ;
4+ using Titanium . Web . Proxy . Network ;
5+
6+ namespace Microsoft . Graph . DeveloperProxy ;
7+
8+ // based on https://github.com/justcoding121/titanium-web-proxy/blob/9e71608d204e5b67085656dd6b355813929801e4/src/Titanium.Web.Proxy/Certificates/Cache/DefaultCertificateDiskCache.cs
9+ public sealed class CertificateDiskCache : ICertificateCache {
10+ private const string DefaultCertificateDirectoryName = "crts" ;
11+ private const string DefaultCertificateFileExtension = ".pfx" ;
12+ private const string DefaultRootCertificateFileName = "rootCert" + DefaultCertificateFileExtension ;
13+ private const string ProxyConfigurationFolderName = "msgraph-developer-proxy" ;
14+
15+ private string ? rootCertificatePath ;
16+
17+ public X509Certificate2 ? LoadRootCertificate ( string pathOrName , string password , X509KeyStorageFlags storageFlags ) {
18+ var path = GetRootCertificatePath ( pathOrName , false ) ;
19+ return LoadCertificate ( path , password , storageFlags ) ;
20+ }
21+
22+ public void SaveRootCertificate ( string pathOrName , string password , X509Certificate2 certificate ) {
23+ var path = GetRootCertificatePath ( pathOrName , true ) ;
24+ var exported = certificate . Export ( X509ContentType . Pkcs12 , password ) ;
25+ File . WriteAllBytes ( path , exported ) ;
26+ }
27+
28+ /// <inheritdoc />
29+ public X509Certificate2 ? LoadCertificate ( string subjectName , X509KeyStorageFlags storageFlags ) {
30+ var filePath = Path . Combine ( GetCertificatePath ( false ) , subjectName + DefaultCertificateFileExtension ) ;
31+ return LoadCertificate ( filePath , string . Empty , storageFlags ) ;
32+ }
33+
34+ /// <inheritdoc />
35+ public void SaveCertificate ( string subjectName , X509Certificate2 certificate ) {
36+ var filePath = Path . Combine ( GetCertificatePath ( true ) , subjectName + DefaultCertificateFileExtension ) ;
37+ var exported = certificate . Export ( X509ContentType . Pkcs12 ) ;
38+ File . WriteAllBytes ( filePath , exported ) ;
39+ }
40+
41+ public void Clear ( ) {
42+ try {
43+ var path = GetCertificatePath ( false ) ;
44+ if ( Directory . Exists ( path ) ) Directory . Delete ( path , true ) ;
45+ }
46+ catch ( Exception ) {
47+ // do nothing
48+ }
49+ }
50+
51+ private X509Certificate2 ? LoadCertificate ( string path , string password , X509KeyStorageFlags storageFlags ) {
52+ byte [ ] exported ;
53+
54+ if ( ! File . Exists ( path ) ) return null ;
55+
56+ try {
57+ exported = File . ReadAllBytes ( path ) ;
58+ }
59+ catch ( IOException ) {
60+ // file or directory not found
61+ return null ;
62+ }
63+
64+ return new X509Certificate2 ( exported , password , storageFlags ) ;
65+ }
66+
67+ private string GetRootCertificatePath ( string pathOrName , bool create ) {
68+ if ( Path . IsPathRooted ( pathOrName ) ) return pathOrName ;
69+
70+ return Path . Combine ( GetRootCertificateDirectory ( create ) ,
71+ string . IsNullOrEmpty ( pathOrName ) ? DefaultRootCertificateFileName : pathOrName ) ;
72+ }
73+
74+ private string GetCertificatePath ( bool create ) {
75+ var path = GetRootCertificateDirectory ( create ) ;
76+
77+ var certPath = Path . Combine ( path , DefaultCertificateDirectoryName ) ;
78+ if ( create && ! Directory . Exists ( certPath ) ) Directory . CreateDirectory ( certPath ) ;
79+
80+ return certPath ;
81+ }
82+
83+ private string GetRootCertificateDirectory ( bool create ) {
84+ if ( rootCertificatePath == null ) {
85+ if ( RunTime . IsUwpOnWindows ) {
86+ rootCertificatePath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , ProxyConfigurationFolderName ) ;
87+ }
88+ else if ( RunTime . IsLinux ) {
89+ rootCertificatePath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) , ProxyConfigurationFolderName ) ;
90+ }
91+ else if ( RunTime . IsMac ) {
92+ rootCertificatePath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) , ProxyConfigurationFolderName ) ;
93+ }
94+ else {
95+ var assemblyLocation = GetType ( ) . Assembly . Location ;
96+
97+ // dynamically loaded assemblies returns string.Empty location
98+ if ( assemblyLocation == string . Empty ) assemblyLocation = Assembly . GetEntryAssembly ( ) ? . Location ;
99+
100+ #if NETSTANDARD2_1
101+ // single-file app returns string.Empty location
102+ if ( assemblyLocation == string . Empty )
103+ {
104+ assemblyLocation = AppContext . BaseDirectory ;
105+ }
106+ #endif
107+
108+ var path = Path . GetDirectoryName ( assemblyLocation ) ;
109+
110+ rootCertificatePath = path ?? throw new NullReferenceException ( ) ;
111+ }
112+ }
113+
114+ if ( create && ! Directory . Exists ( rootCertificatePath ) ) {
115+ Directory . CreateDirectory ( rootCertificatePath ) ;
116+ }
117+
118+ return rootCertificatePath ;
119+ }
120+ }
0 commit comments