Remove dependency on NSwag

This commit is contained in:
nicolas.dorier 2020-03-18 20:08:09 +09:00
parent 8d7b9fcef2
commit e351e0c9ea
No known key found for this signature in database
GPG Key ID: 6618763EF09186FE
13 changed files with 504 additions and 166 deletions

View File

@ -24,6 +24,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.13" />
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" /> <PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="80.0.3987.10600" /> <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="80.0.3987.10600" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />

View File

@ -61,6 +61,7 @@ using NBXplorer.DerivationStrategy;
using BTCPayServer.U2F.Models; using BTCPayServer.U2F.Models;
using BTCPayServer.Security.Bitpay; using BTCPayServer.Security.Bitpay;
using MemoryCache = Microsoft.Extensions.Caching.Memory.MemoryCache; using MemoryCache = Microsoft.Extensions.Caching.Memory.MemoryCache;
using Newtonsoft.Json.Schema;
namespace BTCPayServer.Tests namespace BTCPayServer.Tests
{ {
@ -90,6 +91,20 @@ namespace BTCPayServer.Tests
await Task.WhenAll(checkLinks); await Task.WhenAll(checkLinks);
} }
[Fact]
[Trait("Fast", "Fast")]
public async Task CheckSwaggerIsConformToSchema()
{
JObject swagger = JObject.Parse(File.ReadAllText(Path.Combine(TestUtils.TryGetSolutionDirectoryInfo().FullName, "BTCPayServer", "wwwroot", "swagger", "v1", "swagger.template.json")));
using HttpClient client = new HttpClient();
var resp = await client.GetAsync("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/schemas/v3.0/schema.json");
var schema = JSchema.Parse(await resp.Content.ReadAsStringAsync());
IList<ValidationError> errors;
bool valid = swagger.IsValid(schema, out errors);
Assert.Empty(errors);
Assert.True(valid);
}
private static async Task CheckLinks(Regex regex, HttpClient httpClient, string file) private static async Task CheckLinks(Regex regex, HttpClient httpClient, string file)
{ {
List<Task> checkLinks = new List<Task>(); List<Task> checkLinks = new List<Task>();
@ -2766,7 +2781,6 @@ noninventoryitem:
.Select(p => (ExpectedName: p.Key, ResultAsync: p.Value.GetRatesAsync(default), Fetcher: (BackgroundFetcherRateProvider)p.Value)) .Select(p => (ExpectedName: p.Key, ResultAsync: p.Value.GetRatesAsync(default), Fetcher: (BackgroundFetcherRateProvider)p.Value))
.ToList()) .ToList())
{ {
Logs.Tester.LogInformation($"Testing {result.ExpectedName}"); Logs.Tester.LogInformation($"Testing {result.ExpectedName}");
if (result.ExpectedName == "ndax") if (result.ExpectedName == "ndax")
{ {

View File

@ -48,7 +48,6 @@
<PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.3" /> <PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.3" />
<PackageReference Include="NicolasDorier.RateLimits" Version="1.1.0" /> <PackageReference Include="NicolasDorier.RateLimits" Version="1.1.0" />
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.18" /> <PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.18" />
<PackageReference Include="NSwag.AspNetCore" Version="13.2.2" />
<PackageReference Include="Serilog" Version="2.9.0" /> <PackageReference Include="Serilog" Version="2.9.0" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
@ -223,4 +222,6 @@
<ItemGroup> <ItemGroup>
<_ContentIncludedByDefault Remove="Views\Authorization\Authorize.cshtml" /> <_ContentIncludedByDefault Remove="Views\Authorization\Authorize.cshtml" />
</ItemGroup> </ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties wwwroot_4swagger_4v1_4swagger_1json__JsonSchema="https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/schemas/v3.0/schema.json" /></VisualStudio></ProjectExtensions>
</Project> </Project>

View File

@ -14,22 +14,30 @@ using BTCPayServer.HostedServices;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using BTCPayServer.Data; using BTCPayServer.Data;
using Microsoft.Extensions.FileProviders;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authorization;
using BTCPayServer.Security;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
{ {
public class HomeController : Controller public class HomeController : Controller
{ {
private readonly CssThemeManager _cachedServerSettings; private readonly CssThemeManager _cachedServerSettings;
private readonly IFileProvider _fileProvider;
public IHttpClientFactory HttpClientFactory { get; } public IHttpClientFactory HttpClientFactory { get; }
SignInManager<ApplicationUser> SignInManager { get; } SignInManager<ApplicationUser> SignInManager { get; }
public HomeController(IHttpClientFactory httpClientFactory, public HomeController(IHttpClientFactory httpClientFactory,
CssThemeManager cachedServerSettings, CssThemeManager cachedServerSettings,
IWebHostEnvironment webHostEnvironment,
SignInManager<ApplicationUser> signInManager) SignInManager<ApplicationUser> signInManager)
{ {
HttpClientFactory = httpClientFactory; HttpClientFactory = httpClientFactory;
_cachedServerSettings = cachedServerSettings; _cachedServerSettings = cachedServerSettings;
_fileProvider = webHostEnvironment.WebRootFileProvider;
SignInManager = signInManager; SignInManager = signInManager;
} }
@ -105,6 +113,26 @@ namespace BTCPayServer.Controllers
return View(new BitpayTranslatorViewModel()); return View(new BitpayTranslatorViewModel());
} }
[Route("swagger/v1/swagger.json")]
public async Task<IActionResult> Swagger()
{
var fi = _fileProvider.GetFileInfo("swagger/v1/swagger.template.json");
using var stream = fi.CreateReadStream();
using var reader = new StreamReader(fi.CreateReadStream());
var json = JObject.Parse(await reader.ReadToEndAsync());
var servers = new JArray();
servers.Add(new JObject(new JProperty("url", HttpContext.Request.GetAbsoluteRoot())));
json["servers"] = servers;
return Json(json);
}
[Route("docs")]
public IActionResult SwaggerDocs()
{
return View();
}
[HttpPost] [HttpPost]
[Route("translate")] [Route("translate")]
public async Task<IActionResult> BitpayTranslator(BitpayTranslatorViewModel vm) public async Task<IActionResult> BitpayTranslator(BitpayTranslatorViewModel vm)

View File

@ -5,7 +5,6 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Hosting.OpenApi;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Security.APIKeys; using BTCPayServer.Security.APIKeys;
@ -13,7 +12,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NBitcoin; using NBitcoin;
using NBitcoin.DataEncoders; using NBitcoin.DataEncoders;
using NSwag.Annotations;
using YamlDotNet.Core.Tokens; using YamlDotNet.Core.Tokens;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
@ -82,15 +80,7 @@ namespace BTCPayServer.Controllers
return View("AddApiKey", await SetViewModelValues(new AddApiKeyViewModel())); return View("AddApiKey", await SetViewModelValues(new AddApiKeyViewModel()));
} }
/// <param name="permissions">The permissions to request. Current permissions available: ServerManagement, StoreManagement</param>
/// <param name="applicationName">The name of your application</param>
/// <param name="strict">If permissions are specified, and strict is set to false, it will allow the user to reject some of permissions the application is requesting.</param>
/// <param name="selectiveStores">If the application is requesting the CanModifyStoreSettings permission and selectiveStores is set to true, this allows the user to only grant permissions to selected stores under the user's control.</param>
[HttpGet("~/api-keys/authorize")] [HttpGet("~/api-keys/authorize")]
[OpenApiTags("Authorization")]
[OpenApiOperation("Authorize User",
"Redirect the browser to this endpoint to request the user to generate an api-key with specific permissions")]
[IncludeInOpenApiDocs]
public async Task<IActionResult> AuthorizeAPIKey(string[] permissions, string applicationName = null, public async Task<IActionResult> AuthorizeAPIKey(string[] permissions, string applicationName = null,
bool strict = true, bool selectiveStores = false) bool strict = true, bool selectiveStores = false)
{ {

View File

@ -1,20 +1,16 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Hosting.OpenApi;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Security.APIKeys; using BTCPayServer.Security.APIKeys;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
namespace BTCPayServer.Controllers.RestApi.ApiKeys namespace BTCPayServer.Controllers.RestApi.ApiKeys
{ {
[ApiController] [ApiController]
[IncludeInOpenApiDocs]
[OpenApiTags("API Keys")]
[Authorize(AuthenticationSchemes = AuthenticationSchemes.ApiKey)] [Authorize(AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
public class ApiKeysController : ControllerBase public class ApiKeysController : ControllerBase
{ {
@ -27,9 +23,6 @@ namespace BTCPayServer.Controllers.RestApi.ApiKeys
_userManager = userManager; _userManager = userManager;
} }
[OpenApiOperation("Get current API Key information", "View information about the current API key")]
[SwaggerResponse(StatusCodes.Status200OK, typeof(ApiKeyData),
Description = "Information about the current api key")]
[HttpGet("~/api/v1/api-keys/current")] [HttpGet("~/api/v1/api-keys/current")]
[HttpGet("~/api/v1/users/me/api-keys/current")] [HttpGet("~/api/v1/users/me/api-keys/current")]
public async Task<ActionResult<ApiKeyData>> GetKey() public async Task<ActionResult<ApiKeyData>> GetKey()
@ -38,10 +31,7 @@ namespace BTCPayServer.Controllers.RestApi.ApiKeys
var data = await _apiKeyRepository.GetKey(apiKey); var data = await _apiKeyRepository.GetKey(apiKey);
return Ok(FromModel(data)); return Ok(FromModel(data));
} }
[OpenApiOperation("Revoke the current API Key", "Revoke the current API key so that it cannot be used anymore")]
[SwaggerResponse(StatusCodes.Status200OK, typeof(ApiKeyData),
Description = "The key was revoked and is no longer usable")]
[HttpDelete("~/api/v1/api-keys/current")] [HttpDelete("~/api/v1/api-keys/current")]
[HttpDelete("~/api/v1/users/me/api-keys/current")] [HttpDelete("~/api/v1/users/me/api-keys/current")]
public async Task<ActionResult<ApiKeyData>> RevokeKey() public async Task<ActionResult<ApiKeyData>> RevokeKey()

View File

@ -5,7 +5,6 @@ using BTCPayServer.Client.Models;
using BTCPayServer.Configuration; using BTCPayServer.Configuration;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.Hosting.OpenApi;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Services; using BTCPayServer.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -13,13 +12,10 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using NSwag.Annotations;
namespace BTCPayServer.Controllers.RestApi.Users namespace BTCPayServer.Controllers.RestApi.Users
{ {
[ApiController] [ApiController]
[IncludeInOpenApiDocs]
[OpenApiTags("Users")]
[Authorize(AuthenticationSchemes = AuthenticationSchemes.ApiKey)] [Authorize(AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
public class UsersController : ControllerBase public class UsersController : ControllerBase
{ {
@ -40,9 +36,6 @@ namespace BTCPayServer.Controllers.RestApi.Users
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
} }
[OpenApiOperation("Get current user information", "View information about the current user")]
[SwaggerResponse(StatusCodes.Status200OK, typeof(ApplicationUserData),
Description = "Information about the current user")]
[Authorize(Policy = Policies.CanModifyProfile.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)] [Authorize(Policy = Policies.CanModifyProfile.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
[HttpGet("~/api/v1/users/me")] [HttpGet("~/api/v1/users/me")]
public async Task<ActionResult<ApplicationUserData>> GetCurrentUser() public async Task<ActionResult<ApplicationUserData>> GetCurrentUser()
@ -51,13 +44,6 @@ namespace BTCPayServer.Controllers.RestApi.Users
return FromModel(user); return FromModel(user);
} }
[OpenApiOperation("Create user", "Create a new user")]
[SwaggerResponse(StatusCodes.Status201Created, typeof(ApplicationUserData),
Description = "Information about the new user")]
[SwaggerResponse(StatusCodes.Status422UnprocessableEntity, typeof(ValidationProblemDetails),
Description = "A list of validation errors that occurred")]
[SwaggerResponse(StatusCodes.Status400BadRequest, typeof(ValidationProblemDetails),
Description = "A list of errors that occurred when creating the user")]
[Authorize(Policy = Policies.CanCreateUser.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)] [Authorize(Policy = Policies.CanCreateUser.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
[HttpPost("~/api/v1/users")] [HttpPost("~/api/v1/users")]
public async Task<ActionResult<ApplicationUserData>> CreateUser(CreateApplicationUserRequest request) public async Task<ActionResult<ApplicationUserData>> CreateUser(CreateApplicationUserRequest request)

View File

@ -26,7 +26,6 @@ using System.Threading;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
using BTCPayServer.Logging; using BTCPayServer.Logging;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Hosting.OpenApi;
using BTCPayServer.PaymentRequest; using BTCPayServer.PaymentRequest;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin; using BTCPayServer.Payments.Bitcoin;
@ -264,8 +263,6 @@ namespace BTCPayServer.Hosting
} }
return rateLimits; return rateLimits;
}); });
services.AddBTCPayOpenApi();
services.AddLogging(logBuilder => services.AddLogging(logBuilder =>
{ {
var debugLogFile = BTCPayServerOptions.GetDebugLog(configuration); var debugLogFile = BTCPayServerOptions.GetDebugLog(configuration);

View File

@ -1,9 +0,0 @@
using System;
namespace BTCPayServer.Hosting.OpenApi
{
public class IncludeInOpenApiDocs : Attribute
{
}
}

View File

@ -1,115 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Configuration;
using BTCPayServer.Data;
using BTCPayServer.Payments;
using BTCPayServer.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using NJsonSchema;
using NJsonSchema.Generation.TypeMappers;
using NSwag;
using NSwag.Generation.Processors.Security;
using Org.BouncyCastle.Asn1.Ocsp;
namespace BTCPayServer.Hosting.OpenApi
{
public static class OpenApiExtensions
{
public static IServiceCollection AddBTCPayOpenApi(this IServiceCollection serviceCollection)
{
return serviceCollection.AddOpenApiDocument(config =>
{
config.PostProcess = document =>
{
document.Info.Version = "v1";
document.Info.Title = "BTCPay Greenfield API";
document.Info.Description = "A full API to use your BTCPay Server";
document.Info.TermsOfService = null;
document.Info.Contact = new NSwag.OpenApiContact
{
Name = "BTCPay Server", Email = string.Empty, Url = "https://btcpayserver.org"
};
};
config.AddOperationFilter(context =>
{
var methodInfo = context.MethodInfo;
if (methodInfo != null)
{
return methodInfo.CustomAttributes.Any(data =>
data.AttributeType == typeof(IncludeInOpenApiDocs)) ||
methodInfo.DeclaringType.CustomAttributes.Any(data =>
data.AttributeType == typeof(IncludeInOpenApiDocs));
}
return false;
});
config.AddSecurity("APIKey", Enumerable.Empty<string>(),
new OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
In = OpenApiSecurityApiKeyLocation.Header,
Description =
"BTCPay Server supports authenticating and authorizing users through an API Key that is generated by them. Send the API Key as a header value to Authorization with the format: token {token}. For a smoother experience, you can generate a url that redirects users to an API key creation screen."
});
config.OperationProcessors.Add(
new BTCPayPolicyOperationProcessor("APIKey", AuthenticationSchemes.ApiKey));
config.TypeMappers.Add(
new PrimitiveTypeMapper(typeof(PaymentType), s => s.Type = JsonObjectType.String));
config.TypeMappers.Add(new PrimitiveTypeMapper(typeof(PaymentMethodId),
s => s.Type = JsonObjectType.String));
});
}
public static IApplicationBuilder UseBTCPayOpenApi(this IApplicationBuilder builder)
{
var roothPath = builder.ApplicationServices.GetService<BTCPayServerOptions>().RootPath;
var matched = new PathString($"{roothPath}docs");
return builder.UseOpenApi()
.Use(async (context, next) =>
{
if (context.Request.Path.StartsWithSegments(matched, StringComparison.InvariantCultureIgnoreCase) && !context.User.Claims.Any())
{
context.Response.Redirect( $"{context.Request.GetRelativePath(roothPath)}account/login?returnUrl={context.Request.Path}");
return;
}
await next.Invoke();
})
.UseReDoc(settings =>
{
settings.Path = "/docs";
});
}
class BTCPayPolicyOperationProcessor : AspNetCoreOperationSecurityScopeProcessor
{
private readonly string _authScheme;
public BTCPayPolicyOperationProcessor(string x, string authScheme) : base(x)
{
_authScheme = authScheme;
}
protected override IEnumerable<string> GetScopes(IEnumerable<AuthorizeAttribute> authorizeAttributes)
{
var result = authorizeAttributes
.Where(attribute => attribute?.AuthenticationSchemes != null && attribute.Policy != null &&
attribute.AuthenticationSchemes.Equals(_authScheme,
StringComparison.InvariantCultureIgnoreCase))
.Select(attribute => attribute.Policy);
return result;
}
}
}
}

View File

@ -19,7 +19,6 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using BTCPayServer.Security; using BTCPayServer.Security;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using System.Net; using System.Net;
using BTCPayServer.Hosting.OpenApi;
using BTCPayServer.PaymentRequest; using BTCPayServer.PaymentRequest;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Storage; using BTCPayServer.Storage;
@ -194,7 +193,6 @@ namespace BTCPayServer.Hosting
app.UseProviderStorage(options); app.UseProviderStorage(options);
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
app.UseBTCPayOpenApi();
app.UseSession(); app.UseSession();
app.UseWebSockets(); app.UseWebSockets();

View File

@ -0,0 +1,27 @@
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>ReDoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<!--
ReDoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url="@Url.ActionLink("Swagger")"></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc@2.0.0-rc.24/bundles/redoc.standalone.js" integrity="sha384-ZO+OTQZMsYIcoraCBa8iJW/5b2O8K1ujHmRfOwSvpVBlHUeKq5t3/kh1p8JQJ99X" crossorigin="anonymous"></script>
</body>
</html>

View File

@ -0,0 +1,430 @@
{
"openapi": "3.0.0",
"info": {
"title": "BTCPay Greenfield API",
"description": "A full API to use your BTCPay Server",
"contact": {
"name": "BTCPay Server",
"url": "https://btcpayserver.org",
"email": "nicolas.dorier@gmail.com"
},
"version": "v1"
},
"servers": [
],
"paths": {
"/api-keys/authorize": {
"get": {
"tags": [
"Authorization"
],
"summary": "Authorize User",
"description": "Redirect the browser to this endpoint to request the user to generate an api-key with specific permissions",
"operationId": "Manage_AuthorizeAPIKey",
"parameters": [
{
"name": "permissions",
"description": "The permissions to request. Current permissions available: ServerManagement, StoreManagement",
"in": "query",
"style": "form",
"explode": true,
"schema": {
"type": "array",
"nullable": true,
"items": {
"type": "string"
}
},
"x-position": 1
},
{
"name": "applicationName",
"description": "The name of your application",
"in": "query",
"schema": {
"type": "string",
"nullable": true
},
"x-position": 2
},
{
"name": "strict",
"description": "If permissions are specified, and strict is set to false, it will allow the user to reject some of permissions the application is requesting.",
"in": "query",
"schema": {
"type": "boolean",
"default": true
},
"x-position": 3
},
{
"name": "selectiveStores",
"description": "If the application is requesting the CanModifyStoreSettings permission and selectiveStores is set to true, this allows the user to only grant permissions to selected stores under the user's control.",
"in": "query",
"schema": {
"type": "boolean",
"default": false
},
"x-position": 4
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
},
"security": [
{
"APIKey": []
}
]
}
},
"/api/v1/users/me": {
"get": {
"tags": [
"Users"
],
"summary": "Get current user information",
"description": "View information about the current user",
"operationId": "Users_GetCurrentUser",
"responses": {
"200": {
"description": "Information about the current user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationUserData"
}
}
}
}
},
"security": [
{
"APIKey": [
"btcpay.store.canmodifyprofile"
]
}
]
}
},
"/api/v1/users": {
"post": {
"tags": [
"Users"
],
"summary": "Create user",
"description": "Create a new user",
"operationId": "Users_CreateUser",
"requestBody": {
"x-name": "request",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"email": {
"type": "string",
"nullable": true
},
"password": {
"type": "string",
"nullable": true
},
"isAdministrator": {
"type": "boolean",
"nullable": true
},
"emailConfirmed": {
"type": "boolean",
"nullable": true
}
}
}
}
},
"required": true,
"x-position": 1
},
"responses": {
"201": {
"description": "Information about the new user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationUserData"
}
}
}
},
"422": {
"description": "A list of validation errors that occurred",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationProblemDetails"
}
}
}
},
"400": {
"description": "A list of errors that occurred when creating the user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidationProblemDetails"
}
}
}
}
},
"security": [
{
"APIKey": [
"btcpay.store.cancreateuser"
]
}
]
}
},
"/api/v1/api-keys/current": {
"get": {
"tags": [
"API Keys"
],
"summary": "Get current API Key information",
"description": "View information about the current API key",
"operationId": "ApiKeys_GetKey",
"responses": {
"200": {
"description": "Information about the current api key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiKeyData"
}
}
}
}
},
"security": [
{
"APIKey": []
}
]
},
"delete": {
"tags": [
"API Keys"
],
"summary": "Revoke the current API Key",
"description": "Revoke the current API key so that it cannot be used anymore",
"operationId": "ApiKeys_RevokeKey",
"responses": {
"200": {
"description": "The key was revoked and is no longer usable",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiKeyData"
}
}
}
}
},
"security": [
{
"APIKey": []
}
]
}
},
"/api/v1/users/me/api-keys/current": {
"get": {
"tags": [
"API Keys"
],
"summary": "Get current API Key information",
"description": "View information about the current API key",
"operationId": "ApiKeys_GetKey2",
"responses": {
"200": {
"description": "Information about the current api key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiKeyData"
}
}
}
}
},
"security": [
{
"APIKey": []
}
]
},
"delete": {
"tags": [
"API Keys"
],
"summary": "Revoke the current API Key",
"description": "Revoke the current API key so that it cannot be used anymore",
"operationId": "ApiKeys_RevokeKey2",
"responses": {
"200": {
"description": "The key was revoked and is no longer usable",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiKeyData"
}
}
}
}
},
"security": [
{
"APIKey": []
}
]
}
}
},
"components": {
"schemas": {
"ApplicationUserData": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"nullable": true
},
"email": {
"type": "string",
"nullable": true
},
"emailConfirmed": {
"type": "boolean"
},
"requiresEmailConfirmation": {
"type": "boolean"
}
}
},
"ValidationProblemDetails": {
"allOf": [
{
"$ref": "#/components/schemas/ProblemDetails"
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"errors": {
"type": "object",
"nullable": true,
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
]
},
"ProblemDetails": {
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"type": "integer",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
},
"extensions": {
"type": "object",
"nullable": true,
"additionalProperties": {}
}
}
},
"ApiKeyData": {
"type": "object",
"additionalProperties": false,
"properties": {
"apiKey": {
"type": "string",
"nullable": true
},
"label": {
"type": "string",
"nullable": true
},
"userId": {
"type": "string",
"nullable": true
},
"permissions": {
"type": "array",
"nullable": true,
"items": {
"type": "string"
}
}
}
}
},
"securitySchemes": {
"APIKey": {
"type": "apiKey",
"description": "BTCPay Server supports authenticating and authorizing users through an API Key that is generated by them. Send the API Key as a header value to Authorization with the format: token {token}. For a smoother experience, you can generate a url that redirects users to an API key creation screen.",
"name": "Authorization",
"in": "header"
}
}
},
"security": [
{
"APIKey": []
}
],
"tags": [
{
"name": "Users"
},
{
"name": "API Keys"
}
]
}