aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/moe/yuuta/gplicense
diff options
context:
space:
mode:
authorYuutaW <17158086+Trumeet@users.noreply.github.com>2019-02-28 20:32:26 -0800
committerYuutaW <17158086+Trumeet@users.noreply.github.com>2019-02-28 20:32:26 -0800
commit373bda9f0219ecd3f1069bf5fe0637c61dc87787 (patch)
tree9586d23d13cf1297c3b96cf846a36852f8568839 /app/src/main/java/moe/yuuta/gplicense
parent39de35e09424c573670d4c56742c17a3bdbe8108 (diff)
downloadWorkMode-373bda9f0219ecd3f1069bf5fe0637c61dc87787.tar
WorkMode-373bda9f0219ecd3f1069bf5fe0637c61dc87787.tar.gz
WorkMode-373bda9f0219ecd3f1069bf5fe0637c61dc87787.tar.bz2
WorkMode-373bda9f0219ecd3f1069bf5fe0637c61dc87787.zip
feat(app): hide and obfuscate license checking codes as much as we can
Signed-off-by: YuutaW <17158086+Trumeet@users.noreply.github.com>
Diffstat (limited to 'app/src/main/java/moe/yuuta/gplicense')
-rw-r--r--app/src/main/java/moe/yuuta/gplicense/LicenseChecker.java38
-rw-r--r--app/src/main/java/moe/yuuta/gplicense/LicenseValidator.java2
-rw-r--r--app/src/main/java/moe/yuuta/gplicense/ServerManagedPolicy.java2
-rw-r--r--app/src/main/java/moe/yuuta/gplicense/ipc/ILicenseResultListener.java101
-rw-r--r--app/src/main/java/moe/yuuta/gplicense/ipc/ILicensingService.java101
5 files changed, 25 insertions, 219 deletions
diff --git a/app/src/main/java/moe/yuuta/gplicense/LicenseChecker.java b/app/src/main/java/moe/yuuta/gplicense/LicenseChecker.java
index 92986b8..7d4cfa8 100644
--- a/app/src/main/java/moe/yuuta/gplicense/LicenseChecker.java
+++ b/app/src/main/java/moe/yuuta/gplicense/LicenseChecker.java
@@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.ServiceConnection;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Handler;
import android.os.HandlerThread;
@@ -27,8 +26,11 @@ import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
-import moe.yuuta.gplicense.ipc.ILicenseResultListener;
-import moe.yuuta.gplicense.ipc.ILicensingService;
+import moe.yuuta.ext.ConnCallback;
+import moe.yuuta.ext.IPCResultListener;
+import moe.yuuta.ext.IService;
+import moe.yuuta.ext.LicServiceConn;
+import moe.yuuta.ext.ResultCallback;
import moe.yuuta.gplicense.util.Base64;
import moe.yuuta.gplicense.util.Base64DecoderException;
import moe.yuuta.workmode.BuildConfig;
@@ -44,7 +46,7 @@ import moe.yuuta.workmode.BuildConfig;
* Must also provide the Base64-encoded RSA public key associated with your developer account. The
* public key is obtainable from the publisher site.
*/
-public class LicenseChecker implements ServiceConnection {
+public class LicenseChecker implements ConnCallback {
private static final Logger logger = XLog.tag("LCK").build();
private static final String KEY_FACTORY_ALGORITHM = "RSA";
@@ -55,7 +57,7 @@ public class LicenseChecker implements ServiceConnection {
private static final SecureRandom RANDOM = new SecureRandom();
private static final boolean DEBUG_LICENSE_ERROR = BuildConfig.DEBUG;
- private ILicensingService mService;
+ private IService mService;
private PublicKey mPublicKey;
private final Context mContext;
@@ -70,6 +72,8 @@ public class LicenseChecker implements ServiceConnection {
private final Set<LicenseValidator> mChecksInProgress = new HashSet<LicenseValidator>();
private final Queue<LicenseValidator> mPendingChecks = new LinkedList<LicenseValidator>();
+ private LicServiceConn mConn;
+
/**
* @param context a Context
* @param policy implementation of Policy
@@ -118,7 +122,7 @@ public class LicenseChecker implements ServiceConnection {
* recommend obfuscating the string that is passed into bindService using another method of your
* own devising.
* <p>
- * source string: "com.android.vending.licensing.ILicensingService"
+ * source string: "com.android.vending.licensing.IService"
* <p>
*
* @param callback
@@ -127,7 +131,7 @@ public class LicenseChecker implements ServiceConnection {
// If we have a valid recent LICENSED response, we can skip asking
// Market.
if (mPolicy.allowAccess()) {
- logger.i("Using cached license response");
+ logger.i("Using cached response");
callback.allow(Policy.LICENSED);
} else {
LicenseValidator validator = new LicenseValidator(mPolicy, new NullDeviceLimiter(),
@@ -136,12 +140,13 @@ public class LicenseChecker implements ServiceConnection {
if (mService == null) {
logger.i("Binding to service.");
try {
+ mConn = new LicServiceConn(this);
boolean bindResult = mContext
.bindService(
new Intent(
new String(
// Base64 encoded -
- // com.android.vending.licensing.ILicensingService
+ // com.android.vending.licensing.IService
// Consider encoding this in another way in your
// code to improve security
Base64.decode(
@@ -163,7 +168,7 @@ public class LicenseChecker implements ServiceConnection {
// com.android.vending
Base64.decode(
"Y29tLmFuZHJvaWQudmVuZGluZw=="))),
- this, // ServiceConnection.
+ mConn, // ServiceConnection.
Context.BIND_AUTO_CREATE);
if (bindResult) {
mPendingChecks.offer(validator);
@@ -188,12 +193,12 @@ public class LicenseChecker implements ServiceConnection {
while ((validator = mPendingChecks.poll()) != null) {
try {
logger.i("Executing on service for " + validator.getPackageName());
- mService.checkLicense(
+ mService.exec(
validator.getNonce(), validator.getPackageName(),
- new ResultListener(validator));
+ new IPCResultListener(new ResultListener(validator)));
mChecksInProgress.add(validator);
} catch (RemoteException e) {
- logger.w("RemoteException in checkLicense call.", e);
+ logger.w("RemoteException in exec call.", e);
handleServiceConnectionError(validator);
}
}
@@ -206,7 +211,7 @@ public class LicenseChecker implements ServiceConnection {
}
}
- private class ResultListener extends ILicenseResultListener.Stub {
+ private class ResultListener implements ResultCallback {
private final LicenseValidator mValidator;
private Runnable mOnTimeout;
@@ -226,6 +231,7 @@ public class LicenseChecker implements ServiceConnection {
// Runs in IPC thread pool. Post it to the Handler, so we can guarantee
// either this or the timeout runs.
+ @Override
public void verifyLicense(final int responseCode, final String signedData,
final String signature) {
mHandler.post(() -> {
@@ -280,11 +286,13 @@ public class LicenseChecker implements ServiceConnection {
}
}
+ @Override
public synchronized void onServiceConnected(ComponentName name, IBinder service) {
- mService = ILicensingService.Stub.asInterface(service);
+ mService = IService.Stub.asInterface(service);
runChecks();
}
+ @Override
public synchronized void onServiceDisconnected(ComponentName name) {
// Called when the connection with the service has been
// unexpectedly disconnected. That is, Market crashed.
@@ -311,7 +319,7 @@ public class LicenseChecker implements ServiceConnection {
private void cleanupService() {
if (mService != null) {
try {
- mContext.unbindService(this);
+ mContext.unbindService(mConn);
} catch (IllegalArgumentException e) {
// Somehow we've already been unbound. This is a non-fatal
// error.
diff --git a/app/src/main/java/moe/yuuta/gplicense/LicenseValidator.java b/app/src/main/java/moe/yuuta/gplicense/LicenseValidator.java
index 142f350..d34d614 100644
--- a/app/src/main/java/moe/yuuta/gplicense/LicenseValidator.java
+++ b/app/src/main/java/moe/yuuta/gplicense/LicenseValidator.java
@@ -184,7 +184,7 @@ class LicenseValidator {
handleApplicationError(LicenseCheckerCallback.ERROR_NOT_MARKET_MANAGED);
break;
default:
- logger.e("Unknown response code for license check.");
+ logger.e("Unknown response code for checking.");
handleInvalidResponse();
}
}
diff --git a/app/src/main/java/moe/yuuta/gplicense/ServerManagedPolicy.java b/app/src/main/java/moe/yuuta/gplicense/ServerManagedPolicy.java
index 8355cb8..fcc3451 100644
--- a/app/src/main/java/moe/yuuta/gplicense/ServerManagedPolicy.java
+++ b/app/src/main/java/moe/yuuta/gplicense/ServerManagedPolicy.java
@@ -159,7 +159,7 @@ public class ServerManagedPolicy implements Policy {
lValidityTimestamp = Long.parseLong(validityTimestamp);
} catch (NumberFormatException e) {
// No response or not parsable, expire in one minute.
- logger.w("License validity timestamp (VT) missing, caching for a minute");
+ logger.w("Validity timestamp (VT) missing, caching for a minute");
lValidityTimestamp = System.currentTimeMillis() + MILLIS_PER_MINUTE;
validityTimestamp = Long.toString(lValidityTimestamp);
}
diff --git a/app/src/main/java/moe/yuuta/gplicense/ipc/ILicenseResultListener.java b/app/src/main/java/moe/yuuta/gplicense/ipc/ILicenseResultListener.java
deleted file mode 100644
index a7683b6..0000000
--- a/app/src/main/java/moe/yuuta/gplicense/ipc/ILicenseResultListener.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package moe.yuuta.gplicense.ipc;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.RemoteException;
-
-import androidx.annotation.NonNull;
-
-import moe.yuuta.gplicense.util.Base64;
-import moe.yuuta.gplicense.util.Base64DecoderException;
-
-public interface ILicenseResultListener extends IInterface {
- abstract class Stub extends Binder implements ILicenseResultListener {
- private static final String DESCRIPTOR;
-
- static {
- try {
- // Base64 encoded -
- // com.android.vending.licensing.ILicenseResultListener
- DESCRIPTOR = new String(Base64.decode(
- "Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2VSZXN1bHRMaXN0ZW5lcg=="));
- } catch (Base64DecoderException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected Stub() {
- this.attachInterface(this, DESCRIPTOR);
- }
-
- static ILicenseResultListener asInterface(IBinder obj) {
- if ((obj == null)) {
- return null;
- }
- IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
- if (iin instanceof ILicenseResultListener) {
- return (ILicenseResultListener) iin;
- }
- return new Stub.Proxy(obj);
- }
-
- @Override
- public IBinder asBinder() {
- return this;
- }
-
- @Override
- public boolean onTransact(int code, @NonNull Parcel data, Parcel reply, int flags) throws RemoteException {
- switch (code) {
- case INTERFACE_TRANSACTION: {
- reply.writeString(DESCRIPTOR);
- return true;
- }
- case TRANSACTION_verifyLicense: {
- data.enforceInterface(DESCRIPTOR);
- int responseCode = data.readInt();
- String signedData = data.readString();
- String signature = data.readString();
- this.verifyLicense(responseCode, signedData, signature);
- return true;
- }
- default: {
- return super.onTransact(code, data, reply, flags);
- }
- }
- }
-
- private static class Proxy implements ILicenseResultListener {
- private IBinder mRemote;
-
- Proxy(IBinder remote) {
- mRemote = remote;
- }
-
- @Override
- public IBinder asBinder() {
- return mRemote;
- }
-
- @Override
- public void verifyLicense(int responseCode, String signedData, String signature) throws RemoteException {
- Parcel args = Parcel.obtain();
- try {
- args.writeInterfaceToken(DESCRIPTOR);
- args.writeInt(responseCode);
- args.writeString(signedData);
- args.writeString(signature);
- mRemote.transact(TRANSACTION_verifyLicense, args, null, IBinder.FLAG_ONEWAY);
- } finally {
- args.recycle();
- }
- }
- }
-
- static final int TRANSACTION_verifyLicense = IBinder.FIRST_CALL_TRANSACTION;
- }
-
- void verifyLicense(int responseCode, String signedData, String signature) throws RemoteException;
-} \ No newline at end of file
diff --git a/app/src/main/java/moe/yuuta/gplicense/ipc/ILicensingService.java b/app/src/main/java/moe/yuuta/gplicense/ipc/ILicensingService.java
deleted file mode 100644
index 14e27f4..0000000
--- a/app/src/main/java/moe/yuuta/gplicense/ipc/ILicensingService.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package moe.yuuta.gplicense.ipc;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.RemoteException;
-
-import androidx.annotation.NonNull;
-
-import moe.yuuta.gplicense.util.Base64;
-import moe.yuuta.gplicense.util.Base64DecoderException;
-
-public interface ILicensingService extends IInterface {
- abstract class Stub extends Binder implements ILicensingService {
- private static final String DESCRIPTOR;
-
- static {
- try {
- // Base64 encoded -
- // com.android.vending.licensing.ILicensingService
- DESCRIPTOR = new String(Base64.decode(
- "Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="));
- } catch (Base64DecoderException e) {
- throw new RuntimeException(e);
- }
- }
-
- public Stub() {
- this.attachInterface(this, DESCRIPTOR);
- }
-
- public static ILicensingService asInterface(IBinder obj) {
- if ((obj == null)) {
- return null;
- }
- IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
- if (iin instanceof ILicensingService) {
- return (ILicensingService) iin;
- }
- return new ILicensingService.Stub.Proxy(obj);
- }
-
- @Override
- public IBinder asBinder() {
- return this;
- }
-
- @Override
- public boolean onTransact(int code, @NonNull Parcel data, Parcel reply, int flags) throws RemoteException {
- switch (code) {
- case INTERFACE_TRANSACTION: {
- reply.writeString(DESCRIPTOR);
- return true;
- }
- case TRANSACTION_checkLicense: {
- data.enforceInterface(DESCRIPTOR);
- long nonce = data.readLong();
- String packageName = data.readString();
- ILicenseResultListener listener = ILicenseResultListener.Stub.asInterface(data.readStrongBinder());
- this.checkLicense(nonce, packageName, listener);
- return true;
- }
- default: {
- return super.onTransact(code, data, reply, flags);
- }
- }
- }
-
- private static class Proxy implements ILicensingService {
- private IBinder mRemote;
-
- Proxy(IBinder remote) {
- mRemote = remote;
- }
-
- @Override
- public IBinder asBinder() {
- return mRemote;
- }
-
- @Override
- public void checkLicense(long nonce, String packageName, ILicenseResultListener listener) throws RemoteException {
- Parcel args = Parcel.obtain();
- try {
- args.writeInterfaceToken(DESCRIPTOR);
- args.writeLong(nonce);
- args.writeString(packageName);
- args.writeStrongBinder(listener != null ? listener.asBinder() : null);
- mRemote.transact(TRANSACTION_checkLicense, args, null, IBinder.FLAG_ONEWAY);
- } finally {
- args.recycle();
- }
- }
- }
-
- static final int TRANSACTION_checkLicense = IBinder.FIRST_CALL_TRANSACTION;
- }
-
- void checkLicense(long nonce, String packageName, ILicenseResultListener listener) throws RemoteException;
-} \ No newline at end of file