mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 22:44:29 +01:00
add to client, fix tests and doc
This commit is contained in:
@@ -14,6 +14,8 @@ namespace BTCPayServer.Client
|
|||||||
{
|
{
|
||||||
private readonly string _apiKey;
|
private readonly string _apiKey;
|
||||||
private readonly Uri _btcpayHost;
|
private readonly Uri _btcpayHost;
|
||||||
|
private readonly string _username;
|
||||||
|
private readonly string _password;
|
||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
public string APIKey => _apiKey;
|
public string APIKey => _apiKey;
|
||||||
@@ -32,6 +34,15 @@ namespace BTCPayServer.Client
|
|||||||
_httpClient = httpClient ?? new HttpClient();
|
_httpClient = httpClient ?? new HttpClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BTCPayServerClient(Uri btcpayHost, string username, string password, HttpClient httpClient = null)
|
||||||
|
{
|
||||||
|
_apiKey = APIKey;
|
||||||
|
_btcpayHost = btcpayHost;
|
||||||
|
_username = username;
|
||||||
|
_password = password;
|
||||||
|
_httpClient = httpClient ?? new HttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
protected void HandleResponse(HttpResponseMessage message)
|
protected void HandleResponse(HttpResponseMessage message)
|
||||||
{
|
{
|
||||||
message.EnsureSuccessStatusCode();
|
message.EnsureSuccessStatusCode();
|
||||||
@@ -56,6 +67,10 @@ namespace BTCPayServer.Client
|
|||||||
var httpRequest = new HttpRequestMessage(method ?? HttpMethod.Get, uriBuilder.Uri);
|
var httpRequest = new HttpRequestMessage(method ?? HttpMethod.Get, uriBuilder.Uri);
|
||||||
if (_apiKey != null)
|
if (_apiKey != null)
|
||||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("token", _apiKey);
|
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("token", _apiKey);
|
||||||
|
else if (!string.IsNullOrEmpty(_username))
|
||||||
|
{
|
||||||
|
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic", System.Convert.ToBase64String(Encoding.ASCII.GetBytes(_username + ":" + _password)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return httpRequest;
|
return httpRequest;
|
||||||
|
|||||||
@@ -38,15 +38,23 @@ namespace BTCPayServer.Tests
|
|||||||
user.GrantAccess();
|
user.GrantAccess();
|
||||||
await user.MakeAdmin();
|
await user.MakeAdmin();
|
||||||
var client = await user.CreateClient(Policies.Unrestricted);
|
var client = await user.CreateClient(Policies.Unrestricted);
|
||||||
|
var clientBasic = await user.CreateClient();
|
||||||
//Get current api key
|
//Get current api key
|
||||||
var apiKeyData = await client.GetCurrentAPIKeyInfo();
|
var apiKeyData = await client.GetCurrentAPIKeyInfo();
|
||||||
Assert.NotNull(apiKeyData);
|
Assert.NotNull(apiKeyData);
|
||||||
Assert.Equal(client.APIKey, apiKeyData.ApiKey);
|
Assert.Equal(client.APIKey, apiKeyData.ApiKey);
|
||||||
Assert.Single(apiKeyData.Permissions);
|
Assert.Single(apiKeyData.Permissions);
|
||||||
|
|
||||||
|
//a client using Basic Auth has no business here
|
||||||
|
await AssertHttpError(401, async () => await clientBasic.GetCurrentAPIKeyInfo());
|
||||||
|
|
||||||
//revoke current api key
|
//revoke current api key
|
||||||
await client.RevokeCurrentAPIKeyInfo();
|
await client.RevokeCurrentAPIKeyInfo();
|
||||||
await AssertHttpError(401, async () => await client.GetCurrentAPIKeyInfo());
|
await AssertHttpError(401, async () => await client.GetCurrentAPIKeyInfo());
|
||||||
|
//a client using Basic Auth has no business here
|
||||||
|
await AssertHttpError(401, async () => await clientBasic.RevokeCurrentAPIKeyInfo());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,12 +116,14 @@ namespace BTCPayServer.Tests
|
|||||||
user1Acc.UserId = user1.Id;
|
user1Acc.UserId = user1.Id;
|
||||||
user1Acc.IsAdmin = false;
|
user1Acc.IsAdmin = false;
|
||||||
var user1Client = await user1Acc.CreateClient(Policies.CanModifyServerSettings);
|
var user1Client = await user1Acc.CreateClient(Policies.CanModifyServerSettings);
|
||||||
|
var user1ClientBasic = await user1Acc.CreateClient();
|
||||||
// User1 trying to get server management would still fail to create user
|
// User1 trying to get server management would still fail to create user
|
||||||
await AssertHttpError(403, async () => await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "test8@gmail.com", Password = "afewfoiewiou" }));
|
await AssertHttpError(403, async () => await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "test8@gmail.com", Password = "afewfoiewiou" }));
|
||||||
|
|
||||||
// User1 should be able to create user if subscription unlocked
|
// User1 should be able to create user if subscription unlocked
|
||||||
await settings.UpdateSetting<PoliciesSettings>(new PoliciesSettings() { LockSubscription = false });
|
await settings.UpdateSetting<PoliciesSettings>(new PoliciesSettings() { LockSubscription = false });
|
||||||
await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "test8@gmail.com", Password = "afewfoiewiou" });
|
await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "test8@gmail.com", Password = "afewfoiewiou" });
|
||||||
|
await user1ClientBasic.CreateUser(new CreateApplicationUserRequest() { Email = "testaa8@gmail.com", Password = "afewfoiewiou" });
|
||||||
// But not an admin
|
// But not an admin
|
||||||
await AssertHttpError(403, async () => await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "admin8@gmail.com", Password = "afewfoiewiou", IsAdministrator = true }));
|
await AssertHttpError(403, async () => await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "admin8@gmail.com", Password = "afewfoiewiou", IsAdministrator = true }));
|
||||||
}
|
}
|
||||||
@@ -139,6 +149,7 @@ namespace BTCPayServer.Tests
|
|||||||
var clientProfile = await user.CreateClient(Policies.CanModifyProfile);
|
var clientProfile = await user.CreateClient(Policies.CanModifyProfile);
|
||||||
var clientServer = await user.CreateClient(Policies.CanCreateUser, Policies.CanViewProfile);
|
var clientServer = await user.CreateClient(Policies.CanCreateUser, Policies.CanViewProfile);
|
||||||
var clientInsufficient = await user.CreateClient(Policies.CanModifyStoreSettings);
|
var clientInsufficient = await user.CreateClient(Policies.CanModifyStoreSettings);
|
||||||
|
var clientBasic = await user.CreateClient();
|
||||||
|
|
||||||
|
|
||||||
var apiKeyProfileUserData = await clientProfile.GetCurrentUser();
|
var apiKeyProfileUserData = await clientProfile.GetCurrentUser();
|
||||||
@@ -149,6 +160,7 @@ namespace BTCPayServer.Tests
|
|||||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientInsufficient.GetCurrentUser());
|
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientInsufficient.GetCurrentUser());
|
||||||
await clientServer.GetCurrentUser();
|
await clientServer.GetCurrentUser();
|
||||||
await clientProfile.GetCurrentUser();
|
await clientProfile.GetCurrentUser();
|
||||||
|
await clientBasic.GetCurrentUser();
|
||||||
|
|
||||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientInsufficient.CreateUser(new CreateApplicationUserRequest()
|
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientInsufficient.CreateUser(new CreateApplicationUserRequest()
|
||||||
{
|
{
|
||||||
@@ -163,6 +175,13 @@ namespace BTCPayServer.Tests
|
|||||||
});
|
});
|
||||||
Assert.NotNull(newUser);
|
Assert.NotNull(newUser);
|
||||||
|
|
||||||
|
var newUser2 = await clientBasic.CreateUser(new CreateApplicationUserRequest()
|
||||||
|
{
|
||||||
|
Email = $"{Guid.NewGuid()}@g.com",
|
||||||
|
Password = Guid.NewGuid().ToString()
|
||||||
|
});
|
||||||
|
Assert.NotNull(newUser2);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientServer.CreateUser(new CreateApplicationUserRequest()
|
await Assert.ThrowsAsync<HttpRequestException>(async () => await clientServer.CreateUser(new CreateApplicationUserRequest()
|
||||||
{
|
{
|
||||||
Email = $"{Guid.NewGuid()}",
|
Email = $"{Guid.NewGuid()}",
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ namespace BTCPayServer.Tests
|
|||||||
IsAdmin = true;
|
IsAdmin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<BTCPayServerClient> CreateClient()
|
||||||
|
{
|
||||||
|
return new BTCPayServerClient(parent.PayTester.ServerUri, RegisterDetails.Email, RegisterDetails.Password);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<BTCPayServerClient> CreateClient(params string[] permissions)
|
public async Task<BTCPayServerClient> CreateClient(params string[] permissions)
|
||||||
{
|
{
|
||||||
var manageController = parent.PayTester.GetController<ManageController>(UserId, StoreId, IsAdmin);
|
var manageController = parent.PayTester.GetController<ManageController>(UserId, StoreId, IsAdmin);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace BTCPayServer.Controllers.RestApi
|
namespace BTCPayServer.Controllers.RestApi
|
||||||
{
|
{
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.ApiKeyOrBasic)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
|
||||||
public class ApiKeysController : ControllerBase
|
public class ApiKeysController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly APIKeyRepository _apiKeyRepository;
|
private readonly APIKeyRepository _apiKeyRepository;
|
||||||
@@ -33,7 +33,7 @@ namespace BTCPayServer.Controllers.RestApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("~/api/v1/api-keys/current")]
|
[HttpDelete("~/api/v1/api-keys/current")]
|
||||||
[Authorize(Policy = Policies.Unrestricted, AuthenticationSchemes = AuthenticationSchemes.ApiKeyOrBasic)]
|
[Authorize(Policy = Policies.Unrestricted, AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
|
||||||
public async Task<ActionResult<ApiKeyData>> RevokeKey()
|
public async Task<ActionResult<ApiKeyData>> RevokeKey()
|
||||||
{
|
{
|
||||||
ControllerContext.HttpContext.GetAPIKey(out var apiKey);
|
ControllerContext.HttpContext.GetAPIKey(out var apiKey);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace BTCPayServer.Controllers.RestApi
|
|||||||
|
|
||||||
// Even if subscription are unlocked, it is forbidden to create admin unauthenticated
|
// Even if subscription are unlocked, it is forbidden to create admin unauthenticated
|
||||||
if (anyAdmin && request.IsAdministrator is true && !isAuth)
|
if (anyAdmin && request.IsAdministrator is true && !isAuth)
|
||||||
return Forbid(AuthenticationSchemes.ApiKeyOrBasic);
|
return Forbid(AuthenticationSchemes.ApiKey, AuthenticationSchemes.Basic);
|
||||||
// You are de-facto admin if there is no other admin, else you need to be auth and pass policy requirements
|
// You are de-facto admin if there is no other admin, else you need to be auth and pass policy requirements
|
||||||
bool isAdmin = anyAdmin ? (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanModifyServerSettings))).Succeeded
|
bool isAdmin = anyAdmin ? (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanModifyServerSettings))).Succeeded
|
||||||
&& (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.Unrestricted))).Succeeded
|
&& (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.Unrestricted))).Succeeded
|
||||||
@@ -90,14 +90,14 @@ namespace BTCPayServer.Controllers.RestApi
|
|||||||
: true;
|
: true;
|
||||||
// You need to be admin to create an admin
|
// You need to be admin to create an admin
|
||||||
if (request.IsAdministrator is true && !isAdmin)
|
if (request.IsAdministrator is true && !isAdmin)
|
||||||
return Forbid(AuthenticationSchemes.ApiKeyOrBasic);
|
return Forbid(AuthenticationSchemes.ApiKey, AuthenticationSchemes.Basic);
|
||||||
|
|
||||||
if (!isAdmin && policies.LockSubscription)
|
if (!isAdmin && policies.LockSubscription)
|
||||||
{
|
{
|
||||||
// If we are not admin and subscriptions are locked, we need to check the Policies.CanCreateUser.Key permission
|
// If we are not admin and subscriptions are locked, we need to check the Policies.CanCreateUser.Key permission
|
||||||
var canCreateUser = (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanCreateUser))).Succeeded;
|
var canCreateUser = (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanCreateUser))).Succeeded;
|
||||||
if (!isAuth || !canCreateUser)
|
if (!isAuth || !canCreateUser)
|
||||||
return Forbid(AuthenticationSchemes.ApiKeyOrBasic);
|
return Forbid(AuthenticationSchemes.ApiKey, AuthenticationSchemes.Basic);
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = new ApplicationUser
|
var user = new ApplicationUser
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
public const string Bitpay = "Bitpay";
|
public const string Bitpay = "Bitpay";
|
||||||
public const string ApiKey = "GreenfieldApiKey";
|
public const string ApiKey = "GreenfieldApiKey";
|
||||||
public const string Basic = "Basic";
|
public const string Basic = "Basic";
|
||||||
public const string ApiKeyOrBasic = "Basic,GreenfieldApiKey";
|
public const string ApiKeyOrBasic = ApiKey + "," + Basic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,8 +209,7 @@
|
|||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"GreenField Authentication": [],
|
"GreenField Authentication": []
|
||||||
"Basic": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -234,8 +233,7 @@
|
|||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"GreenField Authentication": [ "unrestricted" ],
|
"GreenField Authentication": [ "unrestricted" ]
|
||||||
"Basic": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user