-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #136 from PinguApps/103-create-oauth2-session
Implemented create oauth2 session
- Loading branch information
Showing
18 changed files
with
634 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,10 +22,12 @@ public async Task Run(string[] args) | |
|
||
Console.WriteLine(_client.Session); | ||
|
||
var response = await _client.Account.CreateEmailPasswordSession(new Shared.Requests.CreateEmailPasswordSessionRequest | ||
var response = _client.Account.CreateOauth2Session(new Shared.Requests.CreateOauth2SessionRequest | ||
{ | ||
Email = "[email protected]", | ||
Password = "password" | ||
Provider = "google", | ||
SuccessUri = "https://localhost:5001/success", | ||
FailureUri = "https://localhost:5001/fail", | ||
Scopes = ["scope1", "scope2"] | ||
}); | ||
|
||
Console.WriteLine(response.Result.Match( | ||
|
12 changes: 12 additions & 0 deletions
12
src/PinguApps.Appwrite.Shared/Attributes/QueryParameterAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System; | ||
|
||
namespace PinguApps.Appwrite.Shared.Attributes; | ||
internal class QueryParameterAttribute : Attribute | ||
{ | ||
public QueryParameterAttribute(string key) | ||
{ | ||
Key = key; | ||
} | ||
|
||
public string Key { get; } | ||
} |
13 changes: 13 additions & 0 deletions
13
src/PinguApps.Appwrite.Shared/Attributes/UrlReplacementAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System; | ||
|
||
namespace PinguApps.Appwrite.Shared.Attributes; | ||
|
||
internal class UrlReplacementAttribute : Attribute | ||
{ | ||
public UrlReplacementAttribute(string pattern) | ||
{ | ||
Pattern = pattern; | ||
} | ||
|
||
public string Pattern { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
namespace PinguApps.Appwrite.Shared; | ||
public record Config( | ||
string Endpoint, | ||
string ProjectId | ||
); |
38 changes: 38 additions & 0 deletions
38
src/PinguApps.Appwrite.Shared/Requests/CreateOauth2SessionRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using System.Collections.Generic; | ||
using PinguApps.Appwrite.Shared.Attributes; | ||
using PinguApps.Appwrite.Shared.Requests.Validators; | ||
|
||
namespace PinguApps.Appwrite.Shared.Requests; | ||
|
||
/// <summary> | ||
/// The request for creating an Oauth2 Session | ||
/// </summary> | ||
public class CreateOauth2SessionRequest : QueryParamBaseRequest<CreateOauth2SessionRequest, CreateOauth2SessionRequestValidator> | ||
{ | ||
/// <summary> | ||
/// OAuth2 Provider. Currently, supported providers are: | ||
/// <para>amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom</para> | ||
/// </summary> | ||
[UrlReplacement("{provider}")] | ||
public string Provider { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an <see href="https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html">open redirect</see> attack against your project API | ||
/// </summary> | ||
[QueryParameter("success")] | ||
public string? SuccessUri { get; set; } | ||
|
||
/// <summary> | ||
/// URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an <see href="https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html">open redirect</see> attack against your project API | ||
/// </summary> | ||
[QueryParameter("failure")] | ||
public string? FailureUri { get; set; } | ||
|
||
/// <summary> | ||
/// A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long | ||
/// </summary> | ||
[QueryParameter("scopes[]")] | ||
public List<string>? Scopes { get; set; } | ||
|
||
protected override string Path => "/account/tokens/oauth2/{provider}"; | ||
} |
105 changes: 105 additions & 0 deletions
105
src/PinguApps.Appwrite.Shared/Requests/QueryParamBaseRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using FluentValidation; | ||
using PinguApps.Appwrite.Shared.Attributes; | ||
|
||
namespace PinguApps.Appwrite.Shared.Requests; | ||
public abstract class QueryParamBaseRequest<TRequest, TValidator> : BaseRequest<TRequest, TValidator> | ||
where TRequest : class | ||
where TValidator : IValidator<TRequest>, new() | ||
{ | ||
public Uri BuildUri(string endpoint, string? projectId) | ||
{ | ||
var endpointUri = new Uri(endpoint); | ||
var endpointPath = endpointUri.AbsolutePath; | ||
|
||
var path = Path; | ||
|
||
var urlReplacementProperties = GetType() | ||
.GetProperties() | ||
.Where(x => Attribute.IsDefined(x, typeof(UrlReplacementAttribute))); | ||
|
||
foreach (var property in urlReplacementProperties) | ||
{ | ||
var value = property.GetValue(this); | ||
|
||
if (value is string strValue) | ||
{ | ||
var attribute = property.GetCustomAttribute<UrlReplacementAttribute>(); | ||
|
||
path = path.Replace(attribute.Pattern, strValue); | ||
} | ||
} | ||
|
||
var combinedPath = CombinePaths(endpointPath, path); | ||
|
||
var builder = new UriBuilder(endpoint) | ||
{ | ||
Path = combinedPath | ||
}; | ||
|
||
var queryProperties = GetType() | ||
.GetProperties() | ||
.Where(x => Attribute.IsDefined(x, typeof(QueryParameterAttribute))); | ||
|
||
var queries = new List<string>(); | ||
|
||
if (projectId is not null) | ||
{ | ||
queries.Add($"project={projectId}"); | ||
} | ||
|
||
foreach (var property in queryProperties) | ||
{ | ||
var value = property.GetValue(this); | ||
|
||
if (value is null) | ||
continue; | ||
|
||
var attribute = property.GetCustomAttribute<QueryParameterAttribute>(); | ||
|
||
if (value is IEnumerable<object> values && value is not string) | ||
{ | ||
foreach (var item in values) | ||
{ | ||
queries.Add($"{attribute.Key}={Uri.EscapeDataString(item.ToString())}"); | ||
} | ||
} | ||
else | ||
{ | ||
queries.Add($"{attribute.Key}={Uri.EscapeDataString(value.ToString())}"); | ||
} | ||
} | ||
|
||
if (queries.Count > 0) | ||
{ | ||
builder.Query = string.Join("&", queries); | ||
} | ||
|
||
return builder.Uri; | ||
} | ||
|
||
static string CombinePaths(string urlPath, string existingPath) | ||
{ | ||
if (urlPath == "/") | ||
{ | ||
return existingPath; | ||
} | ||
|
||
if (!urlPath.EndsWith('/')) | ||
{ | ||
urlPath += "/"; | ||
} | ||
|
||
if (existingPath.StartsWith('/')) | ||
{ | ||
existingPath = existingPath.TrimStart('/'); | ||
} | ||
|
||
return urlPath + existingPath; | ||
} | ||
|
||
protected abstract string Path { get; } | ||
} |
18 changes: 18 additions & 0 deletions
18
src/PinguApps.Appwrite.Shared/Requests/Validators/CreateOauth2SessionRequestValidator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using FluentValidation; | ||
|
||
namespace PinguApps.Appwrite.Shared.Requests.Validators; | ||
public class CreateOauth2SessionRequestValidator : AbstractValidator<CreateOauth2SessionRequest> | ||
{ | ||
public CreateOauth2SessionRequestValidator() | ||
{ | ||
RuleFor(x => x.Provider).NotEmpty().Must(x => string.Equals(x, x.ToLower(), StringComparison.Ordinal)).WithMessage("Provider must be all lower case."); | ||
RuleFor(x => x.SuccessUri).Must(uri => Uri.TryCreate(uri, UriKind.Absolute, out _)).When(x => x.SuccessUri is not null); | ||
RuleFor(x => x.FailureUri).Must(uri => Uri.TryCreate(uri, UriKind.Absolute, out _)).When(x => x.FailureUri is not null); | ||
RuleFor(x => x.Scopes) | ||
.Must(x => x!.Count <= 100).WithMessage("You can have a maximum of 100 scopes") | ||
.Must(x => x!.Count > 0).WithMessage("You must have more than 0 scopes if passing a non null value") | ||
.When(x => x.Scopes is not null); | ||
RuleForEach(x => x.Scopes).MaximumLength(4096); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/PinguApps.Appwrite.Shared/Responses/CreateOauth2Session.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System.Text.Json.Serialization; | ||
|
||
namespace PinguApps.Appwrite.Shared.Responses; | ||
|
||
/// <summary> | ||
/// A Create Oauth2 Session object | ||
/// </summary> | ||
/// <param name="Uri">The Uri that you should redirect the user towards to begin Oauth2 authentication</param> | ||
public record CreateOauth2Session( | ||
[property: JsonPropertyName("uri")] string Uri | ||
); |
38 changes: 38 additions & 0 deletions
38
...PinguApps.Appwrite.Client.Tests/Clients/Account/AccountClientTests.CreateOauth2Session.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using PinguApps.Appwrite.Shared.Requests; | ||
|
||
namespace PinguApps.Appwrite.Client.Tests.Clients.Account; | ||
public partial class AccountClientTests | ||
{ | ||
[Fact] | ||
public void CreateOauth2Session_ShouldReturnSuccess_WhenApiCallSucceeds() | ||
{ | ||
// Arrange | ||
var request = new CreateOauth2SessionRequest() | ||
{ | ||
Provider = "google" | ||
}; | ||
|
||
// Act | ||
var result = _appwriteClient.Account.CreateOauth2Session(request); | ||
|
||
// Assert | ||
Assert.True(result.Success); | ||
} | ||
|
||
[Fact] | ||
public void CreateOauth2Session_ShouldReturnErrorResponse_WhenExceptionOccurs() | ||
{ | ||
// Arrange | ||
var request = new CreateOauth2SessionRequest() | ||
{ | ||
Provider = "" | ||
}; | ||
|
||
// Act | ||
var result = _appwriteClient.Account.CreateOauth2Session(request); | ||
|
||
// Assert | ||
Assert.False(result.Success); | ||
Assert.True(result.IsInternalError); | ||
} | ||
} |
Oops, something went wrong.