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 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 OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -41,6 +52,9 @@ namespace Anihub
string searchQuery = string.IsNullOrEmpty(title) ? original_title : title; string searchQuery = string.IsNullOrEmpty(title) ? original_title : title;
string searchUrl = $"{_init.apihost}/anime/?search={HttpUtility.UrlEncode(searchQuery)}"; 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()); string response = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(response)) if (string.IsNullOrEmpty(response))
@ -75,6 +89,9 @@ namespace Anihub
); );
string sourcesUrl = $"{_init.apihost}/episode-sources/{parsedAnimeId}"; string sourcesUrl = $"{_init.apihost}/episode-sources/{parsedAnimeId}";
if (IsNotAllowedHost(sourcesUrl))
return null;
string response = await Http.Get(sourcesUrl, headers: headers, proxy: _proxyManager.Get()); string response = await Http.Get(sourcesUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(response)) if (string.IsNullOrEmpty(response))
@ -156,6 +173,17 @@ namespace Anihub
return voices; 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) public async Task<List<SeasonTpl>> GetSeasons(AnihubEpisodeSourcesResponse sources)
{ {
var seasons = new List<SeasonTpl>(); var seasons = new List<SeasonTpl>();

View File

@ -13,12 +13,24 @@ using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Text;
namespace Anihub namespace Anihub
{ {
[Route("anihub")] [Route("anihub")]
public class AnihubController : BaseOnlineController 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; ProxyManager proxyManager;
public AnihubController() public AnihubController()
@ -299,6 +311,9 @@ namespace Anihub
requestUrl = iframeUrl + (iframeUrl.Contains("?") ? "&" : "?") + $"player={host}"; requestUrl = iframeUrl + (iframeUrl.Contains("?") ? "&" : "?") + $"player={host}";
} }
if (IsNotAllowedHost(requestUrl))
return null;
// Створюємо HTTP клієнт з правильними заголовками // Створюємо HTTP клієнт з правильними заголовками
using var httpClient = new HttpClient(); using var httpClient = new HttpClient();
@ -349,5 +364,16 @@ namespace Anihub
return null; 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 Shared.Models;
using System.Text.Json; using System.Text.Json;
using System.Linq; using System.Linq;
using System.Text;
using AnimeON.Models; using AnimeON.Models;
using Shared.Engine; using Shared.Engine;
@ -13,6 +14,17 @@ namespace AnimeON
{ {
public class AnimeONInvoke 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 OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -42,6 +54,9 @@ namespace AnimeON
return null; return null;
string searchUrl = $"{_init.host}/api/anime/search?text={System.Web.HttpUtility.UrlEncode(query)}"; 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}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {searchUrl}");
string searchJson = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get()); string searchJson = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(searchJson)) if (string.IsNullOrEmpty(searchJson))
@ -87,6 +102,9 @@ namespace AnimeON
public async Task<List<FundubModel>> GetFundubs(int animeId) public async Task<List<FundubModel>> GetFundubs(int animeId)
{ {
string fundubsUrl = $"{_init.host}/api/player/{animeId}/translations"; string fundubsUrl = $"{_init.host}/api/player/{animeId}/translations";
if (IsNotAllowedHost(fundubsUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {fundubsUrl}"); _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()); 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)) if (string.IsNullOrEmpty(fundubsJson))
@ -112,6 +130,9 @@ namespace AnimeON
public async Task<EpisodeModel> GetEpisodes(int animeId, int playerId, int fundubId) 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}"; 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}"); _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()); 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)) if (string.IsNullOrEmpty(episodesJson))
@ -131,6 +152,9 @@ namespace AnimeON
new HeadersModel("Referer", "https://animeon.club/") new HeadersModel("Referer", "https://animeon.club/")
}; };
if (IsNotAllowedHost(requestUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}");
string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -160,6 +184,9 @@ namespace AnimeON
new HeadersModel("Referer", _init.host) new HeadersModel("Referer", _init.host)
}; };
if (IsNotAllowedHost(url))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}");
string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -184,6 +211,9 @@ namespace AnimeON
try try
{ {
string url = $"{_init.host}/api/player/{episodeId}/episode"; string url = $"{_init.host}/api/player/{episodeId}/episode";
if (IsNotAllowedHost(url))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}"); _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()); 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)) if (string.IsNullOrEmpty(json))
@ -217,6 +247,9 @@ namespace AnimeON
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
return null; return null;
if (IsNotAllowedHost(url))
return null;
if (url.Contains("moonanime.art")) if (url.Contains("moonanime.art"))
return await ParseMoonAnimePage(url); return await ParseMoonAnimePage(url);
@ -226,6 +259,17 @@ namespace AnimeON
return url; 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) 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) if (init != null && init.rhub && rhub != -1)

View File

@ -10,6 +10,7 @@ using Shared;
using Shared.Models.Templates; using Shared.Models.Templates;
using AnimeON.Models; using AnimeON.Models;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using HtmlAgilityPack; using HtmlAgilityPack;
@ -18,6 +19,17 @@ namespace AnimeON.Controllers
{ {
public class Controller : BaseOnlineController 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; ProxyManager proxyManager;
public Controller() public Controller()
@ -190,6 +202,9 @@ namespace AnimeON.Controllers
async Task<List<FundubModel>> GetFundubs(OnlinesSettings init, int animeId) async Task<List<FundubModel>> GetFundubs(OnlinesSettings init, int animeId)
{ {
string fundubsUrl = $"{init.host}/api/player/{animeId}/translations"; 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) }); 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)) if (string.IsNullOrEmpty(fundubsJson))
return null; return null;
@ -214,6 +229,9 @@ namespace AnimeON.Controllers
async Task<EpisodeModel> GetEpisodes(OnlinesSettings init, int animeId, int playerId, int fundubId) 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}"; 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) }); 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)) if (string.IsNullOrEmpty(episodesJson))
return null; return null;
@ -237,6 +255,9 @@ namespace AnimeON.Controllers
return null; return null;
string searchUrl = $"{init.host}/api/anime/search?text={HttpUtility.UrlEncode(query)}"; string searchUrl = $"{init.host}/api/anime/search?text={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
string searchJson = await Http.Get(searchUrl, headers: headers); string searchJson = await Http.Get(searchUrl, headers: headers);
if (string.IsNullOrEmpty(searchJson)) if (string.IsNullOrEmpty(searchJson))
return null; return null;
@ -314,5 +335,16 @@ namespace AnimeON.Controllers
OnLog("AnimeON Play: return call JSON"); OnLog("AnimeON Play: return call JSON");
return Content(jsonResult, "application/json; charset=utf-8"); 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
@ -15,6 +16,17 @@ namespace Bamboo
{ {
public class BambooInvoke 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 OnlinesSettings _init;
private readonly HybridCache _hybridCache; private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog; private readonly Action<string> _onLog;
@ -41,6 +53,9 @@ namespace Bamboo
try try
{ {
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(query)}"; string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
var headers = new List<HeadersModel>() var headers = new List<HeadersModel>()
{ {
new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -106,6 +121,9 @@ namespace Bamboo
new HeadersModel("Referer", _init.host) new HeadersModel("Referer", _init.host)
}; };
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"Bamboo series page: {href}"); _onLog?.Invoke($"Bamboo series page: {href}");
string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -180,6 +198,9 @@ namespace Bamboo
new HeadersModel("Referer", _init.host) new HeadersModel("Referer", _init.host)
}; };
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"Bamboo movie page: {href}"); _onLog?.Invoke($"Bamboo movie page: {href}");
string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -281,12 +302,23 @@ namespace Bamboo
return string.Empty; return string.Empty;
if (url.StartsWith("//")) if (url.StartsWith("//"))
return $"https:{url}"; return IsNotAllowedHost($"https:{url}") ? string.Empty : $"https:{url}";
if (url.StartsWith("/")) 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) private static int? ExtractEpisodeNumber(string title)

View File

@ -5,6 +5,7 @@ using Shared;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using HtmlAgilityPack; using HtmlAgilityPack;
using CikavaIdeya.Models; using CikavaIdeya.Models;
using Shared.Engine; using Shared.Engine;
@ -14,6 +15,17 @@ namespace CikavaIdeya
{ {
public class CikavaIdeyaInvoke 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 OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; 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)}"; 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) }; 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 searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
// Перевіряємо, чи є результати пошуку // Перевіряємо, чи є результати пошуку
if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів")) if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів"))
@ -124,6 +139,9 @@ namespace CikavaIdeya
filmUrl = _init.host + filmUrl; filmUrl = _init.host + filmUrl;
// Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди) // Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди)
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get()); var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
// Перевіряємо, чи не видалено контент // Перевіряємо, чи не видалено контент
if (filmHtml.Contains("Видалено на прохання правовласника")) 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()); 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(); var doc = new HtmlDocument();
doc.LoadHtml(html); doc.LoadHtml(html);
@ -313,6 +334,9 @@ namespace CikavaIdeya
{ {
_onLog($"GetStreamUrlFromAshdi: trying to get stream URL from {url}"); _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/") }; 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()); string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
_onLog($"GetStreamUrlFromAshdi: received HTML, length={html.Length}"); _onLog($"GetStreamUrlFromAshdi: received HTML, length={html.Length}");
@ -347,6 +371,17 @@ namespace CikavaIdeya
return null; 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) 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) if (init != null && init.rhub && rhub != -1)
@ -359,4 +394,4 @@ namespace CikavaIdeya
return TimeSpan.FromMinutes(ctime); return TimeSpan.FromMinutes(ctime);
} }
} }
} }

View File

@ -9,6 +9,7 @@ using HtmlAgilityPack;
using Shared; using Shared;
using Shared.Models.Templates; using Shared.Models.Templates;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using CikavaIdeya.Models; using CikavaIdeya.Models;
@ -17,6 +18,17 @@ namespace CikavaIdeya.Controllers
{ {
public class Controller : BaseOnlineController 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; ProxyManager proxyManager;
public Controller() public Controller()
@ -155,6 +167,9 @@ namespace CikavaIdeya.Controllers
string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(searchTitle)}"; 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) }; 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); var searchHtml = await Http.Get(searchUrl, headers: headers);
// Перевіряємо, чи є результати пошуку // Перевіряємо, чи є результати пошуку
if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів")) if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів"))
@ -208,6 +223,9 @@ namespace CikavaIdeya.Controllers
filmUrl = init.host + filmUrl; filmUrl = init.host + filmUrl;
// Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди) // Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди)
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers); var filmHtml = await Http.Get(filmUrl, headers: headers);
// Перевіряємо, чи не видалено контент // Перевіряємо, чи не видалено контент
if (filmHtml.Contains("Видалено на прохання правовласника")) 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) }); 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(); var doc = new HtmlDocument();
doc.LoadHtml(html); doc.LoadHtml(html);
@ -380,5 +401,16 @@ namespace CikavaIdeya.Controllers
} }
return result; 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
@ -17,6 +18,17 @@ namespace StarLight
private const string PlayerApi = "https://vcms-api2.starlight.digital/player-api"; private const string PlayerApi = "https://vcms-api2.starlight.digital/player-api";
private const string PlayerReferer = "https://teleportal.ua/"; private const string PlayerReferer = "https://teleportal.ua/";
private const string Language = "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 OnlinesSettings _init;
private readonly HybridCache _hybridCache; private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog; private readonly Action<string> _onLog;
@ -41,6 +53,9 @@ namespace StarLight
return cached; return cached;
string url = $"{_init.host}/{Language}/live-search?q={HttpUtility.UrlEncode(query)}"; string url = $"{_init.host}/{Language}/live-search?q={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() var headers = new List<HeadersModel>()
{ {
new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -107,6 +122,9 @@ namespace StarLight
try try
{ {
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"StarLight project: {href}"); _onLog?.Invoke($"StarLight project: {href}");
string payload = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); string payload = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(payload)) if (string.IsNullOrEmpty(payload))
@ -177,6 +195,9 @@ namespace StarLight
return null; return null;
string url = $"{PlayerApi}/{hash}?referer={HttpUtility.UrlEncode(PlayerReferer)}&lang={Language}"; string url = $"{PlayerApi}/{hash}?referer={HttpUtility.UrlEncode(PlayerReferer)}&lang={Language}";
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() var headers = new List<HeadersModel>()
{ {
new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -235,11 +256,21 @@ namespace StarLight
return string.Empty; return string.Empty;
if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) 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) 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.Http;
using System.Net.Security; using System.Net.Security;
using System.Security.Authentication; using System.Security.Authentication;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
@ -24,6 +25,17 @@ namespace UAKino
private const string PlaylistPath = "/engine/ajax/playlists.php"; private const string PlaylistPath = "/engine/ajax/playlists.php";
private const string PlaylistField = "playlist"; private const string PlaylistField = "playlist";
private const string BlacklistRegex = "(/news/)|(/franchise/)"; 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 OnlinesSettings _init;
private readonly HybridCache _hybridCache; private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog; private readonly Action<string> _onLog;
@ -260,6 +272,9 @@ namespace UAKino
private async Task<string> GetString(string url, List<HeadersModel> headers, int timeoutSeconds = 15) private async Task<string> GetString(string url, List<HeadersModel> headers, int timeoutSeconds = 15)
{ {
if (IsNotAllowedHost(url))
return null;
var handler = new SocketsHttpHandler var handler = new SocketsHttpHandler
{ {
AllowAutoRedirect = true, AllowAutoRedirect = true,
@ -403,12 +418,12 @@ namespace UAKino
return string.Empty; return string.Empty;
if (url.StartsWith("//")) if (url.StartsWith("//"))
return $"https:{url}"; return IsNotAllowedHost($"https:{url}") ? string.Empty : $"https:{url}";
if (url.StartsWith("/")) 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) private static bool LooksLikeDirectStream(string url)
@ -421,6 +436,17 @@ namespace UAKino
return Regex.IsMatch(url ?? string.Empty, BlacklistRegex, RegexOptions.IgnoreCase); 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) private static bool IsSeriesUrl(string url)
{ {
return url.Contains("/seriesss/") || url.Contains("/anime-series/") || url.Contains("/cartoonseries/"); 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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
@ -15,6 +16,17 @@ namespace UaTUT
{ {
public class UaTUTInvoke 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 OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -63,6 +75,9 @@ namespace UaTUT
string url = $"{searchUrl}?q={HttpUtility.UrlEncode(query)}"; string url = $"{searchUrl}?q={HttpUtility.UrlEncode(query)}";
_onLog($"UaTUT searching: {url}"); _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 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()); var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
@ -89,6 +104,9 @@ namespace UaTUT
string url = $"{_init.apihost}/{movieId}"; string url = $"{_init.apihost}/{movieId}";
_onLog($"UaTUT getting movie page: {url}"); _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 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()); var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
@ -130,6 +148,9 @@ namespace UaTUT
{ {
_onLog($"UaTUT getting player data from: {playerUrl}"); _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 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()); 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) private PlayerData ParsePlayerData(string playerHtml)
{ {
try try

View File

@ -10,6 +10,7 @@ using HtmlAgilityPack;
using Shared; using Shared;
using Shared.Models.Templates; using Shared.Models.Templates;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using Uaflix.Models; using Uaflix.Models;
@ -19,6 +20,17 @@ namespace Uaflix.Controllers
public class Controller : BaseOnlineController 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; ProxyManager proxyManager;
public Controller() 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)}"; 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) }; 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); 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"); 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 System.Net;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Text;
namespace Uaflix namespace Uaflix
{ {
public class UaflixInvoke 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 OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; 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()); string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get());
// Знайти JSON у new Playerjs({file:'...'}) // Знайти JSON у new Playerjs({file:'...'})
@ -201,6 +216,9 @@ namespace Uaflix
try try
{ {
if (IsNotAllowedHost(iframeUrl))
return (null, null);
string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get());
// Знайти file:"url" // Знайти file:"url"
@ -235,6 +253,9 @@ namespace Uaflix
try try
{ {
if (IsNotAllowedHost(iframeUrl))
return (null, null);
string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get());
// Шукаємо Playerjs конфігурацію з file параметром // Шукаємо Playerjs конфігурацію з file параметром
@ -341,6 +362,9 @@ namespace Uaflix
new HeadersModel("Referer", _init.host) new HeadersModel("Referer", _init.host)
}; };
if (IsNotAllowedHost(firstEpisode.url))
continue;
string html = await Http.Get(firstEpisode.url, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(firstEpisode.url, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); 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)}"; 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) }; 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 searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(searchHtml); doc.LoadHtml(searchHtml);
@ -649,6 +676,9 @@ namespace Uaflix
try try
{ {
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; 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 filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(filmHtml); doc.LoadHtml(filmHtml);
@ -724,6 +754,9 @@ namespace Uaflix
try try
{ {
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; 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 filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
var filmDoc = new HtmlDocument(); var filmDoc = new HtmlDocument();
filmDoc.LoadHtml(filmHtml); filmDoc.LoadHtml(filmHtml);
@ -758,7 +791,11 @@ namespace Uaflix
seasonUrls.Add(filmUrl); 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); var seasonPagesHtml = await Task.WhenAll(seasonTasks);
foreach (var html in seasonPagesHtml) foreach (var html in seasonPagesHtml)
@ -819,6 +856,9 @@ namespace Uaflix
var result = new Uaflix.Models.PlayResult() { streams = new List<(string, string)>() }; var result = new Uaflix.Models.PlayResult() { streams = new List<(string, string)>() };
try 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()); 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(); var doc = new HtmlDocument();
doc.LoadHtml(html); doc.LoadHtml(html);
@ -925,6 +965,9 @@ namespace Uaflix
async Task<List<(string link, string quality)>> ParseAllZetvideoSources(string iframeUrl) async Task<List<(string link, string quality)>> ParseAllZetvideoSources(string iframeUrl)
{ {
var result = new List<(string link, string quality)>(); 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()); 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; if (string.IsNullOrEmpty(html)) return result;
@ -956,6 +999,9 @@ namespace Uaflix
async Task<List<(string link, string quality)>> ParseAllAshdiSources(string iframeUrl) async Task<List<(string link, string quality)>> ParseAllAshdiSources(string iframeUrl)
{ {
var result = new List<(string link, string quality)>(); 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()); 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; if (string.IsNullOrEmpty(html)) return result;
@ -975,7 +1021,11 @@ namespace Uaflix
async Task<SubtitleTpl?> GetAshdiSubtitles(string id) 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; string subtitle = new Regex("subtitle(\")?:\"([^\"]+)\"").Match(html).Groups[2].Value;
if (!string.IsNullOrEmpty(subtitle)) if (!string.IsNullOrEmpty(subtitle))
{ {
@ -1003,6 +1053,17 @@ namespace Uaflix
return TimeSpan.FromMinutes(ctime); 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> /// <summary>
/// Оновлений метод кешування згідно стандарту Lampac /// Оновлений метод кешування згідно стандарту Lampac

View File

@ -8,11 +8,23 @@ using System.Linq;
using Unimay.Models; using Unimay.Models;
using Shared.Engine; using Shared.Engine;
using System.Net; using System.Net;
using System.Text;
namespace Unimay namespace Unimay
{ {
public class UnimayInvoke 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 OnlinesSettings _init;
private ProxyManager _proxyManager; private ProxyManager _proxyManager;
private HybridCache _hybridCache; private HybridCache _hybridCache;
@ -37,6 +49,9 @@ namespace Unimay
string searchQuery = System.Web.HttpUtility.UrlEncode(title ?? original_title ?? ""); string searchQuery = System.Web.HttpUtility.UrlEncode(title ?? original_title ?? "");
string searchUrl = $"{_init.host}/release/search?page=0&page_size=10&title={searchQuery}"; string searchUrl = $"{_init.host}/release/search?page=0&page_size=10&title={searchQuery}";
if (IsNotAllowedHost(searchUrl))
return null;
var headers = httpHeaders(_init); var headers = httpHeaders(_init);
SearchResponse root = await Http.Get<SearchResponse>(searchUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers); 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}"; string releaseUrl = $"{_init.host}/release?code={code}";
if (IsNotAllowedHost(releaseUrl))
return null;
var headers = httpHeaders(_init); var headers = httpHeaders(_init);
ReleaseResponse root = await Http.Get<ReleaseResponse>(releaseUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers); 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") 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) 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) if (init != null && init.rhub && rhub != -1)
@ -170,4 +200,4 @@ namespace Unimay
return TimeSpan.FromMinutes(ctime); return TimeSpan.FromMinutes(ctime);
} }
} }
} }