Skip to content

Commit afb1607

Browse files
committed
chore: extract zip helper methods into separate class
1 parent 8aa55bd commit afb1607

File tree

16 files changed

+220
-192
lines changed

16 files changed

+220
-192
lines changed

.github/stale.yml

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ exemptLabels:
66
- "t: bug"
77
- "t: security"
88
- "t: new platform"
9+
- "s: blocked"
10+
- "s: needs triage"
11+
- "s: we need to go deeper"
912

1013
markComment: >
1114
This issue has been automatically marked as stale because it has not had

common/src/main/java/eu/cloudnetservice/cloudnet/common/encrypt/EncryptTo.java common/src/main/java/eu/cloudnetservice/cloudnet/common/hash/HashUtil.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,18 @@
1414
* limitations under the License.
1515
*/
1616

17-
package eu.cloudnetservice.cloudnet.common.encrypt;
17+
package eu.cloudnetservice.cloudnet.common.hash;
1818

1919
import com.google.common.hash.Hashing;
20+
import java.nio.charset.StandardCharsets;
2021
import lombok.NonNull;
2122

2223
/**
2324
* Shortcut class to guava hashing methods.
2425
*/
25-
public final class EncryptTo {
26+
public final class HashUtil {
2627

27-
private EncryptTo() {
28+
private HashUtil() {
2829
throw new UnsupportedOperationException();
2930
}
3031

@@ -34,8 +35,8 @@ private EncryptTo() {
3435
* @param text the text to hash.
3536
* @return the same input text hashed with the sha256 algorithm.
3637
*/
37-
public static byte @NonNull [] encryptToSHA256(@NonNull String text) {
38-
return Hashing.sha256().hashUnencodedChars(text).asBytes();
38+
public static byte @NonNull [] toSha256(@NonNull String text) {
39+
return Hashing.sha256().hashString(text, StandardCharsets.UTF_8).asBytes();
3940
}
4041

4142
/**
@@ -44,7 +45,7 @@ private EncryptTo() {
4445
* @param bytes the following bytes which should encrypt
4546
* @return the output SHA-256 hash
4647
*/
47-
public static byte @NonNull [] encryptToSHA256(byte @NonNull [] bytes) {
48+
public static byte @NonNull [] toSha256(byte @NonNull [] bytes) {
4849
return Hashing.sha256().hashBytes(bytes).asBytes();
4950
}
5051
}

common/src/main/java/eu/cloudnetservice/cloudnet/common/io/FileUtil.java

+19-163
Original file line numberDiff line numberDiff line change
@@ -23,67 +23,46 @@
2323
import java.io.InputStream;
2424
import java.io.OutputStream;
2525
import java.net.URI;
26-
import java.nio.charset.StandardCharsets;
2726
import java.nio.file.CopyOption;
28-
import java.nio.file.DirectoryStream;
27+
import java.nio.file.DirectoryStream.Filter;
2928
import java.nio.file.FileSystem;
3029
import java.nio.file.FileSystems;
31-
import java.nio.file.FileVisitResult;
3230
import java.nio.file.Files;
33-
import java.nio.file.LinkOption;
3431
import java.nio.file.Path;
35-
import java.nio.file.SimpleFileVisitor;
3632
import java.nio.file.StandardCopyOption;
37-
import java.nio.file.StandardOpenOption;
38-
import java.nio.file.attribute.BasicFileAttributes;
3933
import java.util.Map;
4034
import java.util.UUID;
4135
import java.util.function.BiConsumer;
42-
import java.util.function.Predicate;
43-
import java.util.zip.ZipEntry;
44-
import java.util.zip.ZipInputStream;
45-
import java.util.zip.ZipOutputStream;
4636
import lombok.NonNull;
4737
import org.jetbrains.annotations.ApiStatus.Internal;
4838
import org.jetbrains.annotations.Nullable;
4939

50-
/**
51-
* The FileUtils class has a lot of utility methods, for
52-
* <ol>
53-
* <li>Byte Streams IO</li>
54-
* <li>File IO (Coping, Deleting)</li>
55-
* <li>Zip IO</li>
56-
* </ol>
57-
*/
5840
@Internal
5941
public final class FileUtil {
6042

6143
public static final Path TEMP_DIR = Path.of(System.getProperty("cloudnet.tempDir", "temp"));
6244

6345
private static final Logger LOGGER = LogManager.logger(FileUtil.class);
64-
private static final DirectoryStream.Filter<Path> ACCEPTING_FILTER = $ -> true;
65-
private static final boolean IS_WINDOWS = System.getProperty("os.name").contains("windows");
66-
67-
private static final Map<String, String> ZIP_FILE_SYSTEM_PROPERTIES = Map.of(
68-
"create", "false", "encoding", "UTF-8");
46+
private static final Filter<Path> ACCEPTING_FILTER = $ -> true;
47+
private static final Map<String, String> ZIP_FILE_SYSTEM_PROPERTIES = Map.of("create", "false", "encoding", "UTF-8");
6948

7049
private FileUtil() {
7150
throw new UnsupportedOperationException();
7251
}
7352

74-
public static void openZipFileSystem(@NonNull Path zip, @NonNull ThrowableConsumer<FileSystem, Exception> consumer) {
75-
try (var fs = FileSystems.newFileSystem(URI.create("jar:" + zip.toUri()), ZIP_FILE_SYSTEM_PROPERTIES)) {
53+
public static void openJarFileSystem(@NonNull Path jar, @NonNull ThrowableConsumer<FileSystem, Exception> consumer) {
54+
try (var fs = FileSystems.newFileSystem(URI.create("jar:" + jar.toUri()), ZIP_FILE_SYSTEM_PROPERTIES)) {
7655
consumer.accept(fs);
7756
} catch (Exception throwable) {
78-
LOGGER.severe("Exception while opening file", throwable);
57+
LOGGER.severe("Exception opening jar file system on %s", throwable, jar);
7958
}
8059
}
8160

8261
public static void move(@NonNull Path from, @NonNull Path to, CopyOption @NonNull ... options) {
8362
try {
8463
Files.move(from, to, options);
8564
} catch (IOException exception) {
86-
LOGGER.severe("Unable to move file " + from + " to " + to, exception);
65+
LOGGER.severe("Exception moving file from %s to %s", exception, from, to);
8766
}
8867
}
8968

@@ -92,18 +71,18 @@ public static void copy(@Nullable InputStream inputStream, @Nullable OutputStrea
9271
try {
9372
inputStream.transferTo(outputStream);
9473
} catch (IOException exception) {
95-
LOGGER.severe("Exception copying InputStream to OutputStream", exception);
74+
LOGGER.severe("Exception copying input stream to output stream", exception);
9675
}
9776
}
9877
}
9978

10079
public static void copy(@Nullable InputStream inputStream, @Nullable Path target) {
10180
if (inputStream != null && target != null) {
102-
FileUtil.createDirectory(target.getParent());
81+
createDirectory(target.getParent());
10382
try (var out = Files.newOutputStream(target)) {
10483
FileUtil.copy(inputStream, out);
10584
} catch (IOException exception) {
106-
LOGGER.severe("Exception copying InputStream to Path", exception);
85+
LOGGER.severe("Exception copying input stream to %s", exception, target);
10786
}
10887
}
10988
}
@@ -114,15 +93,15 @@ public static void copy(@NonNull Path from, @NonNull Path to) {
11493
createDirectory(to.getParent());
11594
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
11695
} catch (IOException exception) {
117-
LOGGER.severe("Exception copying file from " + from + " to " + to, exception);
96+
LOGGER.severe("Exception copying file from %s to %s", exception, from, to);
11897
}
11998
}
12099

121100
public static void copyDirectory(@NonNull Path from, @NonNull Path to) {
122101
copyDirectory(from, to, null);
123102
}
124103

125-
public static void copyDirectory(Path from, Path to, DirectoryStream.Filter<Path> filter) {
104+
public static void copyDirectory(@NonNull Path from, @NonNull Path to, @Nullable Filter<Path> filter) {
126105
walkFileTree(from, ($, current) -> {
127106
if (!Files.isDirectory(current)) {
128107
FileUtil.copy(current, to.resolve(from.relativize(current)));
@@ -136,8 +115,9 @@ public static void delete(@Nullable Path path) {
136115
if (Files.isDirectory(path)) {
137116
walkFileTree(path, ($, current) -> FileUtil.delete(current));
138117
}
139-
// remove the directory or the file
118+
140119
try {
120+
// remove the directory or the file
141121
Files.delete(path);
142122
} catch (IOException ignored) {
143123
// ignore these exceptions
@@ -146,124 +126,10 @@ public static void delete(@Nullable Path path) {
146126
}
147127

148128
public static @NonNull Path createTempFile() {
149-
if (Files.notExists(TEMP_DIR)) {
150-
createDirectory(TEMP_DIR);
151-
}
152-
129+
createDirectory(TEMP_DIR);
153130
return TEMP_DIR.resolve(UUID.randomUUID().toString());
154131
}
155132

156-
public static @NonNull InputStream zipToStream(@NonNull Path directory) {
157-
return zipToStream(directory, null);
158-
}
159-
160-
public static @NonNull InputStream zipToStream(@NonNull Path directory, @Nullable Predicate<Path> fileFilter) {
161-
var target = createTempFile();
162-
zipToFile(
163-
directory,
164-
target,
165-
path -> !target.equals(path) && (fileFilter == null || fileFilter.test(path)));
166-
167-
try {
168-
return Files.newInputStream(target, StandardOpenOption.DELETE_ON_CLOSE, LinkOption.NOFOLLOW_LINKS);
169-
} catch (IOException exception) {
170-
throw new IllegalStateException("Unable to open input stream to zip file " + target, exception);
171-
}
172-
}
173-
174-
public static @Nullable Path zipToFile(@NonNull Path directory, @NonNull Path target) {
175-
return zipToFile(directory, target, null);
176-
}
177-
178-
public static @Nullable Path zipToFile(@NonNull Path dir, @NonNull Path target, @Nullable Predicate<Path> filter) {
179-
if (Files.exists(dir)) {
180-
try (var out = new ZipOutputStream(Files.newOutputStream(target), StandardCharsets.UTF_8)) {
181-
zipDir(out, dir, filter);
182-
return target;
183-
} catch (IOException exception) {
184-
LOGGER.severe("Exception while processing new zip entry from directory " + dir, exception);
185-
}
186-
}
187-
188-
return null;
189-
}
190-
191-
private static void zipDir(
192-
@NonNull ZipOutputStream out,
193-
@NonNull Path dir,
194-
@Nullable Predicate<Path> filter
195-
) throws IOException {
196-
Files.walkFileTree(
197-
dir,
198-
new SimpleFileVisitor<>() {
199-
@Override
200-
public FileVisitResult visitFile(@NonNull Path file, @NonNull BasicFileAttributes attrs) throws IOException {
201-
if (filter == null || filter.test(file)) {
202-
try {
203-
out.putNextEntry(new ZipEntry(dir.relativize(file).toString().replace("\\", "/")));
204-
Files.copy(file, out);
205-
} finally {
206-
out.closeEntry();
207-
}
208-
}
209-
// continue search
210-
return FileVisitResult.CONTINUE;
211-
}
212-
}
213-
);
214-
}
215-
216-
public static @Nullable Path extract(@NonNull Path zipPath, @NonNull Path targetDirectory) {
217-
if (Files.exists(zipPath)) {
218-
try (var inputStream = Files.newInputStream(zipPath)) {
219-
return extract(inputStream, targetDirectory);
220-
} catch (IOException exception) {
221-
LOGGER.severe("Unable to extract zip from " + zipPath + " to " + targetDirectory, exception);
222-
}
223-
}
224-
return null;
225-
}
226-
227-
public static @Nullable Path extract(@NonNull InputStream in, @NonNull Path targetDirectory) {
228-
return extractZipStream(
229-
in instanceof ZipInputStream ? (ZipInputStream) in : new ZipInputStream(in, StandardCharsets.UTF_8),
230-
targetDirectory);
231-
}
232-
233-
public static @Nullable Path extractZipStream(@NonNull ZipInputStream zipInputStream, @NonNull Path targetDirectory) {
234-
try {
235-
ZipEntry zipEntry;
236-
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
237-
extractEntry(zipInputStream, zipEntry, targetDirectory);
238-
zipInputStream.closeEntry();
239-
}
240-
241-
return targetDirectory;
242-
} catch (IOException exception) {
243-
LOGGER.severe("Exception unzipping zip file to " + targetDirectory, exception);
244-
return null;
245-
}
246-
}
247-
248-
private static void extractEntry(
249-
@NonNull ZipInputStream in,
250-
@NonNull ZipEntry zipEntry,
251-
@NonNull Path targetDirectory
252-
) throws IOException {
253-
// checks first if the zip entry name is malicious before extracting
254-
ensureSafeZipEntryName(zipEntry.getName());
255-
var file = targetDirectory.resolve(zipEntry.getName());
256-
257-
if (zipEntry.isDirectory()) {
258-
FileUtil.createDirectory(file);
259-
} else {
260-
FileUtil.createDirectory(file.getParent());
261-
try (var outputStream = Files.newOutputStream(file)) {
262-
copy(in, outputStream);
263-
}
264-
}
265-
}
266-
267133
public static void walkFileTree(@NonNull Path root, @NonNull BiConsumer<Path, Path> consumer) {
268134
walkFileTree(root, consumer, true);
269135
}
@@ -289,7 +155,7 @@ public static void walkFileTree(
289155
@NonNull Path root,
290156
@NonNull BiConsumer<Path, Path> consumer,
291157
boolean visitDirectories,
292-
@NonNull DirectoryStream.Filter<Path> filter
158+
@NonNull Filter<Path> filter
293159
) {
294160
if (Files.exists(root)) {
295161
try (var stream = Files.newDirectoryStream(root, filter)) {
@@ -300,14 +166,14 @@ public static void walkFileTree(
300166
if (visitDirectories) {
301167
walkFileTree(path, consumer, true, filter);
302168
} else {
303-
return;
169+
continue;
304170
}
305171
}
306172
// accepts all files and directories
307173
consumer.accept(root, path);
308174
}
309175
} catch (IOException exception) {
310-
LOGGER.severe("Exception walking directory tree from " + root, exception);
176+
LOGGER.severe("Exception walking down directory tree starting at %s", exception, root);
311177
}
312178
}
313179
}
@@ -317,7 +183,7 @@ public static void createDirectory(@Nullable Path directoryPath) {
317183
try {
318184
Files.createDirectories(directoryPath);
319185
} catch (IOException exception) {
320-
LOGGER.severe("Exception while creating directory", exception);
186+
LOGGER.severe("Exception creating directory at %s", exception, directoryPath);
321187
}
322188
}
323189
}
@@ -331,16 +197,6 @@ public static void ensureChild(@NonNull Path root, @NonNull Path child) {
331197
}
332198
}
333199

334-
public static void ensureSafeZipEntryName(@NonNull String name) {
335-
if (name.isEmpty()
336-
|| name.startsWith("/")
337-
|| name.startsWith("\\")
338-
|| name.contains("..")
339-
|| (name.contains(":") && IS_WINDOWS)) {
340-
throw new IllegalStateException(String.format("zip entry name %s contains unsafe characters", name));
341-
}
342-
}
343-
344200
public static @NonNull Path resolve(@NonNull Path base, String @NonNull ... more) {
345201
for (var child : more) {
346202
base = base.resolve(child);

0 commit comments

Comments
 (0)