|
|
|
@ -331,70 +331,90 @@ public class ArbitraryResource {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@GET |
|
|
|
|
@Path("/{service}/{name}") |
|
|
|
|
@Path("/hosted/transactions") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Fetch raw data from file with supplied service, name, and relative path", |
|
|
|
|
description = "An optional rebuild boolean can be supplied. If true, any existing cached data will be invalidated.", |
|
|
|
|
summary = "List arbitrary transactions hosted by this node", |
|
|
|
|
responses = { |
|
|
|
|
@ApiResponse( |
|
|
|
|
description = "Path to file structure containing requested data", |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ArbitraryTransactionData.class)) |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public HttpServletResponse get(@PathParam("service") Service service, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@QueryParam("filepath") String filepath, |
|
|
|
|
@QueryParam("rebuild") boolean rebuild) { |
|
|
|
|
@ApiErrors({ApiError.REPOSITORY_ISSUE}) |
|
|
|
|
public List<ArbitraryTransactionData> getHostedTransactions() { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
return this.download(service, name, null, filepath, rebuild); |
|
|
|
|
try (final Repository repository = RepositoryManager.getRepository()) { |
|
|
|
|
|
|
|
|
|
List<ArbitraryTransactionData> hostedTransactions = ArbitraryDataStorageManager.getInstance().listAllHostedTransactions(repository); |
|
|
|
|
|
|
|
|
|
return hostedTransactions; |
|
|
|
|
|
|
|
|
|
} catch (DataException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@GET |
|
|
|
|
@Path("/{service}/{name}/{identifier}") |
|
|
|
|
@Path("/hosted/resources") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Fetch raw data from file with supplied service, name, identifier, and relative path", |
|
|
|
|
description = "An optional rebuild boolean can be supplied. If true, any existing cached data will be invalidated.", |
|
|
|
|
summary = "List arbitrary resources hosted by this node", |
|
|
|
|
responses = { |
|
|
|
|
@ApiResponse( |
|
|
|
|
description = "Path to file structure containing requested data", |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ArbitraryResourceInfo.class)) |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public HttpServletResponse get(@PathParam("service") Service service, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@PathParam("identifier") String identifier, |
|
|
|
|
@QueryParam("filepath") String filepath, |
|
|
|
|
@QueryParam("rebuild") boolean rebuild) { |
|
|
|
|
@ApiErrors({ApiError.REPOSITORY_ISSUE}) |
|
|
|
|
public List<ArbitraryResourceInfo> getHostedResources( |
|
|
|
|
@Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
return this.download(service, name, identifier, filepath, rebuild); |
|
|
|
|
List<ArbitraryResourceInfo> resources = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
try (final Repository repository = RepositoryManager.getRepository()) { |
|
|
|
|
|
|
|
|
|
List<ArbitraryTransactionData> transactionDataList = ArbitraryDataStorageManager.getInstance().listAllHostedTransactions(repository); |
|
|
|
|
for (ArbitraryTransactionData transactionData : transactionDataList) { |
|
|
|
|
ArbitraryTransaction transaction = new ArbitraryTransaction(repository, transactionData); |
|
|
|
|
if (transaction.isDataLocal()) { |
|
|
|
|
String name = transactionData.getName(); |
|
|
|
|
Service service = transactionData.getService(); |
|
|
|
|
String identifier = transactionData.getIdentifier(); |
|
|
|
|
|
|
|
|
|
if (transactionData.getName() != null) { |
|
|
|
|
List<ArbitraryResourceInfo> transactionResources = repository.getArbitraryRepository() |
|
|
|
|
.getArbitraryResources(service, identifier, name, (identifier == null), null, null, false); |
|
|
|
|
if (transactionResources != null) { |
|
|
|
|
resources.addAll(transactionResources); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (includeStatus != null && includeStatus == true) { |
|
|
|
|
resources = this.addStatusToResources(resources); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return resources; |
|
|
|
|
|
|
|
|
|
} catch (DataException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@POST |
|
|
|
|
@Path("/{service}/{name}") |
|
|
|
|
@Path("/compute") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on a user-supplied path", |
|
|
|
|
summary = "Compute nonce for raw, unsigned ARBITRARY transaction", |
|
|
|
|
requestBody = @RequestBody( |
|
|
|
|
required = true, |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string", example = "/Users/user/Documents/MyDirectoryOrFile" |
|
|
|
|
type = "string", |
|
|
|
|
description = "raw, unsigned ARBITRARY transaction in base58 encoding", |
|
|
|
|
example = "raw transaction base58" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
), |
|
|
|
@ -410,33 +430,59 @@ public class ArbitraryResource {
|
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.INVALID_DATA, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE}) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public String post(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
String path) { |
|
|
|
|
public String computeNonce(String rawBytes58) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
if (path == null || path.isEmpty()) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Path not supplied"); |
|
|
|
|
} |
|
|
|
|
try (final Repository repository = RepositoryManager.getRepository()) { |
|
|
|
|
byte[] rawBytes = Base58.decode(rawBytes58); |
|
|
|
|
// We're expecting unsigned transaction, so append empty signature prior to decoding
|
|
|
|
|
rawBytes = Bytes.concat(rawBytes, new byte[TransactionTransformer.SIGNATURE_LENGTH]); |
|
|
|
|
|
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, null, path, null, null); |
|
|
|
|
TransactionData transactionData = TransactionTransformer.fromBytes(rawBytes); |
|
|
|
|
if (transactionData == null) |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); |
|
|
|
|
|
|
|
|
|
if (transactionData.getType() != TransactionType.ARBITRARY) |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); |
|
|
|
|
|
|
|
|
|
ArbitraryTransaction arbitraryTransaction = (ArbitraryTransaction) Transaction.fromData(repository, transactionData); |
|
|
|
|
|
|
|
|
|
// Quicker validity check first before we compute nonce
|
|
|
|
|
ValidationResult result = arbitraryTransaction.isValid(); |
|
|
|
|
if (result != ValidationResult.OK) |
|
|
|
|
throw TransactionsResource.createTransactionInvalidException(request, result); |
|
|
|
|
|
|
|
|
|
LOGGER.info("Computing nonce..."); |
|
|
|
|
arbitraryTransaction.computeNonce(); |
|
|
|
|
|
|
|
|
|
// Re-check, but ignores signature
|
|
|
|
|
result = arbitraryTransaction.isValidUnconfirmed(); |
|
|
|
|
if (result != ValidationResult.OK) |
|
|
|
|
throw TransactionsResource.createTransactionInvalidException(request, result); |
|
|
|
|
|
|
|
|
|
// Strip zeroed signature
|
|
|
|
|
transactionData.setSignature(null); |
|
|
|
|
|
|
|
|
|
byte[] bytes = ArbitraryTransactionTransformer.toBytes(transactionData); |
|
|
|
|
return Base58.encode(bytes); |
|
|
|
|
} catch (TransformationException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); |
|
|
|
|
} catch (DataException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@POST |
|
|
|
|
@Path("/{service}/{name}/base64") |
|
|
|
|
|
|
|
|
|
@GET |
|
|
|
|
@Path("/{service}/{name}") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on user-supplied base64 encoded data", |
|
|
|
|
requestBody = @RequestBody( |
|
|
|
|
required = true, |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.APPLICATION_OCTET_STREAM, |
|
|
|
|
schema = @Schema(type = "string", format = "byte") |
|
|
|
|
) |
|
|
|
|
), |
|
|
|
|
summary = "Fetch raw data from file with supplied service, name, and relative path", |
|
|
|
|
description = "An optional rebuild boolean can be supplied. If true, any existing cached data will be invalidated.", |
|
|
|
|
responses = { |
|
|
|
|
@ApiResponse( |
|
|
|
|
description = "raw, unsigned, ARBITRARY transaction encoded in Base58", |
|
|
|
|
description = "Path to file structure containing requested data", |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
@ -447,28 +493,57 @@ public class ArbitraryResource {
|
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public String postBase64EncodedData(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
String base64) { |
|
|
|
|
public HttpServletResponse get(@PathParam("service") Service service, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@QueryParam("filepath") String filepath, |
|
|
|
|
@QueryParam("rebuild") boolean rebuild) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
if (base64 == null) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data not supplied"); |
|
|
|
|
} |
|
|
|
|
return this.download(service, name, null, filepath, rebuild); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, null, null, null, base64); |
|
|
|
|
@GET |
|
|
|
|
@Path("/{service}/{name}/{identifier}") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Fetch raw data from file with supplied service, name, identifier, and relative path", |
|
|
|
|
description = "An optional rebuild boolean can be supplied. If true, any existing cached data will be invalidated.", |
|
|
|
|
responses = { |
|
|
|
|
@ApiResponse( |
|
|
|
|
description = "Path to file structure containing requested data", |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public HttpServletResponse get(@PathParam("service") Service service, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@PathParam("identifier") String identifier, |
|
|
|
|
@QueryParam("filepath") String filepath, |
|
|
|
|
@QueryParam("rebuild") boolean rebuild) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
return this.download(service, name, identifier, filepath, rebuild); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Upload data at supplied path
|
|
|
|
|
|
|
|
|
|
@POST |
|
|
|
|
@Path("/{service}/{name}/string") |
|
|
|
|
@Path("/{service}/{name}") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on a user-supplied string", |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on a user-supplied path", |
|
|
|
|
requestBody = @RequestBody( |
|
|
|
|
required = true, |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string", example = "{\"title\":\"\", \"description\":\"\", \"tags\":[]}" |
|
|
|
|
type = "string", example = "/Users/user/Documents/MyDirectoryOrFile" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
), |
|
|
|
@ -485,19 +560,18 @@ public class ArbitraryResource {
|
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public String postString(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
String string) { |
|
|
|
|
public String post(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
String path) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
if (string == null || string.isEmpty()) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data string not supplied"); |
|
|
|
|
if (path == null || path.isEmpty()) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Path not supplied"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, null, null, string, null); |
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, null, path, null, null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@POST |
|
|
|
|
@Path("/{service}/{name}/{identifier}") |
|
|
|
|
@Operation( |
|
|
|
@ -537,17 +611,19 @@ public class ArbitraryResource {
|
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, identifier, path, null, null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Upload base64-encoded data
|
|
|
|
|
|
|
|
|
|
@POST |
|
|
|
|
@Path("/{service}/{name}/{identifier}/string") |
|
|
|
|
@Path("/{service}/{name}/base64") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on user supplied string", |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on user-supplied base64 encoded data", |
|
|
|
|
requestBody = @RequestBody( |
|
|
|
|
required = true, |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string", example = "{\"title\":\"\", \"description\":\"\", \"tags\":[]}" |
|
|
|
|
) |
|
|
|
|
mediaType = MediaType.APPLICATION_OCTET_STREAM, |
|
|
|
|
schema = @Schema(type = "string", format = "byte") |
|
|
|
|
) |
|
|
|
|
), |
|
|
|
|
responses = { |
|
|
|
@ -563,17 +639,16 @@ public class ArbitraryResource {
|
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public String postString(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@PathParam("identifier") String identifier, |
|
|
|
|
String string) { |
|
|
|
|
public String postBase64EncodedData(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
String base64) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
if (string == null || string.isEmpty()) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data string not supplied"); |
|
|
|
|
if (base64 == null) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data not supplied"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, identifier, null, string, null); |
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, null, null, null, base64); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@POST |
|
|
|
@ -601,9 +676,9 @@ public class ArbitraryResource {
|
|
|
|
|
) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public String postBase64EncodedData(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@PathParam("identifier") String identifier, |
|
|
|
|
String base64) { |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@PathParam("identifier") String identifier, |
|
|
|
|
String base64) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
if (base64 == null) { |
|
|
|
@ -613,91 +688,58 @@ public class ArbitraryResource {
|
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, identifier, null, null, base64); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@GET |
|
|
|
|
@Path("/hosted/transactions") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "List arbitrary transactions hosted by this node", |
|
|
|
|
responses = { |
|
|
|
|
@ApiResponse( |
|
|
|
|
content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ArbitraryTransactionData.class)) |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@ApiErrors({ApiError.REPOSITORY_ISSUE}) |
|
|
|
|
public List<ArbitraryTransactionData> getHostedTransactions() { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
try (final Repository repository = RepositoryManager.getRepository()) { |
|
|
|
|
|
|
|
|
|
List<ArbitraryTransactionData> hostedTransactions = ArbitraryDataStorageManager.getInstance().listAllHostedTransactions(repository); |
|
|
|
|
|
|
|
|
|
return hostedTransactions; |
|
|
|
|
|
|
|
|
|
} catch (DataException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Upload plain-text data in string form
|
|
|
|
|
|
|
|
|
|
@GET |
|
|
|
|
@Path("/hosted/resources") |
|
|
|
|
@POST |
|
|
|
|
@Path("/{service}/{name}/string") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "List arbitrary resources hosted by this node", |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on a user-supplied string", |
|
|
|
|
requestBody = @RequestBody( |
|
|
|
|
required = true, |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string", example = "{\"title\":\"\", \"description\":\"\", \"tags\":[]}" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
), |
|
|
|
|
responses = { |
|
|
|
|
@ApiResponse( |
|
|
|
|
content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ArbitraryResourceInfo.class)) |
|
|
|
|
description = "raw, unsigned, ARBITRARY transaction encoded in Base58", |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@ApiErrors({ApiError.REPOSITORY_ISSUE}) |
|
|
|
|
public List<ArbitraryResourceInfo> getHostedResources( |
|
|
|
|
@Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus) { |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public String postString(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
String string) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
List<ArbitraryResourceInfo> resources = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
try (final Repository repository = RepositoryManager.getRepository()) { |
|
|
|
|
|
|
|
|
|
List<ArbitraryTransactionData> transactionDataList = ArbitraryDataStorageManager.getInstance().listAllHostedTransactions(repository); |
|
|
|
|
for (ArbitraryTransactionData transactionData : transactionDataList) { |
|
|
|
|
ArbitraryTransaction transaction = new ArbitraryTransaction(repository, transactionData); |
|
|
|
|
if (transaction.isDataLocal()) { |
|
|
|
|
String name = transactionData.getName(); |
|
|
|
|
Service service = transactionData.getService(); |
|
|
|
|
String identifier = transactionData.getIdentifier(); |
|
|
|
|
|
|
|
|
|
if (transactionData.getName() != null) { |
|
|
|
|
List<ArbitraryResourceInfo> transactionResources = repository.getArbitraryRepository() |
|
|
|
|
.getArbitraryResources(service, identifier, name, (identifier == null), null, null, false); |
|
|
|
|
if (transactionResources != null) { |
|
|
|
|
resources.addAll(transactionResources); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (includeStatus != null && includeStatus == true) { |
|
|
|
|
resources = this.addStatusToResources(resources); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return resources; |
|
|
|
|
|
|
|
|
|
} catch (DataException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); |
|
|
|
|
if (string == null || string.isEmpty()) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data string not supplied"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, null, null, string, null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@POST |
|
|
|
|
@Path("/compute") |
|
|
|
|
@Path("/{service}/{name}/{identifier}/string") |
|
|
|
|
@Operation( |
|
|
|
|
summary = "Compute nonce for raw, unsigned ARBITRARY transaction", |
|
|
|
|
summary = "Build raw, unsigned, ARBITRARY transaction, based on user supplied string", |
|
|
|
|
requestBody = @RequestBody( |
|
|
|
|
required = true, |
|
|
|
|
content = @Content( |
|
|
|
|
mediaType = MediaType.TEXT_PLAIN, |
|
|
|
|
schema = @Schema( |
|
|
|
|
type = "string", |
|
|
|
|
description = "raw, unsigned ARBITRARY transaction in base58 encoding", |
|
|
|
|
example = "raw transaction base58" |
|
|
|
|
type = "string", example = "{\"title\":\"\", \"description\":\"\", \"tags\":[]}" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
), |
|
|
|
@ -713,49 +755,22 @@ public class ArbitraryResource {
|
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.INVALID_DATA, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE}) |
|
|
|
|
@SecurityRequirement(name = "apiKey") |
|
|
|
|
public String computeNonce(String rawBytes58) { |
|
|
|
|
public String postString(@PathParam("service") String serviceString, |
|
|
|
|
@PathParam("name") String name, |
|
|
|
|
@PathParam("identifier") String identifier, |
|
|
|
|
String string) { |
|
|
|
|
Security.checkApiCallAllowed(request); |
|
|
|
|
|
|
|
|
|
try (final Repository repository = RepositoryManager.getRepository()) { |
|
|
|
|
byte[] rawBytes = Base58.decode(rawBytes58); |
|
|
|
|
// We're expecting unsigned transaction, so append empty signature prior to decoding
|
|
|
|
|
rawBytes = Bytes.concat(rawBytes, new byte[TransactionTransformer.SIGNATURE_LENGTH]); |
|
|
|
|
|
|
|
|
|
TransactionData transactionData = TransactionTransformer.fromBytes(rawBytes); |
|
|
|
|
if (transactionData == null) |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); |
|
|
|
|
|
|
|
|
|
if (transactionData.getType() != TransactionType.ARBITRARY) |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); |
|
|
|
|
|
|
|
|
|
ArbitraryTransaction arbitraryTransaction = (ArbitraryTransaction) Transaction.fromData(repository, transactionData); |
|
|
|
|
|
|
|
|
|
// Quicker validity check first before we compute nonce
|
|
|
|
|
ValidationResult result = arbitraryTransaction.isValid(); |
|
|
|
|
if (result != ValidationResult.OK) |
|
|
|
|
throw TransactionsResource.createTransactionInvalidException(request, result); |
|
|
|
|
|
|
|
|
|
LOGGER.info("Computing nonce..."); |
|
|
|
|
arbitraryTransaction.computeNonce(); |
|
|
|
|
if (string == null || string.isEmpty()) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data string not supplied"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Re-check, but ignores signature
|
|
|
|
|
result = arbitraryTransaction.isValidUnconfirmed(); |
|
|
|
|
if (result != ValidationResult.OK) |
|
|
|
|
throw TransactionsResource.createTransactionInvalidException(request, result); |
|
|
|
|
return this.upload(Service.valueOf(serviceString), name, identifier, null, string, null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Strip zeroed signature
|
|
|
|
|
transactionData.setSignature(null); |
|
|
|
|
|
|
|
|
|
byte[] bytes = ArbitraryTransactionTransformer.toBytes(transactionData); |
|
|
|
|
return Base58.encode(bytes); |
|
|
|
|
} catch (TransformationException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); |
|
|
|
|
} catch (DataException e) { |
|
|
|
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Shared methods
|
|
|
|
|
|
|
|
|
|
private String upload(Service service, String name, String identifier, String path, String string, String base64) { |
|
|
|
|
// Fetch public key from registered name
|
|
|
|
|