Files
UnrealEngine/Engine/Source/Programs/Shared/EpicGames.OIDC/MacOSTokenStore.cs
2025-05-18 13:04:45 +08:00

115 lines
2.3 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
#pragma warning disable CS1591 // Missing XML documentation on public types
namespace EpicGames.OIDC
{
public sealed class MacOSTokenStore : ITokenStore
{
public MacOSTokenStore()
{
}
public bool TryGetRefreshToken(string oidcProvider, out string refreshToken)
{
string? token = KeychainHelper.GetKeychainItem(oidcProvider);
if (token == null)
{
refreshToken = "";
return false;
}
refreshToken = token;
return true;
}
public void AddRefreshToken(string providerIdentifier, string refreshToken)
{
KeychainHelper.AddKeychainItem(refreshToken, providerIdentifier);
}
public void Save()
{
}
public void Dispose()
{
}
}
static class KeychainHelper
{
private const string OidcTokenIdentifier = "EpicGames OidcToken";
private static string? RunKeychainHandler(string verb, List<string> args)
{
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "security",
RedirectStandardOutput = true,
RedirectStandardError = true
};
startInfo.ArgumentList.Add(verb);
foreach (string s in args)
{
startInfo.ArgumentList.Add(s);
}
using Process p = Process.Start(startInfo) ?? throw new Exception("Failed to run \"security\" to interact with keychain");
StringBuilder sb = new StringBuilder();
p.OutputDataReceived += (o, e) => { sb.Append(e.Data); };
p.BeginOutputReadLine();
p.WaitForExit();
if (p.ExitCode == 44)
{
return null; // not found
}
if (p.ExitCode == 36)
{
return null; // not found
}
if (p.ExitCode != 0)
{
throw new Exception($"Unhandled exitcode {p.ExitCode} when interacting with keychain");
}
return sb.ToString();
}
public static void AddKeychainItem(string dataToEncrypt, string itemIdentifier)
{
RunKeychainHandler("add-generic-password", new List<string> {
"-a",
itemIdentifier,
"-s",
OidcTokenIdentifier,
"-U",
"-w",
dataToEncrypt
});
}
public static string? GetKeychainItem(string itemIdentifier)
{
string? output = RunKeychainHandler("find-generic-password", new List<string> {
"-a",
itemIdentifier,
"-s",
OidcTokenIdentifier,
"-w"
});
return output;
}
}
}