-
Автор темы
- #1
1. Данный гайд был создан потому что мне было ну совсем нечем заняться
2. Данный гайд был создан потому что я увидел вот этот гайд
3. Данный гайд был создан скорее для тех кто просто начинает изучать шарп и хочет увидеть пример какой-либо проги на шарпе с объяснением ее работы
4. Тулза энивей хуета и вы врятле набрутите себе нитро
Всё постарался объяснить в виде комментариев к коду
2. Данный гайд был создан потому что я увидел вот этот гайд
3. Данный гайд был создан скорее для тех кто просто начинает изучать шарп и хочет увидеть пример какой-либо проги на шарпе с объяснением ее работы
4. Тулза энивей хуета и вы врятле набрутите себе нитро
Всё постарался объяснить в виде комментариев к коду
C#:
// Подключаем пространство имен для консоли и всего такого говна
using System;
// Подключаем пространство имен для работы с файлами и стримами(не на твиче блять)
using System.IO;
// Подключаем пространство имен для работы для отправки запросов
using System.Net;
// Подключаем пространство имен для потоков
using System.Threading;
// Подключаем пространство имен для криптостойкого генератора рандомных чисел
using System.Security.Cryptography;
namespace DiscordNitroGenerator {
class Program {
// Определяем константное числовое значение
// Оно будет использовано позже для определения того, сколько потоку нужно будет подождать перед тем как вызывать сборщик мусора
// 120 - кол-во секунд
// 1000 - т.к. 1 секунда == 1000 милисекунд. В целом, можно было бы просто прописать 120000, разница вообщем-то отсутствует
const int GC_COOLDOWN = 120 * 1000;
// Опять определяем константное числовое значение которое будет использовано позже
// Вот тут важно
// Дискорд не любит когда его задрачивают запросами, поэтому запросы мы будем слать 1 запрос каждые 5 секунд
// Можно и чаще, но статус Rate Limited все равно будет ебать мозги
const int MAIN_COOLDOWN = 5 * 1000;
// Определяем константную строку со всеми символами которые будут использованы для генерации кода
const string CHARS = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz9876543210";
// Создаем экземпляр класса генератора рандомных чисел
static readonly RandomNumberGenerator rng = new RNGCryptoServiceProvider();
// Создаем экземпляр уже другого класса генератора рандомных чисел
// Класс Random отличается от класса RandomNumberGenerator тем, что он не является криптостойким
// В целом, в данной ситуации по большей то части похуй, насколько рнг криптостойкое, но почему бы и нет?
static readonly Random random = new Random();
// Делаем метод для генерации рандомного числа с использованием класса Random
// ну я думаю тут итак понятно все лол.
static int rand(int max) {
return random.Next(0, max);
}
// Делаем метод для генерации рандомного числа с использованием класса RandomNumberGenerator
// а вот тут уже посложнее
static int rand_s(int max) {
// Создаем буфер который будет заполнен методом GetBytes()
// Т.к. возвращаемое число данного метода - int, выделяем под буфер столько же места, сколько тип данных int занимает в памяти, т.е. 4 байта(sizeof(int) == 4)
byte[] data = new byte[sizeof(int)];
// Заполняем буфер рандомными значениями вызвав GetBytes()
rng.GetBytes(data);
// Конвертируем все содержимое буфера в число и делим полученное число на максимальное значение типа данных int
// Если честно в душе не понимаю зачем тут это деление, но без него не работает лол
double u = BitConverter.ToInt32(data, 0) / (int.MaxValue + 1.0);
// Тут уже чисто знания матеши ебаной, объясню только (int) перед вызовом Floor
// Дописав (int) перед вызовом Floor, мы преобразуем тип данных double(т.к. Floor возвращает именно этот тип данных) в тип данных int, т.к. наш метод должен вовращать именно int
// Подробнее про преобразования можно почитать тут: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/types/casting-and-type-conversions
return (int)Math.Floor((double)max * u);
}
// Делаем метод для генерации рандомной строки, т.е. нашего волшебного "кода для получения Discord Nitro"
static string randstr(int length) {
// Создаем буфер(размером указанным в аргументах метода) который будет заполняться рандомными символами
char[] c = new char[length];
// Делаем цикл продолжающийся до тех пор, пока кол-во итераций не будет равно размеру буфера
for (int i = 0; i < c.Length; i++)
c[i] = CHARS[rand(CHARS.Length)]; // При каждой итерации буфер будет заполняться символом с рандомным индексом из того списка, который был определен в начале
// Создаем из уже заполненного буфера строку и возвращаем ее
return new string(c);
}
// Делаем метод для генерации рандомной строки, т.е. нашего волшебного "кода для получения Discord Nitro"
// Этот метод абсолютно такой же как и предыдущий, но использует другой созданный нами генератор рандомных чисел
static string randstr_s(int length) {
char[] c = new char[length];
for (int i = 0; i < c.Length; i++)
c[i] = CHARS[rand_s(CHARS.Length)];
return new string(c);
}
// Создадим метод для отправки GET запросов с нашим кодом
// out - это модификатор позволяющий передать аргумент
// Про out можно почитать тут: https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/out-parameter-modifier
static void webrequest_get(string url, string data, out string r) {
// Создаем экземпляр класса HttpWebRequest, отправляем запрос
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + data);
// Говорим HttpWebRequest'у что метод запроса должен быть именно GET
request.Method = "GET";
// Создаем экземпляр класса HttpWebResponse
HttpWebResponse response = null;
// Получаем ответ (Какого-то хуя оно только так работает.
// Блять, когда я писал этот код я не планировал что так получится.
// Но если что, про try-catch можно почитать тут: https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/try-catch)
try {
response = (HttpWebResponse)request.GetResponse();
}
// Если эта сука по какой-то причине выдала 404 Not Found, то ловим исключение и читаем ответ из него
catch (WebException webex) {
response = (HttpWebResponse)webex.Response;
}
// Создаем экземпляр класса Stream, получаем стрим для чтения ответа
Stream stream = response.GetResponseStream();
// Создаем экземпляр класса StreamReader, для того чтобы прочитать стрим с ответом
StreamReader reader = new StreamReader(stream);
// Читаем ответ, присваиваем его переменной r для дальнейшей передачи этого ответа другой переменной
r = reader.ReadToEnd();
// Удалим 3 ранее созданных экземпляра классов из памяти
// Эти методы можно не вызывать в том случае, если вы юзаете using(что в идеале и нужно делать, просто я дебил)
response.Dispose();
stream.Dispose();
reader.Dispose();
// Как и писалось ранее, я дебил и в идеале этот код должен выглядеть вот так
/*
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream)) {
r = reader.ReadToEnd();
}
*/
}
// Создадим метод для сбора мусора.
// В идеале этого мусора быть итак не должно, но почему бы и нет.
static void collect_garbage() {
// Запускаем бесконечный цикл (while (true) и for (;;) - это одно и то же, если что.)
for (; ; ) {
// Заставляем поток ждать то кол-во времени, которое было указано в начале.
Thread.Sleep(GC_COOLDOWN);
// Вызываем сборщик мусора.
GC.Collect();
}
}
static void Main(string[] args) {
// Даем пользователю самому выбрать, какой генератор рандомных чисел будет использован
// Для этого создадим булевую, значение которой будет зависить от того был ли указан аргумент -srng(или --securerng) и были ли указаны какие-либо аргументы вообще
bool srng = args.Length > 0 && (args[0] == "-srng" || args[0] == "--securerng");
// Создадим поток, вызовем в нем метод для сбора мусора, запустим поток
new Thread(collect_garbage).Start();
// Бесконечный цикл
for (; ; ) {
string response; // Определим переменную которой будем передавать ответ на запрос
// Думаю стоит пояснить за это выражение
// ?: - это условный оператор
// Подробно расписывать не буду(ибо можно почитать тут: https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/operators/conditional-operator), лишь покажу его синтаксис
// condition ? true : false (выражение ? верно : не верно)
// Как я думаю понятно, выражение может представлять из себя ссылку на булевую(как в нашем случае)
string code = (srng ? randstr_s(16) : randstr(16));
// Отправляем запрос
webrequest_get("http://discord.com/api/v6/entitlements/gift-codes/", code + "?with_application=false&with_subscription_plan=true", out response);
// Делаем проверку на валидность кода(или на то не получили ли вы статус Rate Limited, лол)
// Если код валидный, то выводим его в консоль и завершаем цикл(при помощи break;)
// Если же не валидный, то все равно выводим его в консоль вместе с ответом от дискорда
if (!response.Contains("Unknown Gift Code") && !response.Contains("You are being rate limited.")) {
Console.WriteLine(code);
break;
}
else Console.WriteLine(code + " : " + response);
// Удаляем из памяти две строки определенные выше
// Так обычно никто не делает, да и смысла вроде как нет, просто я люблю собирать мусор в ручную лол
// (хотя, просто для справки: такой прием помогает от дампа памяти(в шарпе нет деструкторов так что всякие буферы часто остаются в памяти))
response = null;
code = null;
// Заставим поток поспать, дабы программа не жрала слишком много ресурсов, да и дискорд не любит когда ему спамят запросами
Thread.Sleep(MAIN_COOLDOWN);
}
// Ждем пока пользователь нажмет кнопку
// Без этой строки консоль просто закроется после выхода из цикла
// Хотя нахуй я это написал, это же прям пиздец какие азы, думаю даже обезьяна знает зачем тут эта строка.
Console.ReadKey();
}
}
}