Skip to content

Commit

Permalink
Merge pull request #124 from PinguApps/91-create-2fa-challenge-confir…
Browse files Browse the repository at this point in the history
…mation

Implemented create 2fa challenge confirmation
  • Loading branch information
pingu2k4 authored Aug 10, 2024
2 parents 6f1791b + cd6d39b commit 2333895
Show file tree
Hide file tree
Showing 31 changed files with 662 additions and 70 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,14 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(
```

## ⌛ Progress
<!-- ![23 / 288](https://progress-bar.dev/23/?scale=288&suffix=%20/%20288&width=500) -->
![Server & Client - 23 / 288](https://img.shields.io/badge/Server_&_Client-23%20%2F%20288-red?style=for-the-badge)
<!-- ![24 / 288](https://progress-bar.dev/24/?scale=288&suffix=%20/%20288&width=500) -->
![Server & Client - 24 / 288](https://img.shields.io/badge/Server_&_Client-24%20%2F%20288-red?style=for-the-badge)

<!-- ![2 / 195](https://progress-bar.dev/2/?scale=195&suffix=%20/%20195&width=300) -->
![Server - 2 / 195](https://img.shields.io/badge/Server-2%20%2F%20195-red?style=for-the-badge)

<!-- ![21 / 93](https://progress-bar.dev/21/?scale=93&suffix=%20/%2093&width=300) -->
![Client - 21 / 93](https://img.shields.io/badge/Client-21%20%2F%2093-red?style=for-the-badge)
<!-- ![22 / 93](https://progress-bar.dev/22/?scale=93&suffix=%20/%2093&width=300) -->
![Client - 22 / 93](https://img.shields.io/badge/Client-22%20%2F%2093-red?style=for-the-badge)

### 🔑 Key
| Icon | Definition |
Expand All @@ -155,8 +155,8 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(
|| There is currently no intention to implement the endpoint for the given SDK type (client or server) |

### Account
<!-- ![23 / 52](https://progress-bar.dev/23/?scale=52&suffix=%20/%2052&width=120) -->
![Account - 23 / 52](https://img.shields.io/badge/Account-23%20%2F%2052-yellow?style=for-the-badge)
<!-- ![24 / 52](https://progress-bar.dev/24/?scale=52&suffix=%20/%2052&width=120) -->
![Account - 24 / 52](https://img.shields.io/badge/Account-24%20%2F%2052-yellow?style=for-the-badge)

| Endpoint | Client | Server |
|:-:|:-:|:-:|
Expand All @@ -172,7 +172,7 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(
| [Verify Authenticator](https://appwrite.io/docs/references/1.5.x/client-rest/account#updateMfaAuthenticator) |||
| [Delete Authenticator](https://appwrite.io/docs/references/1.5.x/client-rest/account#deleteMfaAuthenticator) |||
| [Create 2FA Challenge](https://appwrite.io/docs/references/1.5.x/client-rest/account#createMfaChallenge) |||
| [Create MFA Challenge (confirmation)](https://appwrite.io/docs/references/1.5.x/client-rest/account#updateMfaChallenge) | ||
| [Create MFA Challenge (confirmation)](https://appwrite.io/docs/references/1.5.x/client-rest/account#updateMfaChallenge) | ||
| [List Factors](https://appwrite.io/docs/references/1.5.x/client-rest/account#listMfaFactors) |||
| [Get MFA Recovery Codes](https://appwrite.io/docs/references/1.5.x/client-rest/account#getMfaRecoveryCodes) |||
| [Create MFA Recovery Codes](https://appwrite.io/docs/references/1.5.x/client-rest/account#createMfaRecoveryCodes) |||
Expand Down
61 changes: 42 additions & 19 deletions src/PinguApps.Appwrite.Client/Clients/AccountClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ public AccountClient(IServiceProvider services)
string? ISessionAware.Session { get; set; }

ISessionAware? _sessionAware;
public string? Session => GetSession();
private string? GetSession()
public string? Session => GetCurrentSession();

private string? GetCurrentSession()
{
if (_sessionAware is null)
{
Expand All @@ -36,12 +37,17 @@ public AccountClient(IServiceProvider services)
return _sessionAware.Session;
}

private string GetCurrentSessionOrThrow()
{
return GetCurrentSession() ?? throw new Exception(ISessionAware.SessionExceptionMessage);
}

/// <inheritdoc/>
public async Task<AppwriteResult<User>> Get()
{
try
{
var result = await _accountApi.GetAccount(Session);
var result = await _accountApi.GetAccount(GetCurrentSessionOrThrow());

return result.GetApiResponse();
}
Expand Down Expand Up @@ -75,7 +81,7 @@ public async Task<AppwriteResult<User>> UpdateEmail(UpdateEmailRequest request)
{
request.Validate(true);

var result = await _accountApi.UpdateEmail(Session, request);
var result = await _accountApi.UpdateEmail(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand All @@ -92,7 +98,7 @@ public async Task<AppwriteResult<User>> UpdateName(UpdateNameRequest request)
{
request.Validate(true);

var result = await _accountApi.UpdateName(Session, request);
var result = await _accountApi.UpdateName(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand All @@ -109,7 +115,7 @@ public async Task<AppwriteResult<User>> UpdatePassword(UpdatePasswordRequest req
{
request.Validate(true);

var result = await _accountApi.UpdatePassword(Session, request);
var result = await _accountApi.UpdatePassword(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand All @@ -126,7 +132,7 @@ public async Task<AppwriteResult<User>> UpdatePhone(UpdatePhoneRequest request)
{
request.Validate(true);

var result = await _accountApi.UpdatePhone(Session, request);
var result = await _accountApi.UpdatePhone(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand All @@ -141,7 +147,7 @@ public async Task<AppwriteResult<IReadOnlyDictionary<string, string>>> GetAccoun
{
try
{
var result = await _accountApi.GetAccountPreferences(Session);
var result = await _accountApi.GetAccountPreferences(GetCurrentSessionOrThrow());

return result.GetApiResponse();
}
Expand All @@ -158,7 +164,7 @@ public async Task<AppwriteResult<User>> UpdatePreferences(UpdatePreferencesReque
{
request.Validate(true);

var result = await _accountApi.UpdatePreferences(Session, request);
var result = await _accountApi.UpdatePreferences(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand Down Expand Up @@ -207,7 +213,7 @@ public async Task<AppwriteResult<Session>> GetSession(string sessionId = "curren
{
try
{
var result = await _accountApi.GetSession(Session, sessionId);
var result = await _accountApi.GetSession(GetCurrentSessionOrThrow(), sessionId);

return result.GetApiResponse();
}
Expand All @@ -222,7 +228,7 @@ public async Task<AppwriteResult<Session>> UpdateSession(string sessionId = "cur
{
try
{
var result = await _accountApi.UpdateSession(Session, sessionId);
var result = await _accountApi.UpdateSession(GetCurrentSessionOrThrow(), sessionId);

return result.GetApiResponse();
}
Expand All @@ -239,7 +245,7 @@ public async Task<AppwriteResult<Token>> CreateEmailVerification(CreateEmailVeri
{
request.Validate(true);

var result = await _accountApi.CreateEmailVerification(Session, request);
var result = await _accountApi.CreateEmailVerification(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand Down Expand Up @@ -271,7 +277,7 @@ public async Task<AppwriteResult<Jwt>> CreateJwt()
{
try
{
var result = await _accountApi.CreateJwt(Session);
var result = await _accountApi.CreateJwt(GetCurrentSessionOrThrow());

return result.GetApiResponse();
}
Expand All @@ -288,7 +294,7 @@ public async Task<AppwriteResult<LogsList>> ListLogs(List<Query>? queries = null
{
var queryStrings = queries?.Select(x => x.GetQueryString()) ?? [];

var result = await _accountApi.ListLogs(Session, queryStrings);
var result = await _accountApi.ListLogs(GetCurrentSessionOrThrow(), queryStrings);

return result.GetApiResponse();
}
Expand All @@ -305,7 +311,7 @@ public async Task<AppwriteResult<MfaType>> AddAuthenticator(AddAuthenticatorRequ
{
request.Validate(true);

var result = await _accountApi.AddAuthenticator(Session, request.Type);
var result = await _accountApi.AddAuthenticator(GetCurrentSessionOrThrow(), request.Type);

return result.GetApiResponse();
}
Expand All @@ -322,7 +328,7 @@ public async Task<AppwriteResult<User>> VerifyAuthenticator(VerifyAuthenticatorR
{
request.Validate(true);

var result = await _accountApi.VerifyAuthenticator(Session, request.Type, request);
var result = await _accountApi.VerifyAuthenticator(GetCurrentSessionOrThrow(), request.Type, request);

return result.GetApiResponse();
}
Expand All @@ -339,7 +345,7 @@ public async Task<AppwriteResult<User>> UpdateMfa(UpdateMfaRequest request)
{
request.Validate(true);

var result = await _accountApi.UpdateMfa(Session, request);
var result = await _accountApi.UpdateMfa(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand All @@ -356,7 +362,7 @@ public async Task<AppwriteResult> DeleteAuthenticator(DeleteAuthenticatorRequest
{
request.Validate(true);

var result = await _accountApi.DeleteAuthenticator(Session, request.Type, request);
var result = await _accountApi.DeleteAuthenticator(GetCurrentSessionOrThrow(), request.Type, request);

return result.GetApiResponse();
}
Expand All @@ -373,7 +379,7 @@ public async Task<AppwriteResult<MfaChallenge>> Create2faChallenge(Create2faChal
{
request.Validate(true);

var result = await _accountApi.Create2faChallenge(Session, request);
var result = await _accountApi.Create2faChallenge(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
Expand All @@ -382,4 +388,21 @@ public async Task<AppwriteResult<MfaChallenge>> Create2faChallenge(Create2faChal
return e.GetExceptionResponse<MfaChallenge>();
}
}

/// <inheritdoc/>
public async Task<AppwriteResult> Create2faChallengeConfirmation(Create2faChallengeConfirmationRequest request)
{
try
{
request.Validate(true);

var result = await _accountApi.Create2faChallengeConfirmation(GetCurrentSessionOrThrow(), request);

return result.GetApiResponse();
}
catch (Exception e)
{
return e.GetExceptionResponse();
}
}
}
10 changes: 9 additions & 1 deletion src/PinguApps.Appwrite.Client/Clients/IAccountClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,18 @@ public interface IAccountClient
Task<AppwriteResult> DeleteAuthenticator(DeleteAuthenticatorRequest request);

/// <summary>
/// Begin the process of MFA verification after sign-in. Finish the flow with updateMfaChallenge method
/// Begin the process of MFA verification after sign-in. Finish the flow with <see cref="Create2faChallengeConfirmation(Create2faChallengeConfirmationRequest)"/>
/// <para><see href="https://appwrite.io/docs/references/1.5.x/client-rest/account#createMfaChallenge">Appwrite Docs</see></para>
/// </summary>
/// <param name="request">The request content</param>
/// <returns>The Mfa Challenge</returns>
Task<AppwriteResult<MfaChallenge>> Create2faChallenge(Create2faChallengeRequest request);

/// <summary>
/// Complete the MFA challenge by providing the one-time password. Finish the process of MFA verification by providing the one-time password. To begin the flow, use <see cref="Create2faChallenge(Create2faChallengeRequest)"/>
/// <para><see href="https://appwrite.io/docs/references/1.5.x/client-rest/account#updateMfaChallenge">Appwrite Docs</see></para>
/// </summary>
/// <param name="request">The request content</param>
/// <returns>The result</returns>
Task<AppwriteResult> Create2faChallengeConfirmation(Create2faChallengeConfirmationRequest request);
}
2 changes: 2 additions & 0 deletions src/PinguApps.Appwrite.Client/Clients/ISessionAware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ internal interface ISessionAware
public string? Session { get; protected set; }

public void UpdateSession(string? session) => Session = session;

public const string SessionExceptionMessage = "Session cannot be null.";
}
37 changes: 20 additions & 17 deletions src/PinguApps.Appwrite.Client/Internals/IAccountApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,28 @@ namespace PinguApps.Appwrite.Client.Internals;
internal interface IAccountApi : IBaseApi
{
[Get("/account")]
Task<IApiResponse<User>> GetAccount([Header("x-appwrite-session")] string? session);
Task<IApiResponse<User>> GetAccount([Header("x-appwrite-session")] string session);

[Post("/account")]
Task<IApiResponse<User>> CreateAccount(CreateAccountRequest request);

[Patch("/account/email")]
Task<IApiResponse<User>> UpdateEmail([Header("x-appwrite-session")] string? session, UpdateEmailRequest request);
Task<IApiResponse<User>> UpdateEmail([Header("x-appwrite-session")] string session, UpdateEmailRequest request);

[Patch("/account/name")]
Task<IApiResponse<User>> UpdateName([Header("x-appwrite-session")] string? session, UpdateNameRequest request);
Task<IApiResponse<User>> UpdateName([Header("x-appwrite-session")] string session, UpdateNameRequest request);

[Patch("/account/password")]
Task<IApiResponse<User>> UpdatePassword([Header("x-appwrite-session")] string? session, UpdatePasswordRequest request);
Task<IApiResponse<User>> UpdatePassword([Header("x-appwrite-session")] string session, UpdatePasswordRequest request);

[Patch("/account/phone")]
Task<IApiResponse<User>> UpdatePhone([Header("x-appwrite-session")] string? session, UpdatePhoneRequest request);
Task<IApiResponse<User>> UpdatePhone([Header("x-appwrite-session")] string session, UpdatePhoneRequest request);

[Get("/account/prefs")]
Task<IApiResponse<IReadOnlyDictionary<string, string>>> GetAccountPreferences([Header("x-appwrite-session")] string? session);
Task<IApiResponse<IReadOnlyDictionary<string, string>>> GetAccountPreferences([Header("x-appwrite-session")] string session);

[Patch("/account/prefs")]
Task<IApiResponse<User>> UpdatePreferences([Header("x-appwrite-session")] string? session, UpdatePreferencesRequest request);
Task<IApiResponse<User>> UpdatePreferences([Header("x-appwrite-session")] string session, UpdatePreferencesRequest request);

[Post("/account/tokens/email")]
Task<IApiResponse<Token>> CreateEmailToken(CreateEmailTokenRequest request);
Expand All @@ -39,36 +39,39 @@ internal interface IAccountApi : IBaseApi
Task<IApiResponse<Session>> CreateSession(CreateSessionRequest request);

[Get("/account/sessions/{sessionId}")]
Task<IApiResponse<Session>> GetSession([Header("x-appwrite-session")] string? session, string sessionId);
Task<IApiResponse<Session>> GetSession([Header("x-appwrite-session")] string session, string sessionId);

[Patch("/account/sessions/{sessionId}")]
Task<IApiResponse<Session>> UpdateSession([Header("x-appwrite-session")] string? session, string sessionId);
Task<IApiResponse<Session>> UpdateSession([Header("x-appwrite-session")] string session, string sessionId);

[Post("/account/verification")]
Task<IApiResponse<Token>> CreateEmailVerification([Header("x-appwrite-session")] string? session, CreateEmailVerificationRequest request);
Task<IApiResponse<Token>> CreateEmailVerification([Header("x-appwrite-session")] string session, CreateEmailVerificationRequest request);

[Put("/account/verification")]
Task<IApiResponse<Token>> CreateEmailVerificationConfirmation(CreateEmailVerificationConfirmationRequest request);

[Post("/account/jwt")]
Task<IApiResponse<Jwt>> CreateJwt([Header("x-appwrite-session")] string? session);
Task<IApiResponse<Jwt>> CreateJwt([Header("x-appwrite-session")] string session);

[Get("/account/logs")]
[QueryUriFormat(System.UriFormat.Unescaped)]
Task<IApiResponse<LogsList>> ListLogs([Header("x-appwrite-session")] string? session, [Query(CollectionFormat.Multi), AliasAs("queries[]")] IEnumerable<string> queries);
Task<IApiResponse<LogsList>> ListLogs([Header("x-appwrite-session")] string session, [Query(CollectionFormat.Multi), AliasAs("queries[]")] IEnumerable<string> queries);

[Post("/account/mfa/authenticators/{type}")]
Task<IApiResponse<MfaType>> AddAuthenticator([Header("x-appwrite-session")] string? session, string type);
Task<IApiResponse<MfaType>> AddAuthenticator([Header("x-appwrite-session")] string session, string type);

[Put("/account/mfa/authenticators/{type}")]
Task<IApiResponse<User>> VerifyAuthenticator([Header("x-appwrite-session")] string? session, string type, VerifyAuthenticatorRequest request);
Task<IApiResponse<User>> VerifyAuthenticator([Header("x-appwrite-session")] string session, string type, VerifyAuthenticatorRequest request);

[Patch("/account/mfa")]
Task<IApiResponse<User>> UpdateMfa([Header("x-appwrite-session")] string? session, UpdateMfaRequest request);
Task<IApiResponse<User>> UpdateMfa([Header("x-appwrite-session")] string session, UpdateMfaRequest request);

[Delete("/account/mfa/authenticators/{type}")]
Task<IApiResponse> DeleteAuthenticator([Header("x-appwrite-session")] string? session, string type, [Body] DeleteAuthenticatorRequest request);
Task<IApiResponse> DeleteAuthenticator([Header("x-appwrite-session")] string session, string type, [Body] DeleteAuthenticatorRequest request);

[Post("/account/mfa/challenge")]
Task<IApiResponse<MfaChallenge>> Create2faChallenge([Header("x-appwrite-session")] string? session, Create2faChallengeRequest request);
Task<IApiResponse<MfaChallenge>> Create2faChallenge([Header("x-appwrite-session")] string session, Create2faChallengeRequest request);

[Put("/account/mfa/challenge")]
Task<IApiResponse> Create2faChallengeConfirmation([Header("x-appwrite-session")] string session, Create2faChallengeConfirmationRequest request);
}
14 changes: 12 additions & 2 deletions src/PinguApps.Appwrite.Playground/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,25 @@ public async Task Run(string[] args)
{
_client.SetSession(_session);

Console.WriteLine(_client.Session);

//var response = await _client.Account.AddAuthenticator();
var response = await _client.Account.Create2faChallenge(new Shared.Requests.Create2faChallengeRequest
//var response = await _client.Account.Create2faChallenge(new Shared.Requests.Create2faChallengeRequest
//{
// Factor = Shared.Enums.SecondFactor.Email
//});

var response = await _client.Account.Create2faChallengeConfirmation(new Shared.Requests.Create2faChallengeConfirmationRequest
{
Factor = Shared.Enums.SecondFactor.Email
ChallengeId = "66b771b7bdcb152aaa5b",
Otp = "474376"
});

Console.WriteLine(response.Result.Match(
account => account.ToString(),
appwriteError => appwriteError.Message,
internalERror => internalERror.Message));

Console.WriteLine(_client.Session);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
using PinguApps.Appwrite.Shared.Requests.Validators;

namespace PinguApps.Appwrite.Shared.Requests;

/// <summary>
/// The request for creating a 2fa challenge confirmation
/// </summary>
public class Create2faChallengeConfirmationRequest : BaseRequest<Create2faChallengeConfirmationRequest, Create2faChallengeConfirmationRequestValidator>
{
/// <summary>
/// ID of the challenge
/// </summary>
[JsonPropertyName("challengeId")]
public string ChallengeId { get; set; } = string.Empty;

/// <summary>
/// Valid verification token
/// </summary>
[JsonPropertyName("otp")]
public string Otp { get; set; } = string.Empty;
}
Loading

0 comments on commit 2333895

Please sign in to comment.