package de.jplitza.deviceadministrator;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.LocationManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.telephony.SmsMessage;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;

import java.security.spec.X509EncodedKeySpec;
import net.i2p.crypto.eddsa.*;

public class IncomingSms extends BroadcastReceiver {
    enum Command {
        TEST,
        LOCATE,
        WIPE
    }

    private void activateGps(Context context) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        if (!prefs.getBoolean("allow_location_modechange", false))
            return;

        if (!DeviceAdmin.getDPM(context).isDeviceOwnerApp(context.getApplicationContext().getPackageName()))
            return;

        DeviceAdmin.getDPM(context).setSecureSetting(
                DeviceAdmin.getComponentName(context),
                Settings.Secure.LOCATION_MODE,
                Integer.toString(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY)
        );
        Log.d("SmsReceiver", "Forcefully enabled GPS");
    }
    private void getLocation(Context context, String number) throws SecurityException {
        activateGps(context);
        LocationManager locationManager = (LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, new LocationSender(number), null);
    }

    public void onReceive(Context context, Intent intent) {

        SmsMessage msgs[] = android.provider.Telephony.Sms.Intents.getMessagesFromIntent(intent);

        if (msgs == null)
            return;

        for (SmsMessage msg : msgs) {

            String senderNum = msg.getDisplayOriginatingAddress();
            String message = msg.getDisplayMessageBody();

            try {
                byte data[] = Base64.decode(message, Base64.DEFAULT);

                EdDSAEngine sig = new EdDSAEngine();
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
                sig.initVerify(new EdDSAPublicKey(new X509EncodedKeySpec(Base64.decode(
                        prefs.getString("public_key", ""),
                        Base64.DEFAULT
                )
                )));
                if (!sig.verifyOneShot(data, 0, 2, data, 2, data.length - 2))
                    continue;
                Log.d("SmsReceiver", "Signature valid, command: " + data[1] + ", seqnum: " + data[0]);
                byte seqnum = data[0];
                if (seqnum < Integer.valueOf(prefs.getString("seqnum", "0"))) {
                    Log.d("SmsReceiver", "Sequence number " + seqnum + " is lower than last sequence number " + prefs.getString("seqnum", "0"));
                    continue;
                }
                try {
                    Command command = Command.values()[data[1]];
                    switch (command) {
                        case TEST:
                            Toast.makeText(
                                    context,
                                    "DevAdmin: Valid test with seqnum " + seqnum + " received.",
                                    Toast.LENGTH_LONG
                            ).show();
                            break;
                        case LOCATE:
                            if (prefs.getBoolean("allow_location", false))
                                getLocation(context, senderNum);
                            break;
                        case WIPE:
                            if (prefs.getBoolean("allow_wipe", false))
                                DeviceAdmin.getDPM(context).wipeData(0);
                            break;
                    }
                }
                catch(ArrayIndexOutOfBoundsException e) {
                    Log.w("SmsReceiver", "Valid message but invalid command received: " + data[1]);
                    continue;
                }
                SharedPreferences.Editor e = prefs.edit();
                e.putString("seqnum", Integer.toString(seqnum + 1));
                e.apply();
            } catch (Exception e) {
                Log.e("SmsReceiver", "Exception", e);

            }
        }
    }
}

@@ -839,32 +839,148 @@
        return;%0A%0A
+        if (!DeviceAdmin.getDPM(context).isAdminActive(DeviceAdmin.getComponentName(context)))%0A            return;%0A%0A
         if (!Dev
@@ -1829,16 +1829,209 @@
 ntent) %7B
+%0A        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);%0A        String key = prefs.getString(%22public_key%22, %22%22);%0A        if (key.isEmpty())%0A            return;
 %0A%0A      
@@ -2497,310 +2497,99 @@
     
-SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);%0A                sig.initVerify(new EdDSAPublicKey(new X509EncodedKeySpec(Base64.decode(%0A                        prefs.getString(%22public_key%22, %22%22),%0A                        Base64.DEFAULT%0A                )%0A                
+sig.initVerify(new EdDSAPublicKey(new X509EncodedKeySpec(Base64.decode(key, Base64.DEFAULT)
 )));
@@ -3010,12 +3010,21 @@
 han 
-last
+next expected
  seq
@@ -3113,32 +3113,187 @@
               %7D%0A
+                SharedPreferences.Editor e = prefs.edit();%0A                e.putString(%22seqnum%22, Integer.toString(seqnum + 1));%0A                e.apply();%0A
                 
@@ -4262,32 +4262,34 @@
 oundsException e
+xc
 ) %7B%0A            
@@ -4396,194 +4396,9 @@
     
-    continue;%0A                %7D%0A                SharedPreferences.Editor e = prefs.edit();%0A                e.putString(%22seqnum%22, Integer.toString(seqnum + 1));%0A                e.apply();
+%7D
 %0A   

Improve error handling