=== Authorities.aspx ===
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Authorities.aspx.cs" Inherits="Authorities" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <style type="text/css">
        body
        {
        	font-family:Sans-Serif;
        }
        i
        {
        	color:#333333;
        	font-size:small;
        }
        pre
        {
			font-family:Fira Code, Lucida Console, Courier New, monospace;
			font-size:12pt;
        	padding:10px;
        	color:#FFFFFF;
        	background-color:#000000;
			overflow:scroll;
        }
    </style>
    <title>Authorities</title>
</head>
<body>
    <h1>List of authorities</h1>
    This is a list of tor authorities from the official source code (<a href="<%=SOURCE%>">here</a>)<br />
    <br />
    <form action="Authorities.aspx" method="post">
        Cache age: <%=Minutes %> Minutes<br />
        <input type="submit" value="Refresh" name="refresh" />
    </form>
    <pre><%=Server.HtmlEncode(string.Join("\n",AuthList))%></pre>
    <i>
        This page has been created because of repeated trouble with <a href="https://sourceforge.net/projects/advtor/">Advanced Onion Router</a>.
        Replace the authorities list if you can no longer connect to the TOR network using that client.
        <br />
        <a href="Authorities.aspx?source=1">View Source of this</a><br />
        <a href="Authorities.aspx?raw=1">Raw output</a><br />
        Copyright &copy; 2016 Kevin Gut
    </i>
</body>
</html>

=== Authorities.aspx.cs ===
using System;
using System.Collections.Generic;
using System.Net;
using System.IO;

/// <summary>
/// Shows TOR Authorities
/// </summary>
public partial class Authorities : System.Web.UI.Page
{
    /// <summary>
    /// This is the source file for the authorities
    /// </summary>
    public const string SOURCE = "https://gitweb.torproject.org/tor.git/plain/src/app/config/auth_dirs.inc";

    /// <summary>
    /// This will contain all the authorities
    /// </summary>
    protected string[] AuthList = null;

    protected int Minutes = 0;

    /// <summary>
    /// Chars to replace with "nothing" in source
    /// </summary>
    private readonly string[] Repl = new string[] {"\"","\r","\n" };

    /// <summary>
    /// Called when the site loads
    /// </summary>
    protected void Page_Load(object sender, EventArgs e)
    {
        //We allow source printing
        if (Request["Source"] == "1")
        {
            Source();
        }
        else
        {
            //We implement some sort of basic cache here to not tank the source file server
            if (Session["AUTHLIST"] == null || Session["CACHEAGE"]==null || !string.IsNullOrEmpty(Request.Form["refresh"]))
            {
                Session["AUTHLIST"] = AuthList = getAuth();
                Minutes = 0;
                Session["CACHEAGE"] = DateTime.Now;
            }
            else
            {
                AuthList = (string[])Session["AUTHLIST"];
                Minutes = (int)Math.Round(DateTime.Now.Subtract((DateTime)Session["CACHEAGE"]).TotalMinutes);
            }
            if (AuthList == null)
            {
                AuthList = new string[] { "Error reading source file. Please try again later." };
            }

            if (Request["raw"] == "1")
            {
                Response.Clear();
                Response.ContentType = "text/plain";
                Response.Write(string.Join("\r\n", AuthList));
                Response.End();
            }
        }
    }

    /// <summary>
    /// Gets the authorities list from the source file
    /// </summary>
    /// <returns>List of authorities</returns>
    private string[] getAuth()
    {
        string Lines = string.Empty;
        using (WebClient wc = new WebClient())
        {
            try
            {
                //Download the source file
                Lines = wc.DownloadString(SOURCE).Trim();
            }
            catch
            {
                return null;
            }
        }

        while (Lines.Contains("/*"))
        {
            Lines = Lines.Substring(0, Lines.IndexOf("/*")) + Lines.Substring(Lines.IndexOf("*/", Lines.IndexOf("/*")) + 2);
        }
        //create parts
        string[] Parts = Lines.Split(',');
        for (int i = 0; i < Parts.Length; i++)
        {
            //remove unneeded chars
            foreach(string s in Repl)
            {
                Parts[i] = Parts[i].Replace(s, "");
            }
            //remove unneeded whitespace
            while (Parts[i].Contains("  "))
            {
                Parts[i] = Parts[i].Replace("  ", " ");
            }
            //remove more whitespace
            Parts[i] = Parts[i].Trim();
        }
        return Parts;
    }

    /// <summary>
    /// Displays the source code of the current file
    /// </summary>
    private void Source()
    {
        string Answer = string.Format("=== {0} ===\r\n{1}\r\n=== {2} ===\r\n{3}",
            Path.GetFileName(Request.PhysicalPath),
            File.ReadAllText(Request.PhysicalPath),
            Path.GetFileName(Request.PhysicalPath + ".cs"),
            File.ReadAllText(Request.PhysicalPath + ".cs"));
        Response.Clear();
        Response.ContentType="text/plain";
        Response.Write(Answer);
        Response.End();
    }
}