forked from Qortal/qortal
Added /render/authorize/{service}/{resourceId}* APIs
These allow the UI to pre-authorize a resource and therefore avoid having to pass a sensitive API key to a website or app.
This commit is contained in:
parent
d0000c6131
commit
b4f3105035
@ -25,6 +25,7 @@ import org.qortal.api.Security;
|
||||
import org.qortal.arbitrary.misc.Service;
|
||||
import org.qortal.arbitrary.*;
|
||||
import org.qortal.arbitrary.exception.MissingDataException;
|
||||
import org.qortal.controller.arbitrary.ArbitraryDataRenderManager;
|
||||
import org.qortal.data.transaction.ArbitraryTransactionData.*;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.settings.Settings;
|
||||
@ -94,11 +95,34 @@ public class RenderResource {
|
||||
return "Unable to generate preview URL";
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("authorize/{service}/{resourceId}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public boolean authorizeResource(@PathParam("service") Service service,
|
||||
@PathParam("resourceId") String resourceId) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
ArbitraryDataResource resource = new ArbitraryDataResource(resourceId, null, service, null);
|
||||
ArbitraryDataRenderManager.getInstance().addToAuthorizedResources(resource);
|
||||
return true;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("authorize/{service}/{resourceId}/{identifier}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public boolean authorizeResource(@PathParam("service") Service service,
|
||||
@PathParam("resourceId") String resourceId,
|
||||
@PathParam("identifier") String identifier) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
ArbitraryDataResource resource = new ArbitraryDataResource(resourceId, null, service, identifier);
|
||||
ArbitraryDataRenderManager.getInstance().addToAuthorizedResources(resource);
|
||||
return true;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/signature/{signature}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getIndexBySignature(@PathParam("signature") String signature) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
requirePriorAuthorization(signature, Service.WEBSITE, null);
|
||||
return this.get(signature, ResourceIdType.SIGNATURE, null, "/", null, "/render/signature", true, true);
|
||||
}
|
||||
|
||||
@ -106,7 +130,7 @@ public class RenderResource {
|
||||
@Path("/signature/{signature}/{path:.*}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getPathBySignature(@PathParam("signature") String signature, @PathParam("path") String inPath) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
requirePriorAuthorization(signature, Service.WEBSITE, null);
|
||||
return this.get(signature, ResourceIdType.SIGNATURE, null, inPath,null, "/render/signature", true, true);
|
||||
}
|
||||
|
||||
@ -114,7 +138,7 @@ public class RenderResource {
|
||||
@Path("/hash/{hash}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getIndexByHash(@PathParam("hash") String hash58, @QueryParam("secret") String secret58) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
requirePriorAuthorization(hash58, Service.WEBSITE, null);
|
||||
return this.get(hash58, ResourceIdType.FILE_HASH, Service.WEBSITE, "/", secret58, "/render/hash", true, false);
|
||||
}
|
||||
|
||||
@ -123,7 +147,7 @@ public class RenderResource {
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getPathByHash(@PathParam("hash") String hash58, @PathParam("path") String inPath,
|
||||
@QueryParam("secret") String secret58) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
requirePriorAuthorization(hash58, Service.WEBSITE, null);
|
||||
return this.get(hash58, ResourceIdType.FILE_HASH, Service.WEBSITE, inPath, secret58, "/render/hash", true, false);
|
||||
}
|
||||
|
||||
@ -133,7 +157,7 @@ public class RenderResource {
|
||||
public HttpServletResponse getPathByName(@PathParam("service") Service service,
|
||||
@PathParam("name") String name,
|
||||
@PathParam("path") String inPath) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
requirePriorAuthorization(name, service, null);
|
||||
String prefix = String.format("/render/%s", service);
|
||||
return this.get(name, ResourceIdType.NAME, service, inPath, null, prefix, true, true);
|
||||
}
|
||||
@ -143,7 +167,7 @@ public class RenderResource {
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getIndexByName(@PathParam("service") Service service,
|
||||
@PathParam("name") String name) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
requirePriorAuthorization(name, service, null);
|
||||
String prefix = String.format("/render/%s", service);
|
||||
return this.get(name, ResourceIdType.NAME, service, "/", null, prefix, true, true);
|
||||
}
|
||||
@ -176,4 +200,11 @@ public class RenderResource {
|
||||
return renderer.render();
|
||||
}
|
||||
|
||||
private void requirePriorAuthorization(String resourceId, Service service, String identifier) {
|
||||
ArbitraryDataResource resource = new ArbitraryDataResource(resourceId, null, service, identifier);
|
||||
if (!ArbitraryDataRenderManager.getInstance().isAuthorized(resource)) {
|
||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "Call /render/authorize first");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -113,7 +113,23 @@ public class ArbitraryDataResource {
|
||||
}
|
||||
}
|
||||
|
||||
private String resourceIdString() {
|
||||
return resourceId != null ? resourceId : "";
|
||||
}
|
||||
|
||||
private String resourceIdTypeString() {
|
||||
return resourceIdType != null ? resourceIdType.toString() : "";
|
||||
}
|
||||
|
||||
private String serviceString() {
|
||||
return service != null ? service.toString() : "";
|
||||
}
|
||||
|
||||
private String identifierString() {
|
||||
return identifier != null ? identifier : "";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s-%s-%s-%s", resourceIdString(), resourceIdTypeString(), serviceString(), identifierString());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package org.qortal.controller.arbitrary;
|
||||
|
||||
import org.qortal.arbitrary.ArbitraryDataFile;
|
||||
import org.qortal.arbitrary.ArbitraryDataResource;
|
||||
import org.qortal.arbitrary.misc.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ArbitraryDataRenderManager {
|
||||
|
||||
private static ArbitraryDataRenderManager instance;
|
||||
|
||||
/**
|
||||
* List to keep track of authorized resources for rendering.
|
||||
*/
|
||||
private List<ArbitraryDataResource> authorizedResources = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
|
||||
public ArbitraryDataRenderManager() {
|
||||
|
||||
}
|
||||
|
||||
public static ArbitraryDataRenderManager getInstance() {
|
||||
if (instance == null)
|
||||
instance = new ArbitraryDataRenderManager();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public boolean isAuthorized(ArbitraryDataResource resource) {
|
||||
for (ArbitraryDataResource authorizedResource : this.authorizedResources) {
|
||||
if (authorizedResource != null && resource != null) {
|
||||
if (Objects.equals(authorizedResource.toString(), resource.toString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addToAuthorizedResources(ArbitraryDataResource resource) {
|
||||
if (!this.isAuthorized(resource)) {
|
||||
this.authorizedResources.add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user