forked from Qortal/qortal
Add support for API key security, where X-API-KEY header must match apiKey from settings
apiKey in settings is null by default at this point, for backwards compatibility. In the future, the Windows installer could generate a UUID for apiKey. apiKey in settings needs to be at least 8 characters. API calls in the documentation engine are now marked with an open/closed padlock to show where API key might be required. Add support for API key security, where X-API-KEY header must match apiKey from settings apiKey in settings is null by default at this point, for backwards compatibility. In the future, the Windows installer could generate a UUID for apiKey. apiKey in settings needs to be at least 8 characters. API calls in the documentation engine are now marked with an open/closed padlock to show where API key might be required.
This commit is contained in:
parent
ad5050f92e
commit
41f178bf59
@ -5,10 +5,20 @@ import java.net.UnknownHostException;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
public class Security {
|
import org.qortal.settings.Settings;
|
||||||
|
|
||||||
|
public abstract class Security {
|
||||||
|
|
||||||
|
public static final String API_KEY_HEADER = "X-API-KEY";
|
||||||
|
|
||||||
// TODO: replace with proper authentication
|
|
||||||
public static void checkApiCallAllowed(HttpServletRequest request) {
|
public static void checkApiCallAllowed(HttpServletRequest request) {
|
||||||
|
String expectedApiKey = Settings.getInstance().getApiKey();
|
||||||
|
String passedApiKey = request.getHeader(API_KEY_HEADER);
|
||||||
|
|
||||||
|
if ((expectedApiKey != null && !expectedApiKey.equals(passedApiKey)) ||
|
||||||
|
(passedApiKey != null && !passedApiKey.equals(expectedApiKey)))
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.UNAUTHORIZED);
|
||||||
|
|
||||||
InetAddress remoteAddr;
|
InetAddress remoteAddr;
|
||||||
try {
|
try {
|
||||||
remoteAddr = InetAddress.getByName(request.getRemoteAddr());
|
remoteAddr = InetAddress.getByName(request.getRemoteAddr());
|
||||||
@ -19,4 +29,5 @@ public class Security {
|
|||||||
if (!remoteAddr.isLoopbackAddress())
|
if (!remoteAddr.isLoopbackAddress())
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.UNAUTHORIZED);
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Content;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -473,6 +474,7 @@ public class AddressesResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.INVALID_DATA, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.INVALID_DATA, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String computePublicize(String rawBytes58) {
|
public String computePublicize(String rawBytes58) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.media.Content;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -133,6 +134,7 @@ public class AdminResource {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public NodeStatus status() {
|
public NodeStatus status() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -153,6 +155,7 @@ public class AdminResource {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String shutdown() {
|
public String shutdown() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -181,6 +184,7 @@ public class AdminResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public ActivitySummary summary() {
|
public ActivitySummary summary() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -226,6 +230,7 @@ public class AdminResource {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public Controller.StatsSnapshot getEngineStats() {
|
public Controller.StatsSnapshot getEngineStats() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -244,6 +249,7 @@ public class AdminResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public List<MintingAccountData> getMintingAccounts() {
|
public List<MintingAccountData> getMintingAccounts() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -290,6 +296,7 @@ public class AdminResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.REPOSITORY_ISSUE, ApiError.CANNOT_MINT})
|
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.REPOSITORY_ISSUE, ApiError.CANNOT_MINT})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String addMintingAccount(String seed58) {
|
public String addMintingAccount(String seed58) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -342,6 +349,7 @@ public class AdminResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String deleteMintingAccount(String key58) {
|
public String deleteMintingAccount(String key58) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -441,6 +449,7 @@ public class AdminResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_HEIGHT, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_HEIGHT, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String orphan(String targetHeightString) {
|
public String orphan(String targetHeightString) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -482,6 +491,7 @@ public class AdminResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_DATA, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_DATA, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String forceSync(String targetPeerAddress) {
|
public String forceSync(String targetPeerAddress) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -527,6 +537,7 @@ public class AdminResource {
|
|||||||
description = "Requires enough free space to rebuild repository. This will pause your node for a while."
|
description = "Requires enough free space to rebuild repository. This will pause your node for a while."
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public void performRepositoryMaintenance() {
|
public void performRepositoryMaintenance() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
package org.qortal.api.resource;
|
package org.qortal.api.resource;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||||
import io.swagger.v3.oas.annotations.extensions.Extension;
|
import io.swagger.v3.oas.annotations.extensions.Extension;
|
||||||
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
|
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
|
||||||
import io.swagger.v3.oas.annotations.info.Info;
|
import io.swagger.v3.oas.annotations.info.Info;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecuritySchemes;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import org.qortal.api.Security;
|
||||||
|
|
||||||
@OpenAPIDefinition(
|
@OpenAPIDefinition(
|
||||||
info = @Info( title = "Qortal API", description = "NOTE: byte-arrays are encoded in Base58" ),
|
info = @Info( title = "Qortal API", description = "NOTE: byte-arrays are encoded in Base58" ),
|
||||||
tags = {
|
tags = {
|
||||||
@ -30,5 +36,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@SecuritySchemes({
|
||||||
|
@SecurityScheme(name = "basicAuth", type = SecuritySchemeType.HTTP, scheme = "basic"),
|
||||||
|
@SecurityScheme(name = "apiKey", type = SecuritySchemeType.APIKEY, in = SecuritySchemeIn.HEADER, paramName = Security.API_KEY_HEADER)
|
||||||
|
})
|
||||||
public class ApiDefinition {
|
public class ApiDefinition {
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Content;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -156,6 +157,7 @@ public class ChatResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String buildChat(ChatTransactionData transactionData) {
|
public String buildChat(ChatTransactionData transactionData) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -203,6 +205,7 @@ public class ChatResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.INVALID_DATA, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.INVALID_DATA, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String buildChat(String rawBytes58) {
|
public String buildChat(String rawBytes58) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Content;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -155,6 +156,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_DATA, ApiError.INVALID_REFERENCE, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_DATA, ApiError.INVALID_REFERENCE, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String buildTrade(CrossChainBuildRequest tradeRequest) {
|
public String buildTrade(CrossChainBuildRequest tradeRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -250,6 +252,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String buildTradeMessage(CrossChainTradeRequest tradeRequest) {
|
public String buildTradeMessage(CrossChainTradeRequest tradeRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -333,6 +336,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_DATA, ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_DATA, ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String buildRedeemMessage(CrossChainSecretRequest secretRequest) {
|
public String buildRedeemMessage(CrossChainSecretRequest secretRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -404,6 +408,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String buildCancelMessage(CrossChainCancelRequest cancelRequest) {
|
public String buildCancelMessage(CrossChainCancelRequest cancelRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -459,6 +464,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String deriveP2shA(CrossChainBitcoinTemplateRequest templateRequest) {
|
public String deriveP2shA(CrossChainBitcoinTemplateRequest templateRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -485,6 +491,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String deriveP2shB(CrossChainBitcoinTemplateRequest templateRequest) {
|
public String deriveP2shB(CrossChainBitcoinTemplateRequest templateRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -542,6 +549,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public CrossChainBitcoinP2SHStatus checkP2shA(CrossChainBitcoinTemplateRequest templateRequest) {
|
public CrossChainBitcoinP2SHStatus checkP2shA(CrossChainBitcoinTemplateRequest templateRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -568,6 +576,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public CrossChainBitcoinP2SHStatus checkP2shB(CrossChainBitcoinTemplateRequest templateRequest) {
|
public CrossChainBitcoinP2SHStatus checkP2shB(CrossChainBitcoinTemplateRequest templateRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -656,6 +665,7 @@ public class CrossChainResource {
|
|||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
||||||
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String refundP2shA(CrossChainBitcoinRefundRequest refundRequest) {
|
public String refundP2shA(CrossChainBitcoinRefundRequest refundRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -683,6 +693,7 @@ public class CrossChainResource {
|
|||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
||||||
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String refundP2shB(CrossChainBitcoinRefundRequest refundRequest) {
|
public String refundP2shB(CrossChainBitcoinRefundRequest refundRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -793,6 +804,7 @@ public class CrossChainResource {
|
|||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
||||||
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String redeemP2shA(CrossChainBitcoinRedeemRequest redeemRequest) {
|
public String redeemP2shA(CrossChainBitcoinRedeemRequest redeemRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -821,6 +833,7 @@ public class CrossChainResource {
|
|||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN,
|
||||||
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
ApiError.BTC_TOO_SOON, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String redeemP2shB(CrossChainBitcoinRedeemRequest redeemRequest) {
|
public String redeemP2shB(CrossChainBitcoinRedeemRequest redeemRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -935,6 +948,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY})
|
@ApiErrors({ApiError.INVALID_PRIVATE_KEY})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String getBitcoinWalletBalance(String xprv58) {
|
public String getBitcoinWalletBalance(String xprv58) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -969,6 +983,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA, ApiError.INVALID_ADDRESS, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE})
|
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA, ApiError.INVALID_ADDRESS, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String sendBitcoin(BitcoinSendRequest bitcoinSendRequest) {
|
public String sendBitcoin(BitcoinSendRequest bitcoinSendRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -1019,6 +1034,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public List<TradeBotData> getTradeBotStates() {
|
public List<TradeBotData> getTradeBotStates() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -1049,6 +1065,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String tradeBotCreator(TradeBotCreateRequest tradeBotCreateRequest) {
|
public String tradeBotCreator(TradeBotCreateRequest tradeBotCreateRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -1104,6 +1121,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_CRITERIA, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_PUBLIC_KEY, ApiError.INVALID_ADDRESS, ApiError.INVALID_CRITERIA, ApiError.BTC_BALANCE_ISSUE, ApiError.BTC_NETWORK_ISSUE, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String tradeBotResponder(TradeBotRespondRequest tradeBotRespondRequest) {
|
public String tradeBotResponder(TradeBotRespondRequest tradeBotRespondRequest) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -1168,6 +1186,7 @@ public class CrossChainResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String tradeBotDelete(String tradePrivateKey58) {
|
public String tradeBotDelete(String tradePrivateKey58) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Content;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@ -131,6 +132,7 @@ public class PeersResource {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public ExecuteProduceConsume.StatsSnapshot getEngineStats() {
|
public ExecuteProduceConsume.StatsSnapshot getEngineStats() {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -168,6 +170,7 @@ public class PeersResource {
|
|||||||
@ApiErrors({
|
@ApiErrors({
|
||||||
ApiError.INVALID_NETWORK_ADDRESS, ApiError.REPOSITORY_ISSUE
|
ApiError.INVALID_NETWORK_ADDRESS, ApiError.REPOSITORY_ISSUE
|
||||||
})
|
})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String addPeer(String address) {
|
public String addPeer(String address) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -222,6 +225,7 @@ public class PeersResource {
|
|||||||
@ApiErrors({
|
@ApiErrors({
|
||||||
ApiError.INVALID_NETWORK_ADDRESS, ApiError.REPOSITORY_ISSUE
|
ApiError.INVALID_NETWORK_ADDRESS, ApiError.REPOSITORY_ISSUE
|
||||||
})
|
})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String removePeer(String address) {
|
public String removePeer(String address) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -257,6 +261,7 @@ public class PeersResource {
|
|||||||
@ApiErrors({
|
@ApiErrors({
|
||||||
ApiError.REPOSITORY_ISSUE
|
ApiError.REPOSITORY_ISSUE
|
||||||
})
|
})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public String removeKnownPeers(String address) {
|
public String removeKnownPeers(String address) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
@ -296,6 +301,7 @@ public class PeersResource {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiErrors({ApiError.INVALID_DATA, ApiError.REPOSITORY_ISSUE})
|
@ApiErrors({ApiError.INVALID_DATA, ApiError.REPOSITORY_ISSUE})
|
||||||
|
@SecurityRequirement(name = "apiKey")
|
||||||
public List<BlockSummaryData> commonBlock(String targetPeerAddress) {
|
public List<BlockSummaryData> commonBlock(String targetPeerAddress) {
|
||||||
Security.checkApiCallAllowed(request);
|
Security.checkApiCallAllowed(request);
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ public class Settings {
|
|||||||
"::1", "127.0.0.1"
|
"::1", "127.0.0.1"
|
||||||
};
|
};
|
||||||
private Boolean apiRestricted;
|
private Boolean apiRestricted;
|
||||||
|
private String apiKey = null;
|
||||||
private boolean apiLoggingEnabled = false;
|
private boolean apiLoggingEnabled = false;
|
||||||
private boolean apiDocumentationEnabled = false;
|
private boolean apiDocumentationEnabled = false;
|
||||||
// Both of these need to be set for API to use SSL
|
// Both of these need to be set for API to use SSL
|
||||||
@ -275,6 +276,9 @@ public class Settings {
|
|||||||
// Validation goes here
|
// Validation goes here
|
||||||
if (this.minBlockchainPeers < 1)
|
if (this.minBlockchainPeers < 1)
|
||||||
throwValidationError("minBlockchainPeers must be at least 1");
|
throwValidationError("minBlockchainPeers must be at least 1");
|
||||||
|
|
||||||
|
if (this.apiKey != null && this.apiKey.trim().length() < 8)
|
||||||
|
throwValidationError("apiKey must be at least 8 characters");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters / setters
|
// Getters / setters
|
||||||
@ -323,6 +327,10 @@ public class Settings {
|
|||||||
return !BlockChain.getInstance().isTestChain();
|
return !BlockChain.getInstance().isTestChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getApiKey() {
|
||||||
|
return this.apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isApiLoggingEnabled() {
|
public boolean isApiLoggingEnabled() {
|
||||||
return this.apiLoggingEnabled;
|
return this.apiLoggingEnabled;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user