From a48ccdf95b3003c152d0686e381210a70d1f3ccc Mon Sep 17 00:00:00 2001 From: Dima YaFlay <93622229+YaFlay@users.noreply.github.com> Date: Mon, 16 Oct 2023 18:24:17 +0300 Subject: [PATCH 1/5] Add files via upload --- src/Types/PaymentData.cs | 9 ++ src/Types/SkinPart.cs | 13 +++ src/Types/User.cs | 23 ++++ src/spworlds.cs | 221 +++++++++++++++++++++++---------------- 4 files changed, 177 insertions(+), 89 deletions(-) create mode 100644 src/Types/PaymentData.cs create mode 100644 src/Types/SkinPart.cs create mode 100644 src/Types/User.cs diff --git a/src/Types/PaymentData.cs b/src/Types/PaymentData.cs new file mode 100644 index 0000000..0a93126 --- /dev/null +++ b/src/Types/PaymentData.cs @@ -0,0 +1,9 @@ +namespace spworlds.Types; + +public class PaymentData +{ + public int Amount; + public string RedirectUrl; + public string WebHookUrl; + public string Data; +} \ No newline at end of file diff --git a/src/Types/SkinPart.cs b/src/Types/SkinPart.cs new file mode 100644 index 0000000..fe1f2b7 --- /dev/null +++ b/src/Types/SkinPart.cs @@ -0,0 +1,13 @@ +namespace spworlds.Types; + +public enum SkinPart +{ + face; + front; + front_full; + head; + bust; + full; + skin; + +} diff --git a/src/Types/User.cs b/src/Types/User.cs new file mode 100644 index 0000000..0b97abd --- /dev/null +++ b/src/Types/User.cs @@ -0,0 +1,23 @@ +using spworlds; +using System.Text.Json.Nodes; +namespace spworlds.Types; + +public class User +{ + private string Name { get; } + private HttpClient client = new(); + private string nonSerializedUuid = await client.GetStringAsync($"https://api.mojang.com/users/profiles/minecraft/{Name}"); + private JsonNode uuid = JsonNode.Parse(nonSerializedUuid); + private string Uuid { get; } = uuid["id"] + string nonSerializedProfileId = await client.GetStringAsync($"https://sessionserver.mojang.com/session/minecraft/profile/{Uuid}"); + private JsonNode profile = JsonNode.Parse(nonSerializedProfileId); + + public async Task GetSkinPart(SkinPart skinPart, string size) + { + return (string)$"https://visage.surgeplay.com/{skinPart}/{size}/{this.profile["profileId"]}" + } + public string GetName() => this.Name; + public string GetUuid() => this.Uuid; + public JsonNode GetProfile() => return this.profile; + public bool IsPlayer() => this.Name != null : false; +} \ No newline at end of file diff --git a/src/spworlds.cs b/src/spworlds.cs index 361c36e..f2a723d 100644 --- a/src/spworlds.cs +++ b/src/spworlds.cs @@ -1,90 +1,133 @@ -using System.Net.Http.Headers; -using System.Text.Json; -using System.Text; -using System.Text.Json.Nodes; - -namespace spworlds; - -public class SPWorlds -{ - private readonly HttpClient client; - - public SPWorlds(string id, string token) - { - client = new HttpClient(); - var BearerToken = $"{id}:{token}"; - string Base64BearerToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(BearerToken)); - - client.BaseAddress = new Uri("https://spworlds.ru/api/public/"); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Base64BearerToken); - } - - private async Task SendRequest(string endpoint, Boolean getResult = true, Dictionary? body = null) - { - string respond; - string jsonBody; - - if(body == null) - { - return respond = client.GetAsync(endpoint).Result.Content.ReadAsStringAsync().Result; - } - else - { - jsonBody = JsonSerializer.Serialize(body); - var payload = new StringContent(jsonBody, Encoding.UTF8, "application/json"); - - if(getResult) - return respond = client.PostAsync(endpoint, payload).Result.Content.ReadAsStringAsync().Result; - else - await client.PostAsync(endpoint, payload); - } - - return null; - } - - public async Task GetBalance() - { - string respond = await SendRequest("card"); - - var card = JsonObject.Parse(respond); - var balance = card["balance"]; - - return (int)balance; - } - - public async Task CreatTransaction(string receiver, int amount, string comment) - { - var transitionInfo = new Dictionary - { - { "receiver", receiver }, - { "amount", amount }, - { "comment", comment } - }; - - await SendRequest(endpoint: "transactions", body: transitionInfo); - } - - public async Task GetUser(string discordId) - { - var user = JsonObject.Parse(await SendRequest($"users/{discordId}")); - var userName = user["username"]; - - return (string)userName; - } - - public async Task InitPayment(int amount, string redirectUrl, string webhookUrl, string data) - { - var paymentInfo = new Dictionary - { - { "amount", amount }, - { "redirectUrl", redirectUrl }, - { "webhookUrl", webhookUrl }, - { "data", data } - }; - - var payment = JsonObject.Parse(await SendRequest(endpoint: $"payment",body: paymentInfo)); - var url = payment["url"]; - - return (string)url; - } +using System.Net.Http.Headers; +using System.Text.Json; +using System.Text; +using System.Text.Json.Nodes; +using System.Security.Cryptography; +using System.Runtime.InteropServices; + +using spworlds.Types; +namespace spworlds; + +public class SPWorlds +{ + private readonly HttpClient client; + private string token; + + public SPWorlds(string id, string token) + { + client = new HttpClient(); + var BearerToken = $"{id}:{token}"; + this.token = token; + string Base64BearerToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(BearerToken)); + + client.BaseAddress = new Uri("https://spworlds.ru/api/public/"); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Base64BearerToken); + } + + + // Полностью бесполезная функция, вебхук, возвращающийся от сайта по факту невозможно валидировать. + private async Task ValidateWebHook(string webHook, string bodyHash) + { + // Если я правильно все понял, то вот + // Конвертим из string в bytes body_hash + byte[] body = Encoding.UTF8.GetBytes(bodyHash); + // потом конвертим вебхук + byte[] webhook = Encoding.UTF8.GetBytes(webHook); + // создаем объект с токеном(тоже encoded в bytes) для сопостовления + var key = new HMACSHA256(Encoding.UTF8.GetBytes(token)); + // Переводим в Base64 + string webhook64 = Convert.ToBase64String(key.ComputeHash(webhook)); + return webhook64.Equals(body); + /** + * Тот же код, но на Python: + hmacData = hmac.new(token.encode('utf - 8'), webhook.encode('utf - 8'), sha256).digest() + base64Data = b64encode(hmacData) + return hmac.compare_digest(base64Data, bodyHash.encode('utf-8')) + **/ + } + + private async Task SendRequest(string endpoint, Boolean getResult = true, Dictionary? body = null) + { + string respond; + string jsonBody; + + if (body == null) + { + return respond = client.GetAsync(endpoint).Result.Content.ReadAsStringAsync().Result; + } + else + { + jsonBody = JsonSerializer.Serialize(body); + var payload = new StringContent(jsonBody, Encoding.UTF8, "application/json"); + + if (getResult) + return respond = client.PostAsync(endpoint, payload).Result.Content.ReadAsStringAsync().Result; + else + await client.PostAsync(endpoint, payload); + } + + return null; + } + + public async Task GetBalance() + { + string respond = await SendRequest("card"); + + var card = JsonObject.Parse(respond); + var balance = card["balance"]; + + return (int)balance; + } + + public async Task CreateTransaction(string receiver, int amount, string comment) + { + var transitionInfo = new Dictionary + { + { "receiver", receiver }, + { "amount", amount }, + { "comment", comment } + }; + + await SendRequest(endpoint: "transactions", body: transitionInfo); + } + + public async Task GetUser(string discordId) + { + var userResponse = JsonObject.Parse(await SendRequest($"users/{discordId}")); + var userName = userResponse["username"]; + User user = new() { Name = userName} + return (User)user; + } + + public async Task InitPayment(int amount, string redirectUrl, string webhookUrl, string data) + { + var paymentInfo = new Dictionary + { + { "amount", amount }, + { "redirectUrl", redirectUrl }, + { "webhookUrl", webhookUrl }, + { "data", data } + }; + + var payment = JsonObject.Parse(await SendRequest(endpoint: $"payment", body: paymentInfo)); + var url = payment["url"]; + + return (string)url; + } + + public async Task InitPayment(PaymentData paymentData) + { + var paymentInfo = new Dictionary + { + { "amount", paymentData.Amount }, + { "redirectUrl", paymentData.RedirectUrl }, + { "webhookUrl", paymentData.WebHookUrl }, + { "data", paymentData.Data } + }; + + var payment = JsonObject.Parse(await SendRequest(endpoint: $"payment", body: paymentInfo)); + var url = payment["url"]; + + return (string)url; + } } \ No newline at end of file From ff7580987a004e22178c220f327d92457e622489 Mon Sep 17 00:00:00 2001 From: Dima YaFlay <93622229+YaFlay@users.noreply.github.com> Date: Mon, 16 Oct 2023 18:25:01 +0300 Subject: [PATCH 2/5] Create dotnet.yml --- .github/workflows/dotnet.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 0000000..25f43e7 --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,28 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: .NET + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal From fd6811ace3875b5e85d2fa0b58852b06896e683d Mon Sep 17 00:00:00 2001 From: Dima YaFlay <93622229+YaFlay@users.noreply.github.com> Date: Mon, 16 Oct 2023 18:30:09 +0300 Subject: [PATCH 3/5] Update spworlds.cs --- src/spworlds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spworlds.cs b/src/spworlds.cs index f2a723d..6daa06f 100644 --- a/src/spworlds.cs +++ b/src/spworlds.cs @@ -130,4 +130,4 @@ public class SPWorlds return (string)url; } -} \ No newline at end of file +} From 76394247aefbddf03a7044ff7320151ed76c19d0 Mon Sep 17 00:00:00 2001 From: Dima YaFlay <93622229+YaFlay@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:02:04 +0300 Subject: [PATCH 4/5] Update User.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Спасибо Mih4n за код-ревью --- src/Types/User.cs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Types/User.cs b/src/Types/User.cs index 0b97abd..dfa06ff 100644 --- a/src/Types/User.cs +++ b/src/Types/User.cs @@ -4,20 +4,22 @@ namespace spworlds.Types; public class User { - private string Name { get; } + public readonly string Name + public readonly string Uuid + public readonly JsonNode profile + private HttpClient client = new(); - private string nonSerializedUuid = await client.GetStringAsync($"https://api.mojang.com/users/profiles/minecraft/{Name}"); - private JsonNode uuid = JsonNode.Parse(nonSerializedUuid); - private string Uuid { get; } = uuid["id"] - string nonSerializedProfileId = await client.GetStringAsync($"https://sessionserver.mojang.com/session/minecraft/profile/{Uuid}"); - private JsonNode profile = JsonNode.Parse(nonSerializedProfileId); + + public bool IsPlayer() => this.Name != null ? true : false; + + public User() + { + Uuid = JsonNode.Parse(await client.GetStringAsync($"https://api.mojang.com/users/profiles/minecraft/{Name}"))["id"]; + profile = JsonNode.Parse(await client.GetStringAsync($"https://sessionserver.mojang.com/session/minecraft/profile/{Uuid}")); + } - public async Task GetSkinPart(SkinPart skinPart, string size) + public async Task GetSkinPart(SkinPart skinPart, string size = "64") { return (string)$"https://visage.surgeplay.com/{skinPart}/{size}/{this.profile["profileId"]}" } - public string GetName() => this.Name; - public string GetUuid() => this.Uuid; - public JsonNode GetProfile() => return this.profile; - public bool IsPlayer() => this.Name != null : false; -} \ No newline at end of file +} From 6b7f10c8035ded519ee2de35c59a1b5e6a837705 Mon Sep 17 00:00:00 2001 From: Dima YaFlay <93622229+YaFlay@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:06:58 +0300 Subject: [PATCH 5/5] Update User.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit кхм --- src/Types/User.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Types/User.cs b/src/Types/User.cs index dfa06ff..6396b12 100644 --- a/src/Types/User.cs +++ b/src/Types/User.cs @@ -10,15 +10,15 @@ public class User private HttpClient client = new(); - public bool IsPlayer() => this.Name != null ? true : false; + public bool IsPlayer() => Name != null ? true : false; - public User() + public User(string name) { - Uuid = JsonNode.Parse(await client.GetStringAsync($"https://api.mojang.com/users/profiles/minecraft/{Name}"))["id"]; - profile = JsonNode.Parse(await client.GetStringAsync($"https://sessionserver.mojang.com/session/minecraft/profile/{Uuid}")); + Uuid = JsonNode.Parse(client.GetStringAsync($"https://api.mojang.com/users/profiles/minecraft/{name}"))["id"]; + profile = JsonNode.Parse(client.GetStringAsync($"https://sessionserver.mojang.com/session/minecraft/profile/{Uuid}")); } - public async Task GetSkinPart(SkinPart skinPart, string size = "64") + public string GetSkinPart(SkinPart skinPart, string size = "64") { return (string)$"https://visage.surgeplay.com/{skinPart}/{size}/{this.profile["profileId"]}" }