Added pro activation procedure

This commit is contained in:
M66B 2018-08-25 11:27:54 +00:00
parent 15a7939b79
commit 9db8915234
5 changed files with 123 additions and 5 deletions

View File

@ -24,12 +24,14 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
@ -42,11 +44,14 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.security.NoSuchAlgorithmException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
@ -68,6 +73,7 @@ import androidx.lifecycle.Observer;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class ActivityView extends ActivityBase implements FragmentManager.OnBackStackChangedListener {
private View view;
private DrawerLayout drawerLayout;
private ListView drawerList;
private ActionBarDrawerToggle drawerToggle;
@ -83,12 +89,14 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
static final String ACTION_VIEW_MESSAGE = BuildConfig.APPLICATION_ID + ".VIEW_MESSAGE";
static final String ACTION_EDIT_FOLDER = BuildConfig.APPLICATION_ID + ".EDIT_FOLDER";
static final String ACTION_STORE_ATTACHMENT = BuildConfig.APPLICATION_ID + ".STORE_ATTACHMENT";
static final String ACTION_ACTIVATE_PRO = BuildConfig.APPLICATION_ID + ".ACTIVATE_PRO";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view);
view = LayoutInflater.from(this).inflate(R.layout.activity_view, null);
setContentView(view);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
@ -130,6 +138,9 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
case R.string.menu_faq:
onMenuFAQ();
break;
case R.string.menu_pro:
onMenuPro();
break;
case R.string.menu_privacy:
onMenuPrivacy();
break;
@ -180,6 +191,10 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
if (getIntentFAQ().resolveActivity(getPackageManager()) != null)
drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_question_answer_24, R.string.menu_faq));
Intent pro = getIntentPro();
if (pro == null || pro.resolveActivity(getPackageManager()) != null)
drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_monetization_on_24, R.string.menu_pro));
if (getIntentPrivacy().resolveActivity(getPackageManager()) != null)
drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_account_box_24, R.string.menu_privacy));
@ -327,6 +342,7 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
iff.addAction(ACTION_VIEW_MESSAGE);
iff.addAction(ACTION_EDIT_FOLDER);
iff.addAction(ACTION_STORE_ATTACHMENT);
iff.addAction(ACTION_ACTIVATE_PRO);
lbm.registerReceiver(receiver, iff);
if (newIntent) {
@ -388,13 +404,22 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
}
}
private String getChallenge() throws NoSuchAlgorithmException {
String android_id = Settings.System.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
return Helper.sha256(android_id);
}
private String getResponse() throws NoSuchAlgorithmException {
return Helper.sha256(BuildConfig.APPLICATION_ID + getChallenge());
}
private void checkIntent(Intent intent) {
Log.i(Helper.TAG, "View intent=" + intent + " action=" + intent.getAction());
String action = intent.getAction();
intent.setAction(null);
setIntent(intent);
if ("unseen".equals(action)) {
intent.setAction(null);
setIntent(intent);
Bundle args = new Bundle();
args.putLong("time", new Date().getTime());
@ -438,6 +463,20 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
return intent;
}
private Intent getIntentPro() {
if (Helper.isPlayStoreInstall(this))
return null;
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://email.faircode.eu/pro/?challenge=" + getChallenge()));
return intent;
} catch (NoSuchAlgorithmException ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
return null;
}
}
private Intent getIntentOtherApps() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://play.google.com/store/apps/dev?id=8420080860664580239"));
@ -478,6 +517,13 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
startActivity(getIntentFAQ());
}
private void onMenuPro() {
if (Helper.isPlayStoreInstall(this)) {
} else
startActivity(getIntentPro());
}
private void onMenuPrivacy() {
startActivity(getIntentPrivacy());
}
@ -616,6 +662,31 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
create.setType(intent.getStringExtra("type"));
create.putExtra(Intent.EXTRA_TITLE, intent.getStringExtra("name"));
startActivityForResult(create, (int) intent.getLongExtra("id", -1));
} else if (ACTION_ACTIVATE_PRO.equals(intent.getAction())) {
try {
Uri data = intent.getParcelableExtra("uri");
String challenge = getChallenge();
String response = data.getQueryParameter("response");
Log.i(Helper.TAG, "Challenge=" + challenge);
Log.i(Helper.TAG, "Response=" + response);
String expected = getResponse();
if (expected.equals(response)) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ActivityView.this);
prefs.edit().putBoolean("pro", true).apply();
Log.i(Helper.TAG, "Response valid");
Snackbar.make(view, R.string.title_pro_valid, Snackbar.LENGTH_LONG).show();
} else {
Log.i(Helper.TAG, "Response invalid");
Snackbar.make(view, R.string.title_pro_invalid, Snackbar.LENGTH_LONG).show();
}
intent.setData(null);
setIntent(intent);
} catch (NoSuchAlgorithmException ex) {
Log.e(Helper.TAG, Log.getStackTraceString(ex));
Toast.makeText(ActivityView.this, ex.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
};

View File

@ -82,6 +82,7 @@ import androidx.constraintlayout.widget.Group;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Observer;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -187,8 +188,15 @@ public class FragmentMessage extends FragmentEx {
URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0) {
String url = link[0].getURL();
Uri uri = Uri.parse(url);
if (prefs.getBoolean("webview", false)) {
if (BuildConfig.APPLICATION_ID.equals(uri.getHost()) && "/activate/".equals(uri.getPath())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(
new Intent(ActivityView.ACTION_ACTIVATE_PRO)
.putExtra("uri", uri));
} else if (prefs.getBoolean("webview", false)) {
Bundle args = new Bundle();
args.putString("link", url);

View File

@ -42,6 +42,8 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.mail.Address;
import javax.mail.internet.InternetAddress;
@ -163,4 +165,27 @@ public class Helper {
in.close();
}
}
static boolean isPlayStoreInstall(Context context) {
if (false && BuildConfig.DEBUG)
return true;
try {
return "com.android.vending".equals(context.getPackageManager().getInstallerPackageName(context.getPackageName()));
} catch (Throwable ex) {
Log.e(TAG, Log.getStackTraceString(ex));
return false;
}
}
static String sha256(String data) throws NoSuchAlgorithmException {
return sha256(data.getBytes());
}
static String sha256(byte[] data) throws NoSuchAlgorithmException {
byte[] bytes = MessageDigest.getInstance("SHA-256").digest(data);
StringBuilder sb = new StringBuilder();
for (byte b : bytes)
sb.append(String.format("%02x", b));
return sb.toString();
}
}

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13.41,18.09L13.41,20h-2.67v-1.93c-1.71,-0.36 -3.16,-1.46 -3.27,-3.4h1.96c0.1,1.05 0.82,1.87 2.65,1.87 1.96,0 2.4,-0.98 2.4,-1.59 0,-0.83 -0.44,-1.61 -2.67,-2.14 -2.48,-0.6 -4.18,-1.62 -4.18,-3.67 0,-1.72 1.39,-2.84 3.11,-3.21L10.74,4h2.67v1.95c1.86,0.45 2.79,1.86 2.85,3.39L14.3,9.34c-0.05,-1.11 -0.64,-1.87 -2.22,-1.87 -1.5,0 -2.4,0.68 -2.4,1.64 0,0.84 0.65,1.39 2.67,1.91s4.18,1.39 4.18,3.91c-0.01,1.83 -1.38,2.83 -3.12,3.16z"/>
</vector>

View File

@ -35,6 +35,7 @@
<string name="menu_operations">Operations</string>
<string name="menu_legend">Legend</string>
<string name="menu_faq">FAQ</string>
<string name="menu_pro">Pro features</string>
<string name="menu_privacy">Privacy</string>
<string name="menu_about">About</string>
<string name="menu_other">Other apps</string>
@ -175,6 +176,9 @@
<string name="title_legend_connected">Connected</string>
<string name="title_legend_closing">Closing</string>
<string name="title_pro_valid">All pro features activated</string>
<string name="title_pro_invalid">Invalid response</string>
<string name="title_debug_info">Debug info</string>
<string name="title_debug_info_remark">Please describe the problem and indicate the time of the problem:</string>
</resources>