From bb66be7c3af62cc1bdf23875ac07129c43c7e8af Mon Sep 17 00:00:00 2001 From: Glavo Date: Mon, 6 Feb 2023 22:47:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=91=E9=9D=9E=E5=AE=98=E6=96=B9=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E6=B7=BB=E5=8A=A0=E6=8F=90=E7=A4=BA=20(#2069)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update * Add GitHub SHA to manifest * Add unofficial to build channel * Optimize IntegrityChecker * update hint * Add hint --- HMCL/build.gradle.kts | 11 +++++- .../java/org/jackhuang/hmcl/Metadata.java | 1 + .../hmcl/ui/account/CreateAccountPane.java | 37 ++++++++++++++----- .../hmcl/ui/construct/JFXHyperlink.java | 5 +++ .../hmcl/upgrade/IntegrityChecker.java | 36 ++++++++++++------ .../resources/assets/lang/I18N.properties | 5 ++- .../resources/assets/lang/I18N_es.properties | 2 +- .../resources/assets/lang/I18N_ja.properties | 2 +- .../resources/assets/lang/I18N_ru.properties | 2 +- .../resources/assets/lang/I18N_zh.properties | 5 ++- .../assets/lang/I18N_zh_CN.properties | 5 ++- 11 files changed, 83 insertions(+), 28 deletions(-) diff --git a/HMCL/build.gradle.kts b/HMCL/build.gradle.kts index 158cc5da0..896f4a492 100644 --- a/HMCL/build.gradle.kts +++ b/HMCL/build.gradle.kts @@ -11,18 +11,21 @@ plugins { id("com.github.johnrengelman.shadow") version "7.1.2" } +val isOfficial = System.getenv("HMCL_SIGNATURE_KEY") != null + || (System.getenv("GITHUB_REPOSITORY_OWNER") == "huanghongxun" && System.getenv("GITHUB_BASE_REF").isNullOrEmpty()) + val buildNumber = System.getenv("BUILD_NUMBER")?.toInt().let { number -> val offset = System.getenv("BUILD_NUMBER_OFFSET")?.toInt() ?: 0 if (number != null) { (number - offset).toString() } else { val shortCommit = System.getenv("GITHUB_SHA")?.toLowerCase()?.substring(0, 7) - val prefix = if (System.getenv("GITHUB_REPOSITORY_OWNER") == "huanghongxun") "dev" else "unofficial" + val prefix = if (isOfficial) "dev" else "unofficial" if (!shortCommit.isNullOrEmpty()) "$prefix-$shortCommit" else "SNAPSHOT" } } val versionRoot = System.getenv("VERSION_ROOT") ?: "3.5" -val versionType = System.getenv("VERSION_TYPE") ?: "nightly" +val versionType = System.getenv("VERSION_TYPE") ?: if (isOfficial) "nightly" else "unofficial" val microsoftAuthId = System.getenv("MICROSOFT_AUTH_ID") ?: "" val microsoftAuthSecret = System.getenv("MICROSOFT_AUTH_SECRET") ?: "" @@ -131,6 +134,10 @@ tasks.getByName("sha "javafx.controls/javafx.scene.control.skin" ).joinToString(" ") ) + + System.getenv("GITHUB_SHA")?.also { + attributes("GitHub-SHA" to it) + } } doLast { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java b/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java index d047cf1d4..b0fd736d8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java @@ -45,6 +45,7 @@ public final class Metadata { public static final String EULA_URL = "https://hmcl.huangyuhui.net/eula"; public static final String BUILD_CHANNEL = JarUtils.getManifestAttribute("Build-Channel", "nightly"); + public static final String GITHUB_SHA = JarUtils.getManifestAttribute("GitHub-SHA", null); public static final Path MINECRAFT_DIRECTORY = OperatingSystem.getWorkingDirectory("minecraft"); public static final Path HMCL_DIRECTORY; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java index 8ea527f07..0b9f8a425 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java @@ -58,6 +58,7 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.WeakListenerHolder; import org.jackhuang.hmcl.ui.construct.*; +import org.jackhuang.hmcl.upgrade.IntegrityChecker; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter; import org.jackhuang.hmcl.util.javafx.BindingMapping; @@ -289,28 +290,37 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware { FlowPane box = new FlowPane(); box.setHgap(8); JFXHyperlink birthLink = new JFXHyperlink(i18n("account.methods.microsoft.birth")); - birthLink.setOnAction(e -> FXUtils.openLink("https://support.microsoft.com/account-billing/837badbc-999e-54d2-2617-d19206b9540a")); + birthLink.setExternalLink("https://support.microsoft.com/account-billing/837badbc-999e-54d2-2617-d19206b9540a"); JFXHyperlink profileLink = new JFXHyperlink(i18n("account.methods.microsoft.profile")); - profileLink.setOnAction(e -> FXUtils.openLink("https://account.live.com/editprof.aspx")); + profileLink.setExternalLink("https://account.live.com/editprof.aspx"); JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase")); + purchaseLink.setExternalLink(YggdrasilService.PURCHASE_URL); JFXHyperlink deauthorizeLink = new JFXHyperlink(i18n("account.methods.microsoft.deauthorize")); - deauthorizeLink.setOnAction(e -> FXUtils.openLink("https://account.live.com/consent/Edit?client_id=000000004C794E0A")); + deauthorizeLink.setExternalLink("https://account.live.com/consent/Edit?client_id=000000004C794E0A"); JFXHyperlink forgotpasswordLink = new JFXHyperlink(i18n("account.methods.forgot_password")); - forgotpasswordLink.setOnAction(e -> FXUtils.openLink("https://www.minecraft.net/password/forgot")); + forgotpasswordLink.setExternalLink("https://www.minecraft.net/password/forgot"); JFXHyperlink createProfileLink = new JFXHyperlink(i18n("account.methods.microsoft.makegameidsettings")); - createProfileLink.setOnAction(e -> FXUtils.openLink("https://www.minecraft.net/msaprofile/mygames/editprofile")); - purchaseLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.PURCHASE_URL)); + createProfileLink.setExternalLink("https://www.minecraft.net/msaprofile/mygames/editprofile"); box.getChildren().setAll(profileLink, birthLink, purchaseLink, deauthorizeLink, forgotpasswordLink, createProfileLink); GridPane.setColumnSpan(box, 2); - vbox.getChildren().setAll(hintPane, box); + if (!IntegrityChecker.isOfficial()) { + HintPane unofficialHint = new HintPane(MessageDialogPane.MessageType.WARNING); + unofficialHint.setText(i18n("unofficial.hint")); + vbox.getChildren().add(unofficialHint); + } + + vbox.getChildren().addAll(hintPane, box); btnAccept.setDisable(false); } else { HintPane hintPane = new HintPane(MessageDialogPane.MessageType.WARNING); - hintPane.setText(i18n("account.methods.microsoft.snapshot")); + hintPane.setSegment(i18n("account.methods.microsoft.snapshot")); - vbox.getChildren().setAll(hintPane); + JFXHyperlink officialWebsite = new JFXHyperlink(i18n("account.methods.microsoft.snapshot.website")); + officialWebsite.setExternalLink("https://hmcl.huangyuhui.net"); + + vbox.getChildren().setAll(hintPane, officialWebsite); btnAccept.setDisable(true); } @@ -389,6 +399,15 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware { int rowIndex = 0; + if (!IntegrityChecker.isOfficial() && !(factory instanceof OfflineAccountFactory)) { + HintPane hintPane = new HintPane(MessageDialogPane.MessageType.WARNING); + hintPane.setSegment(i18n("unofficial.hint")); + GridPane.setColumnSpan(hintPane, 2); + add(hintPane, 0, rowIndex); + + rowIndex++; + } + if (factory instanceof BoundAuthlibInjectorAccountFactory) { this.server = ((BoundAuthlibInjectorAccountFactory) factory).getServer(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/JFXHyperlink.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/JFXHyperlink.java index 4a8cdb7ae..7296219bd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/JFXHyperlink.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/JFXHyperlink.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui.construct; import javafx.scene.control.Hyperlink; import org.jackhuang.hmcl.setting.Theme; +import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; public class JFXHyperlink extends Hyperlink { @@ -34,5 +35,9 @@ public class JFXHyperlink extends Hyperlink { setGraphic(SVG.launchOutline(Theme.blackFillBinding(), 16, 16)); } + + public void setExternalLink(String externalLink) { + this.setOnAction(e -> FXUtils.openLink(externalLink)); + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IntegrityChecker.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IntegrityChecker.java index 8c387047e..5faaaf8c1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IntegrityChecker.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IntegrityChecker.java @@ -17,7 +17,9 @@ */ package org.jackhuang.hmcl.upgrade; +import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.util.DigestUtils; +import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.JarUtils; @@ -65,7 +67,7 @@ public final class IntegrityChecker { byte[] signature = null; Map fileFingerprints = new TreeMap<>(); try (ZipFile zip = new ZipFile(jarPath.toFile())) { - for (ZipEntry entry : zip.stream().toArray(ZipEntry[]::new)) { + for (ZipEntry entry : Lang.toIterable(zip.entries())) { String filename = entry.getName(); try (InputStream in = zip.getInputStream(entry)) { if (in == null) { @@ -106,25 +108,37 @@ public final class IntegrityChecker { } } - private static Boolean selfVerified = null; + private static volatile Boolean selfVerified = null; /** * Checks whether the current application is verified. * This method is blocking. */ - public static synchronized boolean isSelfVerified() { + public static boolean isSelfVerified() { if (selfVerified != null) { return selfVerified; } - try { - verifySelf(); - LOG.info("Successfully verified current JAR"); - selfVerified = true; - } catch (IOException e) { - LOG.log(Level.WARNING, "Failed to verify myself, is the JAR corrupt?", e); - selfVerified = false; + + synchronized (IntegrityChecker.class) { + if (selfVerified != null) { + return selfVerified; + } + + try { + verifySelf(); + LOG.info("Successfully verified current JAR"); + selfVerified = true; + } catch (IOException e) { + LOG.log(Level.WARNING, "Failed to verify myself, is the JAR corrupt?", e); + selfVerified = false; + } + + return selfVerified; } - return selfVerified; + } + + public static boolean isOfficial() { + return isSelfVerified() || (Metadata.GITHUB_SHA != null && Metadata.BUILD_CHANNEL.equals("nightly")); } private static void verifySelf() throws IOException { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index ab27b023f..6c1f80e77 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -112,7 +112,8 @@ account.methods.microsoft.manual=Your device code is %1$s, please click h If the token used to log in to the Microsoft account is leaked, you can click on "Unauthorize the account" to deauthorize it. account.methods.microsoft.makegameidsettings=Create Profile account.methods.microsoft.profile=Account Profile -account.methods.microsoft.snapshot=HMCL Snapshot version does not support Microsoft login, please use the stable version or beta version to log in. +account.methods.microsoft.snapshot=You are using an unofficial build of HMCL. Please download the official build for login. +account.methods.microsoft.snapshot.website=Official Website account.methods.microsoft.waiting_browser=Waiting for login to complete in the opened window... account.methods.offline=Offline account.methods.offline.name.special_characters=Recommended to use letters, numbers and underscores for naming @@ -1161,6 +1162,8 @@ sponsor.hmcl=Hello Minecraft! Launcher is a FOSS Minecraft launcher which allows system.architecture=Architecture system.operating_system=Operating System +unofficial.hint=You are using an unofficial build of HMCL. We cannot guarantee its security. + update=Update update.accept=Update update.changelog=Changelog diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index f0459496a..4e9994df6 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -107,7 +107,7 @@ account.methods.microsoft.manual=El código de su dispositivo es %1$s, po \n\ Si el token utilizado para acceder a la cuenta de Microsoft se ha filtrado, puedes hacer clic en "Desautorizar la cuenta" para desautorizarla. account.methods.microsoft.profile=Perfil de la cuenta -account.methods.microsoft.snapshot=La versión Snapshot de HMCL no admite el inicio de sesión de Microsoft, por favor, utilice la versión estable o la versión beta para iniciar sesión. +account.methods.microsoft.snapshot=Estás usando una construcción no oficial de hmcls, por favor descargue la construcción oficial para iniciar sesión en microsoft. account.methods.microsoft.waiting_browser=Esperando a que se complete el inicio de sesión en la ventana abierta... account.methods.offline=Sin conexión account.methods.offline.uuid=UUID diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index a8c9e2b2e..5251ed9a4 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -100,7 +100,7 @@ account.methods.microsoft.makegameidsettings=プロファイルを作成 account.methods.microsoft.hint=「ログイン」ボタンをクリックして、新しく開いたブラウザウィンドウでログインプロセスを続行する必要があります。\nMicrosoftアカウントへのログインに使用されたトークンが誤って漏洩した場合は、下の[アカウントのバインドを解除]をクリックして、ログイン認証をキャンセルできます。 account.methods.microsoft.manual=「ログイン」ボタンをクリックした後、新しく開いたブラウザウィンドウで認証を完了する必要があります。ブラウザウィンドウが表示されない場合は、ここをクリックしてURLをコピーし、ブラウザで手動で開くことができます。\nMicrosoftアカウントへのログインに使用されたトークンが誤って漏洩した場合は、下の[アカウントのバインドを解除]をクリックして、ログイン認証をキャンセルできます。 account.methods.microsoft.profile=アカウントプロファイル.. -account.methods.microsoft.snapshot=HMCLスナップショットバージョンはMicrosoftログインをサポートしていません。 +account.methods.microsoft.snapshot=非公式構築 HMCL を使用しているので、公式構築をダウンロードしてマイクロソフトにログインしてください。 account.methods.microsoft.waiting_browser=開いているブラウザウィンドウで認証を待機しています... account.methods.offline=オフライン account.methods.offline.uuid=UUID diff --git a/HMCL/src/main/resources/assets/lang/I18N_ru.properties b/HMCL/src/main/resources/assets/lang/I18N_ru.properties index 227d5e6c6..e6a9d8460 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -100,7 +100,7 @@ account.methods.microsoft.hint=Вам необходимо нажать кноп account.methods.microsoft.manual=После нажатия кнопки «Войти», вы должны завершить авторизацию во вновь открывшемся окне браузера. Если окно браузера не открылось, вы можете щёлкнуть здесь, чтобы скопировать ссылку и вручную открыть её в браузере.\nЕсли токен, используемый для входа в аккаунт Microsoft случайно утёк, вы можете нажать «Отменить авторизацию аккаунта» ниже, чтобы отменить авторизацию. account.methods.microsoft.profile=Профиль аккаунта... account.methods.forgot_password=ЗАБЫЛ ПАРОЛЬ -account.methods.microsoft.snapshot=Лаунчер версии снапшот не поддерживает авторизацию через систему Microsoft. +account.methods.microsoft.snapshot=Вы используете неофициальное построение HMCL, загрузите официальное построение для входа в Microsoft. account.methods.microsoft.waiting_browser=Ожидание авторизации в открытом окне браузера... account.methods.offline=Офлайн account.methods.offline.uuid=UUID diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 8bfee4a33..c78e802b3 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -108,7 +108,8 @@ account.methods.microsoft.hint=你需要按照以下步驟添加:\n1.點擊“ account.methods.microsoft.manual=你需要按照以下步驟添加:\n1.點擊“登入”按鈕\n2.在網頁瀏覽器顯示的網站中輸入該代碼:%1$s(已自動拷貝,請點此再次拷貝),並點擊“下一步”\n3.按照網站的提示登入\n4.當網站顯示“ 是否允許此應用訪問你的信息?”的標識時,請點擊“是”\n5.當網站提示“大功告成”的標示時,即表示登入成功!然後等待賬戶完成添加即可\n-若網站提示“出现错误”的標識,請嘗試重新按照以上步驟登入\n-若賬戶添加失敗,請嘗試重新按照以上步驟登入\n-若網站未能打開,請手動在網頁瀏覽器中打開:%2$s\n-若設備網絡環境不佳,可能登陸網站加載很慢甚至無法加載,此時請使用 VPN 或代理伺服器並重試\n-若登入微軟賬號的 Token 洩露,可點擊下方“解除帳戶授權”解除登入授權,然後等待 Token 過期 account.methods.microsoft.profile=帳戶設置頁 account.methods.forgot_password=忘記密碼 -account.methods.microsoft.snapshot=HMCL 快照版暫不提供微軟登入支持,請使用穩定版或測試版進行登入。 +account.methods.microsoft.snapshot=你正在使用非官方構建的 HMCL,請下載官方構建進行微軟登入。 +account.methods.microsoft.snapshot.website=官方網站 account.methods.microsoft.waiting_browser=等待在新打開的瀏覽器窗口中完成登入... account.methods.offline=離線模式 account.methods.offline.name.special_characters=建議使用英文字符、數字以及下劃線命名! @@ -997,6 +998,8 @@ sponsor.hmcl=Hello Minecraft! Launcher 是一個免費、開源的 Minecraft 啟 system.architecture=架構 system.operating_system=操作系統 +unofficial.hint=你正在使用非官方構建的 HMCL,我們無法保證其安全性,請注意甄別。 + update=啟動器更新 update.accept=更新 update.changelog=更新日誌 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 3cafcc700..da73d8625 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -108,7 +108,8 @@ account.methods.microsoft.hint=你需要按照以下步骤添加:\n1.点击“ account.methods.microsoft.manual=你需要按照以下步骤添加:\n1.点击“登录”按钮\n2.在网页浏览器显示的网站中输入:%1$s(已自动拷贝,点此再次拷贝),并点击“下一步”\n3.按照网站的提示登录\n4.当网站提示“是否允许此应用访问你的信息?”的标识时,请点击“是”\n5.当网站提示“大功告成”的标识时,即表示登录成功!然后等待账户完成添加即可\n-若网站提示“出现错误”的标识时,请重新按照以上步骤重新添加\n-若账户添加失败,请重新按照以上步骤重新添加\n-若网站未能显示,请手动在网页浏览器中打开:%2$s\n-若设备网络环境不佳,可能登录网站加载很慢甚至无法加载,此时请使用 VPN 或代理服务器并重试\n-若登录微软账户的 Token (不是密码)泄露,可点击下方“解除账户绑定”解除登录授权,然后等待 Token 过期 account.methods.microsoft.profile=帐户设置页 account.methods.forgot_password=忘记密码 -account.methods.microsoft.snapshot=HMCL 快照版暂不提供微软登录支持,请使用推荐版本(稳定版)或测试版进行登录! +account.methods.microsoft.snapshot=你正在使用非官方构建的 HMCL,请下载官方构建进行微软登录。 +account.methods.microsoft.snapshot.website=官方网站 account.methods.microsoft.waiting_browser=等待在新打开的浏览器窗口中完成登录…… account.methods.offline=离线模式 account.methods.offline.name.special_characters=建议使用英文字符、数字以及下划线命名! @@ -999,6 +1000,8 @@ sponsor.hmcl=Hello Minecraft! Launcher 是一个免费、自由、开放源代 system.architecture=架构 system.operating_system=操作系统 +unofficial.hint=你正在使用非官方构建的 HMCL,我们无法保证其安全性,请注意甄别。 + update=启动器更新 update.accept=更新 update.changelog=更新日志