From bbd2b22e0c3782f9c71662682a725f79842a37d9 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Tue, 13 Feb 2018 11:52:43 +0800 Subject: [PATCH 1/6] version bump --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f05a1f9..7e35343 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ dependencies { def gitInfo = versionDetails() sourceCompatibility = 1.8 -version = '1.0.' + (System.getenv('BUILD_NUMBER')?:'0-SNAPSHOT') + '-' + gitInfo.gitHashFull[0..6] +version = '1.1.' + (System.getenv('BUILD_NUMBER')?:'0-SNAPSHOT') + '-' + gitInfo.gitHashFull[0..6] if (!gitInfo.isCleanTag) version += '.dirty' jar { From d71cad2085fa40d3c82665e60bdbf9787934af60 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Tue, 13 Feb 2018 11:54:07 +0800 Subject: [PATCH 2/6] remove local config & tweaker --- authlib-injector.example.yaml | 50 ----- build.gradle | 9 +- .../authlibinjector/AuthlibInjector.java | 64 ------- .../tweaker/AuthlibInjectorTweaker.java | 37 ---- .../tweaker/TweakerTransformerAdapter.java | 33 ---- .../resources/META-INF/licenses/snakeyaml.txt | 176 ------------------ 6 files changed, 1 insertion(+), 368 deletions(-) delete mode 100644 authlib-injector.example.yaml delete mode 100644 src/main/java/org/to2mbn/authlibinjector/tweaker/AuthlibInjectorTweaker.java delete mode 100644 src/main/java/org/to2mbn/authlibinjector/tweaker/TweakerTransformerAdapter.java delete mode 100644 src/main/resources/META-INF/licenses/snakeyaml.txt diff --git a/authlib-injector.example.yaml b/authlib-injector.example.yaml deleted file mode 100644 index 225ebdf..0000000 --- a/authlib-injector.example.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# authlib-injector配置文件模板 -# 该文件仅作为参考, 请不要复制粘贴该文件中的内容 - -# 配置文件查找顺序 -# authlib-injector会按照以下顺序搜索配置文件, 并使用第一个找到的 -# - 以javaagent方式启动时指定的参数 -# 例如通过 -javaagent:authlib-injector.jar=my-authlib-injector.yaml -# 指定 my-authlib-injector.yaml 为配置文件 -# - org.to2mbn.authlibinjector.config 属性 -# 例如 -Dorg.to2mbn.authlibinjector.config=my-authlib-injector.yaml -# - JAR中的 /authlib-injector.yaml 文件 -# - 当前目录下的 authlib-injector.yaml 文件 - -# 是否开启调试模式 -# 开启后会将修改过的字节码存于当前目录下名为 -# {className}_modified.class 的文件中 -debug: false - -# API路径 -# 对于如下格式的MojangAPI: https://{subdomain}.mojang.com/{path} -# 将会被替换为: {apiRoot}{subdomain}/{path} -# -# 例如, apiRoot为 https://yggdrasil.example.com/ -# 则 https://sessionserver.mojang.com/session/minecraft/join -# 会被替换为 https://yggdrasil.example.com/sessionserver/session/minecraft/join -apiRoot: https://yggdrasil.example.com/ - -# 加入皮肤白名单的域名后缀 -# 只有以 .minecraft.net, .mojang.com, -# 或以下列表中任一元素为后缀的域名才能提供材质 -skinWhitelistDomains: - - .example.com - -# 用于验证profile properties的公钥 -# 如果不想进行公钥替换, 可将该属性删除 -publicKey: |- - -----BEGIN PUBLIC KEY----- - MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAylB4B6m5lz7jwrcFz6Fd - /fnfUhcvlxsTSn5kIK/2aGG1C3kMy4VjhwlxF6BFUSnfxhNswPjh3ZitkBxEAFY2 - 5uzkJFRwHwVA9mdwjashXILtR6OqdLXXFVyUPIURLOSWqGNBtb08EN5fMnG8iFLg - EJIBMxs9BvF3s3/FhuHyPKiVTZmXY0WY4ZyYqvoKR+XjaTRPPvBsDa4WI2u1zxXM - eHlodT3lnCzVvyOYBLXL6CJgByuOxccJ8hnXfF9yY4F0aeL080Jz/3+EBNG8RO4B - yhtBf4Ny8NQ6stWsjfeUIvH7bU/4zCYcYOq4WrInXHqS8qruDmIl7P5XXGcabuzQ - stPf/h2CRAUpP/PlHXcMlvewjmGU6MfDK+lifScNYwjPxRo4nKTGFZf/0aqHCh/E - AsQyLKrOIYRE0lDG3bzBh8ogIMLAugsAfBb6M3mqCqKaTMAf/VAjh5FFJnjS+7bE - +bZEV0qwax1CEoPPJL1fIQjOS8zj086gjpGRCtSy9+bTPTfTR/SJ+VUB5G2IeCIt - kNHpJX2ygojFZ9n5Fnj7R9ZnOM+L8nyIjPu3aePvtcrXlyLhH/hvOfIOjPxOlqW+ - O5QwSFP4OEcyLAUgDdUgyW36Z5mB285uKW/ighzZsOTevVUG2QwDItObIV6i8RCx - FbN2oDHyPaO5j1tTaBNyVt8CAwEAAQ== - -----END PUBLIC KEY----- diff --git a/build.gradle b/build.gradle index 7e35343..136ca79 100644 --- a/build.gradle +++ b/build.gradle @@ -6,15 +6,10 @@ plugins { repositories { mavenCentral() - maven { url 'https://libraries.minecraft.net/' } } dependencies { compile 'org.ow2.asm:asm:6.0' - compile 'org.yaml:snakeyaml:1.19' - compileOnly ('net.minecraft:launchwrapper:1.12') { - transitive = false - } testCompile 'junit:junit:4.12' } @@ -32,8 +27,7 @@ jar { 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), 'Git-Commit': gitInfo.gitHashFull, 'Git-IsClean': gitInfo.isCleanTag, - 'Premain-Class': 'org.to2mbn.authlibinjector.javaagent.AuthlibInjectorPremain', - 'TweakClass': 'org.to2mbn.authlibinjector.tweaker.AuthlibInjectorTweaker' + 'Premain-Class': 'org.to2mbn.authlibinjector.javaagent.AuthlibInjectorPremain' ) } } @@ -51,7 +45,6 @@ shadowJar { exclude 'META-INF/maven/**' exclude 'module-info.class' - relocate 'org.yaml.snakeyaml', 'org.to2mbn.authlibinjector.internal.org.yaml.snakeyaml' relocate 'org.objectweb.asm', 'org.to2mbn.authlibinjector.internal.org.objectweb.asm' } diff --git a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java index 9cc1200..2eaef10 100644 --- a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java +++ b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java @@ -3,19 +3,11 @@ package org.to2mbn.authlibinjector; import static java.util.Optional.empty; import static java.util.Optional.of; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; import java.lang.instrument.ClassFileTransformer; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.text.MessageFormat; import java.util.Optional; import java.util.function.Consumer; import org.to2mbn.authlibinjector.transform.ClassTransformer; -import org.yaml.snakeyaml.Yaml; public final class AuthlibInjector { @@ -58,62 +50,6 @@ public final class AuthlibInjector { } private static Optional configure() { - // 1. remote config - Optional localConfig = loadLocalConfig(); - if (localConfig.isPresent()) return localConfig; - - // 2. local config - Optional remoteConfig = loadRemoteConfig(); - if (remoteConfig.isPresent()) return remoteConfig; - - return empty(); - } - - private static Optional loadLocalConfig() { - try { - Optional localConfig = locateLocalConfig(); - if (localConfig.isPresent()) { - try (Reader reader = new InputStreamReader(localConfig.get(), StandardCharsets.UTF_8)) { - return of(new Yaml().loadAs(reader, InjectorConfig.class)); - } - } - } catch (IOException e) { - log("unable to configure locally: {0}", e); - } - return empty(); - } - - private static Optional locateLocalConfig() throws IOException { - // 1. the specified config file - String configProperty = System.getProperty("org.to2mbn.authlibinjector.config"); - if (configProperty != null && !configProperty.startsWith("@")) { - Path configFile = Paths.get(configProperty); - if (Files.exists(configFile)) { - log("using config: " + configProperty); - return of(Files.newInputStream(configFile)); - } else { - log("file not exists: {0}", configProperty); - } - } - - // 2. the config file in jar - InputStream packedConfig = AuthlibInjector.class.getResourceAsStream("/authlib-injector.yaml"); - if (packedConfig != null) { - log("using config: jar:/authlib-injector.yaml"); - return of(packedConfig); - } - - // 3. the config in the current dir - Path currentConfigFile = Paths.get("authlib-injector.yaml"); - if (Files.exists(currentConfigFile)) { - log("using config: ./authlib-injector.yaml"); - return of(Files.newInputStream(currentConfigFile)); - } - - return empty(); - } - - private static Optional loadRemoteConfig() { String configProperty = System.getProperty("org.to2mbn.authlibinjector.config"); if (configProperty == null || !configProperty.startsWith("@")) { return empty(); diff --git a/src/main/java/org/to2mbn/authlibinjector/tweaker/AuthlibInjectorTweaker.java b/src/main/java/org/to2mbn/authlibinjector/tweaker/AuthlibInjectorTweaker.java deleted file mode 100644 index cd129cf..0000000 --- a/src/main/java/org/to2mbn/authlibinjector/tweaker/AuthlibInjectorTweaker.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.to2mbn.authlibinjector.tweaker; - -import static org.to2mbn.authlibinjector.AuthlibInjector.bootstrap; -import static org.to2mbn.authlibinjector.AuthlibInjector.log; -import java.io.File; -import java.util.List; -import net.minecraft.launchwrapper.ITweaker; -import net.minecraft.launchwrapper.LaunchClassLoader; - -public class AuthlibInjectorTweaker implements ITweaker { - - @Override - public void acceptOptions(List args, File gameDir, File assetsDir, String profile) {} - - @Override - public void injectIntoClassLoader(LaunchClassLoader launchClassLoader) { - ClassLoader originalCtxCl = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); - try { - log("launched from tweaker"); - bootstrap(TweakerTransformerAdapter.transformers::add); - launchClassLoader.registerTransformer(TweakerTransformerAdapter.class.getName()); - } finally { - Thread.currentThread().setContextClassLoader(originalCtxCl); - } - } - - @Override - public String getLaunchTarget() { - return "net.minecraft.client.main.Main"; - } - - @Override - public String[] getLaunchArguments() { - return new String[0]; - } -} diff --git a/src/main/java/org/to2mbn/authlibinjector/tweaker/TweakerTransformerAdapter.java b/src/main/java/org/to2mbn/authlibinjector/tweaker/TweakerTransformerAdapter.java deleted file mode 100644 index 6d989a9..0000000 --- a/src/main/java/org/to2mbn/authlibinjector/tweaker/TweakerTransformerAdapter.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.to2mbn.authlibinjector.tweaker; - -import static org.to2mbn.authlibinjector.AuthlibInjector.log; -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.util.ArrayList; -import java.util.List; -import net.minecraft.launchwrapper.IClassTransformer; -import net.minecraft.launchwrapper.Launch; - -public class TweakerTransformerAdapter implements IClassTransformer { - - public static List transformers = new ArrayList<>(); - - @Override - public byte[] transform(String name, String transformedName, byte[] classBuffer) { - String internalClassName = name.replace('.', '/'); - for (ClassFileTransformer transformer : transformers) { - byte[] result = null; - try { - result = transformer.transform(Launch.classLoader, internalClassName, null, null, classBuffer); - } catch (IllegalClassFormatException e) { - log("exception while invoking {0}: {1}", transformer, e); - e.printStackTrace(); - } - if (result != null) { - classBuffer = result; - } - } - return classBuffer; - } - -} diff --git a/src/main/resources/META-INF/licenses/snakeyaml.txt b/src/main/resources/META-INF/licenses/snakeyaml.txt deleted file mode 100644 index d9a10c0..0000000 --- a/src/main/resources/META-INF/licenses/snakeyaml.txt +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS From cd5b42140c2aa466efd4d2884d4bb2831e8c9190 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Tue, 13 Feb 2018 11:57:44 +0800 Subject: [PATCH 3/6] refactor remote config & update readme --- README.md | 38 +------------------ .../authlibinjector/AuthlibInjector.java | 7 ++-- 2 files changed, 5 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 190534a..d80d34c 100644 --- a/README.md +++ b/README.md @@ -17,41 +17,7 @@ gradle 或者直接从[Jenkins](https://ci.to2mbn.org/job/authlib-injector)下载构建好的JAR。 ## 部署 - -### 配置 -配置文件模板位于[authlib-injector.example.yaml](https://github.com/to2mbn/authlib-injector/blob/master/authlib-injector.example.yaml)。 - -#### 生成签名公钥 -服务端返回的profile properties需要带有数字签名。 - -生成方法见[签名密钥对](https://github.com/to2mbn/authlib-injector/wiki/%E7%AD%BE%E5%90%8D%E5%AF%86%E9%92%A5%E5%AF%B9)。 - -### 加载 -#### 作为javaagent加载 -向JVM参数中添加`-javaagent:` - -该方法适用于所有客户端、服务端、启动器等。 - -#### 作为mod加载 -直接放入mods目录即可。 - -该方法适用于Forge及Liteloader。 - -### 指定配置文件 -authlib-injector提供了以下方式来指定配置文件(按优先级排序): - -1. 通过javaagent参数指定 - * 在`javaagent`参数后面添加`=` - * 例如`-javaagent:authlib-injector.jar=my-authlib-injector.yaml` - * 仅适用于通过javaagent加载 -2. 通过`org.to2mbn.authlibinjector.config`属性指定 - * 如`-Dorg.to2mbn.authlibinjector.config=my-authlib-injector.yaml` -3. JAR中的`/authlib-injector.yaml`文件 - * 可以在编译时向`src/main/resources`中添加配置文件,或者直接向JAR中添加(JAR为zip格式) -4. 当前目录下的`authlib-injector.yaml`文件 - -### 远程自动配置 -对于实现了本规范中[扩展API](https://github.com/to2mbn/authlib-injector/wiki/Yggdrasil%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83#%E6%89%A9%E5%B1%95api)的Yggdrasil服务端,可以直接通过添加以下JVM参数来配置,不需要配置文件: +对于实现了本规范中[扩展API](https://github.com/to2mbn/authlib-injector/wiki/Yggdrasil%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83#%E6%89%A9%E5%B1%95api)的Yggdrasil服务端,可以直接通过添加以下JVM参数来配置: ``` --javaagent:{authlib-injector.jar的路径}=@{Yggdrasil服务端的URL(API Root)} +-javaagent:{authlib-injector.jar的路径}={Yggdrasil服务端的URL(API Root)} ``` diff --git a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java index 2eaef10..fcb3994 100644 --- a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java +++ b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java @@ -50,15 +50,14 @@ public final class AuthlibInjector { } private static Optional configure() { - String configProperty = System.getProperty("org.to2mbn.authlibinjector.config"); - if (configProperty == null || !configProperty.startsWith("@")) { + String url = System.getProperty("org.to2mbn.authlibinjector.config"); + if (url == null) { return empty(); } - String url = configProperty.substring(1); log("trying to config remotely: {0}", url); InjectorConfig config = new InjectorConfig(); - config.setDebug("true".equals(System.getProperty("org.to2mbn.authlibinjector.remoteconfig.debug"))); + config.setDebug("true".equals(System.getProperty("org.to2mbn.authlibinjector.debug"))); RemoteConfiguration remoteConfig; try { From a671ee8339ebf1120712b3b93ac4e5311995c5c9 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Tue, 13 Feb 2018 12:36:30 +0800 Subject: [PATCH 4/6] support prefetched metadata & refactor --- .../authlibinjector/AuthlibInjector.java | 96 +++++++++------ .../authlibinjector/InjectorConfig.java | 56 --------- ...ation.java => YggdrasilConfiguration.java} | 20 +-- .../javaagent/AuthlibInjectorPremain.java | 4 +- .../transform/ClassTransformer.java | 17 ++- .../transform/LdcTransformUnit.java | 4 +- .../authlibinjector/util/HttpRequester.java | 114 ------------------ .../to2mbn/authlibinjector/util/IOUtils.java | 13 +- 8 files changed, 86 insertions(+), 238 deletions(-) delete mode 100644 src/main/java/org/to2mbn/authlibinjector/InjectorConfig.java rename src/main/java/org/to2mbn/authlibinjector/{RemoteConfiguration.java => YggdrasilConfiguration.java} (73%) delete mode 100644 src/main/java/org/to2mbn/authlibinjector/util/HttpRequester.java diff --git a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java index fcb3994..9fb32ec 100644 --- a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java +++ b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java @@ -2,12 +2,16 @@ package org.to2mbn.authlibinjector; import static java.util.Optional.empty; import static java.util.Optional.of; +import static org.to2mbn.authlibinjector.util.IOUtils.readURL; import java.io.IOException; import java.lang.instrument.ClassFileTransformer; import java.text.MessageFormat; import java.util.Optional; import java.util.function.Consumer; import org.to2mbn.authlibinjector.transform.ClassTransformer; +import org.to2mbn.authlibinjector.transform.SkinWhitelistTransformUnit; +import org.to2mbn.authlibinjector.transform.YggdrasilApiTransformUnit; +import org.to2mbn.authlibinjector.transform.YggdrasilKeyTransformUnit; public final class AuthlibInjector { @@ -19,60 +23,82 @@ public final class AuthlibInjector { private AuthlibInjector() {} private static boolean booted = false; + private static boolean debug = "true".equals(System.getProperty("org.to2mbn.authlibinjector.debug")); - public static void log(String message, Object... args) { + public static void info(String message, Object... args) { System.err.println("[authlib-injector] " + MessageFormat.format(message, args)); } + public static void debug(String message, Object... args) { + if (debug) { + info(message, args); + } + } + public static void bootstrap(Consumer transformerRegistry) { if (booted) { - log("already booted, skipping"); + info("already booted, skipping"); return; } booted = true; - Optional optionalConfig = configure(); + Optional optionalConfig = configure(); if (!optionalConfig.isPresent()) { - log("no config is found, exiting"); + info("no config available"); return; } - InjectorConfig config = optionalConfig.get(); + transformerRegistry.accept(createTransformer(optionalConfig.get())); + } + + private static Optional configure() { + String apiRoot = System.getProperty("org.to2mbn.authlibinjector.config"); + if (apiRoot == null) return empty(); + info("api root: {0}", apiRoot); + + String metadataResponse = System.getProperty("org.to2mbn.authlibinjector.config.prefetched"); + + if (metadataResponse == null) { + info("fetching metadata"); + try { + metadataResponse = readURL(apiRoot); + } catch (IOException e) { + info("unable to fetch metadata: {0}", e); + return empty(); + } + + } else { + info("prefetched metadata detected"); + } + + debug("metadata: {0}", metadataResponse); + + YggdrasilConfiguration configuration; + try { + configuration = YggdrasilConfiguration.parse(apiRoot, metadataResponse); + } catch (IOException e) { + info("unable to parse metadata: {0}\n" + + "metadata to parse:\n" + + "{1}", + e, metadataResponse); + return empty(); + } + debug("parsed metadata: {0}", configuration); + return of(configuration); + } + + private static ClassTransformer createTransformer(YggdrasilConfiguration config) { ClassTransformer transformer = new ClassTransformer(); - - if (config.isDebug()) transformer.debug = true; - + transformer.debugSaveClass = debug; for (String ignore : nonTransformablePackages) transformer.ignores.add(ignore); - config.applyTransformers(transformer.units); - transformerRegistry.accept(transformer); - } + transformer.units.add(new YggdrasilApiTransformUnit(config.getApiRoot())); + transformer.units.add(new SkinWhitelistTransformUnit(config.getSkinDomains().toArray(new String[0]))); + config.getDecodedPublickey().ifPresent( + key -> transformer.units.add(new YggdrasilKeyTransformUnit(key.getEncoded()))); - private static Optional configure() { - String url = System.getProperty("org.to2mbn.authlibinjector.config"); - if (url == null) { - return empty(); - } - log("trying to config remotely: {0}", url); - - InjectorConfig config = new InjectorConfig(); - config.setDebug("true".equals(System.getProperty("org.to2mbn.authlibinjector.debug"))); - - RemoteConfiguration remoteConfig; - try { - remoteConfig = RemoteConfiguration.fetch(url); - } catch (IOException e) { - log("unable to configure remotely: {0}", e); - return empty(); - } - - if (config.isDebug()) { - log("fetched remote config: {0}", remoteConfig); - } - - remoteConfig.applyToInjectorConfig(config); - return of(config); + return transformer; } } diff --git a/src/main/java/org/to2mbn/authlibinjector/InjectorConfig.java b/src/main/java/org/to2mbn/authlibinjector/InjectorConfig.java deleted file mode 100644 index 2c385f7..0000000 --- a/src/main/java/org/to2mbn/authlibinjector/InjectorConfig.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.to2mbn.authlibinjector; - -import static org.to2mbn.authlibinjector.util.KeyUtils.decodePublicKey; -import java.util.List; -import org.to2mbn.authlibinjector.transform.SkinWhitelistTransformUnit; -import org.to2mbn.authlibinjector.transform.TransformUnit; -import org.to2mbn.authlibinjector.transform.YggdrasilApiTransformUnit; -import org.to2mbn.authlibinjector.transform.YggdrasilKeyTransformUnit; - -public class InjectorConfig { - - private String apiRoot; - private List skinWhitelistDomains; - private String publicKey; - private boolean debug; - - public String getApiRoot() { - return apiRoot; - } - - public void setApiRoot(String apiRoot) { - this.apiRoot = apiRoot; - } - - public List getSkinWhitelistDomains() { - return skinWhitelistDomains; - } - - public void setSkinWhitelistDomains(List skinWhitelistDomains) { - this.skinWhitelistDomains = skinWhitelistDomains; - } - - public String getPublicKey() { - return publicKey; - } - - public void setPublicKey(String publicKey) { - this.publicKey = publicKey; - } - - public boolean isDebug() { - return debug; - } - - public void setDebug(boolean debug) { - this.debug = debug; - } - - public void applyTransformers(List units) { - units.add(new YggdrasilApiTransformUnit(apiRoot)); - units.add(new SkinWhitelistTransformUnit(skinWhitelistDomains.toArray(new String[0]))); - if (publicKey != null) { - units.add(new YggdrasilKeyTransformUnit(decodePublicKey(publicKey))); - } - } -} diff --git a/src/main/java/org/to2mbn/authlibinjector/RemoteConfiguration.java b/src/main/java/org/to2mbn/authlibinjector/YggdrasilConfiguration.java similarity index 73% rename from src/main/java/org/to2mbn/authlibinjector/RemoteConfiguration.java rename to src/main/java/org/to2mbn/authlibinjector/YggdrasilConfiguration.java index 6cd364c..8dbd123 100644 --- a/src/main/java/org/to2mbn/authlibinjector/RemoteConfiguration.java +++ b/src/main/java/org/to2mbn/authlibinjector/YggdrasilConfiguration.java @@ -6,8 +6,6 @@ import static java.util.Objects.requireNonNull; import static java.util.Optional.empty; import static java.util.Optional.of; import static java.util.Optional.ofNullable; -import static org.to2mbn.authlibinjector.util.HttpRequester.http; -import static org.to2mbn.authlibinjector.util.IOUtils.asJson; import static org.to2mbn.authlibinjector.util.KeyUtils.decodePublicKey; import static org.to2mbn.authlibinjector.util.KeyUtils.loadX509PublicKey; import java.io.IOException; @@ -21,13 +19,13 @@ import java.util.TreeMap; import org.to2mbn.authlibinjector.internal.org.json.JSONException; import org.to2mbn.authlibinjector.internal.org.json.JSONObject; -public class RemoteConfiguration { +public class YggdrasilConfiguration { - public static RemoteConfiguration fetch(String apiRoot) throws IOException { + public static YggdrasilConfiguration parse(String apiRoot, String metadataResponse) throws IOException { if (!apiRoot.endsWith("/")) apiRoot += "/"; try { - JSONObject response = asJson(http.request("GET", apiRoot)); + JSONObject response = new JSONObject(metadataResponse); List skinDomains = new ArrayList<>(); ofNullable(response.optJSONArray("skinDomains")) @@ -54,7 +52,7 @@ public class RemoteConfiguration { .map(JSONObject::toMap) .ifPresent(it -> it.forEach((k, v) -> meta.put(k, String.valueOf(v)))); - return new RemoteConfiguration(apiRoot, unmodifiableList(skinDomains), signaturePublickey, unmodifiableMap(meta), decodedPublickey); + return new YggdrasilConfiguration(apiRoot, unmodifiableList(skinDomains), signaturePublickey, unmodifiableMap(meta), decodedPublickey); } catch (JSONException e) { throw new IOException("Invalid json", e); } @@ -66,7 +64,7 @@ public class RemoteConfiguration { private Optional decodedPublickey; private Map meta; - public RemoteConfiguration(String apiRoot, List skinDomains, Optional signaturePublickey, Map meta, Optional decodedPublickey) { + public YggdrasilConfiguration(String apiRoot, List skinDomains, Optional signaturePublickey, Map meta, Optional decodedPublickey) { this.apiRoot = requireNonNull(apiRoot); this.skinDomains = requireNonNull(skinDomains); this.signaturePublickey = requireNonNull(signaturePublickey); @@ -94,14 +92,8 @@ public class RemoteConfiguration { return decodedPublickey; } - public void applyToInjectorConfig(InjectorConfig config) { - config.setApiRoot(apiRoot); - config.setPublicKey(signaturePublickey.orElse(null)); - config.setSkinWhitelistDomains(skinDomains); - } - @Override public String toString() { - return "RemoteConfiguration [apiRoot=" + apiRoot + ", skinDomains=" + skinDomains + ", signaturePublickey=" + signaturePublickey + ", meta=" + meta + "]"; + return "YggdrasilConfiguration [apiRoot=" + apiRoot + ", skinDomains=" + skinDomains + ", signaturePublickey=" + signaturePublickey + ", meta=" + meta + "]"; } } diff --git a/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java b/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java index fe3d98d..3154223 100644 --- a/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java +++ b/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java @@ -1,14 +1,14 @@ package org.to2mbn.authlibinjector.javaagent; import static org.to2mbn.authlibinjector.AuthlibInjector.bootstrap; -import static org.to2mbn.authlibinjector.AuthlibInjector.log; +import static org.to2mbn.authlibinjector.AuthlibInjector.info; import java.lang.instrument.Instrumentation; public class AuthlibInjectorPremain { public static void premain(String arg, Instrumentation instrumentation) { try { - log("launched from javaagent"); + info("launched from javaagent"); if (arg != null && !arg.isEmpty()) { System.setProperty("org.to2mbn.authlibinjector.config", arg); } diff --git a/src/main/java/org/to2mbn/authlibinjector/transform/ClassTransformer.java b/src/main/java/org/to2mbn/authlibinjector/transform/ClassTransformer.java index 389ddc6..75f37aa 100644 --- a/src/main/java/org/to2mbn/authlibinjector/transform/ClassTransformer.java +++ b/src/main/java/org/to2mbn/authlibinjector/transform/ClassTransformer.java @@ -1,6 +1,7 @@ package org.to2mbn.authlibinjector.transform; -import static org.to2mbn.authlibinjector.AuthlibInjector.log; +import static org.to2mbn.authlibinjector.AuthlibInjector.debug; +import static org.to2mbn.authlibinjector.AuthlibInjector.info; import java.io.IOException; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; @@ -21,7 +22,7 @@ public class ClassTransformer implements ClassFileTransformer { public List units = new ArrayList<>(); public Set ignores = new HashSet<>(); - public boolean debug; + public boolean debugSaveClass; private static class TransformHandle { @@ -51,7 +52,7 @@ public class ClassTransformer implements ClassFileTransformer { ClassReader reader = new ClassReader(classBuffer); reader.accept(optionalVisitor.get(), 0); if (currentModified) { - log("transform {0} using {1}", className, unit); + info("transform {0} using {1}", className, unit); modified = true; classBuffer = writer.toByteArray(); } @@ -82,18 +83,16 @@ public class ClassTransformer implements ClassFileTransformer { units.forEach(handle::accept); if (handle.getResult().isPresent()) { byte[] classBuffer = handle.getResult().get(); - if (debug) { + if (debugSaveClass) { saveClassFile(className, classBuffer); } return classBuffer; } else { - if (debug) { - log("no transform performed on {0}", className); - } + debug("no transform performed on {0}", className); return null; } } catch (Throwable e) { - log("unable to transform {0}: {1}", internalClassName, e); + info("unable to transform {0}: {1}", internalClassName, e); e.printStackTrace(); } } @@ -104,7 +103,7 @@ public class ClassTransformer implements ClassFileTransformer { try { Files.write(Paths.get(className + "_dump.class"), classBuffer, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException e) { - log("unable to dump class {0}: {1}", className, e); + info("unable to dump class {0}: {1}", className, e); e.printStackTrace(); } } diff --git a/src/main/java/org/to2mbn/authlibinjector/transform/LdcTransformUnit.java b/src/main/java/org/to2mbn/authlibinjector/transform/LdcTransformUnit.java index 83bca53..986c330 100644 --- a/src/main/java/org/to2mbn/authlibinjector/transform/LdcTransformUnit.java +++ b/src/main/java/org/to2mbn/authlibinjector/transform/LdcTransformUnit.java @@ -1,7 +1,7 @@ package org.to2mbn.authlibinjector.transform; import static org.objectweb.asm.Opcodes.ASM6; -import static org.to2mbn.authlibinjector.AuthlibInjector.log; +import static org.to2mbn.authlibinjector.AuthlibInjector.info; import java.util.Optional; import java.util.function.Function; import org.objectweb.asm.ClassVisitor; @@ -29,7 +29,7 @@ public class LdcTransformUnit implements TransformUnit { Optional transformed = ldcMapper.apply((String) cst); if (transformed.isPresent() && !transformed.get().equals(cst)) { modifiedCallback.run(); - log("transform [{0}] to [{1}]", cst, transformed.get()); + info("transform [{0}] to [{1}]", cst, transformed.get()); super.visitLdcInsn(transformed.get()); } else { super.visitLdcInsn(cst); diff --git a/src/main/java/org/to2mbn/authlibinjector/util/HttpRequester.java b/src/main/java/org/to2mbn/authlibinjector/util/HttpRequester.java deleted file mode 100644 index 666e7f0..0000000 --- a/src/main/java/org/to2mbn/authlibinjector/util/HttpRequester.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.to2mbn.authlibinjector.util; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.to2mbn.authlibinjector.util.IOUtils.asString; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Map; - -public class HttpRequester { - - /** Common http requester */ - public static final HttpRequester http = new HttpRequester(); - - private int timeout = 15000; - - public int getTimeout() { - return timeout; - } - - public void setTimeout(int timeout) { - this.timeout = timeout; - } - - public String request(String method, String url) throws IOException { - return request(method, url, null); - } - - public String request(String method, String url, Map headers) throws IOException { - HttpURLConnection conn = createConnection(url, headers); - conn.setRequestMethod(method); - try { - conn.connect(); - try (InputStream in = conn.getInputStream()) { - return asString(in); - } - } catch (IOException e) { - try (InputStream in = conn.getErrorStream()) { - return readErrorStream(in, e); - } - } finally { - conn.disconnect(); - } - } - - public String requestWithPayload(String method, String url, Object payload, String contentType) throws IOException { - return requestWithPayload(method, url, payload, contentType, null); - } - - public String requestWithPayload(String method, String url, Object payload, String contentType, Map headers) throws IOException { - byte[] bytePayload; - if (payload instanceof byte[]) { - bytePayload = (byte[]) payload; - } else if (payload == null) { - bytePayload = new byte[0]; - } else { - bytePayload = String.valueOf(payload).getBytes(UTF_8); - } - - HttpURLConnection conn = createConnection(url, headers); - conn.setRequestMethod(method); - conn.setRequestProperty("Content-Type", contentType); - conn.setRequestProperty("Content-Length", String.valueOf(bytePayload.length)); - conn.setDoOutput(true); - - try { - conn.connect(); - try (OutputStream out = conn.getOutputStream()) { - out.write(bytePayload); - } - try (InputStream in = conn.getInputStream()) { - return asString(in); - } - } catch (IOException e) { - try (InputStream in = conn.getErrorStream()) { - return readErrorStream(in, e); - } - } finally { - conn.disconnect(); - } - } - - private String readErrorStream(InputStream in, IOException e) throws IOException { - if (in == null) - throw e; - - try { - return asString(in); - } catch (IOException e1) { - if (e != e1) - e1.addSuppressed(e); - - throw e1; - } - } - - private HttpURLConnection createConnection(String url, Map headers) throws IOException { - HttpURLConnection conn = createConnection(new URL(url)); - if (headers != null) - headers.forEach((key, value) -> conn.setRequestProperty(key, value)); - return conn; - } - - private HttpURLConnection createConnection(URL url) throws IOException { - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setConnectTimeout(timeout); - conn.setReadTimeout(timeout); - conn.setUseCaches(false); - return conn; - } - -} diff --git a/src/main/java/org/to2mbn/authlibinjector/util/IOUtils.java b/src/main/java/org/to2mbn/authlibinjector/util/IOUtils.java index 0fc787c..c21178b 100644 --- a/src/main/java/org/to2mbn/authlibinjector/util/IOUtils.java +++ b/src/main/java/org/to2mbn/authlibinjector/util/IOUtils.java @@ -6,11 +6,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; -import org.to2mbn.authlibinjector.internal.org.json.JSONException; -import org.to2mbn.authlibinjector.internal.org.json.JSONObject; +import java.net.URL; public final class IOUtils { + public static String readURL(String url) throws IOException { + try (InputStream in = new URL(url).openStream()) { + return asString(in); + } + } + public static String asString(InputStream in) throws IOException { CharArrayWriter w = new CharArrayWriter(); Reader reader = new InputStreamReader(in, UTF_8); @@ -22,10 +27,6 @@ public final class IOUtils { return new String(w.toCharArray()); } - public static JSONObject asJson(String data) throws JSONException { - return new JSONObject(data); - } - private IOUtils() {} } From cdae2408bc352d93f1a5f34618ce850d5381e562 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Tue, 13 Feb 2018 12:59:25 +0800 Subject: [PATCH 5/6] refactor YggdrasilConfiguration.toString() --- .../org/to2mbn/authlibinjector/YggdrasilConfiguration.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/to2mbn/authlibinjector/YggdrasilConfiguration.java b/src/main/java/org/to2mbn/authlibinjector/YggdrasilConfiguration.java index 8dbd123..2152c6b 100644 --- a/src/main/java/org/to2mbn/authlibinjector/YggdrasilConfiguration.java +++ b/src/main/java/org/to2mbn/authlibinjector/YggdrasilConfiguration.java @@ -1,5 +1,6 @@ package org.to2mbn.authlibinjector; +import static java.text.MessageFormat.format; import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableMap; import static java.util.Objects.requireNonNull; @@ -94,6 +95,7 @@ public class YggdrasilConfiguration { @Override public String toString() { - return "YggdrasilConfiguration [apiRoot=" + apiRoot + ", skinDomains=" + skinDomains + ", signaturePublickey=" + signaturePublickey + ", meta=" + meta + "]"; + return format("YggdrasilConfiguration [apiRoot={0}, skinDomains={1}, signaturePublickey={2}, decodedPublickey={3}, meta={4}]", apiRoot, skinDomains, signaturePublickey, decodedPublickey, meta); } + } From 7f940c500b14925da55a30828ff00fa20b2696a8 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Fri, 16 Feb 2018 22:37:36 +0800 Subject: [PATCH 6/6] update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d80d34c..545e5eb 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,8 @@ gradle 或者直接从[Jenkins](https://ci.to2mbn.org/job/authlib-injector)下载构建好的JAR。 ## 部署 -对于实现了本规范中[扩展API](https://github.com/to2mbn/authlib-injector/wiki/Yggdrasil%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83#%E6%89%A9%E5%B1%95api)的Yggdrasil服务端,可以直接通过添加以下JVM参数来配置: +需要服务端实现本规范中的[扩展API](https://github.com/to2mbn/authlib-injector/wiki/Yggdrasil%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83#%E6%89%A9%E5%B1%95api)。 +通过添加以下JVM参数来配置: ``` -javaagent:{authlib-injector.jar的路径}={Yggdrasil服务端的URL(API Root)} ```