aboutsummaryrefslogtreecommitdiff
path: root/docker/crupest-api
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-12-02 11:04:34 +0800
committercrupest <crupest@outlook.com>2022-12-02 13:35:35 +0800
commit879fb614c6853ab3bb83155c82722afb2933fc60 (patch)
tree2f80b57945408b8af83556a4efe5a92dea98e025 /docker/crupest-api
parent31416d8e047e4209f797881fd24e0e77256f3da1 (diff)
downloadcrupest-879fb614c6853ab3bb83155c82722afb2933fc60.tar.gz
crupest-879fb614c6853ab3bb83155c82722afb2933fc60.tar.bz2
crupest-879fb614c6853ab3bb83155c82722afb2933fc60.zip
...
Diffstat (limited to 'docker/crupest-api')
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/CrupestApi.Commons.csproj9
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs19
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs3
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs40
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj4
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/CrupestApi.Secrets.csproj4
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/ISecretsService.cs21
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretInfo.cs21
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretModifyRequest.cs30
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretNotExistException.cs18
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsConstants.cs6
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsWebApplicationExtensions.cs42
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Secrets/VerifySecretException.cs11
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj4
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs21
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.sln6
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj2
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi/Program.cs7
18 files changed, 250 insertions, 18 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/CrupestApi.Commons.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Commons/CrupestApi.Commons.csproj
new file mode 100644
index 0000000..72a1294
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/CrupestApi.Commons.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ <Nullable>enable</Nullable>
+ <ImplicitUsings>enable</ImplicitUsings>
+ </PropertyGroup>
+
+</Project>
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs
new file mode 100644
index 0000000..b298f7a
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs
@@ -0,0 +1,19 @@
+namespace CrupestApi.Commons;
+
+public class ErrorBody
+{
+ public ErrorBody(string message)
+ {
+ Message = message;
+ }
+
+ public string Message { get; set; }
+}
+
+public static class CrupestApiErrorExtensions
+{
+ public static async Task WriteErrorMessageAsync(this HttpResponse response, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default)
+ {
+ await response.WriteJsonAsync(new ErrorBody(message), statusCode: statusCode, beforeWriteBody, cancellationToken);
+ }
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs
new file mode 100644
index 0000000..4b76066
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs
@@ -0,0 +1,3 @@
+namespace CrupestApi.Commons;
+
+public delegate Task HttpResponseAction(HttpResponse response);
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
new file mode 100644
index 0000000..0ec3ff0
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
@@ -0,0 +1,40 @@
+using System.Text;
+using System.Text.Json;
+
+namespace CrupestApi.Commons;
+
+
+public static class CrupestApiJsonExtensions
+{
+ public static IServiceCollection AddJsonOptions(this IServiceCollection services)
+ {
+ services.AddOptions<JsonSerializerOptions>();
+ services.Configure<JsonSerializerOptions>(config =>
+ {
+ config.AllowTrailingCommas = true;
+ config.PropertyNameCaseInsensitive = true;
+ config.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ });
+
+ return services;
+ }
+
+
+ public static async Task WriteJsonAsync<T>(this HttpResponse response, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default)
+ {
+ var jsonOptions = response.HttpContext.RequestServices.GetRequiredService<JsonSerializerOptions>();
+ byte[] json = JsonSerializer.SerializeToUtf8Bytes<T>(bodyObject, jsonOptions);
+
+ var byteCount = json.Length;
+ response.StatusCode = statusCode;
+ response.Headers.ContentType = "application/json; charset=utf-8";
+ response.Headers.ContentLength = byteCount;
+
+ if (beforeWriteBody is not null)
+ {
+ await beforeWriteBody(response);
+ }
+
+ await response.Body.WriteAsync(json, cancellationToken);
+ }
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj
index 72a1294..2d78adb 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj
@@ -1,5 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
+ <ItemGroup>
+ <ProjectReference Include="..\CrupestApi.Commons\CrupestApi.Commons.csproj" />
+ </ItemGroup>
+
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/CrupestApi.Secrets.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/CrupestApi.Secrets.csproj
index 72a1294..2d78adb 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/CrupestApi.Secrets.csproj
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/CrupestApi.Secrets.csproj
@@ -1,5 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
+ <ItemGroup>
+ <ProjectReference Include="..\CrupestApi.Commons\CrupestApi.Commons.csproj" />
+ </ItemGroup>
+
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/ISecretsService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/ISecretsService.cs
new file mode 100644
index 0000000..c42fbdc
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/ISecretsService.cs
@@ -0,0 +1,21 @@
+namespace CrupestApi.Secrets;
+
+public interface ISecretsService
+{
+ Task<List<SecretInfo>> GetSecretListAsync(bool includeExpired = false, bool includeRevoked = false);
+
+ Task<List<SecretInfo>> GetSecretListByKeyAsync(string key, bool includeExpired = false, bool includeRevoked = false);
+
+ Task<bool> VerifySecretAsync(string key, string secret);
+
+ // Check if "secret" query param exists and is only one. Then check the secret is valid for given key.
+ // If check fails, will throw a VerifySecretException with proper message that can be send to client.
+ Task VerifySecretForHttpRequestAsync(HttpRequest request, string key, string queryKey = "secret");
+
+ Task<SecretInfo> CreateSecretAsync(string key, string description, DateTime? expireTime = null);
+
+ Task RevokeSecretAsync(string secret);
+
+ // Throw SecretNotExistException if request secret does not exist.
+ Task<SecretInfo> ModifySecretAsync(string secret, SecretModifyRequest modifyRequest);
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretInfo.cs
new file mode 100644
index 0000000..46ce501
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretInfo.cs
@@ -0,0 +1,21 @@
+namespace CrupestApi.Secrets;
+
+public class SecretInfo
+{
+ public SecretInfo(string key, string secret, string description, DateTime? expireTime, bool revoked, DateTime createdTime)
+ {
+ Key = key;
+ Secret = secret;
+ Description = description;
+ ExpireTime = expireTime;
+ Revoked = revoked;
+ CreateTime = createdTime;
+ }
+
+ public string Key { get; set; }
+ public string Secret { get; set; }
+ public string Description { get; set; }
+ public DateTime? ExpireTime { get; set; }
+ public bool Revoked { get; set; }
+ public DateTime CreateTime { get; set; }
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretModifyRequest.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretModifyRequest.cs
new file mode 100644
index 0000000..dfff347
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretModifyRequest.cs
@@ -0,0 +1,30 @@
+namespace CrupestApi.Secrets;
+
+public class SecretModifyRequest
+{
+ public SecretModifyRequest()
+ {
+
+ }
+
+ public SecretModifyRequest(string? key, string? description)
+ {
+ Key = key;
+ Description = description;
+ SetExpireTime = false;
+ ExpireTime = null;
+ }
+
+ public SecretModifyRequest(string? key, string? description, DateTime? expireTime)
+ {
+ Key = key;
+ Description = description;
+ SetExpireTime = true;
+ ExpireTime = expireTime;
+ }
+
+ public string? Key { get; set; }
+ public string? Description { get; set; }
+ public bool SetExpireTime { get; set; }
+ public DateTime? ExpireTime { get; set; }
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretNotExistException.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretNotExistException.cs
new file mode 100644
index 0000000..ad082ee
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretNotExistException.cs
@@ -0,0 +1,18 @@
+namespace CrupestApi.Secrets;
+
+public class SecretNotExistException : Exception
+{
+ public SecretNotExistException(string requestSecret)
+ : base($"Request secret {requestSecret} not found.")
+ {
+ RequestSecret = requestSecret;
+ }
+
+ public SecretNotExistException(string requestSecret, string message)
+ : base(message)
+ {
+ RequestSecret = requestSecret;
+ }
+
+ public string RequestSecret { get; set; }
+} \ No newline at end of file
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsConstants.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsConstants.cs
new file mode 100644
index 0000000..ea659a9
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsConstants.cs
@@ -0,0 +1,6 @@
+namespace CrupestApi.Secrets;
+
+public static class SecretsConstants
+{
+ public const string SecretManagementKey = "crupest.secrets.management";
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsWebApplicationExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsWebApplicationExtensions.cs
new file mode 100644
index 0000000..a771547
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsWebApplicationExtensions.cs
@@ -0,0 +1,42 @@
+using CrupestApi.Commons;
+
+namespace CrupestApi.Secrets;
+
+public static class SecretsWebApplicationExtensions
+{
+ public static WebApplication UseCatchVerifySecretException(this WebApplication app)
+ {
+ app.Use(async (context, next) =>
+ {
+ try
+ {
+ await next(context);
+ }
+ catch (VerifySecretException e)
+ {
+ await context.Response.WriteErrorMessageAsync(e.Message, 401);
+ }
+ });
+
+ return app;
+ }
+
+ public static async Task CheckSecret(this HttpContext context, string key)
+ {
+ var secretsService = context.RequestServices.GetRequiredService<ISecretsService>();
+ await secretsService.VerifySecretForHttpRequestAsync(context.Request, SecretsConstants.SecretManagementKey);
+ }
+
+ public static WebApplication MapSecrets(this WebApplication app, string path)
+ {
+ app.MapGet(path, async (context) =>
+ {
+ await context.CheckSecret(SecretsConstants.SecretManagementKey);
+ var secretsService = context.RequestServices.GetRequiredService<ISecretsService>();
+ var secrets = secretsService.GetSecretListAsync();
+ await context.Response.WriteJsonAsync(secrets);
+ });
+
+ return app;
+ }
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/VerifySecretException.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/VerifySecretException.cs
new file mode 100644
index 0000000..c9f60a1
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/VerifySecretException.cs
@@ -0,0 +1,11 @@
+namespace CrupestApi.Secrets;
+
+public class VerifySecretException : Exception
+{
+ public VerifySecretException(string requestKey, string message) : base(message)
+ {
+ RequestKey = requestKey;
+ }
+
+ public string RequestKey { get; set; }
+} \ No newline at end of file
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj
index 72a1294..2d78adb 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj
@@ -1,5 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
+ <ItemGroup>
+ <ProjectReference Include="..\CrupestApi.Commons\CrupestApi.Commons.csproj" />
+ </ItemGroup>
+
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs
index 575dc4f..b3647f1 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs
@@ -1,8 +1,4 @@
-using System;
-using System.Text.Json;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
+using CrupestApi.Commons;
namespace CrupestApi.Todos;
@@ -15,24 +11,19 @@ public static class TodosWebApplicationExtensions
throw new ArgumentNullException(nameof(app));
}
- app.MapGet(path, async ([FromServices] TodosService todosService) =>
+ app.MapGet(path, async (context) =>
{
- var jsonOptions = new JsonSerializerOptions
- {
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase
- };
+ var todosService = context.RequestServices.GetRequiredService<TodosService>();
try
{
var todos = await todosService.GetTodosAsync();
- return Results.Json(todos, jsonOptions, statusCode: 200);
+ await context.Response.WriteJsonAsync(todos);
+
}
catch (Exception e)
{
- return Results.Json(new
- {
- e.Message
- }, jsonOptions, statusCode: StatusCodes.Status503ServiceUnavailable);
+ await context.Response.WriteErrorMessageAsync(e.Message, statusCode: StatusCodes.Status503ServiceUnavailable);
}
});
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.sln b/docker/crupest-api/CrupestApi/CrupestApi.sln
index 9869d3b..5f21ff5 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.sln
+++ b/docker/crupest-api/CrupestApi/CrupestApi.sln
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrupestApi.Todos", "Crupest
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrupestApi.Secrets", "CrupestApi.Secrets\CrupestApi.Secrets.csproj", "{9A7CC9F9-70CB-408A-ADFC-5119C0BDB236}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrupestApi.Commons", "CrupestApi.Commons\CrupestApi.Commons.csproj", "{38083CCA-E56C-4D24-BAB6-EEC30E0F478F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -30,5 +32,9 @@ Global
{9A7CC9F9-70CB-408A-ADFC-5119C0BDB236}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A7CC9F9-70CB-408A-ADFC-5119C0BDB236}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A7CC9F9-70CB-408A-ADFC-5119C0BDB236}.Release|Any CPU.Build.0 = Release|Any CPU
+ {38083CCA-E56C-4D24-BAB6-EEC30E0F478F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {38083CCA-E56C-4D24-BAB6-EEC30E0F478F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {38083CCA-E56C-4D24-BAB6-EEC30E0F478F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {38083CCA-E56C-4D24-BAB6-EEC30E0F478F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj b/docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj
index c15ec91..c408c7d 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj
+++ b/docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj
@@ -3,6 +3,8 @@
<ItemGroup>
<ProjectReference Include="..\CrupestApi.Todos\CrupestApi.Todos.csproj" />
<ProjectReference Include="..\CrupestApi.Files\CrupestApi.Files.csproj" />
+ <ProjectReference Include="..\CrupestApi.Commons\CrupestApi.Commons.csproj" />
+ <ProjectReference Include="..\CrupestApi.Secrets\CrupestApi.Secrets.csproj" />
</ItemGroup>
<PropertyGroup>
diff --git a/docker/crupest-api/CrupestApi/CrupestApi/Program.cs b/docker/crupest-api/CrupestApi/CrupestApi/Program.cs
index e18252f..ff8f02f 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi/Program.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi/Program.cs
@@ -1,6 +1,5 @@
-using System;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.Extensions.Configuration;
+using CrupestApi.Commons;
+using CrupestApi.Secrets;
using CrupestApi.Todos;
var builder = WebApplication.CreateBuilder(args);
@@ -8,10 +7,12 @@ var builder = WebApplication.CreateBuilder(args);
string configFilePath = Environment.GetEnvironmentVariable("CRUPEST_API_CONFIG_FILE") ?? "/crupest-api-config.json";
builder.Configuration.AddJsonFile(configFilePath, optional: false, reloadOnChange: true);
+builder.Services.AddJsonOptions();
builder.Services.AddTodos();
var app = builder.Build();
app.MapTodos("/api/todos");
+app.MapSecrets("/api/secrets");
app.Run();