Compare commits

...
16 Commits
10 changed files with 144 additions and 84 deletions

No files matched your search

+9 -8
View File
@@ -1,16 +1,14 @@
name: Check Update
on:
push:
branches:
- javafx
workflow_dispatch:
schedule:
- cron: '30 * * * *'
jobs:
check-update:
if: ${{ github.repository_owner == 'huanghongxun' }}
runs-on: ubuntu-latest
env:
HMCL_BASE_VERSION: '3.4'
steps:
- uses: actions/checkout@v2
- name: Fetch tags
@@ -20,7 +18,11 @@ jobs:
- name: Fetch last version
run: |
wget -O ci.json https://ci.huangyuhui.net/job/HMCL/lastSuccessfulBuild/api/json
export HMCL_EXE_FILE_NAME=`cat ci.json | jq -M -r '.artifacts[] | select(.fileName | endswith(".exe")) | .fileName'`
if [ -z `echo $HMCL_EXE_FILE_NAME | grep "^HMCL-[0-9]\.[0-9]\.[0-9]\{3\}\.exe\$"` ]; then exit 1; fi
export HMCL_BASE_VERSION=${HMCL_EXE_FILE_NAME:5:3}
export HMCL_BUILD_NUMBER=`cat ci.json | jq -M -r '.id'`
export HMCL_VERSION="$HMCL_BASE_VERSION.$HMCL_BUILD_NUMBER"
export HMCL_COMMIT_SHA=`cat ci.json | jq -M -r '.actions[] | select(._class == "hudson.plugins.git.util.BuildData") | .lastBuiltRevision.SHA1'`
@@ -28,6 +30,7 @@ jobs:
if [ "${#HMCL_BUILD_NUMBER}" != 3 ]; then exit 1; fi
if [ "${#HMCL_COMMIT_SHA}" != 40 ]; then exit 1; fi
echo "HMCL_BASE_VERSION=$HMCL_BASE_VERSION" >> $GITHUB_ENV
echo "HMCL_BUILD_NUMBER=$HMCL_BUILD_NUMBER" >> $GITHUB_ENV
echo "HMCL_VERSION=$HMCL_VERSION" >> $GITHUB_ENV
echo "HMCL_COMMIT_SHA=$HMCL_COMMIT_SHA" >> $GITHUB_ENV
@@ -63,5 +66,3 @@ jobs:
target_commitish: ${{ env.HMCL_COMMIT_SHA }}
name: ${{ env.HMCL_TAG_NAME }}
tag_name: ${{ env.HMCL_TAG_NAME }}
-44
View File
@@ -1,44 +0,0 @@
name: Create Release
on:
push:
tags:
- "v*.*.*"
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Check and set HMCL version
run: |
export HMCL_VERSION=`echo ${{ github.ref }} | awk '{print substr($0,12)}'`
echo "HMCL_VERSION=$HMCL_VERSION" >> $GITHUB_ENV
if [ -z `echo $HMCL_VERSION | grep "^[0-9]\.[0-9]\.[0-9]\{3\}\$"` ]; then
exit 1
fi
echo "HMCL_BUILD_NUMBER=`echo $HMCL_VERSION | awk '{print substr($0,5)}'`" >> $GITHUB_ENV
- name: Download artifacts
run: |
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe.sha1"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar.sha1"
env:
DOWNLOAD_BASE_URL: https://ci.huangyuhui.net/job/HMCL/${{ env.HMCL_BUILD_NUMBER }}/artifact/HMCL/build/libs
- name: Generate release note
run: |
echo "HMCL v$HMCL_VERSION" >> RELEASE_NOTE
echo "" >> RELEASE_NOTE
echo "The full changelogs can be found on the website: https://hmcl.huangyuhui.net/changelog/dev.html" >> RELEASE_NOTE
echo "Notice: changelogs are written in Chinese." >> RELEASE_NOTE
- name: Create release
uses: softprops/action-gh-release@v1
with:
body_path: RELEASE_NOTE
files: |
HMCL-${{ env.HMCL_VERSION }}.exe
HMCL-${{ env.HMCL_VERSION }}.exe.sha1
HMCL-${{ env.HMCL_VERSION }}.jar
HMCL-${{ env.HMCL_VERSION }}.jar.sha1
@@ -494,7 +494,7 @@ public final class LauncherHelper {
// Cannot allocate too much memory exceeding free space.
if (!suggested && OperatingSystem.TOTAL_MEMORY > 0 && OperatingSystem.TOTAL_MEMORY < setting.getMaxMemory()) {
Controllers.confirm(i18n("launch.advice.not_enough_space", OperatingSystem.TOTAL_MEMORY), i18n("message.error"), continueAction, null);
Controllers.confirm(i18n("launch.advice.not_enough_space", OperatingSystem.TOTAL_MEMORY), i18n("message.error"), continueAction, breakAction);
suggested = true;
}
@@ -506,7 +506,7 @@ public final class LauncherHelper {
VersionNumber.VERSION_COMPARATOR.compare(it.getVersion(), "1.12.2-14.23.5.2773") < 0);
boolean hasLiteLoader = version.getLibraries().stream().anyMatch(it -> it.is("com.mumfrey", "liteloader"));
if (hasForge2760 && hasLiteLoader && gameVersion.compareTo(VersionNumber.asVersion("1.12.2")) == 0) {
Controllers.confirm(i18n("launch.advice.forge2760_liteloader"), i18n("message.error"), continueAction, null);
Controllers.confirm(i18n("launch.advice.forge2760_liteloader"), i18n("message.error"), continueAction, breakAction);
suggested = true;
}
}
@@ -518,12 +518,12 @@ public final class LauncherHelper {
VersionNumber.VERSION_COMPARATOR.compare("1.14.4-28.2.2", it.getVersion()) <= 0);
boolean hasOptiFine = version.getLibraries().stream().anyMatch(it -> it.is("optifine", "OptiFine"));
if (hasForge28_2_2 && hasOptiFine && gameVersion.compareTo(VersionNumber.asVersion("1.14.4")) == 0) {
Controllers.confirm(i18n("launch.advice.forge28_2_2_optifine"), i18n("message.error"), continueAction, null);
Controllers.confirm(i18n("launch.advice.forge28_2_2_optifine"), i18n("message.error"), continueAction, breakAction);
suggested = true;
}
}
if (!suggested) {
if (!future.isDone()) {
future.complete(javaVersion);
}
@@ -31,12 +31,14 @@ import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.io.Unzipper;
import org.jackhuang.hmcl.util.platform.CommandBuilder;
import org.jackhuang.hmcl.util.platform.JavaVersion;
import org.jackhuang.hmcl.util.platform.ManagedProcess;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.Bits;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.io.*;
import java.net.InetSocketAddress;
@@ -178,6 +180,16 @@ public class DefaultLauncher extends Launcher {
res.addDefault("-Dfml.ignoreInvalidMinecraftCertificates=", "true");
res.addDefault("-Dfml.ignorePatchDiscrepancies=", "true");
// Fix RCE vulnerability of log4j2
res.addDefault("-Dlog4j2.formatMsgNoLookups=", "true");
res.addDefault("-Djava.rmi.server.useCodebaseOnly=", "true");
res.addDefault("-Dcom.sun.jndi.rmi.object.trustURLCodebase=", "false");
res.addDefault("-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=", "false");
}
if (isUsingLog4j()) {
res.addDefault("-Dlog4j.configurationFile=", getLog4jConfigurationFile().getAbsolutePath());
}
Proxy proxy = options.getProxy();
@@ -333,6 +345,29 @@ public class DefaultLauncher extends Launcher {
}
}
private boolean isUsingLog4j() {
return VersionNumber.VERSION_COMPARATOR.compare(repository.getGameVersion(version).orElse("Unknown"), "1.7") >= 0;
}
public File getLog4jConfigurationFile() {
return new File(repository.getVersionRoot(version.getId()), "log4j2.xml");
}
public void extractLog4jConfigurationFile() throws IOException {
File targetFile = getLog4jConfigurationFile();
InputStream source;
if (VersionNumber.VERSION_COMPARATOR.compare(repository.getGameVersion(version).orElse("Unknown"), "1.12") < 0) {
source = DefaultLauncher.class.getResourceAsStream("/assets/game/log4j2-1.7.xml");
} else {
source = DefaultLauncher.class.getResourceAsStream("/assets/game/log4j2-1.12.xml");
}
try (InputStream input = source;
OutputStream output = new FileOutputStream(targetFile)) {
IOUtils.copyTo(input, output);
}
}
protected Map<String, String> getConfigurations() {
return mapOf(
// defined by Minecraft official launcher
@@ -400,6 +435,10 @@ public class DefaultLauncher extends Launcher {
decompressNatives(nativeFolder);
}
if (isUsingLog4j()) {
extractLog4jConfigurationFile();
}
File runDirectory = repository.getRunDirectory(version.getId());
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
@@ -437,6 +476,7 @@ public class DefaultLauncher extends Launcher {
private Map<String, String> getEnvVars() {
String versionName = Optional.ofNullable(options.getVersionName()).orElse(version.getId());
Map<String, String> env = new HashMap<>();
env.put("LOG4J_FORMAT_MSG_NO_LOOKUPS", "true");
env.put("INST_NAME", versionName);
env.put("INST_ID", versionName);
env.put("INST_DIR", repository.getVersionRoot(version.getId()).getAbsolutePath());
@@ -474,6 +514,10 @@ public class DefaultLauncher extends Launcher {
decompressNatives(nativeFolder);
}
if (isUsingLog4j()) {
extractLog4jConfigurationFile();
}
String scriptExtension = FileUtils.getExtension(scriptFile);
boolean usePowerShell = "ps1".equals(scriptExtension);
@@ -17,13 +17,14 @@
*/
package org.jackhuang.hmcl.util;
import org.jackhuang.hmcl.util.io.IOUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.text.MessageFormat;
import java.util.Date;
import java.util.logging.*;
@@ -35,7 +36,7 @@ public final class Logging {
}
public static final Logger LOG = Logger.getLogger("HMCL");
private static ByteArrayOutputStream storedLogs = new ByteArrayOutputStream();
private static final ByteArrayOutputStream storedLogs = new ByteArrayOutputStream(IOUtils.DEFAULT_BUFFER_SIZE);
public static void start(Path logFolder) {
LOG.setLevel(Level.ALL);
@@ -46,6 +47,7 @@ public final class Logging {
FileHandler fileHandler = new FileHandler(logFolder.resolve("hmcl.log").toAbsolutePath().toString());
fileHandler.setLevel(Level.FINEST);
fileHandler.setFormatter(DefaultFormatter.INSTANCE);
fileHandler.setEncoding("UTF-8");
LOG.addHandler(fileHandler);
} catch (IOException e) {
System.err.println("Unable to create hmcl.log, " + e.getMessage());
@@ -87,27 +89,29 @@ public final class Logging {
}
public static String getLogs() {
return storedLogs.toString();
try {
return storedLogs.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InternalError(e);
}
}
private static final class DefaultFormatter extends Formatter {
static final DefaultFormatter INSTANCE = new DefaultFormatter();
private final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
private static final MessageFormat format = new MessageFormat("[{0,date,HH:mm:ss}] [{1}.{2}/{3}] {4}\n");
@Override
public String format(LogRecord record) {
String date = format.format(new Date(record.getMillis()));
String log = String.format("[%s] [%s.%s/%s] %s%n",
date, record.getSourceClassName(), record.getSourceMethodName(),
record.getLevel().getName(), record.getMessage()
);
ByteArrayOutputStream builder = new ByteArrayOutputStream();
String log = format.format(new Object[]{
new Date(record.getMillis()),
record.getSourceClassName(), record.getSourceMethodName(), record.getLevel().getName(),
record.getMessage()
}, new StringBuffer(128), null).toString();
if (record.getThrown() != null)
try (PrintWriter writer = new PrintWriter(builder)) {
record.getThrown().printStackTrace(writer);
}
return log + builder.toString();
log += StringUtils.getStackTrace(record.getThrown());
return log;
}
}
@@ -19,9 +19,7 @@ package org.jackhuang.hmcl.util;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.io.*;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
@@ -37,13 +35,11 @@ public final class StringUtils {
}
public static String getStackTrace(Throwable throwable) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
throwable.printStackTrace(new PrintStream(stream, false, "UTF-8"));
return stream.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InternalError(e);
StringWriter stringWriter = new StringWriter(512);
try (PrintWriter printWriter = new PrintWriter(stringWriter)) {
throwable.printStackTrace(printWriter);
}
return stringWriter.toString();
}
public static String getStackTrace(StackTraceElement[] elements) {
@@ -80,7 +80,7 @@ public final class Zipper implements Closeable {
if (filter != null && !filter.test(relativePath.replace('\\', '/'))) {
return FileVisitResult.SKIP_SUBTREE;
}
Files.copy(file, root.resolve(relativePath));
Files.copy(file, root.resolve(relativePath), StandardCopyOption.COPY_ATTRIBUTES);
return FileVisitResult.CONTINUE;
}
@@ -104,11 +104,11 @@ public final class Zipper implements Closeable {
}
public void putFile(Path file, String path) throws IOException {
Files.copy(file, fs.getPath(path));
Files.copy(file, fs.getPath(path), StandardCopyOption.COPY_ATTRIBUTES);
}
public void putStream(InputStream in, String path) throws IOException {
Files.copy(in, fs.getPath(path));
Files.copy(in, fs.getPath(path), StandardCopyOption.COPY_ATTRIBUTES);
}
public void putTextFile(String text, String path) throws IOException {
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="SysOut" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
</Console>
<Queue name="ServerGuiConsole">
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
</Queue>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<OnStartupTriggeringPolicy />
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="info">
<filters>
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL" />
</filters>
<AppenderRef ref="SysOut"/>
<AppenderRef ref="File"/>
<AppenderRef ref="ServerGuiConsole"/>
</Root>
</Loggers>
</Configuration>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="SysOut" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
</Console>
<Queue name="ServerGuiConsole">
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
</Queue>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<OnStartupTriggeringPolicy />
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="info">
<filters>
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL" />
<RegexFilter regex=".*\$\{[^}]*\}.*" onMatch="DENY" onMismatch="NEUTRAL"/>
</filters>
<AppenderRef ref="SysOut"/>
<AppenderRef ref="File"/>
<AppenderRef ref="ServerGuiConsole"/>
</Root>
</Loggers>
</Configuration>
+3 -1
View File
@@ -11,7 +11,9 @@ No plugin API is provided.
## Download
Download the latest version [from the official website](https://hmcl.huangyuhui.net/download)
Note: Github releases are outdated.
Note: The recent versions in Github release is the beta version, which contains extra testing functions compared to the release versions on the official website. However, they may be unstable and you're more likely to encounter bugs or unexpected problems.
If not necessary, it is recommended to download the ones from the official website.
## License
The software is distributed under [GPL v3](https://www.gnu.org/licenses/gpl-3.0.html) with additional terms.