Added docs and test
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Darkmatter.FonepayUnity.Editor",
|
||||
"rootNamespace": "Darkmatter.Fonepay.Editor",
|
||||
"references": [
|
||||
"Darkmatter.FonepayUnity"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e655521fa332549829d66024acdbcc5c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Darkmatter.Fonepay.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Bakes EditorPrefs secrets into a temporary Resources asset before player build,
|
||||
/// then deletes the asset after the build (success or fail) so secrets never linger on disk.
|
||||
/// </summary>
|
||||
internal sealed class FonepayBuildSecretsInjector : IPreprocessBuildWithReport, IPostprocessBuildWithReport
|
||||
{
|
||||
private const string ResourcesDir = "Assets/Resources";
|
||||
private const string AssetPath = "Assets/Resources/FonepayBakedSecrets.asset";
|
||||
|
||||
public int callbackOrder => 0;
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
if (!FonepaySecretsStore.HasAll())
|
||||
throw new BuildFailedException(
|
||||
"Fonepay secrets missing. Open Tools > Fonepay > Settings before building.");
|
||||
|
||||
if (!Directory.Exists(ResourcesDir))
|
||||
Directory.CreateDirectory(ResourcesDir);
|
||||
|
||||
var baked = ScriptableObject.CreateInstance<FonepayBakedSecrets>();
|
||||
baked.password = FonepaySecretsStore.GetPassword();
|
||||
baked.secretKey = FonepaySecretsStore.GetSecretKey();
|
||||
|
||||
AssetDatabase.CreateAsset(baked, AssetPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
public void OnPostprocessBuild(BuildReport report)
|
||||
{
|
||||
if (AssetDatabase.LoadAssetAtPath<FonepayBakedSecrets>(AssetPath) != null)
|
||||
AssetDatabase.DeleteAsset(AssetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abf4fd45c03134382a1e0052168c60c7
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Darkmatter.Fonepay.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Per-project secret storage backed by EditorPrefs.
|
||||
/// Keys are namespaced with project path hash so different machines/projects never collide.
|
||||
/// EditorPrefs lives in OS user store (Keychain on macOS, registry on Windows) — not in repo.
|
||||
/// </summary>
|
||||
public static class FonepaySecretsStore
|
||||
{
|
||||
private const string PrefixBase = "Darkmatter.Fonepay.";
|
||||
|
||||
private static string ProjectKey =>
|
||||
PrefixBase + Application.dataPath.GetHashCode().ToString("X") + ".";
|
||||
|
||||
public static string PasswordKey => ProjectKey + "Password";
|
||||
public static string SecretKeyKey => ProjectKey + "SecretKey";
|
||||
|
||||
public static string GetPassword() => EditorPrefs.GetString(PasswordKey, string.Empty);
|
||||
public static string GetSecretKey() => EditorPrefs.GetString(SecretKeyKey, string.Empty);
|
||||
|
||||
public static void SetPassword(string v) => EditorPrefs.SetString(PasswordKey, v ?? string.Empty);
|
||||
public static void SetSecretKey(string v) => EditorPrefs.SetString(SecretKeyKey, v ?? string.Empty);
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
EditorPrefs.DeleteKey(PasswordKey);
|
||||
EditorPrefs.DeleteKey(SecretKeyKey);
|
||||
}
|
||||
|
||||
public static bool HasAll() =>
|
||||
!string.IsNullOrEmpty(GetPassword()) && !string.IsNullOrEmpty(GetSecretKey());
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void RegisterRuntimeProvider()
|
||||
{
|
||||
FonepayConfig.EditorSecretsProvider = () => (GetPassword(), GetSecretKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b9868ef88aab4e2594c17b50c42df62
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Darkmatter.Fonepay.Editor
|
||||
{
|
||||
public sealed class FonepaySettingsWindow : EditorWindow
|
||||
{
|
||||
private const string ResourcesDir = "Assets/Resources";
|
||||
private const string ConfigAssetPath = "Assets/Resources/FonepayConfig.asset";
|
||||
|
||||
private FonepayConfigSO _config;
|
||||
private SerializedObject _serialized;
|
||||
private SerializedProperty _envProp, _merchantProp, _userProp;
|
||||
|
||||
private string _password;
|
||||
private string _secretKey;
|
||||
private bool _showSecrets;
|
||||
private Vector2 _scroll;
|
||||
|
||||
[MenuItem("Tools/Darkmatter/Fonepay/Settings")]
|
||||
public static void Open()
|
||||
{
|
||||
var w = GetWindow<FonepaySettingsWindow>("Fonepay");
|
||||
w.minSize = new Vector2(420, 360);
|
||||
w.Show();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
LoadOrPrepare();
|
||||
_password = FonepaySecretsStore.GetPassword();
|
||||
_secretKey = FonepaySecretsStore.GetSecretKey();
|
||||
}
|
||||
|
||||
private void LoadOrPrepare()
|
||||
{
|
||||
_config = AssetDatabase.LoadAssetAtPath<FonepayConfigSO>(ConfigAssetPath);
|
||||
if (_config != null)
|
||||
{
|
||||
_serialized = new SerializedObject(_config);
|
||||
_envProp = _serialized.FindProperty("environment");
|
||||
_merchantProp = _serialized.FindProperty("merchantCode");
|
||||
_userProp = _serialized.FindProperty("username");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
_scroll = EditorGUILayout.BeginScrollView(_scroll);
|
||||
|
||||
EditorGUILayout.LabelField("Fonepay Setup", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"Non-secret fields saved to Resources/FonepayConfig.asset (commit safe).\n" +
|
||||
"Password & Secret Key saved to EditorPrefs (per-machine, never in repo).\n" +
|
||||
"On player build, secrets baked into a temp Resources asset, removed after build.",
|
||||
MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (_config == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No FonepayConfig asset. Click below to create.", MessageType.Warning);
|
||||
if (GUILayout.Button("Create Config Asset", GUILayout.Height(28)))
|
||||
CreateConfigAsset();
|
||||
EditorGUILayout.EndScrollView();
|
||||
return;
|
||||
}
|
||||
|
||||
_serialized.Update();
|
||||
EditorGUILayout.PropertyField(_envProp);
|
||||
EditorGUILayout.PropertyField(_merchantProp);
|
||||
EditorGUILayout.PropertyField(_userProp);
|
||||
_serialized.ApplyModifiedProperties();
|
||||
|
||||
EditorGUILayout.Space(12);
|
||||
EditorGUILayout.LabelField("Secrets (EditorPrefs)", EditorStyles.boldLabel);
|
||||
|
||||
_showSecrets = EditorGUILayout.ToggleLeft("Show secrets", _showSecrets);
|
||||
_password = DrawSecret("Password", _password);
|
||||
_secretKey = DrawSecret("Secret Key", _secretKey);
|
||||
|
||||
EditorGUILayout.Space(12);
|
||||
DrawStatus();
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Save", GUILayout.Height(28)))
|
||||
Save();
|
||||
if (GUILayout.Button("Clear Secrets", GUILayout.Height(28)))
|
||||
ClearSecrets();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private string DrawSecret(string label, string value)
|
||||
{
|
||||
return _showSecrets
|
||||
? EditorGUILayout.TextField(label, value ?? string.Empty)
|
||||
: EditorGUILayout.PasswordField(label, value ?? string.Empty);
|
||||
}
|
||||
|
||||
private void DrawStatus()
|
||||
{
|
||||
var ok = !string.IsNullOrEmpty(_merchantProp.stringValue)
|
||||
&& !string.IsNullOrEmpty(_userProp.stringValue)
|
||||
&& !string.IsNullOrEmpty(_password)
|
||||
&& !string.IsNullOrEmpty(_secretKey);
|
||||
|
||||
EditorGUILayout.HelpBox(
|
||||
ok ? "All required fields set." : "Missing fields — fill all values then Save.",
|
||||
ok ? MessageType.Info : MessageType.Warning);
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
_serialized.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(_config);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
FonepaySecretsStore.SetPassword(_password);
|
||||
FonepaySecretsStore.SetSecretKey(_secretKey);
|
||||
|
||||
FonepayConfig.Invalidate();
|
||||
ShowNotification(new GUIContent("Saved"));
|
||||
}
|
||||
|
||||
private void ClearSecrets()
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("Clear Fonepay secrets",
|
||||
"Remove password and secret key from EditorPrefs on this machine?",
|
||||
"Clear", "Cancel"))
|
||||
return;
|
||||
FonepaySecretsStore.Clear();
|
||||
_password = _secretKey = string.Empty;
|
||||
FonepayConfig.Invalidate();
|
||||
}
|
||||
|
||||
private void CreateConfigAsset()
|
||||
{
|
||||
if (!Directory.Exists(ResourcesDir))
|
||||
Directory.CreateDirectory(ResourcesDir);
|
||||
var so = ScriptableObject.CreateInstance<FonepayConfigSO>();
|
||||
AssetDatabase.CreateAsset(so, ConfigAssetPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
LoadOrPrepare();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0327216de93347279c639b786a694b2
|
||||
@@ -0,0 +1,31 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Darkmatter.Fonepay.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
internal static class FonepayStartupCheck
|
||||
{
|
||||
private const string SessionFlag = "Darkmatter.Fonepay.StartupChecked";
|
||||
private const string ConfigAssetPath = "Assets/Resources/FonepayConfig.asset";
|
||||
|
||||
static FonepayStartupCheck()
|
||||
{
|
||||
EditorApplication.delayCall += RunOnce;
|
||||
}
|
||||
|
||||
private static void RunOnce()
|
||||
{
|
||||
if (SessionState.GetBool(SessionFlag, false)) return;
|
||||
SessionState.SetBool(SessionFlag, true);
|
||||
|
||||
var so = AssetDatabase.LoadAssetAtPath<FonepayConfigSO>(ConfigAssetPath);
|
||||
var hasConfig = so != null
|
||||
&& !string.IsNullOrEmpty(so.MerchantCode)
|
||||
&& !string.IsNullOrEmpty(so.Username);
|
||||
var hasSecrets = FonepaySecretsStore.HasAll();
|
||||
|
||||
if (!hasConfig || !hasSecrets)
|
||||
FonepaySettingsWindow.Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3b5a436eccc14d9d889ed58ec3b0682
|
||||
Reference in New Issue
Block a user