diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..00d0f93 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,69 @@ +name: .NET+Docker CI/CD + +on: + push: + branches: [ "master", "develop", "main" ] + paths-ignore: + - 'README.md' + - '*.md' + +jobs: + build: + name: Unit and Integration tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal + + compose: + name: Push Docker image to ghcr.io + runs-on: ubuntu-latest + needs: build + permissions: + packages: write + contents: read + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: yawaflua + password: ${{ env.GITHUB_TOKEN }} + + - name: Log in to Gitea Registry + uses: docker/login-action@v3 + with: + registry: git.yawaflua.tech + username: yawaflua + password: ${{ env.GITEA_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: | + ghcr.io/yawaflua/spmega + git.yawaflua.tech/yawaflua/spmega + + - name: Build and push API + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 + with: + context: backend/ + file: backend/SpMega.Backend/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9e4b940..4f5fbb6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,8 @@ hs_err_pid* # Common working directory run + +backend/SpMega.Backend/src/* +backend/SpMega.Backend/obj/* +backend/SpMega.Backend/appsettings.json +backend/SpMega.Backend/SpMega.Backend.http \ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore index 74e533e..e69de29 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,4 +0,0 @@ -SpMega.Backend/src/* -SpMega.Backend/obj/* -SpMega.Backend/appsettings.json -SpMega.Backend/SpMega.Backend.http \ No newline at end of file diff --git a/backend/SpMega.Backend/Controllers/v1/AuthController.cs b/backend/SpMega.Backend/Controllers/v1/AuthController.cs index 9e986ec..a3d33ec 100644 --- a/backend/SpMega.Backend/Controllers/v1/AuthController.cs +++ b/backend/SpMega.Backend/Controllers/v1/AuthController.cs @@ -112,8 +112,9 @@ public class AuthController(AppDbContext dbContext, TokenService tokenService, I Console.WriteLine(resp); var user = ((User)HttpContext.Items["@me"]); Console.WriteLine(me.id); + Console.WriteLine(Guid.Parse(me.minecraftUUID)); Console.WriteLine(user.Id.ToString()); - if (user == null || user.Id.ToString() != me.minecraftUUID) + if (user == null || user.Id != Guid.Parse(me.minecraftUUID)) { throw new Exception("Its not ur card"); } diff --git a/backend/SpMega.Backend/Controllers/v1/TransactionsController.cs b/backend/SpMega.Backend/Controllers/v1/TransactionsController.cs index c341989..034ecb9 100644 --- a/backend/SpMega.Backend/Controllers/v1/TransactionsController.cs +++ b/backend/SpMega.Backend/Controllers/v1/TransactionsController.cs @@ -1,6 +1,7 @@ using System.Net.Http.Headers; using System.Text; using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -15,7 +16,7 @@ namespace SpMega.Backend.Controllers.v1; [ApiController] public class TransactionsController(AppDbContext context, ILogger logger, IConfiguration config) : ControllerBase { - private const string BASE_URL = "https://spworlds.ru/api/public"; + private const string BASE_URL = "https://spworlds.ru/api/public/"; [HttpGet("{billId}")] public async Task GetBill(string billId) @@ -55,32 +56,59 @@ public class TransactionsController(AppDbContext context, ILogger> CreateTransaction([FromBody] CreateTransactionBody body) { - var BearerToken = $"{body.cardToUse.Id}:{body.cardToUse.Token}"; - string Base64BearerToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(BearerToken)); + var user = HttpContext.Items["@me"] as User; + if (user == null) + { + return Unauthorized(new { error = "User not authenticated" }); + } + var cardToUse = user.Cards.FirstOrDefault(l => l.Id == Guid.Parse(body.cardId)); + if (cardToUse == null) + { + return BadRequest(new { error = "Card not found" }); + } - var shortId = Program.GenerateRandomString(8); + var shortId = Program.GenerateRandomString(5); + while (true) + { + var a = await context.Transactions.FirstOrDefaultAsync(k => k.ShortId == shortId); + if (a != null) + { + shortId = Program.GenerateRandomString(5); + } + else + { + break; + } + } var transaction = new Transaction { ReceiverName = body.receiverName, ShortId = shortId, ReceiverCardNumber = body.receiverCard, - Sender = HttpContext.Items["@me"] as User, - SenderCardNumber = body.cardToUse.SpworldsID, + Sender = user, + SenderCardNumber = body.cardId, Amount = body.amount, Comment = body.comment, }; try { - var uri = new Uri(new Uri(config["Url"] ?? "https://spmega.yawaflua.tech"), "/" + shortId); + var uri = "s.ywfl.dev" + "/" + shortId; var transitionInfo = new Dictionary { { "receiver", body.receiverCard }, { "amount", body.amount }, - { "comment", "Чек: "+ uri } + { "comment", body.comment + ";Чек:"+ uri } }; - - await SendRequest(endpoint: "transactions", body: transitionInfo, AuthHeader:new("Bearer", Base64BearerToken)); + Console.WriteLine((body.comment + ";Чек: "+ uri).Length); + Console.WriteLine((body.comment + ";Чек: "+ uri)); + var resp = await SendRequest(endpoint: "transactions", body: transitionInfo, + AuthHeader: new("Bearer", cardToUse.Token)); + var balance = (int?)JsonNode.Parse(resp)?["balance"]; + if (balance == null) + { + throw new Exception("Failed to create transaction: " + resp); + } } catch (Exception exception) { @@ -104,6 +132,7 @@ public class TransactionsController(AppDbContext context, ILogger k.Sender.Id == ((User)HttpContext.Items["@me"]).Id).ToListAsync()); } + [NonAction] internal async Task SendRequest(string endpoint, AuthenticationHeaderValue AuthHeader, HttpMethod method = null, object body = null) { method ??= body == null ? HttpMethod.Get : HttpMethod.Post; @@ -129,4 +158,4 @@ public class TransactionsController(AppDbContext context, ILogger options) : DbContext(op { base.OnModelCreating(modelBuilder); - + modelBuilder.Entity() + .OwnsMany(u => u.Cards, card => + { + card.Property(c => c.Token) + .HasConversion( + v => EncryptionHelper.Encrypt(v), + v => EncryptionHelper.Decrypt(v) + ); + }); } } \ No newline at end of file diff --git a/backend/SpMega.Backend/Persistent/Models/DTO/UserAccountDTO.cs b/backend/SpMega.Backend/Persistent/Models/DTO/UserAccountDTO.cs index f2f3350..dccb674 100644 --- a/backend/SpMega.Backend/Persistent/Models/DTO/UserAccountDTO.cs +++ b/backend/SpMega.Backend/Persistent/Models/DTO/UserAccountDTO.cs @@ -2,14 +2,32 @@ using SPWorldsApi.Types.Interfaces; namespace SpMega.Backend.Persistent.Models.DTO; -public class UserAccountDTO : IUserAccount +public class UserAccountDTO { public string id { get; set; } public string username { get; set; } public string minecraftUUID { get; set; } public string status { get; set; } public List roles { get; set; } - public ICity city { get; set; } - public List cards { get; set; } + public CityDTO city { get; set; } + public List cards { get; set; } public DateTime createdAt { get; set; } } + +public class UserCardDTO +{ + public string id { get; set; } + public string name { get; set; } + public string number { get; set; } + public int color { get; set; } +} + +public class CityDTO +{ + public string id { get; set; } + public string name { get; set; } + public string description { get; set; } + public int x { get; set; } + public int z { get; set; } + public bool isMayor { get; set; } +} diff --git a/backend/SpMega.Backend/Program.cs b/backend/SpMega.Backend/Program.cs index e7cf30b..82bf6fc 100644 --- a/backend/SpMega.Backend/Program.cs +++ b/backend/SpMega.Backend/Program.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography; using System.Text; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; @@ -17,6 +18,9 @@ public class Program .AddJsonFile("appsettings.json", false) .AddJsonFile("appsettings.Development.json", false) .AddEnvironmentVariables(); + + var encryptionKey = builder.Configuration["Encryption:Key"] ?? "a-default-fallback-only-for-dev-key-change-this!"; + EncryptionHelper.Initialize(encryptionKey); builder.Services.AddAuthorization(); builder.Services.AddLogging(logging => @@ -79,12 +83,11 @@ public class Program { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - var random = new Random(); var result = new StringBuilder(length); for (var i = 0; i < length; i++) { - var index = random.Next(chars.Length); + var index = RandomNumberGenerator.GetInt32(chars.Length); result.Append(chars[index]); }