feat(security): add host blocking mechanism across all online services

Adds a comprehensive host blocking system that prevents requests to specific disallowed hosts across all online streaming services. The implementation includes:

- New `NotAllowedHosts` HashSet containing base64-encoded blocked hostnames
- `IsNotAllowedHost()` method to validate URLs before making HTTP requests
- Integration in all service classes (Anihub, AnimeON, Bamboo, CikavaIdeya, StarLight, UAKino, UaTUT, Uaflix, Unimay)
- Checks applied to search, content fetching, and streaming URL resolution
- Consistent implementation pattern across both Invoke and Controller classes

This security enhancement prevents connections to potentially malicious or unauthorized streaming hosts while maintaining existing functionality for allowed sources.
This commit is contained in:
baliasnyifeliks 2026-01-14 13:21:34 +02:00
parent 0c06d065d5
commit 6041ea950b
13 changed files with 448 additions and 14 deletions

View File

@ -19,6 +19,17 @@ namespace Anihub
{
public class AnihubInvoke
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init;
private HybridCache _hybridCache;
private Action<string> _onLog;
@ -41,6 +52,9 @@ namespace Anihub
string searchQuery = string.IsNullOrEmpty(title) ? original_title : title;
string searchUrl = $"{_init.apihost}/anime/?search={HttpUtility.UrlEncode(searchQuery)}";
if (IsNotAllowedHost(searchUrl))
return null;
string response = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(response))
@ -75,6 +89,9 @@ namespace Anihub
);
string sourcesUrl = $"{_init.apihost}/episode-sources/{parsedAnimeId}";
if (IsNotAllowedHost(sourcesUrl))
return null;
string response = await Http.Get(sourcesUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(response))
@ -156,6 +173,17 @@ namespace Anihub
return voices;
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
public async Task<List<SeasonTpl>> GetSeasons(AnihubEpisodeSourcesResponse sources)
{
var seasons = new List<SeasonTpl>();

View File

@ -13,12 +13,24 @@ using Shared.Models.Online.Settings;
using Shared.Models;
using System.Net;
using System.Net.Http;
using System.Text;
namespace Anihub
{
[Route("anihub")]
public class AnihubController : BaseOnlineController
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager;
public AnihubController()
@ -299,6 +311,9 @@ namespace Anihub
requestUrl = iframeUrl + (iframeUrl.Contains("?") ? "&" : "?") + $"player={host}";
}
if (IsNotAllowedHost(requestUrl))
return null;
// Створюємо HTTP клієнт з правильними заголовками
using var httpClient = new HttpClient();
@ -349,5 +364,16 @@ namespace Anihub
return null;
}
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
}
}

View File

@ -6,6 +6,7 @@ using Shared.Models.Online.Settings;
using Shared.Models;
using System.Text.Json;
using System.Linq;
using System.Text;
using AnimeON.Models;
using Shared.Engine;
@ -13,6 +14,17 @@ namespace AnimeON
{
public class AnimeONInvoke
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init;
private HybridCache _hybridCache;
private Action<string> _onLog;
@ -42,6 +54,9 @@ namespace AnimeON
return null;
string searchUrl = $"{_init.host}/api/anime/search?text={System.Web.HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {searchUrl}");
string searchJson = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(searchJson))
@ -87,6 +102,9 @@ namespace AnimeON
public async Task<List<FundubModel>> GetFundubs(int animeId)
{
string fundubsUrl = $"{_init.host}/api/player/{animeId}/translations";
if (IsNotAllowedHost(fundubsUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {fundubsUrl}");
string fundubsJson = await Http.Get(fundubsUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(fundubsJson))
@ -112,6 +130,9 @@ namespace AnimeON
public async Task<EpisodeModel> GetEpisodes(int animeId, int playerId, int fundubId)
{
string episodesUrl = $"{_init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}";
if (IsNotAllowedHost(episodesUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {episodesUrl}");
string episodesJson = await Http.Get(episodesUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(episodesJson))
@ -131,6 +152,9 @@ namespace AnimeON
new HeadersModel("Referer", "https://animeon.club/")
};
if (IsNotAllowedHost(requestUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}");
string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html))
@ -160,6 +184,9 @@ namespace AnimeON
new HeadersModel("Referer", _init.host)
};
if (IsNotAllowedHost(url))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}");
string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html))
@ -184,6 +211,9 @@ namespace AnimeON
try
{
string url = $"{_init.host}/api/player/{episodeId}/episode";
if (IsNotAllowedHost(url))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}");
string json = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(json))
@ -217,6 +247,9 @@ namespace AnimeON
if (string.IsNullOrEmpty(url))
return null;
if (IsNotAllowedHost(url))
return null;
if (url.Contains("moonanime.art"))
return await ParseMoonAnimePage(url);
@ -226,6 +259,17 @@ namespace AnimeON
return url;
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1)
{
if (init != null && init.rhub && rhub != -1)

View File

@ -10,6 +10,7 @@ using Shared;
using Shared.Models.Templates;
using AnimeON.Models;
using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings;
using Shared.Models;
using HtmlAgilityPack;
@ -18,6 +19,17 @@ namespace AnimeON.Controllers
{
public class Controller : BaseOnlineController
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager;
public Controller()
@ -190,6 +202,9 @@ namespace AnimeON.Controllers
async Task<List<FundubModel>> GetFundubs(OnlinesSettings init, int animeId)
{
string fundubsUrl = $"{init.host}/api/player/{animeId}/translations";
if (IsNotAllowedHost(fundubsUrl))
return null;
string fundubsJson = await Http.Get(fundubsUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
if (string.IsNullOrEmpty(fundubsJson))
return null;
@ -214,6 +229,9 @@ namespace AnimeON.Controllers
async Task<EpisodeModel> GetEpisodes(OnlinesSettings init, int animeId, int playerId, int fundubId)
{
string episodesUrl = $"{init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}";
if (IsNotAllowedHost(episodesUrl))
return null;
string episodesJson = await Http.Get(episodesUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
if (string.IsNullOrEmpty(episodesJson))
return null;
@ -237,6 +255,9 @@ namespace AnimeON.Controllers
return null;
string searchUrl = $"{init.host}/api/anime/search?text={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
string searchJson = await Http.Get(searchUrl, headers: headers);
if (string.IsNullOrEmpty(searchJson))
return null;
@ -314,5 +335,16 @@ namespace AnimeON.Controllers
OnLog("AnimeON Play: return call JSON");
return Content(jsonResult, "application/json; charset=utf-8");
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
@ -15,6 +16,17 @@ namespace Bamboo
{
public class BambooInvoke
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private readonly OnlinesSettings _init;
private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog;
@ -41,6 +53,9 @@ namespace Bamboo
try
{
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
var headers = new List<HeadersModel>()
{
new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -106,6 +121,9 @@ namespace Bamboo
new HeadersModel("Referer", _init.host)
};
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"Bamboo series page: {href}");
string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html))
@ -180,6 +198,9 @@ namespace Bamboo
new HeadersModel("Referer", _init.host)
};
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"Bamboo movie page: {href}");
string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html))
@ -281,12 +302,23 @@ namespace Bamboo
return string.Empty;
if (url.StartsWith("//"))
return $"https:{url}";
return IsNotAllowedHost($"https:{url}") ? string.Empty : $"https:{url}";
if (url.StartsWith("/"))
return $"{_init.host}{url}";
return IsNotAllowedHost(_init.host) ? string.Empty : $"{_init.host}{url}";
return url;
return IsNotAllowedHost(url) ? string.Empty : url;
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
private static int? ExtractEpisodeNumber(string title)

View File

@ -5,6 +5,7 @@ using Shared;
using Shared.Models.Online.Settings;
using Shared.Models;
using System.Text.RegularExpressions;
using System.Text;
using HtmlAgilityPack;
using CikavaIdeya.Models;
using Shared.Engine;
@ -14,6 +15,17 @@ namespace CikavaIdeya
{
public class CikavaIdeyaInvoke
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init;
private HybridCache _hybridCache;
private Action<string> _onLog;
@ -71,6 +83,9 @@ namespace CikavaIdeya
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(searchTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(searchUrl))
return null;
var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
// Перевіряємо, чи є результати пошуку
if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів"))
@ -124,6 +139,9 @@ namespace CikavaIdeya
filmUrl = _init.host + filmUrl;
// Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди)
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
// Перевіряємо, чи не видалено контент
if (filmHtml.Contains("Видалено на прохання правовласника"))
@ -286,6 +304,9 @@ namespace CikavaIdeya
}
// Інакше парсимо сторінку
if (IsNotAllowedHost(url))
return result;
string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
var doc = new HtmlDocument();
doc.LoadHtml(html);
@ -313,6 +334,9 @@ namespace CikavaIdeya
{
_onLog($"GetStreamUrlFromAshdi: trying to get stream URL from {url}");
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") };
if (IsNotAllowedHost(url))
return null;
string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
_onLog($"GetStreamUrlFromAshdi: received HTML, length={html.Length}");
@ -347,6 +371,17 @@ namespace CikavaIdeya
return null;
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1)
{
if (init != null && init.rhub && rhub != -1)
@ -359,4 +394,4 @@ namespace CikavaIdeya
return TimeSpan.FromMinutes(ctime);
}
}
}
}

View File

@ -9,6 +9,7 @@ using HtmlAgilityPack;
using Shared;
using Shared.Models.Templates;
using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings;
using Shared.Models;
using CikavaIdeya.Models;
@ -17,6 +18,17 @@ namespace CikavaIdeya.Controllers
{
public class Controller : BaseOnlineController
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager;
public Controller()
@ -155,6 +167,9 @@ namespace CikavaIdeya.Controllers
string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(searchTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) };
if (IsNotAllowedHost(searchUrl))
return null;
var searchHtml = await Http.Get(searchUrl, headers: headers);
// Перевіряємо, чи є результати пошуку
if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів"))
@ -208,6 +223,9 @@ namespace CikavaIdeya.Controllers
filmUrl = init.host + filmUrl;
// Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди)
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers);
// Перевіряємо, чи не видалено контент
if (filmHtml.Contains("Видалено на прохання правовласника"))
@ -359,6 +377,9 @@ namespace CikavaIdeya.Controllers
}
// Інакше парсимо сторінку
if (IsNotAllowedHost(url))
return result;
string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
var doc = new HtmlDocument();
doc.LoadHtml(html);
@ -380,5 +401,16 @@ namespace CikavaIdeya.Controllers
}
return result;
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Web;
@ -17,6 +18,17 @@ namespace StarLight
private const string PlayerApi = "https://vcms-api2.starlight.digital/player-api";
private const string PlayerReferer = "https://teleportal.ua/";
private const string Language = "ua";
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private readonly OnlinesSettings _init;
private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog;
@ -41,6 +53,9 @@ namespace StarLight
return cached;
string url = $"{_init.host}/{Language}/live-search?q={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>()
{
new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -107,6 +122,9 @@ namespace StarLight
try
{
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"StarLight project: {href}");
string payload = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(payload))
@ -177,6 +195,9 @@ namespace StarLight
return null;
string url = $"{PlayerApi}/{hash}?referer={HttpUtility.UrlEncode(PlayerReferer)}&lang={Language}";
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>()
{
new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -235,11 +256,21 @@ namespace StarLight
return string.Empty;
if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
return path;
return IsNotAllowedHost(path) ? string.Empty : path;
return $"{_init.host}{path}";
return IsNotAllowedHost(_init.host) ? string.Empty : $"{_init.host}{path}";
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1)
{

View File

@ -5,6 +5,7 @@ using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
@ -24,6 +25,17 @@ namespace UAKino
private const string PlaylistPath = "/engine/ajax/playlists.php";
private const string PlaylistField = "playlist";
private const string BlacklistRegex = "(/news/)|(/franchise/)";
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private readonly OnlinesSettings _init;
private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog;
@ -260,6 +272,9 @@ namespace UAKino
private async Task<string> GetString(string url, List<HeadersModel> headers, int timeoutSeconds = 15)
{
if (IsNotAllowedHost(url))
return null;
var handler = new SocketsHttpHandler
{
AllowAutoRedirect = true,
@ -403,12 +418,12 @@ namespace UAKino
return string.Empty;
if (url.StartsWith("//"))
return $"https:{url}";
return IsNotAllowedHost($"https:{url}") ? string.Empty : $"https:{url}";
if (url.StartsWith("/"))
return $"{_init.host}{url}";
return IsNotAllowedHost(_init.host) ? string.Empty : $"{_init.host}{url}";
return url;
return IsNotAllowedHost(url) ? string.Empty : url;
}
private static bool LooksLikeDirectStream(string url)
@ -421,6 +436,17 @@ namespace UAKino
return Regex.IsMatch(url ?? string.Empty, BlacklistRegex, RegexOptions.IgnoreCase);
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
private static bool IsSeriesUrl(string url)
{
return url.Contains("/seriesss/") || url.Contains("/anime-series/") || url.Contains("/cartoonseries/");

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
@ -15,6 +16,17 @@ namespace UaTUT
{
public class UaTUTInvoke
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init;
private HybridCache _hybridCache;
private Action<string> _onLog;
@ -63,6 +75,9 @@ namespace UaTUT
string url = $"{searchUrl}?q={HttpUtility.UrlEncode(query)}";
_onLog($"UaTUT searching: {url}");
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") };
var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
@ -89,6 +104,9 @@ namespace UaTUT
string url = $"{_init.apihost}/{movieId}";
_onLog($"UaTUT getting movie page: {url}");
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") };
var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
@ -130,6 +148,9 @@ namespace UaTUT
{
_onLog($"UaTUT getting player data from: {playerUrl}");
if (IsNotAllowedHost(playerUrl))
return null;
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") };
var response = await Http.Get(playerUrl, headers: headers, proxy: _proxyManager.Get());
@ -145,6 +166,17 @@ namespace UaTUT
}
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
private PlayerData ParsePlayerData(string playerHtml)
{
try

View File

@ -10,6 +10,7 @@ using HtmlAgilityPack;
using Shared;
using Shared.Models.Templates;
using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings;
using Shared.Models;
using Uaflix.Models;
@ -19,6 +20,17 @@ namespace Uaflix.Controllers
public class Controller : BaseOnlineController
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager;
public Controller()
@ -50,6 +62,9 @@ namespace Uaflix.Controllers
string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) };
if (IsNotAllowedHost(searchUrl))
return OnError("uaflix", proxyManager);
var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: proxyManager.Get(), timeoutSeconds: 10);
// Швидка перевірка наявності результатів без повного парсингу
@ -329,6 +344,16 @@ namespace Uaflix.Controllers
return rjson ? Content(tpl.ToJson(), "application/json; charset=utf-8") : Content(tpl.ToHtml(), "text/html; charset=utf-8");
}
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
}
}

View File

@ -14,11 +14,23 @@ using Shared.Models.Templates;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text;
namespace Uaflix
{
public class UaflixInvoke
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init;
private HybridCache _hybridCache;
private Action<string> _onLog;
@ -90,6 +102,9 @@ namespace Uaflix
}
}
if (IsNotAllowedHost(requestUrl))
return null;
string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get());
// Знайти JSON у new Playerjs({file:'...'})
@ -201,6 +216,9 @@ namespace Uaflix
try
{
if (IsNotAllowedHost(iframeUrl))
return (null, null);
string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get());
// Знайти file:"url"
@ -235,6 +253,9 @@ namespace Uaflix
try
{
if (IsNotAllowedHost(iframeUrl))
return (null, null);
string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get());
// Шукаємо Playerjs конфігурацію з file параметром
@ -341,6 +362,9 @@ namespace Uaflix
new HeadersModel("Referer", _init.host)
};
if (IsNotAllowedHost(firstEpisode.url))
continue;
string html = await Http.Get(firstEpisode.url, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument();
@ -557,6 +581,9 @@ namespace Uaflix
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(searchUrl))
return null;
var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument();
doc.LoadHtml(searchHtml);
@ -649,6 +676,9 @@ namespace Uaflix
try
{
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument();
doc.LoadHtml(filmHtml);
@ -724,6 +754,9 @@ namespace Uaflix
try
{
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
var filmDoc = new HtmlDocument();
filmDoc.LoadHtml(filmHtml);
@ -758,7 +791,11 @@ namespace Uaflix
seasonUrls.Add(filmUrl);
}
var seasonTasks = seasonUrls.Select(url => Http.Get(url, headers: headers, proxy: _proxyManager.Get()).AsTask());
var safeSeasonUrls = seasonUrls.Where(url => !IsNotAllowedHost(url)).ToList();
if (safeSeasonUrls.Count == 0)
return null;
var seasonTasks = safeSeasonUrls.Select(url => Http.Get(url, headers: headers, proxy: _proxyManager.Get()).AsTask());
var seasonPagesHtml = await Task.WhenAll(seasonTasks);
foreach (var html in seasonPagesHtml)
@ -819,6 +856,9 @@ namespace Uaflix
var result = new Uaflix.Models.PlayResult() { streams = new List<(string, string)>() };
try
{
if (IsNotAllowedHost(url))
return result;
string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
var doc = new HtmlDocument();
doc.LoadHtml(html);
@ -925,6 +965,9 @@ namespace Uaflix
async Task<List<(string link, string quality)>> ParseAllZetvideoSources(string iframeUrl)
{
var result = new List<(string link, string quality)>();
if (IsNotAllowedHost(iframeUrl))
return result;
var html = await Http.Get(iframeUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://zetvideo.net/") }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) return result;
@ -956,6 +999,9 @@ namespace Uaflix
async Task<List<(string link, string quality)>> ParseAllAshdiSources(string iframeUrl)
{
var result = new List<(string link, string quality)>();
if (IsNotAllowedHost(iframeUrl))
return result;
var html = await Http.Get(iframeUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) return result;
@ -975,7 +1021,11 @@ namespace Uaflix
async Task<SubtitleTpl?> GetAshdiSubtitles(string id)
{
var html = await Http.Get($"https://ashdi.vip/vod/{id}", headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get());
string url = $"https://ashdi.vip/vod/{id}";
if (IsNotAllowedHost(url))
return null;
var html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get());
string subtitle = new Regex("subtitle(\")?:\"([^\"]+)\"").Match(html).Groups[2].Value;
if (!string.IsNullOrEmpty(subtitle))
{
@ -1003,6 +1053,17 @@ namespace Uaflix
return TimeSpan.FromMinutes(ctime);
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
/// <summary>
/// Оновлений метод кешування згідно стандарту Lampac

View File

@ -8,11 +8,23 @@ using System.Linq;
using Unimay.Models;
using Shared.Engine;
using System.Net;
using System.Text;
namespace Unimay
{
public class UnimayInvoke
{
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2"
"bGFtcGEuc3RyZWFt"
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init;
private ProxyManager _proxyManager;
private HybridCache _hybridCache;
@ -37,6 +49,9 @@ namespace Unimay
string searchQuery = System.Web.HttpUtility.UrlEncode(title ?? original_title ?? "");
string searchUrl = $"{_init.host}/release/search?page=0&page_size=10&title={searchQuery}";
if (IsNotAllowedHost(searchUrl))
return null;
var headers = httpHeaders(_init);
SearchResponse root = await Http.Get<SearchResponse>(searchUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers);
@ -67,6 +82,9 @@ namespace Unimay
{
string releaseUrl = $"{_init.host}/release?code={code}";
if (IsNotAllowedHost(releaseUrl))
return null;
var headers = httpHeaders(_init);
ReleaseResponse root = await Http.Get<ReleaseResponse>(releaseUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers);
@ -158,6 +176,18 @@ namespace Unimay
new HeadersModel("Accept", "application/json")
};
}
private static bool IsNotAllowedHost(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return false;
return NotAllowedHosts.Contains(uri.Host);
}
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1)
{
if (init != null && init.rhub && rhub != -1)
@ -170,4 +200,4 @@ namespace Unimay
return TimeSpan.FromMinutes(ctime);
}
}
}
}