static void Main(string[] args) { SslLabsClient client = new SslLabsClient(); Analysis analysis = client.GetAnalysisBlocking("mbwarez.dk", null, AnalyzeOptions.StartNew, analysis1 => { Console.WriteLine("Status: " + analysis1.Status + " (" + analysis1.StatusMessage + ")"); }); Console.WriteLine(analysis); }
public void HpkpTest() { SslLabsClient client = new SslLabsClient(); Host analysis = client.GetAnalysisBlocking("scotthelme.co.uk", options: AnalyzeOptions.ReturnAll); Assert.IsNotNull(analysis); Assert.AreEqual(AnalysisStatus.READY, analysis.Status, "scotthelme.co.uk analysis was not ready. Wait for the analysis to complete."); Endpoint endpoint = analysis.Endpoints.First(); HpkpPolicy hpkpPolicy = endpoint.Details.HpkpPolicy; TestHelpers.EnsureAllPropertiesSet(hpkpPolicy, nameof(HpkpPolicy.Error)); Assert.IsTrue(hpkpPolicy.MaxAge > 0); Assert.IsTrue(hpkpPolicy.IncludeSubDomains); Assert.AreEqual(HpkpStatus.Valid, hpkpPolicy.Status); Assert.IsTrue(hpkpPolicy.Pins.Any()); Assert.IsTrue(hpkpPolicy.MatchedPins.Any()); }
public void GeneralTest() { SslLabsClient client = new SslLabsClient(); Host analysis = client.GetAnalysisBlocking("scotthelme.co.uk", options: AnalyzeOptions.ReturnAll); Assert.IsNotNull(analysis); Assert.AreEqual(AnalysisStatus.READY, analysis.Status, "scotthelme.co.uk analysis was not ready. Wait for the analysis to complete."); TestHelpers.EnsureAllPropertiesSet(analysis, nameof(Host.StatusMessage)); Assert.IsTrue(analysis.Endpoints.Any()); Endpoint endpoint = analysis.Endpoints.First(); TestHelpers.EnsureAllPropertiesSet(endpoint, nameof(Endpoint.StatusDetails), nameof(Endpoint.StatusDetailsMessage)); EndpointDetails details = endpoint.Details; TestHelpers.EnsureAllPropertiesSet(details, nameof(EndpointDetails.StaplingRevocationErrorMessage), nameof(EndpointDetails.HttpForwarding)); }
public void HstsTest() { SslLabsClient client = new SslLabsClient(); Host analysis = client.GetAnalysisBlocking("scotthelme.co.uk", options: AnalyzeOptions.ReturnAll); Assert.IsNotNull(analysis); Assert.AreEqual(AnalysisStatus.READY, analysis.Status, "scotthelme.co.uk analysis was not ready. Wait for the analysis to complete."); Endpoint endpoint = analysis.Endpoints.First(); HstsPolicy hstsPolicy = endpoint.Details.HstsPolicy; Assert.IsTrue(hstsPolicy.MaxAge > 0); Assert.IsTrue(hstsPolicy.Preload); Assert.IsTrue(hstsPolicy.IncludeSubDomains); Assert.AreEqual(HstsStatus.Present, hstsPolicy.Status); List <HstsPreload> hstsPreloads = endpoint.Details.HstsPreloads; Assert.IsTrue(hstsPreloads.Any(s => s.Source == "Chrome")); }
/// <summary> /// Takes in host URL and returns Qualys SSL Labs API result /// </summary> /// <param name="url"></param> /// <returns></returns> public Task <Analysis> QualysReport(string domainUrl) { try { if (string.IsNullOrEmpty(domainUrl)) { throw new ArgumentNullException("Host URL was null or empty."); } var client = new SslLabsClient(); var result = client.GetAnalysisBlocking(domainUrl, 24, AnalyzeOptions.FromCache | AnalyzeOptions.ReturnAll); return(Task.FromResult(result)); } catch (HttpRequestException ex) { throw ex; } catch (Exception ex) { // TODO: log this exception throw ex; } }
static int Main(string[] args) { Options options = new Options(); options.MaxConcurrentAssesments = DefaultMaxAssesments; options.MaxAge = DefaultMaxAge; OptionSet parser = new OptionSet(); parser.Add("f|file=", "Input file, one host pr. line, required", s => options.Input = s); parser.Add("o|output=", "Output directory, will be created", s => options.Output = s); parser.Add("n|new", "Forces new scans", s => options.ForceNew = true); parser.Add("p|publish", "Published scans", s => options.Publish = true); parser.Add("w|overwrite", "Overwrite local scans, older than MaxAge", s => options.Overwrite = true); parser.Add <int>("a|maxage=", "Specify a MaxAge parameter, default: " + DefaultMaxAge, s => options.MaxAge = s); parser.Add <int>("m|max=", "Max concurrent scans, default: " + DefaultMaxAssesments, s => options.MaxConcurrentAssesments = s); parser.Add("e|endpoint=", "Endpoint. 'prod' or 'dev'", s => options.Endpoint = s); List <string> excessArgs = parser.Parse(args); if (string.IsNullOrEmpty(options.Input) || !File.Exists(options.Input)) { Console.WriteLine("Missing input file"); Console.WriteLine(); Console.WriteLine("Help:"); parser.WriteOptionDescriptions(Console.Out); return(1); } if (string.IsNullOrEmpty(options.Output)) { Console.WriteLine("Missing output directory"); Console.WriteLine(); Console.WriteLine("Help:"); parser.WriteOptionDescriptions(Console.Out); return(1); } if (!Directory.Exists(options.Output)) { Directory.CreateDirectory(options.Output); } Queue <string> domains = new Queue <string>(); bool anyBadInput = false; foreach (string line in File.ReadLines(options.Input)) { if (Uri.CheckHostName(line) != UriHostNameType.Dns) { Console.WriteLine("Bad input: " + line); anyBadInput = true; } else { domains.Enqueue(line); } } if (anyBadInput) { Console.WriteLine("One or more bad lines found - please correct"); return(2); } Console.WriteLine("Beginning work on {0:N0} domains", domains.Count); Uri endpoint = new Uri("https://api.ssllabs.com/api/v2/"); if (options.Endpoint == "dev") { endpoint = new Uri("https://api.dev.ssllabs.com/api/v2/"); } int completedTasks = 0; SslLabsClient client = new SslLabsClient(endpoint); client.WaitTimePreScan = TimeSpan.FromSeconds(20); client.WaitTimeScan = TimeSpan.FromSeconds(10); Info sslLabsInfo = client.GetInfo(); int?maxAge = options.MaxAge; AnalyzeOptions startOptions = AnalyzeOptions.None; if (options.ForceNew) { startOptions |= AnalyzeOptions.StartNew; maxAge = null; } else { startOptions = AnalyzeOptions.ReturnAllIfDone; } if (options.Publish) { startOptions |= AnalyzeOptions.Publish; } DateTime lastStatus = DateTime.UtcNow; object lastStatusLock = new object(); Action printStatus = () => { lock (lastStatusLock) { if ((DateTime.UtcNow - lastStatus).TotalSeconds < 5) { return; } lastStatus = DateTime.UtcNow; Console.WriteLine("Queue: {0:N0}, running: {1:N0} (cur.limit: {2:N0}), completed: {3:N0}", domains.Count, client.CurrentAssesments, client.MaxAssesments, completedTasks); } }; AutoResetEvent limitChangedEvent = new AutoResetEvent(false); client.MaxAssesmentsChanged += () => limitChangedEvent.Set(); client.CurrentAssesmentsChanged += () => limitChangedEvent.Set(); while (domains.Any()) { string domain = domains.Peek(); string scanPath = Path.Combine(options.Output, domain + ".scan"); // Is it done already? Analysis analysis; if (File.Exists(scanPath)) { if (options.Overwrite && maxAge.HasValue) { analysis = JsonConvert.DeserializeObject <Analysis>(File.ReadAllText(scanPath)); int age = (int)(DateTime.UtcNow - analysis.TestTime).TotalHours; if (age > maxAge) { // Process this analysis = null; } else { // Skip domains.Dequeue(); continue; } } else { // Skip domains.Dequeue(); continue; } } // Attempt to start the task while (true) { TryStartResult didStart; try { didStart = client.TryStartAnalysis(domain, maxAge, out analysis, startOptions); } catch (WebException ex) { Console.WriteLine("(Domain: " + domain + ") Webexception starting scan, waiting 3s: " + ex.Message); limitChangedEvent.WaitOne(3000); continue; } catch (Exception ex) { Console.WriteLine("(Domain: " + domain + ") Exception while starting scan, waiting 30s: " + ex.Message); Thread.Sleep(30000); continue; } if (didStart == TryStartResult.RateLimit) { Thread.Sleep(sslLabsInfo.NewAssessmentCoolOff); continue; } if (didStart == TryStartResult.Ok) { printStatus(); break; } // Wait for one to free up, fall back to trying every 30s limitChangedEvent.WaitOne(30000); printStatus(); } // The task was started domains.Dequeue(); //Console.WriteLine("Started " + domain); Task.Factory.StartNew(() => { Analysis innerAnalysis = null; if (analysis != null && analysis.Status == AnalysisStatus.READY) { // Use the one we fetched immediately innerAnalysis = analysis; } while (innerAnalysis == null) { try { // Block till we have an analysis innerAnalysis = client.GetAnalysisBlocking(domain); } catch (WebException ex) { Console.WriteLine("(Domain: " + domain + ") Webexception waiting for scan, waiting 3s: " + ex.Message); Thread.Sleep(3000); } catch (Exception ex) { Console.WriteLine("(Domain: " + domain + ") Exception while waiting for scan, waiting 30s: " + ex.Message); Thread.Sleep(30000); } } File.WriteAllText(scanPath, JsonConvert.SerializeObject(innerAnalysis)); Console.WriteLine("Completed " + domain); Interlocked.Increment(ref completedTasks); limitChangedEvent.Set(); }); } Timer timer = new Timer(2000); timer.Elapsed += (sender, eventArgs) => printStatus(); timer.Start(); while (true) { Info info = client.GetInfo(); if (info.CurrentAssessments == 0) { break; } // Wait for tasks to finish, fall back to checking every 15s limitChangedEvent.WaitOne(15000); } timer.Stop(); return(0); }
private static Host HandleFetch(Options options) { Action <Host> progress = prg => { if (prg.Endpoints == null) { using (AwesomeConsole.BeginSequentialWrite()) AwesomeConsole.WriteLine("Progress {0}", prg.Status); return; } float max = prg.Endpoints.Count * 100; float pct = prg.Endpoints.Sum(s => (float)(s.Progress == -1 ? 0 : s.Progress)) / max; string current = prg.Endpoints.SkipWhile(s => s.Progress == 100).Select(s => s.StatusDetailsMessage).FirstOrDefault(); List <Tuple <int, string> > states = prg.Endpoints.Select(s => new Tuple <int, string>(s.Progress, s.StatusMessage)).ToList(); using (AwesomeConsole.BeginSequentialWrite()) { AwesomeConsole.Write("Progress {0:P}", pct); AwesomeConsole.Write(" (servers: "); for (int i = 0; i < states.Count; i++) { Tuple <int, string> state = states[i]; if (state.Item1 == 100) { AwesomeConsole.Write("{0}", ConsoleColor.DarkGreen, state.Item2); } else { AwesomeConsole.Write("{0}", ConsoleColor.Yellow, state.Item2); } if (i > 0) { AwesomeConsole.Write(" | "); } } AwesomeConsole.Write(") (current: "); AwesomeConsole.Write("{0}", ConsoleColor.Cyan, current); AwesomeConsole.WriteLine(")"); } }; if (!options.Progress) { progress = null; } AnalyzeOptions analyzeOptions = AnalyzeOptions.ReturnAllIfDone; if (options.New) { analyzeOptions |= AnalyzeOptions.StartNew; } else { analyzeOptions |= AnalyzeOptions.FromCache; } Host analysis = Client.GetAnalysisBlocking(options.Hostname, null, analyzeOptions, progress); return(analysis); }