using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; namespace IdleMafiaBot { static class Trust { static readonly string[] Bundles = { "/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/certs/ca-bundle.crt", "/etc/ssl/cert.pem", "/etc/ssl/ca-bundle.pem" }; public static string Sync() { try { string bundle = Bundles.FirstOrDefault(File.Exists); if (bundle == null) return "Discord: no system certificate list found (/etc/ssl/certs) - Discord messages may fail"; string home = Environment.GetEnvironmentVariable("HOME"); if (string.IsNullOrEmpty(home)) return null; string trustDir = Path.Combine(home, ".config/.mono/new-certs/Trust"); if (Directory.Exists(trustDir)) { var files = Directory.GetFiles(trustDir); if (files.Length >= 20 && files.Max(f => File.GetLastWriteTimeUtc(f)) >= File.GetLastWriteTimeUtc(bundle)) return null; } var ders = Pem(File.ReadAllText(bundle)); if (ders.Count == 0) return null; var asm = Assembly.Load("Mono.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756"); var certT = asm.GetType("Mono.Security.X509.X509Certificate", true); var mgr = asm.GetType("Mono.Security.X509.X509StoreManager", true); var stores = mgr.GetProperty("NewCurrentUser", BindingFlags.Public | BindingFlags.Static).GetValue(null, null); var store = stores.GetType().GetProperty("TrustedRoot").GetValue(stores, null); var import = store.GetType().GetMethod("Import", new[] { certT }); var have = store.GetType().GetProperty("Certificates").GetValue(store, null); var contains = have.GetType().GetMethod("Contains", new[] { certT }); int added = 0; foreach (var der in ders) { object c; try { c = Activator.CreateInstance(certT, new object[] { der }); } catch (Exception) { continue; } if ((bool)contains.Invoke(have, new[] { c })) continue; try { import.Invoke(store, new[] { c }); added++; } catch (Exception) { } } if (added == 0 && Directory.Exists(trustDir)) { var f = Directory.GetFiles(trustDir).FirstOrDefault(); if (f != null) File.SetLastWriteTimeUtc(f, DateTime.UtcNow); } return added > 0 ? "Discord: put the system's " + added + " trusted certificates into Mono's list (Discord messages need them)" : null; } catch (Exception e) { var inner = e is TargetInvocationException && e.InnerException != null ? e.InnerException : e; return "Discord: couldn't fill Mono's certificate list (" + inner.GetType().Name + ": " + inner.Message + ") - Discord messages may fail"; } } static List Pem(string text) { var list = new List(); const string begin = "-----BEGIN CERTIFICATE-----", end = "-----END CERTIFICATE-----"; int i = 0; while ((i = text.IndexOf(begin, i, StringComparison.Ordinal)) >= 0) { int j = text.IndexOf(end, i, StringComparison.Ordinal); if (j < 0) break; string b64 = text.Substring(i + begin.Length, j - i - begin.Length); try { list.Add(Convert.FromBase64String(new string(b64.Where(ch => !char.IsWhiteSpace(ch)).ToArray()))); } catch (FormatException) { } i = j + end.Length; } return list; } } }