Skip to content

Commit

Permalink
Code refactoring and maintenance
Browse files Browse the repository at this point in the history
  • Loading branch information
akacdev committed Nov 25, 2023
1 parent 1309d1b commit c35c478
Show file tree
Hide file tree
Showing 20 changed files with 355 additions and 287 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/build-and-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Build and Release

env:
DOTNET_VERSION: '8.x'
NUGET_SOURCE_URL: 'https://api.nuget.org/v3/index.json'
BUILD_DIRECTORY: '${{ github.workspace }}/build'

on:
push:
tags:
- 'v*.*.*'

jobs:
build-and-release:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v2

- name: Get Version
id: get_version
run: |
echo "tag=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
- name: Get Project Metadata
id: get_project_meta
run: |
name=$(echo '${{ github.repository }}' | cut -d '/' -f 2)
echo "name=${name}" >> $GITHUB_OUTPUT
echo "path=${name}/${name}.csproj" >> $GITHUB_OUTPUT
- name: Setup .NET
uses: actions/[email protected]
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Restore Packages
run: dotnet restore ${{ steps.get_project_meta.outputs.path }}

- name: Build Project
run: dotnet build ${{ steps.get_project_meta.outputs.path }} /p:ContinuousIntegrationBuild=true --no-restore --configuration Release

- name: Pack Project
run: dotnet pack ${{ steps.get_project_meta.outputs.path }} --no-restore --no-build --configuration Release --include-symbols -p:PackageVersion=${{ steps.get_version.outputs.version }} --output ${{ env.BUILD_DIRECTORY }}

- name: Push Package
env:
NUGET_AUTH_TOKEN: ${{ secrets.NUGET_AUTH_TOKEN }}
run: dotnet nuget push ${{ env.BUILD_DIRECTORY }}/*.nupkg -k $NUGET_AUTH_TOKEN -s ${{ env.NUGET_SOURCE_URL }}

- name: Create Release
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: ${{ steps.get_version.outputs.tag }}
body: ${{ github.event.head_commit.message }}
files: '${{ env.BUILD_DIRECTORY }}/*'
4 changes: 2 additions & 2 deletions Example/Example.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
38 changes: 19 additions & 19 deletions Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,72 +1,72 @@
using System;
using System.Threading.Tasks;
using Netcraft;
using Netcraft.Modules;
using Netcraft.Entities;
using System.Linq;

namespace Example
{
public static class Program
{
private static readonly NetcraftClient Client = new();

public static async Task Main()
{
NetcraftClient client = new();

Console.WriteLine("Enter the email to submit a report from:");
string email = Console.ReadLine();

Console.WriteLine($"> Reporting a malicious URL");
string uuid = await client.Report.Urls(email, "Phishing against the Turkish Government.", new UrlReportParmeters[]
{
string uuid = await Client.Report.Urls(email, "Phishing against the Turkish Government.",
[
new()
{
Value = "http://basvuruedevletmobilden.ml/",
Country = "US"
}
});
]);

Console.WriteLine($"Successfully reported, submission UUID: {uuid}");

Console.WriteLine("> Getting submission's details");

Submission submission = await client.Submission.GetSubmissionDetails(uuid);
Console.WriteLine("\n> Getting submission's details");
Submission submission = await Client.Submission.GetSubmissionDetails(uuid);

Console.WriteLine($"Fetched submission's details, state: {submission.State}");

Console.WriteLine("> Getting submission's URLs");

SubmissionUrl[] submissionUrls = await client.Submission.GetSubmissionUrls(uuid);
Console.WriteLine("\n> Getting submission's URLs");
SubmissionUrl[] submissionUrls = await Client.Submission.GetSubmissionUrls(uuid);

Console.WriteLine($"Fetched {submissionUrls.Length} submission's URLs");

Console.WriteLine("> Getting submission's email");

SubmissionEmail submissionEmail = await client.Submission.GetSubmissionEmail(uuid);
Console.WriteLine("\n> Getting submission's email");
SubmissionEmail submissionEmail = await Client.Submission.GetSubmissionEmail(uuid);

Console.WriteLine(
$"Fetched a submission email" +
$"{(submissionEmail.State == State.Processing ? ", which is currently being processed" : $"with subject '{submissionEmail.Subject}'")}");

Console.WriteLine("> Getting submission's cryptocurrency addresses");

CryptocurrencyAddress[] submissionCryptoAddresses = await client.Submission.GetSubmissionCryptocurrencyAddresses(uuid);
Console.WriteLine("\n> Getting submission's cryptocurrency addresses");
CryptocurrencyAddress[] submissionCryptoAddresses = await Client.Submission.GetSubmissionCryptocurrencyAddresses(uuid);

Console.WriteLine($"Fetched {submissionCryptoAddresses.Length} cryptocurrency addresses");

Console.WriteLine("> Getting submission's files");

SubmissionFile[] submissionFiles = await client.Submission.GetSubmissionFiles(uuid);
Console.WriteLine("\n> Getting submission's files");
SubmissionFile[] submissionFiles = await Client.Submission.GetSubmissionFiles(uuid);

Console.WriteLine($"Fetched {submissionFiles.Length} files");

Console.WriteLine("> Getting the submission leaderboard");

LeaderboardEntry[] entries = await client.Misc.GetLeaderboard();
Console.WriteLine("\n> Getting the submission leaderboard");
LeaderboardEntry[] entries = await Client.Misc.GetLeaderboard();

Console.WriteLine($"Fetched the leaderboard, top 5 users: {string.Join(", ", entries.Take(5).Select(x => x.Nickname))}");

Console.WriteLine("Demo finished");

Console.WriteLine("\nDemo finished");
Console.ReadKey();
}
}
Expand Down
81 changes: 21 additions & 60 deletions Netcraft/API.cs
Original file line number Diff line number Diff line change
@@ -1,103 +1,64 @@
using Netcraft.Entities;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace Netcraft
{
public static class API
internal static class API
{
public const int MaxRetries = 3;
public const int RetryDelay = 1000 * 1;
public const int PreviewMaxLength = 500;

public static async Task<HttpResponseMessage> Request
(
this HttpClient cl,
HttpMethod method,
string url,
string path,
object obj,
HttpStatusCode target = HttpStatusCode.OK,
JsonSerializerOptions options = null)
=> await Request(cl, method, url, new StringContent(JsonSerializer.Serialize(obj, options ?? Constants.EnumOptions), Encoding.UTF8, "application/json"), target);
=> await Request(cl, method, path, await obj.Serialize(options ?? Constants.EnumOptions), target);

public static async Task<HttpResponseMessage> Request
(
this HttpClient cl,
HttpMethod method,
string url,
string path,
HttpContent content = null,
HttpStatusCode target = HttpStatusCode.OK)
{
HttpRequestMessage req = new(method, url)
using HttpRequestMessage req = new(method, path)
{
Content = content
};

HttpResponseMessage res = await cl.SendAsync(req);
content?.Dispose();

if ((int)res.StatusCode > 500) throw new NetcraftException("Received a failure status code.");

if (!target.HasFlag(res.StatusCode))
{
string text = await res.Content.ReadAsStringAsync();

MediaTypeHeaderValue contentType = res.Content.Headers.ContentType;
if (contentType is null) throw new NetcraftException("The 'Content-Type' header is missing in the response.", method.ToString(), url);
if (target.HasFlag(res.StatusCode)) return res;

bool isJson = contentType.MediaType.StartsWith("application/json", StringComparison.InvariantCultureIgnoreCase);
if (!isJson)
throw new NetcraftException(
$"received status code {res.StatusCode} and Content-Type {contentType.MediaType}" +
$"\nPreview: {text[..Math.Min(text.Length, PreviewMaxLength)]}",
method.ToString(),
url);
NetcraftError error = await res.Deseralize<NetcraftError>() ??
throw new NetcraftException($"Failed to request {method} {path}, received status code {res.StatusCode}\nPreview: {await res.GetPreview()}", res);

NetcraftError error = await res.Deseralize<NetcraftError>();
if (error is null) throw new NetcraftException("Parsed error object is null.", method.ToString(), url);
StringBuilder sb = new();

StringBuilder sb = new();
sb.AppendLine("Operation resulted in the following API error:");
sb.AppendLine($"\nStatus: {error.Status}");
if (!string.IsNullOrEmpty(error.Description)) sb.AppendLine($"\nDescription: {error.Description}");
sb.AppendLine($"Failed to request {method} {path}, received the following API error:");
sb.AppendLine($"Status: {error.Status}");
if (!string.IsNullOrEmpty(error.Description)) sb.AppendLine($"Description: {error.Description}");

if (error.Details is not null && error.Details.Length > 0)
if (error.Details is not null && error.Details.Length > 0)
{
for (int i = 0; i < error.Details.Length; i++)
{
for (int i = 0; i < error.Details.Length; i++)
{
ErrorDetail detail = error.Details[i];
ErrorDetail detail = error.Details[i];

sb.AppendLine($"[#{i + 1}] {detail.Message} caused by input '{detail.Input}' at '{detail.Path}'");
}
sb.AppendLine(string.Concat(
$"[#{i + 1}] {detail.Message}",
(string.IsNullOrEmpty(detail.Input) || string.IsNullOrEmpty(detail.Path)) ? "" : $" caused by input \"{detail.Input}\" at \"{detail.Path}\""));
}

throw new NetcraftException(sb.ToString());
}

return res;
}

public static async Task<T> Deseralize<T>(this HttpResponseMessage res, JsonSerializerOptions options = null)
{
Stream stream = await res.Content.ReadAsStreamAsync();
if (stream.Length == 0) throw new NetcraftException("Response content is empty, can't parse as JSON.");

try
{
return await JsonSerializer.DeserializeAsync<T>(stream, options ?? Constants.EnumOptions);
}
catch (Exception ex)
{
using StreamReader sr = new(stream);
string text = await sr.ReadToEndAsync();

throw new NetcraftException($"Exception while parsing JSON: {ex.GetType().Name} => {ex.Message}\nPreview: {text[..Math.Min(text.Length, PreviewMaxLength)]}");
}
throw new NetcraftException(sb.ToString(), res);
}
}
}
39 changes: 33 additions & 6 deletions Netcraft/Constants.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
using System.Text.Json;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Netcraft
{
internal class Constants
{
/// <summary>
/// The version of the API to send requests to.
/// </summary>
public const int Version = 3;
/// <summary>
/// The base URI to send requests to.
/// </summary>
public static readonly Uri BaseUri = new($"https://report.netcraft.com/api/v{Version}/");
/// <summary>
/// The preferred HTTP request version to use.
/// </summary>
public static readonly Version HttpVersion = new(2, 0);
/// <summary>
/// The <c>User-Agent</c> header value to send along requests.
/// </summary>
public const string UserAgent = "Netcraft C# Client - actually-akac/Netcraft";

/// <summary>
/// The maximum string length when displaying a preview of a response body.
/// </summary>
public const int PreviewMaxLength = 500;
/// <summary>
/// A string used to identify successfull reports.
/// </summary>
public const string SuccessReportMessage = "Successfully reported";
/// <summary>
/// A string used to identify successfull mistake reports.
/// </summary>
public const string SuccessMistakeReportMessage = "Successfully reported mistake";
/// <summary>
/// JSON serializer options used to serialize enums.
/// </summary>
public static readonly JsonSerializerOptions EnumOptions = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Expand All @@ -15,8 +45,5 @@ internal class Constants
new JsonStringEnumConverter(new EnumNamingPolicy())
}
};

public const string SuccessReportMessage = "Successfully reported";
public const string SuccessMistakeReportMessage = "Successfully reported mistake";
}
}
}
2 changes: 1 addition & 1 deletion Netcraft/Entities/Misc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ public class LeaderboardEntry
[JsonPropertyName("rank")]
public int Rank { get; set; }
}
}
}
4 changes: 2 additions & 2 deletions Netcraft/Entities/Report.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ReportResult
public string Message { get; set; }

[JsonPropertyName("uuid")]
public string UUID { get; set; }
public string Uuid { get; set; }
}

/// <summary>
Expand Down Expand Up @@ -115,4 +115,4 @@ public class MistakeReportParameters
[JsonPropertyName("url")]
public string Url { get; set; }
}
}
}
2 changes: 1 addition & 1 deletion Netcraft/Entities/Submission.cs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ public class SubmissionUrlsContainer
public class SubmissionUrl
{
[JsonPropertyName("uuid")]
public string UUID { get; set; }
public string Uuid { get; set; }

[JsonPropertyName("url")]
public string Value { get; set; }
Expand Down
Loading

0 comments on commit c35c478

Please sign in to comment.