package fuzion24.device.vulnerability.vulnerabilities.framework.media;

import android.content.Context;
import android.content.res.AssetManager;
import android.os.Build;
import android.util.Log;

import org.apache.commons.compress.utils.Charsets;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.io.FilenameUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import fuzion24.device.vulnerability.vulnerabilities.VulnerabilityTest;

/**
 * Created by fuzion24 on 8/10/15.
 */

public class StageFright {

    private static final String TAG = "StageFright";

    static {
        System.loadLibrary("stagefright");
    }

    private static native int checkItunesMeta();


    private static void exec(String blah) throws Exception {
        Runtime.getRuntime().exec(blah);
    }

    public static List<VulnerabilityTest> getTests(Context context) {
        try {
            File dataDir = context.getFilesDir();

            AssetManager assetManager = context.getAssets();
            final String stageFrightAssetPath = "stagefright/stagefright_media_files";
            String[] stagefrightMediaFiles = assetManager.list(stageFrightAssetPath);

            List<VulnerabilityTest> tests = new ArrayList<VulnerabilityTest>();

            final String extractedBinaryTester = dataDir.getAbsolutePath() + File.separator + getNativeAppName();
            extractAsset(context, "stagefright" + File.separator + getNativeAppName(),
                    extractedBinaryTester);

            exec("chmod 744 " + extractedBinaryTester);

            for (final String mediaFile : stagefrightMediaFiles) {

                final String extractedAssetPath = dataDir.getAbsolutePath() + File.separator + mediaFile;

                extractAsset(context,
                        stageFrightAssetPath + File.separator + mediaFile,
                        extractedAssetPath);

                tests.add(new VulnerabilityTest() {
                    @Override
                    public String getName() {
                        return "StageFright: " + FilenameUtils.removeExtension(mediaFile);
                    }

                    @Override
                    public boolean isVulnerable(Context context) throws Exception {
                        return testMedia(extractedBinaryTester, extractedAssetPath);
                    }
                });
            }

            tests.add(new VulnerabilityTest() {
                @Override
                public String getName() {
                    return "Stagefright-ItunesMeta";
                }

                @Override
                public boolean isVulnerable(Context context) throws Exception {
                    int ret = checkItunesMeta();
                    if(ret == 0) {
                        return false;
                    } else if(ret == 1){
                        return true;
                    }else {
                        throw new Exception("Error Running Test with err code " + ret);
                    }
                }
            });

            return tests;
        }catch(Exception e){
            e.printStackTrace();
        }

        return new ArrayList<VulnerabilityTest>();
    }

    private static boolean testMedia(String binary, String media) throws Exception {
        Process process = Runtime.getRuntime().exec(binary + " " + media);
        InputStream is = process.getInputStream();

        String content = readFully(is, Charsets.UTF_8.displayName());
        String errStream = readFully(process.getErrorStream(), Charsets.UTF_8.displayName());

        if(errStream.contains("Fatal signal") || content.contains("Boom goes the dynamite")){
            return true;
        }
        process.waitFor();
        return false;
    }

    private static final int BUFFER_SIZE = 2 * 1024 * 1024;
    private static void copy(InputStream input, OutputStream output) throws IOException {
        try {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = input.read(buffer);
            while (bytesRead != -1) {
                output.write(buffer, 0, bytesRead);
                bytesRead = input.read(buffer);
            }
            //If needed, close streams.
        } finally {
            input.close();
            output.close();
        }
    }

    public static String readFully(InputStream inputStream, String encoding)
            throws IOException {
        return new String(readFully(inputStream), encoding);
    }


    private static byte[] readFully(InputStream inputStream)
            throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length = 0;
        while ((length = inputStream.read(buffer)) != -1) {
            baos.write(buffer, 0, length);
        }
        return baos.toByteArray();
    }


    private static void extractAsset(Context ctx, String name, String destination) throws Exception {
        Log.d(TAG, "Extracting \'" + name + "\' from assets to \'" + destination + "\' ...");

        try {
            File f = new File(destination);
            if(f.exists()) {
                f.delete();
            }
        }
        catch(Exception e) {e.printStackTrace();}

        AssetManager assetManager = ctx.getAssets();
        InputStream asset = assetManager.open(name);
        FileOutputStream fos = new FileOutputStream(destination);
        copy(asset,fos);

    }

    public static String getNativeAppName() {
        return Build.VERSION.SDK_INT >= 16 ? "stagefrightCheck-pie" : "stagefrightCheck";
    }

}

@@ -2624,32 +2624,35 @@
 %0A            %7D%0A%0A
+/*%0A
             test
@@ -3300,16 +3300,19 @@
      %7D);
+%0A*/
 %0A%0A      

Disable new stagefright check for now