Skip to content

Commit 9ebc873

Browse files
committed
implement external-libraries API
(cherry picked from commit 99b526b)
1 parent c8da300 commit 9ebc873

3 files changed

Lines changed: 135 additions & 1 deletion

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Knowage, Open Source Business Intelligence suite
3+
* Copyright (C) 2021 Engineering Ingegneria Informatica S.p.A.
4+
*
5+
* Knowage is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* Knowage is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package it.eng.knowage.resourcemanager.resource;
19+
20+
import java.io.File;
21+
import java.io.IOException;
22+
import java.nio.file.Files;
23+
24+
import javax.activation.MimetypesFileTypeMap;
25+
import javax.ws.rs.GET;
26+
import javax.ws.rs.Path;
27+
import javax.ws.rs.Produces;
28+
import javax.ws.rs.QueryParam;
29+
import javax.ws.rs.core.MediaType;
30+
import javax.ws.rs.core.Response;
31+
32+
import org.springframework.beans.factory.annotation.Autowired;
33+
import org.springframework.stereotype.Component;
34+
35+
import it.eng.knowage.boot.context.BusinessRequestContext;
36+
import it.eng.knowage.boot.error.KnowageBusinessException;
37+
import it.eng.knowage.boot.error.KnowageRuntimeException;
38+
import it.eng.knowage.knowageapi.utils.PathTraversalChecker;
39+
import it.eng.knowage.resourcemanager.service.ResourceManagerAPI;
40+
import it.eng.spagobi.services.security.SpagoBIUserProfile;
41+
42+
@Path("/2.0/resources/external-libraries")
43+
@Component
44+
public class ExternalLibrariesResource {
45+
46+
@Autowired
47+
ResourceManagerAPI resourceManagerAPIservice;
48+
49+
@Autowired
50+
BusinessRequestContext businessContext;
51+
52+
@GET
53+
@Produces(MediaType.APPLICATION_OCTET_STREAM)
54+
public Response downloadExternalLibrary(@QueryParam("libraryName") String libraryName) throws KnowageBusinessException {
55+
if (libraryName == null || libraryName.trim().isEmpty()) {
56+
return Response.status(Response.Status.BAD_REQUEST).entity("Missing libraryName").build();
57+
}
58+
59+
String requestedLibraryName = libraryName.trim();
60+
try {
61+
PathTraversalChecker.isValidFileName(requestedLibraryName);
62+
} catch (KnowageRuntimeException e) {
63+
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid libraryName").build();
64+
}
65+
66+
SpagoBIUserProfile profile = businessContext.getUserProfile();
67+
try {
68+
java.nio.file.Path externalLibraryPath = resourceManagerAPIservice.getExternalLibraryPath(requestedLibraryName, profile);
69+
File externalLibrary = externalLibraryPath.toFile();
70+
String mimeType = Files.probeContentType(externalLibraryPath);
71+
if (mimeType == null || mimeType.trim().isEmpty()) {
72+
mimeType = new MimetypesFileTypeMap().getContentType(externalLibrary.getName());
73+
}
74+
if (mimeType == null || mimeType.trim().isEmpty()) {
75+
mimeType = MediaType.APPLICATION_OCTET_STREAM;
76+
}
77+
78+
return Response.ok(externalLibrary, mimeType)
79+
.header("Content-length", String.valueOf(Files.size(externalLibraryPath)))
80+
.header("Content-Disposition", String.format("attachment; filename=\"%s\"", externalLibrary.getName()))
81+
.build();
82+
} catch (KnowageBusinessException e) {
83+
throw new KnowageBusinessException(e, businessContext.getLocale());
84+
} catch (IOException e) {
85+
throw new KnowageRuntimeException("Error calculating file size for " + requestedLibraryName, e);
86+
} catch (Exception e) {
87+
throw new KnowageRuntimeException(e);
88+
}
89+
}
90+
}

knowage-api/src/main/java/it/eng/knowage/resourcemanager/service/ResourceManagerAPI.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public interface ResourceManagerAPI {
4949

5050
java.nio.file.Path getDownloadFilePath(List<String> path, SpagoBIUserProfile profile, boolean multi) throws ImpossibleToDownloadFileException;
5151

52+
Path getExternalLibraryPath(String libraryName, SpagoBIUserProfile profile) throws ImpossibleToReadFilesListException;
53+
5254
boolean canSee(Path path, SpagoBIUserProfile profile) throws IOException;
5355

5456
void importFile(InputStream archiveInputStream, String path, SpagoBIUserProfile profile)

knowage-api/src/main/java/it/eng/knowage/resourcemanager/service/impl/ResourceManagerAPIImpl.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import it.eng.knowage.knowageapi.error.ImpossibleToReadMetadataException;
6363
import it.eng.knowage.knowageapi.error.ImpossibleToSaveMetadataException;
6464
import it.eng.knowage.knowageapi.error.ImpossibleToUploadFileException;
65+
import it.eng.knowage.knowageapi.utils.PathTraversalChecker;
6566
import it.eng.knowage.resourcemanager.resource.dto.FileDTO;
6667
import it.eng.knowage.resourcemanager.resource.dto.FolderDTO;
6768
import it.eng.knowage.resourcemanager.resource.dto.MetadataDTO;
@@ -78,7 +79,8 @@ public class ResourceManagerAPIImpl implements ResourceManagerAPI {
7879
private static final String METADATA_JSON = "metadata.json";
7980
private static final String MODELS = "models";
8081
private static final Logger LOGGER = Logger.getLogger(ResourceManagerAPIImpl.class);
81-
private static final String DOCS_FOLDER = "docs";
82+
private static final String DOCS_FOLDER = "docs";
83+
private static final String EXTERNAL_LIBRARIES_FOLDER = "external-libraries";
8284
private static Map<String, List<String>> foldersForDevs = new HashMap<>();
8385
private final Map<String, HashMap<String, Object>> cachedNodesInfo = new HashMap<>();
8486

@@ -345,6 +347,46 @@ public Path getDownloadFilePath(List<String> path, SpagoBIUserProfile profile, b
345347
return pathToReturn;
346348
}
347349

350+
@Override
351+
public Path getExternalLibraryPath(String libraryName, SpagoBIUserProfile profile)
352+
throws ImpossibleToReadFilesListException {
353+
try {
354+
PathTraversalChecker.isValidFileName(libraryName);
355+
356+
Path workDirectory = getWorkDirectory(profile).normalize();
357+
Path externalLibrariesDirectory = workDirectory.resolve(EXTERNAL_LIBRARIES_FOLDER).normalize();
358+
if (!Files.isDirectory(externalLibrariesDirectory)) {
359+
throw new ImpossibleToReadFilesListException("External libraries folder not found");
360+
}
361+
362+
Path realWorkDirectory = workDirectory.toRealPath();
363+
Path realExternalLibrariesDirectory = externalLibrariesDirectory.toRealPath();
364+
if (!realExternalLibrariesDirectory.startsWith(realWorkDirectory)) {
365+
throw new ImpossibleToReadFilesListException("Invalid external libraries folder");
366+
}
367+
Path candidatePath = realExternalLibrariesDirectory.resolve(libraryName).normalize();
368+
if (!candidatePath.startsWith(realExternalLibrariesDirectory)) {
369+
throw new ImpossibleToReadFilesListException("Invalid library name");
370+
}
371+
if (!Files.exists(candidatePath) || !Files.isRegularFile(candidatePath)) {
372+
throw new ImpossibleToReadFilesListException("External library not found: " + libraryName);
373+
}
374+
375+
Path realCandidatePath = candidatePath.toRealPath();
376+
if (!realCandidatePath.startsWith(realExternalLibrariesDirectory)) {
377+
throw new ImpossibleToReadFilesListException("Invalid library name");
378+
}
379+
380+
return realCandidatePath;
381+
} catch (ImpossibleToReadFilesListException e) {
382+
throw e;
383+
} catch (KnowageRuntimeException e) {
384+
throw new ImpossibleToReadFilesListException("Invalid library name", e);
385+
} catch (IOException e) {
386+
throw new ImpossibleToReadFilesListException("Error while resolving external library " + libraryName, e);
387+
}
388+
}
389+
348390
public Path getFullRootByPath(String path, SpagoBIUserProfile profile) throws IOException {
349391
String separator = File.separator.equals("\\") ? "\\\\" : File.separator;
350392
String rootElement = path.split(separator)[0];

0 commit comments

Comments
 (0)