mirror of
https://github.com/Jackett/Jackett.git
synced 2025-12-24 06:54:49 +01:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dd5b1e5f0 | ||
|
|
fb9845d1e3 | ||
|
|
70b0aa1f67 | ||
|
|
368afcfc5a | ||
|
|
29d28e2607 | ||
|
|
b023e8fe6d | ||
|
|
d51752f682 | ||
|
|
ec40699cdc | ||
|
|
3c798127c5 | ||
|
|
61b263dd98 | ||
|
|
dd11b7e6cd | ||
|
|
bec42c4ac0 | ||
|
|
9b08d7ad46 | ||
|
|
9311af24b5 | ||
|
|
9e5d79d2a4 | ||
|
|
15c64f9f66 | ||
|
|
f1f8f0f756 | ||
|
|
b3d4ec6f23 | ||
|
|
7f33664f97 | ||
|
|
43aaaf4142 | ||
|
|
20a0bedc3b | ||
|
|
31e0a19eeb | ||
|
|
ccb98cbe48 | ||
|
|
6560931e42 | ||
|
|
46082db9b9 | ||
|
|
89f4a9fb89 |
@@ -831,7 +831,7 @@ Detailed instructions are available at [Jackett's Wiki](https://github.com/Jacke
|
||||
|
||||
|
||||
## Running Jackett behind a reverse proxy
|
||||
When running jackett behind a reverse proxy make sure that the original hostname of the request is passed to Jackett. If HTTPS is used also set the X-Forwarded-Proto header to "https". Don't forget to adjust the "Base path override" Jackett option accordingly.
|
||||
When running Jackett behind a reverse proxy make sure that the original hostname of the request is passed to Jackett. If HTTPS is used also set the X-Forwarded-Proto header to "https". Don't forget to adjust the "Base path override" Jackett option accordingly.
|
||||
|
||||
Example config for apache:
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFrameworks>netstandard2.0;net9.0</TargetFrameworks>
|
||||
<LangVersion>9</LangVersion>
|
||||
<NoWarn />
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
|
||||
@@ -152,7 +152,7 @@ search:
|
||||
keywordsfilters:
|
||||
# drop the year from searches since site titles do not include year
|
||||
- name: re_replace
|
||||
args: ["(\\b((19|20)\\d{2})\\b)", ""]
|
||||
args: ["(\\s*\\b((19|20)\\d{2})\\b)", ""]
|
||||
|
||||
rows:
|
||||
selector: "div#fancy-list-group ul.list-group li.list-group-item{{ if .Config.freeleech }}:has(span.badge-success:contains(\"FREE\")){{ else }}{{ end }}"
|
||||
|
||||
@@ -94,8 +94,6 @@ search:
|
||||
selector: details_link
|
||||
download:
|
||||
selector: download_link
|
||||
infohash:
|
||||
selector: info_hash
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
@@ -145,4 +143,4 @@ search:
|
||||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
# json UNIT3D 9.1.5 (custom)
|
||||
# json UNIT3D 9.1.7 (custom)
|
||||
|
||||
@@ -5,8 +5,6 @@ description: "HDGalaKtik is a RUSSIAN Semi-Private tracker for MOVIES / TV / GEN
|
||||
language: ru-RU
|
||||
type: semi-private
|
||||
encoding: UTF-8
|
||||
certificates:
|
||||
- 89cb539248b0d0cb0e92aa3f286ddfdd8347c3be # CN=mail.trackerpmr.com
|
||||
links:
|
||||
- https://www.trackerpmr.com/
|
||||
- https://freetmd.com/
|
||||
@@ -16,20 +14,20 @@ legacylinks:
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 13, cat: Movies, desc: "Фильмы (Movies)"}
|
||||
- {id: 6, cat: TV, desc: "Мультфильмы (Cartoons)"}
|
||||
- {id: 10, cat: Audio, desc: "Музыка (Music)"}
|
||||
- {id: 26, cat: PC, desc: "Программы (Programs)"}
|
||||
- {id: 5, cat: Console, desc: "Игры (Games)"}
|
||||
- {id: 25, cat: Other, desc: "Картинки (Pictures)"}
|
||||
- {id: 11, cat: TV, desc: "Сериалы (TV Series)"}
|
||||
- {id: 12, cat: TV/Anime, desc: "Аниме (Anime)"}
|
||||
- {id: 16, cat: Books, desc: "Книги (Books)"}
|
||||
- {id: 18, cat: Audio/Video, desc: "Клипы / Ролики (Clips / Trailers)"}
|
||||
- {id: 22, cat: TV, desc: "ТВ / Передачи (TV)"}
|
||||
- {id: 27, cat: PC/Mobile-Other, desc: "Игры - Мобила / КПК (Mobile)"}
|
||||
- {id: 1, cat: PC/ISO, desc: "Образы (ISO)"}
|
||||
- {id: 4, cat: Other, desc: "Другое (Other)"}
|
||||
- {id: 13, cat: Movies, desc: "Фильмы"}
|
||||
- {id: 11, cat: TV, desc: "Сериалы"}
|
||||
- {id: 6, cat: TV, desc: "Мультфильмы"}
|
||||
- {id: 10, cat: Audio, desc: "Музыка"}
|
||||
- {id: 26, cat: PC, desc: "Программы"}
|
||||
- {id: 5, cat: Console, desc: "Игры"}
|
||||
- {id: 25, cat: Other, desc: "Картинки"}
|
||||
- {id: 12, cat: TV/Anime, desc: "Аниме"}
|
||||
- {id: 16, cat: Books, desc: "Книги"}
|
||||
- {id: 18, cat: Audio/Video, desc: "Клипы / Ролики"}
|
||||
- {id: 22, cat: TV, desc: "ТВ / Передачи"}
|
||||
- {id: 27, cat: PC/Mobile-Other, desc: "Игры - Мобила / КПК"}
|
||||
- {id: 1, cat: PC/ISO, desc: "Образы"}
|
||||
- {id: 4, cat: Other, desc: "Другое"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
@@ -117,24 +115,20 @@ search:
|
||||
args: ["[^a-zA-Z0-9]+", "%"]
|
||||
|
||||
rows:
|
||||
selector: table.table > tbody > tr.torcontduo
|
||||
selector: div.torrent-card
|
||||
|
||||
fields:
|
||||
category:
|
||||
selector: a[href^="browse.php?cat="]
|
||||
attribute: href
|
||||
categorydesc:
|
||||
selector: div.category-badge
|
||||
optional: true
|
||||
default: 4
|
||||
default: Другое
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
- name: replace
|
||||
args: ["---", "Другое"]
|
||||
title:
|
||||
selector: a[href^="details.php?id="]
|
||||
selector: a.torrent-title-link
|
||||
attribute: title
|
||||
filters:
|
||||
- name: regexp
|
||||
args: \'>(.+?)</div
|
||||
- name: htmldecode
|
||||
# normalize to SXXEYY format
|
||||
- name: re_replace
|
||||
args: ["(?i)[CС]езоны?[\\s:]*(\\d+(?:-\\d+)?).+?(?:\\s*(?:[CС]ери[ияй]|Эпизод|Выпуски?))[\\s:]*(\\d+(?:-\\d+)?)\\s*из\\s*(\\w?)", "S$1E$2 of $3"]
|
||||
@@ -193,16 +187,19 @@ search:
|
||||
- name: append
|
||||
args: "{{ if .Config.addrussiantotitle }} RUS{{ else }}{{ end }}"
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
selector: a.torrent-title-link
|
||||
attribute: href
|
||||
# there is either a magnet or a download link
|
||||
magnet:
|
||||
selector: a[href^="magnet:?xt="]
|
||||
attribute: href
|
||||
optional: true
|
||||
download:
|
||||
selector: a[href^="details.php?id="]
|
||||
selector: a[href^="download.php?id="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: replace
|
||||
args: ["details", "download"]
|
||||
optional: true
|
||||
poster:
|
||||
selector: img.s
|
||||
selector: img.torrent-poster
|
||||
attribute: src
|
||||
imdbid:
|
||||
selector: a[href^="browse.php?imdb="]
|
||||
@@ -211,46 +208,26 @@ search:
|
||||
- name: querystring
|
||||
args: imdb
|
||||
size:
|
||||
selector: td:nth-child(4)
|
||||
selector: div.size-section
|
||||
seeders:
|
||||
selector: span[title="Раздают"]
|
||||
selector: span.peers-seeders
|
||||
leechers:
|
||||
selector: span[title="Качают"]
|
||||
date_day:
|
||||
# Сегодня в 18:22
|
||||
# Вчера в 20:52
|
||||
selector: a[href^="browse.php?date="]:contains("Сегодня"), a[href^="browse.php?date="]:contains("Вчера")
|
||||
optional: true
|
||||
filters:
|
||||
- name: regexp
|
||||
args: "((Вчера в|Сегодня в)( \\d{2}:\\d{2}))"
|
||||
- name: replace
|
||||
args: ["Сегодня в", "Today"]
|
||||
- name: replace
|
||||
args: ["Вчера в", "Yesterday"]
|
||||
- name: fuzzytime
|
||||
date_year:
|
||||
# 23:48 24/07
|
||||
selector: a[href^="browse.php?date="]:contains("/")
|
||||
optional: true
|
||||
filters:
|
||||
- name: regexp
|
||||
args: "(\\d{2}:\\d{2} \\d{2}/\\d{2})"
|
||||
- name: append
|
||||
args: " +03:00" # MSK
|
||||
- name: dateparse
|
||||
args: "HH:mm dd/MM zzz"
|
||||
selector: span.peers-leechers
|
||||
grabs:
|
||||
selector: span:has(i.fa-download)
|
||||
date:
|
||||
text: "{{ if or .Result.date_year .Result.date_day }}{{ or .Result.date_year .Result.date_day }}{{ else }}now{{ end }}"
|
||||
selector: div.added-date
|
||||
filters:
|
||||
- name: timeago
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img[src="/pic/freedownload.gif"]: 0
|
||||
span.bg-success: 0
|
||||
"*": 1
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
description:
|
||||
selector: a[href*="?tag="]
|
||||
selector: a.tag
|
||||
attribute: title
|
||||
# engine n/a
|
||||
|
||||
@@ -39,6 +39,7 @@ caps:
|
||||
- {id: "AnimeLiveAction[English-translated]", cat: TV/Anime, desc: "Anime Live Action English-translated"}
|
||||
- {id: "AnimeLiveAction[Non-English]", cat: TV/Anime, desc: "Anime Live Action Non-English"}
|
||||
- {id: "AnimeLiveAction[Raw]", cat: TV/Anime, desc: "Anime Live Action Raw"}
|
||||
- {id: AnimePictures, cat: Other, desc: Anime Pictures}
|
||||
- {id: AnimeRaw, cat: TV/Anime, desc: Anime Raw}
|
||||
- {id: AnimeSubs, cat: TV/Anime, desc: Anime Subs}
|
||||
- {id: Apps, cat: PC, desc: Apps}
|
||||
|
||||
@@ -281,6 +281,7 @@ caps:
|
||||
- {id: 2281, cat: PC/ISO, desc: "Web Security Dojo"}
|
||||
- {id: 2246, cat: PC/ISO, desc: "Whonix"}
|
||||
- {id: 2155, cat: PC/ISO, desc: "Wifislax"}
|
||||
- {id: 2229, cat: PC/ISO, desc: "XiVa Studio"}
|
||||
- {id: 2251, cat: PC/ISO, desc: "XigmaNAS"}
|
||||
- {id: 607, cat: PC/ISO, desc: "Xubuntu"}
|
||||
- {id: 612, cat: PC/ISO, desc: "Zen"}
|
||||
|
||||
@@ -9,15 +9,12 @@ encoding: UTF-8
|
||||
links:
|
||||
- https://magnetcatcat.com/
|
||||
- https://clmclm.com/
|
||||
- https://www.8800517.xyz/
|
||||
- https://www.8800518.xyz/
|
||||
- https://www.8800519.xyz/
|
||||
- https://www.8800520.xyz/
|
||||
- https://www.8800521.xyz/
|
||||
- https://www.8800522.xyz/
|
||||
- https://www.8800523.xyz/
|
||||
legacylinks:
|
||||
- https://www.clm472.sbs/
|
||||
- https://www.8800498.xyz/
|
||||
- https://www.8800497.xyz/
|
||||
- https://www.8800499.xyz/
|
||||
- https://www.8800500.xyz/
|
||||
- https://www.8800503.xyz/
|
||||
- https://www.8800504.xyz/
|
||||
@@ -31,6 +28,9 @@ legacylinks:
|
||||
- https://www.8800514.xyz/
|
||||
- https://www.8800515.xyz/
|
||||
- https://www.8800516.xyz/
|
||||
- https://www.8800517.xyz/
|
||||
- https://www.8800518.xyz/
|
||||
- https://www.8800520.xyz/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
||||
@@ -32,7 +32,7 @@ search:
|
||||
paths:
|
||||
- path: search
|
||||
inputs:
|
||||
q: "{{ if .Keywords }}{{ .Keywords }}{{ else }}*{{ end }}"
|
||||
query: "{{ if .Keywords }}{{ .Keywords }}{{ else }}*{{ end }}"
|
||||
|
||||
rows:
|
||||
selector: a.list-group-item
|
||||
|
||||
@@ -26,6 +26,8 @@ settings:
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: info_flaresolverr
|
||||
type: info_flaresolverr
|
||||
- name: info_category_8000
|
||||
type: info_category_8000
|
||||
- name: hidef
|
||||
|
||||
@@ -26,6 +26,8 @@ settings:
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: info_flaresolverr
|
||||
type: info_flaresolverr
|
||||
- name: info_category_8000
|
||||
type: info_category_8000
|
||||
- name: hidef
|
||||
|
||||
@@ -9,22 +9,8 @@ type: semi-private
|
||||
encoding: windows-1251
|
||||
followredirect: true
|
||||
links:
|
||||
- https://nov12.rudub.pics/
|
||||
- https://nov19.rudub.pics/
|
||||
legacylinks:
|
||||
- https://oct28.rudub.homes/
|
||||
- http://oct29.rudub.homes/
|
||||
- https://oct29.rudub.homes/
|
||||
- http://oct30.rudub.homes/
|
||||
- https://oct30.rudub.homes/
|
||||
- http://oct31.rudub.homes/
|
||||
- https://oct31.rudub.homes/
|
||||
- http://nov01.rudub.homes/
|
||||
- https://nov01.rudub.homes/
|
||||
- http://nov02.rudub.homes/
|
||||
- https://nov02.rudub.homes/
|
||||
- http://nov03.rudub.homes/
|
||||
- https://nov03.rudub.homes/
|
||||
- http://nov04.rudub.homes/
|
||||
- https://nov04.rudub.homes/
|
||||
- http://nov05.rudub.homes/
|
||||
- https://nov05.rudub.homes/
|
||||
@@ -41,6 +27,20 @@ legacylinks:
|
||||
- http://nov11.rudub.pics/
|
||||
- https://nov11.rudub.pics/
|
||||
- http://nov12.rudub.pics/
|
||||
- https://nov12.rudub.pics/
|
||||
- http://nov13.rudub.pics/
|
||||
- https://nov13.rudub.pics/
|
||||
- http://nov14.rudub.pics/
|
||||
- https://nov14.rudub.pics/
|
||||
- http://nov15.rudub.pics/
|
||||
- https://nov15.rudub.pics/
|
||||
- http://nov16.rudub.pics/
|
||||
- https://nov16.rudub.pics/
|
||||
- http://nov17.rudub.pics/
|
||||
- https://nov17.rudub.pics/
|
||||
- http://nov18.rudub.pics/
|
||||
- https://nov18.rudub.pics/
|
||||
- http://nov19.rudub.pics/
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: TV, desc: "TV"}
|
||||
|
||||
@@ -51,8 +51,10 @@ caps:
|
||||
- {id: 41, cat: XXX, desc: "Homemade"}
|
||||
- {id: 42, cat: XXX, desc: "Pregnant"}
|
||||
- {id: 43, cat: XXX, desc: "Gay"}
|
||||
- {id: 1, cat: Movies, desc: "Movie"}
|
||||
- {id: 2, cat: TV, desc: "TV Show"}
|
||||
- {id: 45, cat: XXX, desc: "Classic"}
|
||||
- {id: 44, cat: XXX, desc: "SiteFan"}
|
||||
- {id: 1, cat: Movies, desc: "Movies"}
|
||||
- {id: 2, cat: TV, desc: "TV"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
|
||||
@@ -7,11 +7,10 @@ type: public
|
||||
encoding: UTF-8
|
||||
followredirect: true
|
||||
links:
|
||||
- https://torrentqq393.com/
|
||||
- https://torrentqq394.com/
|
||||
- https://torrentegg83.com/
|
||||
legacylinks:
|
||||
- https://torrentegg68.com/
|
||||
- https://torrentqq378.com/
|
||||
- https://torrentegg69.com/
|
||||
- https://torrentqq379.com/
|
||||
- https://torrentegg70.com/
|
||||
@@ -40,6 +39,7 @@ legacylinks:
|
||||
- https://torrentegg81.com/
|
||||
- https://torrentqq392.com/
|
||||
- https://torrentegg82.com/
|
||||
- https://torrentqq393.com/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
||||
@@ -31,10 +31,8 @@ caps:
|
||||
- {id: 190, cat: Movies, desc: " |- Фильмы в 4K и 3D"}
|
||||
- {id: 34, cat: Movies, desc: " |- Перевод на узбекский"}
|
||||
- {id: 25, cat: Movies, desc: "Узбекские кинофильмы"}
|
||||
- {id: 32, cat: Movies, desc: " |- Новинки"}
|
||||
- {id: 30, cat: Movies, desc: " |- Фильмы 2011-2024 годов"}
|
||||
- {id: 29, cat: Movies, desc: " |- Фильмы 2000-2010 годов"}
|
||||
- {id: 26, cat: Movies, desc: " |- Фильмы до 2000 года"}
|
||||
- {id: 32, cat: Movies, desc: " |- Пр-во Узбекфильм (на русском)"}
|
||||
- {id: 30, cat: Movies, desc: " |- Пр-во Узбекфильм (на узбекском языке)"}
|
||||
# Сериалы, Видео и ТВ # Series, Videos and TV
|
||||
- {id: 97, cat: TV, desc: "Сериалы"}
|
||||
- {id: 333, cat: TV, desc: " |- Игра престолов / Game of Thrones"}
|
||||
@@ -85,6 +83,7 @@ caps:
|
||||
- {id: 132, cat: Audio, desc: " |- Классическая музыа"}
|
||||
- {id: 125, cat: Audio, desc: " |- New Age, Relax, Meditative & Flamenco"}
|
||||
- {id: 124, cat: Audio, desc: " |- Фольклор, Народная и Этническая музыка"}
|
||||
- {id: 338, cat: Audio, desc: " |- Country"}
|
||||
- {id: 231, cat: Audio, desc: " |- Сборники и альбомы выходившие неофициальными изданиями."}
|
||||
- {id: 144, cat: Audio, desc: "♫ ROCK & METAL ♫"}
|
||||
- {id: 201, cat: Audio, desc: " |- Русский Rock, Metal (mp3)"}
|
||||
@@ -170,6 +169,7 @@ caps:
|
||||
- {id: 289, cat: PC/Games, desc: " |- Horror"}
|
||||
- {id: 307, cat: PC/Games, desc: " |- Logic"}
|
||||
- {id: 304, cat: PC/Games, desc: " |- Lifestyle"}
|
||||
- {id: 336, cat: PC/Games, desc: " |- Sports"}
|
||||
- {id: 306, cat: PC/Games, desc: " |- Exploration"}
|
||||
- {id: 305, cat: PC/Games, desc: " |- Management"}
|
||||
- {id: 115, cat: PC/Games, desc: " |- Аркады"}
|
||||
|
||||
34
src/Jackett.Common/Extensions/HashingExtensions.cs
Normal file
34
src/Jackett.Common/Extensions/HashingExtensions.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Jackett.Common.Extensions
|
||||
{
|
||||
public static class HashingExtensions
|
||||
{
|
||||
public static string SHA1Hash(this string input)
|
||||
{
|
||||
using var hash = SHA1.Create();
|
||||
|
||||
return GetHash(hash.ComputeHash(Encoding.UTF8.GetBytes(input)));
|
||||
}
|
||||
|
||||
public static string SHA256Hash(this string input)
|
||||
{
|
||||
using var hash = SHA256.Create();
|
||||
|
||||
return GetHash(hash.ComputeHash(Encoding.UTF8.GetBytes(input)));
|
||||
}
|
||||
|
||||
private static string GetHash(byte[] bytes)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
foreach (var b in bytes)
|
||||
{
|
||||
stringBuilder.Append(b.ToString("x2"));
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ namespace Jackett.Common.Indexers.Definitions
|
||||
var maxPages = 2; // we scrape only 2 pages for recent torrents
|
||||
if (!string.IsNullOrWhiteSpace(query.GetQueryString()))
|
||||
{
|
||||
searchString = Uri.EscapeUriString(query.GetQueryString());
|
||||
searchString = Uri.EscapeDataString(query.GetQueryString());
|
||||
maxPages = MaxSearchPageLimit;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,11 @@ using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Html.Parser;
|
||||
using Jackett.Common.Extensions;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.IndexerConfig;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
@@ -253,11 +252,13 @@ namespace Jackett.Common.Indexers.Definitions
|
||||
if (string.IsNullOrWhiteSpace(sessionId))
|
||||
throw new ExceptionWithConfigData("Error getting the Session ID", configData);
|
||||
|
||||
await Task.Delay(3000);
|
||||
|
||||
// The second page send the login with the hash
|
||||
// The hash is reverse engineering from https://www.zonaq.pw/retorno/2/smf/Themes/smf_ZQ/scripts/script.js
|
||||
// doForm.hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_to8bit().php_strtolower() + doForm.passwrd.value.php_to8bit()) + cur_session_id);
|
||||
Thread.Sleep(3000);
|
||||
var hashPassword = Sha1Hash(Sha1Hash(configData.Username.Value.ToLower() + configData.Password.Value) + sessionId);
|
||||
var hashPassword = $"{(configData.Username.Value.ToLowerInvariant() + configData.Password.Value).SHA1Hash()}{sessionId}".SHA1Hash();
|
||||
|
||||
var pairs = new Dictionary<string, string> {
|
||||
{ "user", configData.Username.Value },
|
||||
{ "passwrd", configData.Password.Value },
|
||||
@@ -288,11 +289,5 @@ namespace Jackett.Common.Indexers.Definitions
|
||||
Thread.Sleep(3000);
|
||||
await RequestWithCookiesAsync(Login4Url);
|
||||
}
|
||||
|
||||
private static string Sha1Hash(string input)
|
||||
{
|
||||
var hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input));
|
||||
return string.Concat(hash.Select(b => b.ToString("x2")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFrameworks>netstandard2.0;net9.0</TargetFrameworks>
|
||||
<Version>0.0.0</Version>
|
||||
<LangVersion>9</LangVersion>
|
||||
<NoWarn />
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Jackett.Common.Extensions;
|
||||
using Jackett.Common.Indexers;
|
||||
using Jackett.Common.Models;
|
||||
using Jackett.Common.Models.Config;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
|
||||
@@ -36,8 +34,7 @@ namespace Jackett.Common.Services
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly ServerConfig _serverConfig;
|
||||
private readonly SHA256Managed _sha256 = new SHA256Managed();
|
||||
private readonly Dictionary<string, TrackerCache> _cache = new Dictionary<string, TrackerCache>();
|
||||
private readonly Dictionary<string, TrackerCache> _cache = new();
|
||||
|
||||
public CacheService(Logger logger, ServerConfig serverConfig)
|
||||
{
|
||||
@@ -236,11 +233,11 @@ namespace Jackett.Common.Services
|
||||
}
|
||||
}
|
||||
|
||||
private string GetQueryHash(TorznabQuery query)
|
||||
private static string GetQueryHash(TorznabQuery query)
|
||||
{
|
||||
var json = GetSerializedQuery(query);
|
||||
// Compute the hash
|
||||
return BitConverter.ToString(_sha256.ComputeHash(Encoding.UTF8.GetBytes(json)));
|
||||
|
||||
return json.SHA256Hash();
|
||||
}
|
||||
|
||||
private static string GetSerializedQuery(TorznabQuery query)
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace Jackett.Common.Services
|
||||
if (!Directory.Exists(GetAppDataFolder()))
|
||||
{
|
||||
var dir = Directory.CreateDirectory(GetAppDataFolder());
|
||||
if (Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var access = dir.GetAccessControl();
|
||||
var directorySecurity = new DirectorySecurity(GetAppDataFolder(), AccessControlSections.All);
|
||||
@@ -126,7 +127,7 @@ namespace Jackett.Common.Services
|
||||
if (!Directory.Exists(destFolder))
|
||||
{
|
||||
var dir = Directory.CreateDirectory(destFolder);
|
||||
if (Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var directorySecurity = new DirectorySecurity(destFolder, AccessControlSections.All);
|
||||
directorySecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow));
|
||||
@@ -137,7 +138,7 @@ namespace Jackett.Common.Services
|
||||
{
|
||||
File.Copy(file, destPath);
|
||||
// The old files were created when running as admin so make sure they are editable by normal users / services.
|
||||
if (Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var fileInfo = new FileInfo(destFolder);
|
||||
var fileSecurity = new FileSecurity(destPath, AccessControlSections.All);
|
||||
|
||||
@@ -74,8 +74,6 @@ namespace Jackett.Common.Services
|
||||
}
|
||||
}
|
||||
|
||||
private bool AcceptCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => true;
|
||||
|
||||
private async Task CheckForUpdates()
|
||||
{
|
||||
logger.Info($"Checking for updates... Jackett variant: {variant}");
|
||||
@@ -180,14 +178,7 @@ namespace Jackett.Common.Services
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Error checking for updates.\n{e}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!isWindows)
|
||||
{
|
||||
System.Net.ServicePointManager.ServerCertificateValidationCallback -= AcceptCert;
|
||||
}
|
||||
logger.Error(e, $"Error checking for updates.\n{e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using System.ServiceProcess;
|
||||
using Jackett.Common.Services.Interfaces;
|
||||
using Jackett.Common.Utils;
|
||||
@@ -9,6 +10,9 @@ using NLog;
|
||||
|
||||
namespace Jackett.Common.Services
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class WindowsServiceConfigService : IServiceConfigService
|
||||
{
|
||||
private const string NAME = "Jackett";
|
||||
|
||||
@@ -29,8 +29,13 @@ namespace Jackett.Common.Utils.Clients
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages
|
||||
public static bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
public bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sender.GetType() != typeof(HttpWebRequest))
|
||||
return sslPolicyErrors == SslPolicyErrors.None;
|
||||
|
||||
@@ -51,24 +56,11 @@ namespace Jackett.Common.Utils.Clients
|
||||
|
||||
public override void SetTimeout(int seconds) => ClientTimeout = seconds;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
// custom handler for our own internal certificates
|
||||
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
|
||||
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
|
||||
else
|
||||
ServicePointManager.ServerCertificateValidationCallback += ValidateCertificate;
|
||||
}
|
||||
|
||||
protected override async Task<WebResult> Run(WebRequest webRequest)
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072;
|
||||
|
||||
var cookies = new CookieContainer
|
||||
{
|
||||
PerDomainCapacity = 100 // By default only 20 cookies are allowed per domain
|
||||
PerDomainCapacity = 100 // By default, only 20 cookies are allowed per domain
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(webRequest.Cookies))
|
||||
{
|
||||
@@ -86,14 +78,17 @@ namespace Jackett.Common.Utils.Clients
|
||||
clearanceHandlr.ProxyUrl = serverConfig.GetProxyUrl(false);
|
||||
clearanceHandlr.ProxyUsername = serverConfig.ProxyUsername;
|
||||
clearanceHandlr.ProxyPassword = serverConfig.ProxyPassword;
|
||||
|
||||
using (var clientHandlr = new HttpClientHandler
|
||||
{
|
||||
CookieContainer = cookies,
|
||||
AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more.
|
||||
UseCookies = true,
|
||||
Proxy = webProxy,
|
||||
UseProxy = (webProxy != null),
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
|
||||
UseProxy = webProxy != null,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
|
||||
MaxConnectionsPerServer = 20,
|
||||
ServerCertificateCustomValidationCallback = ValidateCertificate,
|
||||
})
|
||||
{
|
||||
clearanceHandlr.InnerHandler = clientHandlr;
|
||||
|
||||
@@ -33,14 +33,19 @@ namespace Jackett.Common.Utils.Clients
|
||||
{
|
||||
cookies = new CookieContainer
|
||||
{
|
||||
PerDomainCapacity = 100 // By default only 20 cookies are allowed per domain
|
||||
PerDomainCapacity = 100 // By default, only 20 cookies are allowed per domain
|
||||
};
|
||||
CreateClient();
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode] // avoid "Exception User-Unhandled" Visual Studio messages
|
||||
public static bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
public bool ValidateCertificate(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var hash = certificate.GetCertHashString();
|
||||
|
||||
trustedCertificates.TryGetValue(hash, out var hosts);
|
||||
@@ -70,16 +75,12 @@ namespace Jackett.Common.Utils.Clients
|
||||
AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more.
|
||||
UseCookies = true,
|
||||
Proxy = webProxy,
|
||||
UseProxy = (webProxy != null),
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
|
||||
UseProxy = webProxy != null,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
|
||||
MaxConnectionsPerServer = 20,
|
||||
ServerCertificateCustomValidationCallback = ValidateCertificate,
|
||||
};
|
||||
|
||||
// custom certificate validation handler (netcore version)
|
||||
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)
|
||||
clientHandlr.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
|
||||
else
|
||||
clientHandlr.ServerCertificateCustomValidationCallback = ValidateCertificate;
|
||||
|
||||
clearanceHandlr.InnerHandler = clientHandlr;
|
||||
client = new HttpClient(clearanceHandlr);
|
||||
|
||||
@@ -103,13 +104,6 @@ namespace Jackett.Common.Utils.Clients
|
||||
client.Timeout = TimeSpan.FromSeconds(ClientTimeout);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072;
|
||||
}
|
||||
|
||||
protected override async Task<WebResult> Run(WebRequest webRequest)
|
||||
{
|
||||
var request = new HttpRequestMessage();
|
||||
|
||||
@@ -220,11 +220,7 @@ namespace Jackett.Common.Utils.Clients
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
protected virtual async Task<WebResult> Run(WebRequest webRequest) => throw new NotImplementedException();
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
|
||||
public virtual void Init() => ServicePointManager.DefaultConnectionLimit = 1000;
|
||||
protected virtual Task<WebResult> Run(WebRequest webRequest) => throw new NotImplementedException();
|
||||
|
||||
public virtual void OnCompleted() => throw new NotImplementedException();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using Jackett.Common.Utils.Clients;
|
||||
|
||||
@@ -75,7 +76,11 @@ namespace Jackett.Common.Utils
|
||||
|
||||
public static bool IsUserAdministrator()
|
||||
{
|
||||
//bool value to hold our return value
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isAdmin;
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Jackett.Common.Utils
|
||||
{
|
||||
public static class StringCipher
|
||||
{
|
||||
// This constant is used to determine the keysize of the encryption algorithm in bits.
|
||||
// We divide this by 8 within the code below to get the equivalent number of bytes.
|
||||
private const int Keysize = 256;
|
||||
|
||||
// This constant determines the number of iterations for the password bytes generation function.
|
||||
private const int DerivationIterations = 1000;
|
||||
|
||||
public static string Encrypt(string plainText, string passPhrase)
|
||||
{
|
||||
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
|
||||
// so that the same Salt and IV values can be used when decrypting.
|
||||
var saltStringBytes = Generate256BitsOfRandomEntropy();
|
||||
var ivStringBytes = Generate256BitsOfRandomEntropy();
|
||||
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
|
||||
{
|
||||
var keyBytes = password.GetBytes(Keysize / 8);
|
||||
using (var symmetricKey = new RijndaelManaged())
|
||||
{
|
||||
symmetricKey.BlockSize = 256;
|
||||
symmetricKey.Mode = CipherMode.CBC;
|
||||
symmetricKey.Padding = PaddingMode.PKCS7;
|
||||
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
|
||||
{
|
||||
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
|
||||
var cipherTextBytes = saltStringBytes;
|
||||
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
|
||||
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
|
||||
memoryStream.Close();
|
||||
cryptoStream.Close();
|
||||
return Convert.ToBase64String(cipherTextBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string Decrypt(string cipherText, string passPhrase)
|
||||
{
|
||||
// Get the complete stream of bytes that represent:
|
||||
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
|
||||
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
|
||||
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
|
||||
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
|
||||
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
|
||||
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
|
||||
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
|
||||
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
|
||||
|
||||
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
|
||||
{
|
||||
var keyBytes = password.GetBytes(Keysize / 8);
|
||||
using (var symmetricKey = new RijndaelManaged())
|
||||
{
|
||||
symmetricKey.BlockSize = 256;
|
||||
symmetricKey.Mode = CipherMode.CBC;
|
||||
symmetricKey.Padding = PaddingMode.PKCS7;
|
||||
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(cipherTextBytes))
|
||||
{
|
||||
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
var plainTextBytes = new byte[cipherTextBytes.Length];
|
||||
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
|
||||
memoryStream.Close();
|
||||
cryptoStream.Close();
|
||||
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] Generate256BitsOfRandomEntropy()
|
||||
{
|
||||
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
|
||||
using (var rngCsp = new RNGCryptoServiceProvider())
|
||||
{
|
||||
// Fill the array with cryptographically secure random bytes.
|
||||
rngCsp.GetBytes(randomBytes);
|
||||
}
|
||||
return randomBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,7 @@ namespace Jackett.Server.Services
|
||||
return null;
|
||||
|
||||
var ue = new UnicodeEncoding();
|
||||
#pragma warning disable SYSLIB0021
|
||||
var hashString = new SHA512Managed();
|
||||
#pragma warning restore SYSLIB0021
|
||||
var hashString = SHA512.Create();
|
||||
|
||||
// Append key as salt
|
||||
input += _serverConfig.APIKey;
|
||||
|
||||
@@ -341,7 +341,6 @@ namespace Jackett.Server.Services
|
||||
|
||||
// Load indexers
|
||||
indexerService.InitIndexers(configService.GetCardigannDefinitionsFolders());
|
||||
client.Init();
|
||||
|
||||
updater.CleanupTempDir();
|
||||
updater.CheckUpdaterLock();
|
||||
|
||||
@@ -48,9 +48,5 @@ namespace Jackett.Test.TestHelpers
|
||||
});
|
||||
throw new Exception($"You have to mock the URL {request.Url} with RegisterRequestCallback");
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user