more samples

This commit is contained in:
paragon
2026-05-24 13:38:44 -04:00
parent 512dabe4dd
commit 792c254a3c
14 changed files with 546 additions and 6 deletions
@@ -0,0 +1,13 @@
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// Defines service key constants for protectors.
/// </summary>
public static class Protectors
{
/// <summary>
/// Gets the service key for protected byte array types.
/// </summary>
public const string ProtectedByteArrayServiceKey = nameof(ProtectedByteArrayServiceKey);
}
}
@@ -41,7 +41,7 @@ namespace TriunniaLabs.Arch.Sample.Server
}
/// <summary>
/// A sample method that shows how to work with the Keys Api.
/// A sample method that shows how to work with the Application Api.
/// </summary>
internal async Task SampleAsync()
{
@@ -0,0 +1,60 @@
using TriunniaLabs.Arch.Api.Comments.Client;
using TriunniaLabs.Arch.Microservice;
using TriunniaLabs.Memory.Protected;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work with the Comments Api.
/// </summary>
public class CommentsApiSampleController : ArchControllerBase
{
// Services
private readonly ICommentsApiClient _commentsApiClient;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="microserviceContext">Reference to the microservice context.</param>
/// <param name="commentsApiClient">Reference to the Comments Api client.</param>
public CommentsApiSampleController(IMicroserviceContext microserviceContext, ICommentsApiClient commentsApiClient) : base(microserviceContext)
{
_commentsApiClient = commentsApiClient ?? throw new ArgumentNullException(nameof(commentsApiClient));
}
/// <summary>
/// A sample method that shows how to work with the Comments Api.
/// </summary>
internal async Task SampleAsync()
{
// Comments are posted within a context. The context can be anything, like an article, forum category, another comment (in the case of a reply), etc.
var contextId = Guid.NewGuid().ToString().AsProtected(); // Id of the context to which the comment applies.
var contextType = 1; // Developer-defined type for the context
var commentType = 1; // Developer-defined type for the comment
var commentStatus = 1; // Developer-defined type for the comment's status
var commentText = "This is my comment".AsProtected(); // The encrypted text of the comment
var authorUserId = Guid.NewGuid().ToString().AsProtected(); // Id of the user who wrote the comment
var encryptionKey = "SampleEncryptionKey".AsProtected(); // Per-row encryption key for the entity
var commentId = Guid.NewGuid();
// Create a new comment in the system
await _commentsApiClient.CreateCommentAsync(contextId, contextType, commentType, commentStatus, commentText, authorUserId, encryptionKey);
// Get the specified comment
var comment = await _commentsApiClient.GetCommentAsync(contextId, contextType, commentId, encryptionKey);
// Get all comments within a context
var comments = await _commentsApiClient.GetCommentsAsync(contextId, contextType, encryptionKey);
// Update an existing comment
comment.CommentText = "This is my updated comment".AsProtected();
await _commentsApiClient.UpdateCommentAsync(comment, encryptionKey);
// Delete the specified comment from the context
await _commentsApiClient.DeleteCommentAsync(contextId, contextType, comment.CommentId);
// Delete the entire comment thread
await _commentsApiClient.DeleteCommentsAsync(contextId, contextType);
}
}
}
@@ -0,0 +1,42 @@
using TriunniaLabs.Arch.Microservice;
using TriunniaLabs.Arch.Relay.Email.Blazor;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work with the Email Api Relay Client.
/// This controller demonstrates using the Relay client from a Blazor page.
/// Relay clients contact their corresponding server endpoints that are brought in via TriunniaLabs.Arch.Relay.Email.Server.
/// Those server endpoints then contact the normal Email Api Client.
/// </summary>
public class EmailApiRelaySampleController : ArchControllerBase
{
// Services
private readonly IEmailApiRelayClient _emailApiRelayClient;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="microserviceContext">Reference to the microservice context.</param>
/// <param name="emailApiRelayClient">Reference to the Email Api Relay client.</param>
public EmailApiRelaySampleController(IMicroserviceContext microserviceContext, IEmailApiRelayClient emailApiRelayClient) : base(microserviceContext)
{
_emailApiRelayClient = emailApiRelayClient ?? throw new ArgumentNullException(nameof(emailApiRelayClient));
}
/// <summary>
/// A sample method that shows how to work with the Email Api.
/// </summary>
internal async Task SampleAsync()
{
var verifyToken = Guid.NewGuid(); // A verify token from the verification email
// Verifies the user's email address, given the verify token
await _emailApiRelayClient.VerifyEmailAddressAsync(verifyToken);
// Reports abuse of the email address, given the verify token.
// This would be called by the actual owner of the email address, who did not register the email in our system.
await _emailApiRelayClient.ReportAbuseAsync(verifyToken);
}
}
}
@@ -5,7 +5,7 @@ using TriunniaLabs.Memory.Protected;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work the Email Api.
/// A controller that shows how to work with the Email Api.
/// </summary>
public class EmailApiSampleController : ArchControllerBase
{
@@ -16,7 +16,7 @@ namespace TriunniaLabs.Arch.Sample.Server
/// Constructor.
/// </summary>
/// <param name="microserviceContext">Reference to the microservice context.</param>
/// <param name="emailApiClient">Reference to the Tokens Api client.</param>
/// <param name="emailApiClient">Reference to the Email Api client.</param>
public EmailApiSampleController(IMicroserviceContext microserviceContext, IEmailApiClient emailApiClient) : base(microserviceContext)
{
_emailApiClient = emailApiClient ?? throw new ArgumentNullException(nameof(emailApiClient));
@@ -45,9 +45,12 @@ namespace TriunniaLabs.Arch.Sample.Server
var emailResponse = await _emailApiClient.GetEmailAddressAsync(emailAddress.Hash, encryptionKey); // Get by hash
emailResponse = await _emailApiClient.GetEmailAddressAsync(emailId, encryptionKey); // Get by Id
// Email verification procedure. This will send an email to the user with the verify token. Record its verification or abuse with the other methods.
// Email verification procedure. This will send an email to the user with the verify token.
await _emailApiClient.InitEmailVerifyAsync(emailId, encryptionKey, ipAddress);
var result = await _emailApiClient.CommitEmailVerifyAsync(verifyToken, ipAddress);
// Reports abuse of the email address, given the verify token.
// This would be called by the actual owner of the email address, who did not register the email in our system.
result = await _emailApiClient.ReportAbuseAsync(verifyToken);
// When using Postmark, receive their webhooks and forward to the Email Api with this call.
@@ -0,0 +1,100 @@
using System.Text;
using System.Text.Json;
using TriunniaLabs.Arch.Api.Entity.Client;
using TriunniaLabs.Arch.Microservice;
using TriunniaLabs.Memory.Protected;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work with the Entity Api.
/// </summary>
public class EntityApiSampleController : ArchControllerBase
{
// Services
private readonly IEntityApiClient _entityApiClient;
private readonly IProtector<byte[]> _byteArrayProtector;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="microserviceContext">Reference to the microservice context.</param>
/// <param name="entityApiClient">Reference to the Entity Api client.</param>
/// <param name="byteArrayProtector">A custom protector for protecting byte[] data types.</param>
public EntityApiSampleController(IMicroserviceContext microserviceContext, IEntityApiClient entityApiClient,
[FromKeyedServices(Protectors.ProtectedByteArrayServiceKey)] IProtector<byte[]> byteArrayProtector)
: base(microserviceContext)
{
_entityApiClient = entityApiClient ?? throw new ArgumentNullException(nameof(entityApiClient));
_byteArrayProtector = byteArrayProtector ?? throw new ArgumentNullException(nameof(byteArrayProtector));
}
/// <summary>
/// A sample method that shows how to work with the Entity Api.
/// </summary>
internal async Task SampleAsync()
{
var entity = new SampleEntity { Id = Guid.NewGuid(), Name = "MyEntity", Value = 1234 };
var encryptionKey = "SampleEncryptionKey".AsProtected(); // Per-row encryption key for the entity
var entityId = entity.Id.AsProtected();
var entityType = entity.GetType().FullName!.AsProtected();
// Serialize the entity to bytes if you want to do your own serialization (and protection)
var serialized = JsonSerializer.Serialize(entity);
var bytes = Encoding.UTF8.GetBytes(serialized);
// Create a new entity in the system with the specified id
await _entityApiClient.CreateEntityAsync(entityId, entity, _byteArrayProtector, encryptionKey);
await _entityApiClient.CreateEntityAsync(entityId, entityType, bytes, encryptionKey);
await _entityApiClient.CreateEntityAsync<SampleEntity>(entityId, bytes, encryptionKey);
// Update an existing entity in the system
entity.Value = 5678;
await _entityApiClient.UpdateEntityAsync(entityId, entity, _byteArrayProtector, encryptionKey);
await _entityApiClient.UpdateEntityAsync(entityId, entityType, bytes, encryptionKey);
await _entityApiClient.UpdateEntityAsync<SampleEntity>(entityId, bytes, encryptionKey);
// Get the entity and metadata, then deserialize
var entityResponse = await _entityApiClient.GetEntityAsync(entityId, entityType, encryptionKey);
entityResponse = await _entityApiClient.GetEntityAsync<SampleEntity>(entityId, encryptionKey);
entity = JsonSerializer.Deserialize<SampleEntity>(entityResponse!.Data.GetDecryptedValue());
// Get the deserialized entity immediately
entity = await _entityApiClient.GetEntityDeserializedAsync<SampleEntity>(entityId, encryptionKey, _byteArrayProtector);
// The Entity Api records and versions all changes to an entity. Get the history of all changes and their metadata with this call.
var history = await _entityApiClient.GetEntityHistoryAsync(entityId, entityType, encryptionKey);
history = await _entityApiClient.GetEntityHistoryAsync<SampleEntity>(entityId, encryptionKey);
// Or just get the history of the entities directly without any metadata
var deserializedHistory = await _entityApiClient.GetEntityHistoryDeserializedAsync<SampleEntity>(entityId, encryptionKey, _byteArrayProtector);
// Gets the archived version of the specified entity and its metadata
entityResponse = await _entityApiClient.GetEntityArchivedAsync(entityId, entityType, encryptionKey);
entityResponse = await _entityApiClient.GetEntityArchivedAsync<SampleEntity>(entityId, encryptionKey);
// Or just get the archived version without any metadata
entity = await _entityApiClient.GetEntityArchivedDeserializedAsync<SampleEntity>(entityId, encryptionKey, _byteArrayProtector);
// Mark the entity has deleted without actually deleting it
await _entityApiClient.SoftDeleteEntityAsync(entityId, entityType);
await _entityApiClient.SoftDeleteEntityAsync<SampleEntity>(entityId);
// Purge the entity from the system. This is a hard delete. It also deletes all archives and histories.
await _entityApiClient.PurgeEntityAsync(entityId, entityType);
await _entityApiClient.PurgeEntityAsync<SampleEntity>(entityId);
}
private class SampleEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Value { get; set; }
}
}
}
@@ -0,0 +1,70 @@
using TriunniaLabs.Arch.Api.Files.Client;
using TriunniaLabs.Arch.Microservice;
using TriunniaLabs.Memory.Protected;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work with the Files Api.
/// </summary>
public class FilesApiSampleController : ArchControllerBase
{
// Services
private readonly IFilesApiClient _filesApiClient;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="microserviceContext">Reference to the microservice context.</param>
/// <param name="filesApiClient">Reference to the Files Api client.</param>
public FilesApiSampleController(IMicroserviceContext microserviceContext, IFilesApiClient filesApiClient) : base(microserviceContext)
{
_filesApiClient = filesApiClient ?? throw new ArgumentNullException(nameof(filesApiClient));
}
/// <summary>
/// A sample method that shows how to work with the Files Api.
/// </summary>
internal async Task SampleAsync()
{
var applicationId = MicroserviceContext.Settings.Application.ApplicationId; // Id of this application
var folder = "MySampleFolder".AsProtected(); // Files are stored in folders
var filename = "MySampleFile".AsProtected(); // The name of the file
var encryptionKey = "SampleEncryptionKey".AsProtected(); // Per-row encryption key for the file
var fileContents = new byte[] { 1, 2, 3, 4 };
using var fileStream = new MemoryStream(fileContents);
// Upload a file; overwrite if it exists Protect the stream to upload it.
var protectedStream = new Protected<Stream>(fileStream, encryptionKey.GetDecryptedValue());
await _filesApiClient.UploadFileAsync(applicationId, folder, filename, protectedStream, encryptionKey);
// Download a file via streaming
protectedStream = await _filesApiClient.DownloadFileAsync(applicationId, folder, filename, encryptionKey);
using (var stream = protectedStream.GetDecryptedValueAsStream()) // Decrypt the stream for writing, if you want
{
// Save the stream to a file
}
// Download a file and get its bytes directly. Does not stream. Use for small files only.
var protectedFileBytes = await _filesApiClient.DownloadSmallFileAsync(applicationId, folder, filename, encryptionKey);
// Check if the file exists
var exists = await _filesApiClient.GetFileExistsAsync(applicationId, folder, filename);
// Gets the list of all files stored in the folder
var filenames = await _filesApiClient.GetFilesAsync(applicationId, folder);
// Get the size of the file, in bytes
var size = await _filesApiClient.GetFileSizeAsync(applicationId, folder, filename);
// Get the list of all folders in the application
var folders = await _filesApiClient.GetFoldersAsync(applicationId);
// Delete the specified file from the server
await _filesApiClient.DeleteFileAsync(applicationId, folder, filename);
// Delete the specified folder and all files within from the server, for the application
await _filesApiClient.DeleteFolderAsync(applicationId);
}
}
}
@@ -5,7 +5,7 @@ using TriunniaLabs.Memory.Protected;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work the Keys Api.
/// A controller that shows how to work with the Keys Api.
/// </summary>
public class KeysApiSampleController : ArchControllerBase
{
@@ -5,7 +5,7 @@ using TriunniaLabs.Memory.Protected;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work the Tokens Api.
/// A controller that shows how to work with the Tokens Api.
/// </summary>
public class TokensApiSampleController : ArchControllerBase
{
@@ -0,0 +1,101 @@
using TriunniaLabs.Arch.Microservice;
using TriunniaLabs.Arch.Microservice.Client;
using TriunniaLabs.Arch.Relay.Users.Blazor;
using TriunniaLabs.Memory.Protected;
using TriunniaLabs.Blazor.ZeroKnowledge;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work with the Users Api Relay Client.
/// This controller demonstrates using the Relay client from a Blazor page.
/// Relay clients contact their corresponding server endpoints that are brought in via TriunniaLabs.Arch.Relay.Users.Server.
/// Those server endpoints then contact the normal Users Api Client.
/// </summary>
public class UsersApiRelaySampleController : ArchControllerBase
{
// Services
private readonly IUsersApiRelayClient _usersApiRelayClient;
private readonly IZeroKnowledgeService _zeroKnowledgeService;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="microserviceContext">Reference to the microservice context.</param>
/// <param name="usersApiRelayClient">Reference to the Users Api Relay client.</param>
/// <param name="zeroKnowledgeService">Client-side logic for the zero-knowledge protocol in Blazor.</param>
public UsersApiRelaySampleController(IMicroserviceContext microserviceContext, IUsersApiRelayClient usersApiRelayClient, IZeroKnowledgeService zeroKnowledgeService) : base(microserviceContext)
{
_usersApiRelayClient = usersApiRelayClient ?? throw new ArgumentNullException(nameof(usersApiRelayClient));
_zeroKnowledgeService = zeroKnowledgeService ?? throw new ArgumentNullException(nameof(zeroKnowledgeService));
}
/// <summary>
/// A sample method that shows how to work with the Users Api.
/// </summary>
internal async Task SampleAsync()
{
var encryptionKey = "SampleEncryptionKey".AsProtected(); // Per-row encryption key for the email address
var emailAddress = "sample@email.address".AsProtected(encryptionKey.GetDecryptedValue()); // Per-row encrypted email address
var checkEmailAddress = "sample@email.address".AsRelayProtected(); // Relay encrypted email address (lower security)
var ipAddress = IpAddress.AsProtected(); // User's ip address
var sessionToken = Guid.NewGuid().ToString().AsProtected(); // Authenticated session token
var resetToken = Guid.NewGuid().AsProtected(); // Password reset token
var deleteToken = Guid.NewGuid().AsProtected(); // Delete account token
// Construct origin graph -- the mechanism that verifies the user's password without knowing it
var originGraph = await _zeroKnowledgeService.GenerateOriginGraphAsync("password");
// Generate the key file, then save keyFileContents to a file. The file itself is password-protected via metadataPassword
var cycle = await _zeroKnowledgeService.GenerateHamiltonianCycleAsync(originGraph, "password");
var keyFileContents = await _zeroKnowledgeService.SerializeZeroKnowledgeMetadataAsync(originGraph, cycle, "metadataPassword");
// Read origin graph from key file
var (origin, cycle2) = await _zeroKnowledgeService.DeserializeZeroKnowledgeMetadataAsync(keyFileContents, "metadataPassword", "password");
// Set http headers on the client for authentication
_usersApiRelayClient.SetAuthorizationHeader("MySampleAuthScheme", sessionToken); // Authentication scheme must match appsettings.json
// Register a new user in the system
sessionToken = await _usersApiRelayClient.RegisterAsync(emailAddress, originGraph);
// Sign in to the system. It requires passing up to 12 challenges.
// The server knows the user's origin graph. It is asking the user to validate it by issuing challenges that the user answers.
// The Relay client does this procedure for you and returns the session token if the user authenticates successfully.
sessionToken = await _usersApiRelayClient.LoginAsync(emailAddress, originGraph, cycle);
// End the authenticated session; log the user out of the system
await _usersApiRelayClient.LogoutAsync();
// Check if the email address already exists in the system
var exists = await _usersApiRelayClient.CheckEmailAsync(checkEmailAddress);
// Get the user's email address and metadata
var emailResponse = await _usersApiRelayClient.GetEmailAsync();
// Update the user's email address
await _usersApiRelayClient.UpdateEmailAsync("updated.sample@email.address".AsProtected());
// Send a verification email for the user
await _usersApiRelayClient.SendVerificationEmailAsync();
// Validate a user's session token. Used to verify that a user is in fact signed in
var validated = _usersApiRelayClient.ValidateAsync(sessionToken);
// Password reset procedure
await _usersApiRelayClient.InitiatePasswordResetAsync(emailAddress); // Sends a verification email with resetToken
await _usersApiRelayClient.ValidatePasswordResetTokenAsync(emailAddress, resetToken);
await _usersApiRelayClient.CommitPasswordResetAsync(emailAddress, resetToken, originGraph); // Generate a new origin graph based on a new password for the user
// Delete account procedure
await _usersApiRelayClient.InitiateDeleteAccountAsync(); // Sends a confirmation email with deleteToken
await _usersApiRelayClient.CommitDeleteAccountAsync(deleteToken);
}
}
}
@@ -0,0 +1,119 @@
using TriunniaLabs.Arch.Api.Users.Client;
using TriunniaLabs.Arch.Microservice;
using TriunniaLabs.Arch.Microservice.Client;
using TriunniaLabs.Memory.Protected;
using TriunniaLabs.ZeroKnowledge.Client;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// A controller that shows how to work with the Users Api.
/// </summary>
public class UsersApiSampleController : ArchControllerBase
{
// Services
private readonly IUsersApiClient _usersApiClient;
private readonly IZeroKnowledgeService _zeroKnowledgeService;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="microserviceContext">Reference to the microservice context.</param>
/// <param name="usersApiClient">Reference to the Users Api client.</param>
/// <param name="zeroKnowledgeService">Client-side logic for the zero-knowledge protocol.</param>
public UsersApiSampleController(IMicroserviceContext microserviceContext, IUsersApiClient usersApiClient, IZeroKnowledgeService zeroKnowledgeService) : base(microserviceContext)
{
_usersApiClient = usersApiClient ?? throw new ArgumentNullException(nameof(usersApiClient));
_zeroKnowledgeService = zeroKnowledgeService ?? throw new ArgumentNullException(nameof(zeroKnowledgeService));
}
/// <summary>
/// A sample method that shows how to work with the Users Api.
/// </summary>
internal async Task SampleAsync()
{
var encryptionKey = "SampleEncryptionKey".AsProtected(); // Per-row encryption key for the email address
var emailAddress = "sample@email.address".AsProtected(encryptionKey.GetDecryptedValue()); // Per-row encrypted email address
var checkEmailAddress = "sample@email.address".AsRelayProtected(); // Relay encrypted email address (lower security)
var ipAddress = IpAddress.AsProtected(); // User's ip address
var sessionToken = Guid.NewGuid().ToString().AsProtected(); // Authenticated session token
var resetToken = Guid.NewGuid().AsProtected(); // Password reset token
var deleteToken = Guid.NewGuid().AsProtected(); // Delete account token
// Construct origin graph -- the mechanism that verifies the user's password without knowing it
var originGraph = _zeroKnowledgeService.GenerateOriginGraph("password");
var serializedOrigin = _zeroKnowledgeService.SerializeOriginGraph(originGraph);
var protectedOrigin = new Protected<string>(serializedOrigin);
// Generate the key file, then save keyFileContents to a file. The file itself is password-protected via metadataPassword
var cycle = _zeroKnowledgeService.GenerateHamiltonianCycle(originGraph, "password");
var keyFileContents = _zeroKnowledgeService.SerializeZeroKnowledgeMetadata(originGraph, cycle, "metadataPassword");
// Read origin graph from key file
_zeroKnowledgeService.DeserializeZeroKnowledgeMetadata(keyFileContents, "metadataPassword", "password", out originGraph!, out cycle!);
// Set http headers on the client for authentication
_usersApiClient.SetAuthorizationHeader(sessionToken);
_usersApiClient.SetIpAddressOriginHeader(ipAddress);
// Register a new user in the system
sessionToken = await _usersApiClient.RegisterAsync(emailAddress, protectedOrigin);
// Sign in to the system. It requires passing up to 12 challenges.
// The server knows the user's origin graph. It is asking the user to validate it by issuing challenges that the user answers.
// Challenges have their own session token. Not to be confused with the user's session token.
await _usersApiClient.InitiateLoginAsync(emailAddress);
for (int i = 0; i < 12; i++)
{
// Create the challenge
var challengeResponse = await _usersApiClient.CreateChallengeAsync(emailAddress);
var challenge = new ZeroKnowledge.Client.ChallengeResponse { Seed = challengeResponse.Seed, SessionToken = challengeResponse.SessionToken };
// Answer the challenge
var answer = _zeroKnowledgeService.AnswerChallenge(challenge, originGraph, cycle);
sessionToken = await _usersApiClient.EvaluateAnswerAsync(emailAddress, challenge.SessionToken, answer.Isomorphism.ToArray(), answer.Cycle);
if (sessionToken is not null && !sessionToken.IsEmpty)
{
// Session token returned -- User is authenticated
}
}
// Authentication fails if the loop is finished after 12 tries with no session token
// End the authenticated session; log the user out of the system
await _usersApiClient.LogoutAsync();
// Check if the email address already exists in the system
var exists = await _usersApiClient.CheckEmailAsync(checkEmailAddress);
// Get the user's email address and metadata
var emailResponse = await _usersApiClient.GetEmailAsync();
// Update the user's email address
await _usersApiClient.UpdateEmailAsync("updated.sample@email.address".AsProtected());
// Send a verification email for the user
await _usersApiClient.SendVerificationEmailAsync();
// Get user metadata
var user = await _usersApiClient.GetUserAsync();
// Validate a user's session token. Used to verify that a user is in fact signed in
var userId = _usersApiClient.ValidateSessionAsync(sessionToken, ipAddress);
// Password reset procedure
await _usersApiClient.InitiatePasswordResetAsync(emailAddress); // Sends a verification email with resetToken
await _usersApiClient.ValidatePasswordResetTokenAsync(emailAddress, resetToken);
await _usersApiClient.CommitPasswordResetAsync(emailAddress, resetToken, protectedOrigin); // Generate a new origin graph based on a new password for the user
// Delete account procedure
await _usersApiClient.InitiateDeleteAccountAsync(); // Sends a confirmation email with deleteToken
await _usersApiClient.CommitDeleteAccountAsync(deleteToken);
}
}
}
@@ -0,0 +1,26 @@
using TriunniaLabs.Memory.Protected;
namespace TriunniaLabs.Arch.Sample.Server
{
/// <summary>
/// Defines the protectors used by the application.
/// </summary>
public class ProtectorDefinitions
{
/// <summary>
/// Defines the protector for byte arrays.
/// </summary>
/// <remarks>
/// In Program.cs, the call to AddTriunniaLabsMicroservice() will internally call AddTriunniaLabsMemoryProtection(),
/// which will scan types in the assemblies for any protector registrations such as this one and automatically create protectors
/// for them. The protector matching this definition can be obtained by injecting
/// [FromKeyedServices(Protectors.ProtectedByteArrayServiceKey)] IProtector<byte[]>.
/// </remarks>
[HashAlgorithm(HmacSha512HashAlgorithm.ServiceKey)]
[EncryptionAlgorithm(AesEncryptionAlgorithm.ServiceKey, Order = 1)]
[EncryptionAlgorithm(GZipCompressionAlgorithm.ServiceKey, Order = 2)]
[StringConverter(Base65536StringConverter.ServiceKey)]
[Protector(Protectors.ProtectedByteArrayServiceKey)]
public Protected<byte[]> ByteArrayProtector { get; set; } = Protected<byte[]>.Empty;
}
}
@@ -12,6 +12,7 @@ using TriunniaLabs.Arch.Relay.Email.Server;
using TriunniaLabs.Arch.Relay.Users.Server;
using TriunniaLabs.Arch.Sample.Server;
using TriunniaLabs.Memory.Protected;
using TriunniaLabs.ZeroKnowledge.Client;
// Start the ASP.NET application builder
var builder = WebApplication.CreateBuilder(args);
@@ -27,6 +28,7 @@ builder.Services.AddTriunniaLabsUsersApi(builder.Configuration, builder.Services
builder.Services.AddTriunniaLabsCommentsApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
builder.Services.AddTriunniaLabsEntityApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
builder.Services.AddTriunniaLabsFilesApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
builder.Services.AddZeroKnowledge();
// Configuration
builder.Services.AddRouting(options => options.LowercaseUrls = true);
@@ -15,8 +15,12 @@
<PackageReference Include="TriunniaLabs.Arch.Api.Tokens.Client" Version="0.3.1" />
<PackageReference Include="TriunniaLabs.Arch.Api.Users.Client" Version="0.2.44" />
<PackageReference Include="TriunniaLabs.Arch.Microservice" Version="0.9.8" />
<PackageReference Include="TriunniaLabs.Arch.Relay.Email.Blazor" Version="0.2.2" />
<PackageReference Include="TriunniaLabs.Arch.Relay.Email.Server" Version="0.2.2" />
<PackageReference Include="TriunniaLabs.Arch.Relay.Users.Blazor" Version="0.2.44" />
<PackageReference Include="TriunniaLabs.Arch.Relay.Users.Server" Version="0.2.44" />
<PackageReference Include="TriunniaLabs.Blazor.ZeroKnowledge" Version="0.1.4" />
<PackageReference Include="TriunniaLabs.ZeroKnowledge.Client" Version="0.1.4" />
</ItemGroup>
</Project>