lib_unity_purchase/Editor/Obfuscation/Service/ObfuscationGenerator.cs

223 lines
8.0 KiB
C#
Raw Normal View History

2024-01-29 18:49:33 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace UnityEditor.Purchasing
{
class ObfuscationGenerator
{
const string m_GeneratedCredentialsTemplateFilename = "IAPGeneratedCredentials.cs.template";
const string m_GeneratedCredentialsTemplateFilenameNoExtension = "IAPGeneratedCredentials.cs";
const string k_AppleCertPath = "Packages/com.unity.purchasing/Editor/AppleIncRootCertificate.cer";
const string k_AppleStoreKitTestCertPath = "Packages/com.unity.purchasing/Editor/StoreKitTestCertificate.cer";
const string k_AppleClassIncompleteErr = "Invalid Apple Root Certificate";
const string k_AppleStoreKitTestClassIncompleteErr = "Invalid Apple StoreKit Test Certificate";
internal static string ObfuscateAppleSecrets()
{
var appleError = WriteObfuscatedAppleClassAsAsset();
AssetDatabase.Refresh();
return appleError;
}
internal static string ObfuscateGoogleSecrets(string googlePlayPublicKey)
{
var googleError = WriteObfuscatedGooglePlayClassAsAsset(googlePlayPublicKey);
AssetDatabase.Refresh();
return googleError;
}
/// <summary>
/// Generates specified obfuscated class files.
/// </summary>
internal static void ObfuscateSecrets(bool includeGoogle, ref string appleError, ref string googleError, string googlePlayPublicKey)
{
try
{
// First things first! Obfuscate! XHTLOA!
appleError = WriteObfuscatedAppleClassAsAsset();
if (includeGoogle)
{
googleError = WriteObfuscatedGooglePlayClassAsAsset(googlePlayPublicKey);
}
}
catch (Exception e)
{
Debug.LogWarning(e.StackTrace);
}
// Ensure all the Tangle classes exist, even if they were not generated at this time.
if (!DoesGooglePlayTangleClassExist())
{
try
{
WriteObfuscatedClassAsAsset(TangleFileConsts.k_GooglePlayClassPrefix, 0, new int[0], new byte[0], false);
}
catch (Exception e)
{
Debug.LogWarning(e.StackTrace);
}
}
AssetDatabase.Refresh();
}
static string WriteObfuscatedAppleClassAsAsset()
{
var err = WriteObfuscatedAppleClassAsAsset(k_AppleCertPath, k_AppleClassIncompleteErr, TangleFileConsts.k_AppleClassPrefix);
if (err == null)
{
err = WriteObfuscatedAppleClassAsAsset(k_AppleStoreKitTestCertPath, k_AppleStoreKitTestClassIncompleteErr, TangleFileConsts.k_AppleStoreKitTestClassPrefix);
}
return err;
}
static string WriteObfuscatedAppleClassAsAsset(string certPath, string classIncompleteErr, string classPrefix)
{
string appleError = null;
var key = 0;
var order = new int[0];
var tangled = new byte[0];
try
{
var bytes = File.ReadAllBytes(certPath);
order = new int[bytes.Length / 20 + 1];
// TODO: Integrate with upgraded Tangle!
tangled = TangleObfuscator.Obfuscate(bytes, order, out key);
}
catch (Exception e)
{
Debug.LogWarning($"{classIncompleteErr}. Generating incomplete credentials file. " + e);
appleError = $" {classIncompleteErr}";
}
WriteObfuscatedClassAsAsset(classPrefix, key, order, tangled, tangled.Length != 0);
return appleError;
}
static string WriteObfuscatedGooglePlayClassAsAsset(string googlePlayPublicKey)
{
string googleError = null;
var key = 0;
var order = new int[0];
var tangled = new byte[0];
try
{
var bytes = Convert.FromBase64String(googlePlayPublicKey);
order = new int[bytes.Length / 20 + 1];
tangled = TangleObfuscator.Obfuscate(bytes, order, out key);
}
catch (Exception e)
{
Debug.LogWarning("Invalid Google Play Public Key. Generating incomplete credentials file. " + e);
googleError =
" The Google Play License Key is invalid. GooglePlayTangle was generated with incomplete credentials.";
}
WriteObfuscatedClassAsAsset(TangleFileConsts.k_GooglePlayClassPrefix, key, order, tangled, tangled.Length != 0);
return googleError;
}
static string FullPathForTangleClass(string classnamePrefix)
{
return Path.Combine(TangleFileConsts.k_OutputPath, string.Format($"{classnamePrefix}{TangleFileConsts.k_ObfuscationClassSuffix}"));
}
internal static bool DoesAppleTangleClassExist()
{
return ObfuscatedClassExists(TangleFileConsts.k_AppleClassPrefix) &&
ObfuscatedClassExists(TangleFileConsts.k_AppleStoreKitTestClassPrefix);
}
internal static bool DoesGooglePlayTangleClassExist()
{
return ObfuscatedClassExists(TangleFileConsts.k_GooglePlayClassPrefix);
}
static bool ObfuscatedClassExists(string classnamePrefix)
{
return File.Exists(FullPathForTangleClass(classnamePrefix));
}
static void WriteObfuscatedClassAsAsset(string classnamePrefix, int key, int[] order, byte[] data, bool populated)
{
var substitutionDictionary = new Dictionary<string, string>()
{
{"{NAME}", classnamePrefix.ToString()},
{"{KEY}", key.ToString()},
{"{ORDER}", String.Format("{0}",String.Join(",", Array.ConvertAll(order, i => i.ToString())))},
{"{DATA}", Convert.ToBase64String(data)},
{"{POPULATED}", populated.ToString().ToLowerInvariant()} // Defaults to XML-friendly values
};
var templateText = LoadTemplateText(out var templateRelativePath);
if (templateText != null)
{
var outfileText = templateText;
// Apply the parameters to the template
foreach (var pair in substitutionDictionary)
{
outfileText = outfileText.Replace(pair.Key, pair.Value);
}
Directory.CreateDirectory(TangleFileConsts.k_OutputPath);
File.WriteAllText(FullPathForTangleClass(classnamePrefix), outfileText);
}
}
/// <summary>
/// Loads the template file.
/// </summary>
/// <returns>The template file's text.</returns>
/// <param name="templateRelativePath">Relative Assets/ path to template file.</param>
static string LoadTemplateText(out string templateRelativePath)
{
var assetGUIDs =
AssetDatabase.FindAssets(m_GeneratedCredentialsTemplateFilenameNoExtension);
string templateGUID = null;
templateRelativePath = null;
if (assetGUIDs.Length > 0)
{
templateGUID = assetGUIDs[0];
}
else
{
Debug.LogError(String.Format("Could not find template \"{0}\"",
m_GeneratedCredentialsTemplateFilename));
}
string templateText = null;
if (templateGUID != null)
{
templateRelativePath = AssetDatabase.GUIDToAssetPath(templateGUID);
var templateAbsolutePath =
Path.GetDirectoryName(Application.dataPath)
+ Path.DirectorySeparatorChar
+ templateRelativePath;
templateText = File.ReadAllText(templateAbsolutePath);
}
return templateText;
}
}
}