--- /dev/null
+*.iml
+.gradle
+/local.properties
+/.idea/
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+/gradle/
+/gradlew
+/gradlew.bat
+/README.html
--- /dev/null
+********************
+OUYA plain purchases
+********************
+
+Xposed__ module that deactivates encryption on the OUYA Android gaming console.
+
+Its goal is that purchase requests get sent plain-text to the
+`discover store server`__,
+and the server may reply with plain text purchase receipts.
+
+Works by patching ``javax.crypto.Cipher::doFinal(byte[])`` to return
+the input without encryption/decryption.
+
+__ https://repo.xposed.info/module/de.robv.android.xposed.installer
+__ http://cweiske.de/ouya-store-api-docs.htm
--- /dev/null
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.3'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
--- /dev/null
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+
--- /dev/null
+include ':xposed-ouya-plain-purchases'
+rootProject.name='OUYA plain purchases Xposed module'
--- /dev/null
+/build
+/release/
--- /dev/null
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 16
+ buildToolsVersion '19.1.0'
+ defaultConfig {
+ applicationId "de.cweiske.ouya.plainpurchases"
+ minSdkVersion 15
+ targetSdkVersion 16
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ }
+ }
+ lintOptions {
+ checkReleaseBuilds false
+ // Or, if you prefer, you can continue to check for errors in release builds,
+ // but continue the build even when errors are found:
+ abortOnError false
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ compileOnly 'de.robv.android.xposed:api:53'
+}
--- /dev/null
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="de.cweiske.ouya.plainpurchases">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/broken_encryption_48"
+ android:label="OUYA plain purchases"
+ tools:ignore="GoogleAppIndexingWarning">
+ <meta-data
+ android:name="xposedmodule"
+ android:value="true" />
+ <meta-data
+ android:name="xposeddescription"
+ android:value="Do not encrypt JSON purchase requests to the OUYA API" />
+ <meta-data
+ android:name="xposedminversion"
+ android:value="47" />
+ </application>
+</manifest>
--- /dev/null
+de.cweiske.ouya.plainpurchases.PlainPurchases
--- /dev/null
+package de.cweiske.ouya.plainpurchases;
+
+import javax.crypto.Cipher;
+
+import de.robv.android.xposed.IXposedHookLoadPackage;
+import de.robv.android.xposed.XC_MethodHook;
+import de.robv.android.xposed.XposedBridge;
+import de.robv.android.xposed.XposedHelpers;
+import de.robv.android.xposed.callbacks.XC_LoadPackage;
+
+/**
+ * Hook into Java's main encryption method and simply return the input.
+ * This disables encryption completely, and allows our OUYA store to retrieve
+ * plain text requests and send plain text responses that the OUYA understands
+ *
+ * @author Christian Weiske <cweiske+ouya@cweiske.de>
+ */
+public class PlainPurchases implements IXposedHookLoadPackage
+{
+ @Override
+ public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam)
+ {
+ //we cannot filter on lpparam.packagename because that breaks
+ // in-game receipt decryption
+
+ //XposedBridge.log("Loaded app: " + lpparam.packageName);
+
+ XposedHelpers.findAndHookMethod(Cipher.class, "doFinal", byte[].class, new XC_MethodHook() {
+ @Override
+ protected void beforeHookedMethod(MethodHookParam param) {
+ byte[] input = (byte[]) param.args[0];
+
+ //XposedBridge.log("input: " + new String(input));
+ //XposedBridge.log("returning unencrypted input");
+ //XposedBridge.log(new Exception("doFinal stack trace"));
+ param.setResult(input);
+ }
+ });
+ }
+}
--- /dev/null
+<resources>
+ <string name="app_name">OUYA plain purchases Xposed module</string>
+</resources>