@@ -31,7 +31,7 @@ namespace Teknik.Areas.API.Controllers | |||
{ | |||
try | |||
{ | |||
Tracking.TrackPageView(Request, "Upload", Subdomain); | |||
Tracking.TrackPageView(Request, "Upload"); | |||
if (file != null) | |||
{ | |||
if (file.ContentLength <= Config.UploadConfig.MaxUploadSize) | |||
@@ -131,7 +131,7 @@ namespace Teknik.Areas.API.Controllers | |||
{ | |||
try | |||
{ | |||
Tracking.TrackPageView(Request, "Paste", Subdomain); | |||
Tracking.TrackPageView(Request, "Paste"); | |||
Paste.Models.Paste paste = PasteHelper.CreatePaste(code, title, syntax, expireUnit, expireLength, password, hide); | |||
db.Pastes.Add(paste); | |||
@@ -160,7 +160,7 @@ namespace Teknik.Areas.API.Controllers | |||
{ | |||
try | |||
{ | |||
Tracking.TrackPageView(Request, "Shorten", Subdomain); | |||
Tracking.TrackPageView(Request, "Shorten"); | |||
if (url.IsValidUrl()) | |||
{ | |||
ShortenedUrl newUrl = Shortener.Shortener.ShortenUrl(url, Config.ShortenerConfig.UrlLength); |
@@ -147,7 +147,7 @@ namespace Teknik.Areas.Upload.Controllers | |||
Response.AppendHeader("Content-Disposition", cd.ToString()); | |||
// Handle Piwik Tracking if enabled | |||
Tracking.TrackAction(Request.UserAgent, Request.Url.ToString()); | |||
Tracking.TrackAction(Request, Request.Url.ToString()); | |||
return File(data, upload.ContentType); | |||
} |
@@ -14,11 +14,14 @@ namespace Teknik.Configuration | |||
public int SiteId { get; set; } | |||
public string TokenAuth { get; set; } | |||
public PiwikConfig() | |||
{ | |||
Enabled = false; | |||
Url = string.Empty; | |||
SiteId = 1; | |||
TokenAuth = string.Empty; | |||
} | |||
} | |||
} |
@@ -20,30 +20,14 @@ namespace Teknik.Filters | |||
public override void OnActionExecuted(ActionExecutedContext filterContext) | |||
{ | |||
Config config = Config.Load(); | |||
if (config.PiwikConfig.Enabled) | |||
{ | |||
try | |||
{ | |||
string sub = filterContext.HttpContext.Request.RequestContext.RouteData.Values["sub"].ToString(); | |||
if (string.IsNullOrEmpty(sub)) | |||
{ | |||
sub = filterContext.HttpContext.Request.Url.AbsoluteUri.GetSubdomain(); | |||
} | |||
string title = config.Title; | |||
Page page = filterContext.HttpContext.Handler as Page; | |||
if (page != null) | |||
{ | |||
title = page.Title; | |||
} | |||
Tracking.TrackPageView(filterContext.HttpContext.Request, title, sub); | |||
} | |||
catch (Exception ex) | |||
{ | |||
string title = string.Empty; | |||
Page page = filterContext.HttpContext.Handler as Page; | |||
} | |||
if (page != null) | |||
{ | |||
title = page.Title; | |||
} | |||
Tracking.TrackPageView(filterContext.HttpContext.Request, title); | |||
base.OnActionExecuted(filterContext); | |||
} |
@@ -46,40 +46,22 @@ namespace Teknik | |||
var stopwatch = new Stopwatch(); | |||
HttpContext.Current.Items["Stopwatch"] = stopwatch; | |||
stopwatch.Start(); | |||
// Handle Piwik Tracking if enabled | |||
Config config = Config.Load(); | |||
if (config.PiwikConfig.Enabled) | |||
{ | |||
try | |||
{ | |||
HttpRequest request = base.Request; | |||
string sub = request.RequestContext.RouteData.Values["sub"].ToString(); | |||
if (string.IsNullOrEmpty(sub)) | |||
{ | |||
sub = request.Url.AbsoluteUri.GetSubdomain(); | |||
} | |||
string title = config.Title; | |||
Page page = HttpContext.Current.Handler as Page; | |||
if (page != null) | |||
{ | |||
title = page.Title; | |||
} | |||
Tracking.TrackPageView(new HttpRequestWrapper(request), title, sub); | |||
} | |||
catch (Exception ex) | |||
{ | |||
} | |||
} | |||
} | |||
protected void Application_EndRequest(object sender, EventArgs e) | |||
{ | |||
HttpContext context = HttpContext.Current; | |||
// Handle Piwik | |||
string title = string.Empty; | |||
Page page = HttpContext.Current.Handler as Page; | |||
if (page != null) | |||
{ | |||
title = page.Title; | |||
} | |||
Tracking.TrackPageView(new HttpRequestWrapper(context.Request), title); | |||
Stopwatch stopwatch = (Stopwatch)context.Items["Stopwatch"]; | |||
stopwatch.Stop(); | |||
@@ -15,6 +15,29 @@ using System; | |||
namespace Teknik.Helpers | |||
{ | |||
public class MD5 | |||
{ | |||
public static string Hash(string value) | |||
{ | |||
byte[] valBytes = Encoding.ASCII.GetBytes(value); | |||
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); | |||
byte[] hashBytes = md5.ComputeHash(valBytes); | |||
StringBuilder sBuilder = new StringBuilder(); | |||
// Loop through each byte of the hashed data | |||
// and format each one as a hexadecimal string. | |||
for (int i = 0; i < hashBytes.Length; i++) | |||
{ | |||
sBuilder.Append(hashBytes[i].ToString("x2")); | |||
} | |||
// Return the hexadecimal string. | |||
return sBuilder.ToString(); | |||
} | |||
} | |||
public class SHA384 | |||
{ | |||
public static string Hash(string key, string value) |
@@ -0,0 +1,231 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Net.Sockets; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using System.Web; | |||
namespace Teknik.Helpers | |||
{ | |||
public static class RequestHelper | |||
{ | |||
/// <summary> | |||
/// method to get Client ip address | |||
/// </summary> | |||
/// <param name="GetLan"> set to true if want to get local(LAN) Connected ip address</param> | |||
/// <returns></returns> | |||
public static string GetVisitorIPAddress(bool GetLan = false) | |||
{ | |||
string visitorIPAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; | |||
if (String.IsNullOrEmpty(visitorIPAddress)) | |||
visitorIPAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; | |||
if (string.IsNullOrEmpty(visitorIPAddress)) | |||
visitorIPAddress = HttpContext.Current.Request.UserHostAddress; | |||
if (string.IsNullOrEmpty(visitorIPAddress) || visitorIPAddress.Trim() == "::1") | |||
{ | |||
GetLan = true; | |||
visitorIPAddress = string.Empty; | |||
} | |||
if (GetLan) | |||
{ | |||
if (string.IsNullOrEmpty(visitorIPAddress)) | |||
{ | |||
//This is for Local(LAN) Connected ID Address | |||
string stringHostName = Dns.GetHostName(); | |||
//Get Ip Host Entry | |||
IPHostEntry ipHostEntries = Dns.GetHostEntry(stringHostName); | |||
//Get Ip Address From The Ip Host Entry Address List | |||
IPAddress[] arrIpAddress = ipHostEntries.AddressList; | |||
try | |||
{ | |||
visitorIPAddress = arrIpAddress[arrIpAddress.Length - 2].ToString(); | |||
} | |||
catch | |||
{ | |||
try | |||
{ | |||
visitorIPAddress = arrIpAddress[0].ToString(); | |||
} | |||
catch | |||
{ | |||
try | |||
{ | |||
arrIpAddress = Dns.GetHostAddresses(stringHostName); | |||
visitorIPAddress = arrIpAddress[0].ToString(); | |||
} | |||
catch | |||
{ | |||
visitorIPAddress = "127.0.0.1"; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return visitorIPAddress; | |||
} | |||
// based on http://www.grantburton.com/2008/11/30/fix-for-incorrect-ip-addresses-in-wordpress-comments/ | |||
public static string ClientIPFromRequest(this HttpRequestBase request, bool skipPrivate) | |||
{ | |||
foreach (var item in s_HeaderItems) | |||
{ | |||
var ipString = request.Headers[item.Key]; | |||
if (String.IsNullOrEmpty(ipString)) | |||
continue; | |||
if (item.Split) | |||
{ | |||
foreach (var ip in ipString.Split(',')) | |||
if (ValidIP(ip, skipPrivate)) | |||
return ip; | |||
} | |||
else | |||
{ | |||
if (ValidIP(ipString, skipPrivate)) | |||
return ipString; | |||
} | |||
} | |||
return request.UserHostAddress; | |||
} | |||
public static string DumpHeaders(this HttpRequestBase request) | |||
{ | |||
var headers = string.Empty; | |||
foreach (var key in request.Headers.AllKeys) | |||
headers += key + "=" + request.Headers[key] + Environment.NewLine; | |||
return headers; | |||
} | |||
public static string DumpServerVariables(this HttpRequestBase request) | |||
{ | |||
var variables = string.Empty; | |||
foreach (var key in request.ServerVariables.AllKeys) | |||
variables += key + "=" + request.ServerVariables[key] + Environment.NewLine; | |||
return variables; | |||
} | |||
private static bool ValidIP(string ip, bool skipPrivate) | |||
{ | |||
IPAddress ipAddr; | |||
ip = ip == null ? String.Empty : ip.Trim(); | |||
if (0 == ip.Length | |||
|| false == IPAddress.TryParse(ip, out ipAddr) | |||
|| (ipAddr.AddressFamily != AddressFamily.InterNetwork | |||
&& ipAddr.AddressFamily != AddressFamily.InterNetworkV6)) | |||
return false; | |||
if (skipPrivate && ipAddr.AddressFamily == AddressFamily.InterNetwork) | |||
{ | |||
var addr = IpRange.AddrToUInt64(ipAddr); | |||
foreach (var range in s_PrivateRanges) | |||
{ | |||
if (range.Encompasses(addr)) | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/// <summary> | |||
/// Provides a simple class that understands how to parse and | |||
/// compare IP addresses (IPV4) ranges. | |||
/// </summary> | |||
private sealed class IpRange | |||
{ | |||
private readonly UInt64 _start; | |||
private readonly UInt64 _end; | |||
public IpRange(string startStr, string endStr) | |||
{ | |||
_start = ParseToUInt64(startStr); | |||
_end = ParseToUInt64(endStr); | |||
} | |||
public static UInt64 AddrToUInt64(IPAddress ip) | |||
{ | |||
var ipBytes = ip.GetAddressBytes(); | |||
UInt64 value = 0; | |||
foreach (var abyte in ipBytes) | |||
{ | |||
value <<= 8; // shift | |||
value += abyte; | |||
} | |||
return value; | |||
} | |||
public static UInt64 ParseToUInt64(string ipStr) | |||
{ | |||
var ip = IPAddress.Parse(ipStr); | |||
return AddrToUInt64(ip); | |||
} | |||
public bool Encompasses(UInt64 addrValue) | |||
{ | |||
return _start <= addrValue && addrValue <= _end; | |||
} | |||
public bool Encompasses(IPAddress addr) | |||
{ | |||
var value = AddrToUInt64(addr); | |||
return Encompasses(value); | |||
} | |||
}; | |||
private static readonly IpRange[] s_PrivateRanges = | |||
new IpRange[] { | |||
new IpRange("0.0.0.0","2.255.255.255"), | |||
new IpRange("10.0.0.0","10.255.255.255"), | |||
new IpRange("127.0.0.0","127.255.255.255"), | |||
new IpRange("169.254.0.0","169.254.255.255"), | |||
new IpRange("172.16.0.0","172.31.255.255"), | |||
new IpRange("192.0.2.0","192.0.2.255"), | |||
new IpRange("192.168.0.0","192.168.255.255"), | |||
new IpRange("255.255.255.0","255.255.255.255") | |||
}; | |||
/// <summary> | |||
/// Describes a header item (key) and if it is expected to be | |||
/// a comma-delimited string | |||
/// </summary> | |||
private sealed class HeaderItem | |||
{ | |||
public readonly string Key; | |||
public readonly bool Split; | |||
public HeaderItem(string key, bool split) | |||
{ | |||
Key = key; | |||
Split = split; | |||
} | |||
} | |||
// order is in trust/use order top to bottom | |||
private static readonly HeaderItem[] s_HeaderItems = | |||
new HeaderItem[] { | |||
new HeaderItem("HTTP_CLIENT_IP",false), | |||
new HeaderItem("HTTP_X_FORWARDED_FOR",true), | |||
new HeaderItem("HTTP_X_FORWARDED",false), | |||
new HeaderItem("HTTP_X_CLUSTER_CLIENT_IP",false), | |||
new HeaderItem("HTTP_FORWARDED_FOR",false), | |||
new HeaderItem("HTTP_FORWARDED",false), | |||
new HeaderItem("HTTP_VIA",false), | |||
new HeaderItem("REMOTE_ADDR",false) | |||
}; | |||
} | |||
} |
@@ -11,7 +11,7 @@ namespace Teknik.Helpers | |||
{ | |||
public static class Tracking | |||
{ | |||
public static void TrackPageView(HttpRequestBase request, string title, string sub) | |||
public static void TrackPageView(HttpRequestBase request, string title) | |||
{ | |||
Config config = Config.Load(); | |||
// Handle Piwik Tracking if enabled | |||
@@ -19,22 +19,35 @@ namespace Teknik.Helpers | |||
{ | |||
try | |||
{ | |||
string sub = request.RequestContext.RouteData.Values["sub"].ToString(); | |||
if (string.IsNullOrEmpty(sub)) | |||
{ | |||
sub = request.Url.AbsoluteUri.GetSubdomain(); | |||
} | |||
if (string.IsNullOrEmpty(title)) | |||
{ | |||
title = config.Title; | |||
} | |||
PiwikTracker.URL = config.PiwikConfig.Url; | |||
PiwikTracker tracker = new PiwikTracker(config.PiwikConfig.SiteId); | |||
tracker.setForceVisitDateTime(DateTime.Now); | |||
tracker.setUserAgent(request.UserAgent); | |||
tracker.setResolution(request.Browser.ScreenPixelsWidth, request.Browser.ScreenPixelsHeight); | |||
tracker.setBrowserHasCookies(request.Browser.Cookies); | |||
string ipAddress = request.UserHostAddress; | |||
string ipAddress = request.ClientIPFromRequest(true); | |||
tracker.setIp(ipAddress); | |||
tracker.setTokenAuth(config.PiwikConfig.TokenAuth); | |||
tracker.setUrl(request.Url.ToString()); | |||
tracker.setUrlReferrer(request.UrlReferrer.ToString()); | |||
if (request.UrlReferrer != null) | |||
tracker.setUrlReferrer(request.UrlReferrer.ToString()); | |||
tracker.setRequestTimeout(5); | |||
tracker.doTrackPageView(string.Format("{0} / {1}", sub, title)); | |||
} | |||
catch (Exception ex) | |||
@@ -44,7 +57,7 @@ namespace Teknik.Helpers | |||
} | |||
} | |||
public static void TrackAction(string userAgent, string url) | |||
public static void TrackAction(HttpRequestBase request, string url) | |||
{ | |||
Config config = Config.Load(); | |||
// Handle Piwik Tracking if enabled | |||
@@ -55,7 +68,12 @@ namespace Teknik.Helpers | |||
PiwikTracker.URL = config.PiwikConfig.Url; | |||
PiwikTracker tracker = new PiwikTracker(config.PiwikConfig.SiteId); | |||
tracker.setUserAgent(userAgent); | |||
tracker.setUserAgent(request.UserAgent); | |||
string ipAddress = request.ClientIPFromRequest(true); | |||
tracker.setIp(ipAddress); | |||
tracker.setTokenAuth(config.PiwikConfig.TokenAuth); | |||
tracker.doTrackAction(url, PiwikTracker.ActionType.download); | |||
} |
@@ -30,8 +30,6 @@ namespace Teknik.Modules | |||
if (requestContext.Response.ContentType == "text/html" && requestContext.Response.StatusCode == 200) | |||
{ | |||
Uri requestUrl = requestContext.Request.Url; | |||
double ms = (double)timer.ElapsedMilliseconds; | |||
string result = string.Format("{0:F0}", ms); | |||
@@ -266,6 +266,7 @@ | |||
<Compile Include="Helpers\HttpRequestExtensions.cs" /> | |||
<Compile Include="Helpers\MysqlDatabase.cs" /> | |||
<Compile Include="Helpers\MarkdownHelper.cs" /> | |||
<Compile Include="Helpers\RequestHelper.cs" /> | |||
<Compile Include="Helpers\RSSFeedResult.cs" /> | |||
<Compile Include="Helpers\Tracking.cs" /> | |||
<Compile Include="Helpers\UrlExtensions.cs" /> |
@@ -30,6 +30,12 @@ | |||
</div> | |||
<!-- NoScript Alert --> | |||
<noscript> | |||
@if (Model.Config.PiwikConfig.Enabled) | |||
{ | |||
<!-- Piwik Image Tracker--> | |||
<img src="https://stats.teknik.io/piwik.php?idsite=1&rec=1" style="border:0" alt="" /> | |||
<!-- End Piwik --> | |||
} | |||
<div class="container"> | |||
<div class="row"> | |||
<div class="col-xs-12 text-center"> | |||
@@ -45,6 +51,27 @@ | |||
@RenderBody() | |||
</div> | |||
@Html.Partial("_Footer") | |||
@if (Model.Config.PiwikConfig.Enabled) | |||
{ | |||
<!-- Piwik --> | |||
<script type="text/javascript"> | |||
var _paq = _paq || []; | |||
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]); | |||
_paq.push(["setCookieDomain", "*.teknik.io"]); | |||
_paq.push(["setDomains", ["*.teknik.io"]]); | |||
_paq.push(['trackPageView']); | |||
_paq.push(['enableLinkTracking']); | |||
(function() { | |||
var u="//stats.teknik.io/"; | |||
_paq.push(['setTrackerUrl', u+'piwik.php']); | |||
_paq.push(['setSiteId', 1]); | |||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; | |||
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); | |||
})(); | |||
</script> | |||
<!-- End Piwik Code --> | |||
} | |||
<script type="text/javascript"> | |||
$(document).ready(function () {pageloadDoTimer();}); |