Jan 19 | 3:55 PM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Jan 19 | 4:10 PM |
Paul R. | has entered the room |
Paul R. |
Greetings Mark
|
Paul R. |
I have two questions today.
|
Mark M. |
hello, Paul!
|
Mark M. |
fire away!
|
Paul R. |
First up: tell me about securely using an API key in an Android app. Is it possible to achieve near perfect security?
|
Mark M. |
yes: by not putting the API key in the Android app
|
Mark M. |
otherwise, no
|
Paul R. |
Let's drill into that.
|
Mark M. |
for example, if the API in question is something that you could actually execute from your Web service, perhaps you do that, with your app calling your Web service
|
Jan 19 | 4:15 PM |
Paul R. |
How do I ensure that the web service knows it is my app?
|
Mark M. |
well, to an extent, you might not strictly care
|
Mark M. |
what matters is whether the user who is accessing your Web service is your user or not
|
Mark M. |
now, if your Web service does not involve users with accounts, then you have a problem
|
Mark M. |
your Web service is a publicly accessible API, like it or not, even though it may be an undocumented and unsupported API
|
Paul R. |
My concern is that given an APK, a hacker can figure out how to access the web service. Then the hacker need only replicate that from another app to exploit the web service.
|
Mark M. |
sure
|
Paul R. |
How do I prevent this from happening?
|
Mark M. |
stop programming computers, I guess
|
Mark M. |
I mean, if you are making the endpoint publicly accessible, there is no "publicly accessible only from a certain piece of client software"
|
Mark M. |
simply because bits on the wire have no provenance, proving that they came from a certain piece of client software
|
Jan 19 | 4:20 PM |
Mark M. |
that's why I asked if your Web service is tied to users and accounts
|
Mark M. |
if it is, then the primary "defense" is "you have to have a valid account"
|
Mark M. |
and from there, whether the client is yours or some third party's ideally should not matter
|
Paul R. |
Yes, as long as the web service verifies the User, that makes sense.
|
Mark M. |
obfuscation of various forms (ProGuard/DexGuard-style tools, NDK, etc.) can slow down somebody cloning an app or extracting an API key, but it can't stop them
|
Mark M. |
initially, when your app has no users, nobody will bother attacking the app or its Web service, because there may be no perceived value
|
Paul R. |
I'll be back in a minute with my second question. You did good with the first.
|
Jan 19 | 4:25 PM |
Paul R. |
ok, second issue is streaming. With either Kotlin (preferred) or Java, how would you sketch out reading a large (many megabytes) gz file containing lines of JSON data such that the parsing can be done a line at a time without having to read in the whole batch of lines?
|
Mark M. |
JSON isn't a great format for this
|
Mark M. |
you can't strictly parse JSON without having the entire thing in memory
|
Paul R. |
Might be, but I have no control over that.
|
Mark M. |
or, at least, access to the entire thing by the time that you're done
|
Paul R. |
I can definitely parse a line at a time.
|
Paul R. |
The whole file is not aJSON object, but each line is.
|
Mark M. |
ah
|
Mark M. |
that's a rather strange data structure
|
Mark M. |
but, anyway, there are Gzip classes in the Android SDK
|
Jan 19 | 4:30 PM |
Mark M. | |
Mark M. |
so, you should be able to get a GZIPInputStream wrapped around a FileInputStream (with perhaps a BufferedInputStream in there somewhere)
|
Mark M. |
then, wrap that in an InputStreamReader
|
Mark M. |
then use forEachLine() in Kotlin
|
Paul R. |
View paste
|
Mark M. |
switch readLines() to forEachLine() for line-by-line processing
|
Mark M. |
so, decoder.forEachLine { line -> TODO() }
|
Paul R. |
That simple? That's awesome.
|
Mark M. |
lotsa nice extension functions in Kotlin!
|
Mark M. |
now, I have no idea what the underlying implementation is and whether you'll run into some memory problem
|
Mark M. |
but, in principle, this should work
|
Mark M. |
also, you might consider val decoder = gzStream.bufferedReader("UTF-8"), to get buffering in there
|
Mark M. |
(and since UTF-8 is the default for bufferedReader(), gzStream.bufferedReader() is probably sufficient)
|
Jan 19 | 4:35 PM |
Paul R. |
Very cool. Last question. I just re-upped my CommonsWare subscription that lapsed last november. Have you added much since then for Kotlin?
|
Mark M. |
well, there's Elements of Kotlin 0.1 as a partial implementation of an intro guide to the language
|
Paul R. |
A separate book?
|
Mark M. |
yes
|
Paul R. |
Good idea.
|
Mark M. | |
Mark M. |
that explains a bit of what the future holds
|
Paul R. |
I'll check it out. As always you've been very helpful. Thank you.
|
Mark M. |
during the timeframe of your subscription, you'll get a complete Elements of Kotlin, a complete Elements of Android Jetpack (intro guide to Android, dual Java/Kotlin examples), and a rewritten Exploring Android (step-by-step tutorials, Kotlin/Jetpack)
|
Mark M. |
plus some other new stuff
|
Mark M. |
(e.g., Elements of Android Q, presumably)
|
Mark M. |
and thanks for the kind words!
|
Paul R. |
No problem. Talk to you soon.
|
Paul R. | has left the room |
Jan 19 | 4:55 PM |
Mark M. | turned off guest access |