311 lines
8.5 KiB
C#
311 lines
8.5 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.Net.Http;
|
|
using System.Net.Sockets;
|
|
using System.Threading.Tasks;
|
|
using JetBrains.Annotations;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
#if UNITY_2021_1_OR_NEWER
|
|
using SystemInfo = UnityEngine.Device.SystemInfo;
|
|
#else
|
|
using SystemInfo = UnityEngine.SystemInfo;
|
|
#endif
|
|
|
|
namespace Needle.Engine
|
|
{
|
|
internal static class NeedleEngineAuthorization
|
|
{
|
|
private const int trialDuration = 15;
|
|
|
|
internal static bool TrialEnded => DaysUntilTrialEnds < 0;
|
|
internal static bool IsInTrialPeriod => DaysUntilTrialEnds >= 0;
|
|
|
|
internal static int DaysUntilTrialEnds
|
|
{
|
|
get
|
|
{
|
|
if (_daysUntilTrialEnds != null) return _daysUntilTrialEnds.Value;
|
|
_daysUntilTrialEnds = (GetFirstInstallation().AddDays(trialDuration) - DateTime.Now).Days;
|
|
return _daysUntilTrialEnds.Value;
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private static DateTime _firstInstallationTime = default;
|
|
|
|
[InitializeOnLoadMethod]
|
|
private static void Init()
|
|
{
|
|
_firstInstallationTime = GetFirstInstallation();
|
|
_daysUntilTrialEnds = DaysUntilTrialEnds;
|
|
}
|
|
#endif
|
|
|
|
private static int? _daysUntilTrialEnds;
|
|
|
|
private static DateTime GetFirstInstallation()
|
|
{
|
|
try
|
|
{
|
|
#if !UNITY_EDITOR
|
|
return DateTime.Now;
|
|
#else
|
|
if (_firstInstallationTime != default)
|
|
return _firstInstallationTime;
|
|
var now = DateTime.Now;
|
|
var nowStr = now.ToString(CultureInfo.CurrentCulture);
|
|
var firstInstallTimeStr = EditorPrefs.GetString("NEEDLE_ENGINE_first_installation_date", nowStr);
|
|
if (firstInstallTimeStr == nowStr)
|
|
{
|
|
EditorPrefs.SetString("NEEDLE_ENGINE_first_installation_date", nowStr);
|
|
return now;
|
|
}
|
|
// Looks like trial time was modified -> this is invalid
|
|
if (string.IsNullOrWhiteSpace(firstInstallTimeStr))
|
|
{
|
|
}
|
|
if (DateTime.TryParse(firstInstallTimeStr, DateTimeFormatInfo.CurrentInfo,
|
|
DateTimeStyles.AllowWhiteSpaces, out var firstInstallTime))
|
|
{
|
|
return firstInstallTime;
|
|
}
|
|
if (DateTime.TryParse(firstInstallTimeStr, DateTimeFormatInfo.InvariantInfo,
|
|
DateTimeStyles.AllowWhiteSpaces, out firstInstallTime))
|
|
{
|
|
return firstInstallTime;
|
|
}
|
|
return DateTime.Now.Subtract(TimeSpan.FromDays(99999));
|
|
#endif
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// ignore
|
|
}
|
|
return DateTime.Now;
|
|
}
|
|
|
|
private static HttpClient _client;
|
|
private static HttpClient client => _client ??= new HttpClient() { Timeout = TimeSpan.FromSeconds(10) };
|
|
|
|
internal static async void OnBeforeExport()
|
|
{
|
|
#if UNITY_EDITOR
|
|
var scene = SceneManager.GetActiveScene();
|
|
if (scene.IsValid())
|
|
{
|
|
await Authentication.EnsureServerIsRunning();
|
|
var user = await Authentication.GetUserInformation();
|
|
if (user == null)
|
|
{
|
|
return;
|
|
}
|
|
var url = Authentication.localServerUrl + "/api/projects";
|
|
var guid = AssetDatabase.AssetPathToGUID(scene.path);
|
|
var body = new JObject();
|
|
body["project_id"] = guid;
|
|
body["project_name"] = scene.name;
|
|
var bodyStr = body.ToString();
|
|
await client.PostAsync(url,
|
|
new StringContent(bodyStr, System.Text.Encoding.UTF8, "application/json"));
|
|
}
|
|
#else
|
|
await Task.CompletedTask;
|
|
#endif
|
|
}
|
|
|
|
internal struct UserProjectIsValidResponse
|
|
{
|
|
public bool license_satisfied;
|
|
/// <summary>
|
|
/// How many other users have access to this project
|
|
/// </summary>
|
|
public int other_user_count;
|
|
/// <summary>
|
|
/// Is the user in the project
|
|
/// </summary>
|
|
public bool user_is_in_project;
|
|
public bool all_users_have_team_license;
|
|
[CanBeNull] public string code;
|
|
[CanBeNull] public string message;
|
|
[CanBeNull] public string reason;
|
|
public bool treat_as_error;
|
|
public bool display_message_to_user;
|
|
}
|
|
|
|
#pragma warning disable CS0414
|
|
private static bool loginInProgress = false;
|
|
#pragma warning restore CS0414
|
|
private static DateTime lastLoginClickedTime;
|
|
internal static bool OnGUI(out bool invalidLicense)
|
|
{
|
|
#if !UNITY_EDITOR
|
|
invalidLicense = false;
|
|
return false;
|
|
#else
|
|
var didDrawGUI = false;
|
|
invalidLicense = false;
|
|
|
|
#pragma warning disable CS4014
|
|
IsAuthorized(false);
|
|
#pragma warning restore CS4014
|
|
if (_response.success == false && _response.response != null)
|
|
{
|
|
var res = _response.response.Value;
|
|
if (res.code == "missing_team_license")
|
|
{;
|
|
if (res.treat_as_error)
|
|
{
|
|
didDrawGUI = true;
|
|
invalidLicense = true;
|
|
EditorGUILayout.HelpBox(res.message, MessageType.Warning);
|
|
EditorGUILayout.HelpBox(res.reason, MessageType.None);
|
|
}
|
|
}
|
|
}
|
|
else if (!Authentication.IsLoggedIn())
|
|
{
|
|
didDrawGUI = true;
|
|
invalidLicense = true;
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
var checksAreRunning =
|
|
Authentication.LoginCheckInProgress || Authentication.UserInfoCheckInProgress;
|
|
|
|
if (Authentication.LoginCheckInProgress)
|
|
{
|
|
EditorGUILayout.HelpBox("Checking login status...", MessageType.None);
|
|
}
|
|
else if (Authentication.UserInfoCheckInProgress)
|
|
{
|
|
EditorGUILayout.HelpBox("Getting user information...", MessageType.None);
|
|
}
|
|
else if (!loginInProgress)
|
|
{
|
|
var msg = Authentication._userInformationError;
|
|
if (string.IsNullOrWhiteSpace(msg))
|
|
{
|
|
msg = "Please log in to start using Needle Engine.";
|
|
}
|
|
EditorGUILayout.HelpBox(msg, MessageType.Warning);
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.HelpBox("Logging in... Please complete the login in the browser.", MessageType.Info);
|
|
}
|
|
if (!checksAreRunning)
|
|
{
|
|
async void RunAction()
|
|
{
|
|
loginInProgress = true;
|
|
// If the user just recently clicked the login and is still not logged in try to logout
|
|
// Maybe he's already logged in to another account but login fails because the new account is
|
|
// Logged in on too many machines...
|
|
if(DateTime.Now - lastLoginClickedTime < TimeSpan.FromSeconds(60))
|
|
{
|
|
await Authentication.Logout();
|
|
}
|
|
lastLoginClickedTime = DateTime.Now;
|
|
await Authentication.LoginAsync(true, false);
|
|
loginInProgress = false;
|
|
}
|
|
if (GUILayout.Button("Login", GUILayout.Height(38),
|
|
GUILayout.Width(60)))
|
|
{
|
|
RunAction();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return didDrawGUI;
|
|
#endif
|
|
}
|
|
|
|
private static AuthorizedResponse _response = default;
|
|
private static DateTime _lastAuthorizedCheckTime = DateTime.MinValue;
|
|
|
|
internal struct AuthorizedResponse
|
|
{
|
|
public bool success;
|
|
public string message;
|
|
public UserProjectIsValidResponse? response;
|
|
}
|
|
internal static async Task<AuthorizedResponse> IsAuthorized(bool force)
|
|
{
|
|
if (!force)
|
|
{
|
|
var checkThreshold = _response.success ? 30 : 5;
|
|
if (DateTime.Now - _lastAuthorizedCheckTime < TimeSpan.FromSeconds(checkThreshold))
|
|
{
|
|
return _response;
|
|
}
|
|
}
|
|
_lastAuthorizedCheckTime = DateTime.Now;
|
|
#if UNITY_EDITOR
|
|
var scene = SceneManager.GetActiveScene();
|
|
if (scene.IsValid())
|
|
{
|
|
var loggedIn = Authentication.IsLoggedIn();
|
|
if (!loggedIn)
|
|
{
|
|
await Authentication.EnsureServerIsRunning();
|
|
loggedIn = Authentication.IsLoggedIn();
|
|
}
|
|
|
|
if (loggedIn == false)
|
|
{
|
|
_response.success = false;
|
|
_response.response = null;
|
|
_response.message = "Please log in to your Needle account";
|
|
return _response;
|
|
}
|
|
var guid = AssetDatabase.AssetPathToGUID(scene.path);
|
|
var url = $"{Authentication.localServerUrl}/api/projects/{guid}?org={Authentication.SelectedTeam}";
|
|
try
|
|
{
|
|
var res = await client.GetAsync(url);
|
|
if (res.IsSuccessStatusCode)
|
|
{
|
|
var content = await res.Content.ReadAsStringAsync();
|
|
if (content.StartsWith("{"))
|
|
{
|
|
var json = JsonConvert.DeserializeObject<UserProjectIsValidResponse>(content);
|
|
if (json.license_satisfied)
|
|
{
|
|
_response.success = true;
|
|
_response.response = json;
|
|
return _response;
|
|
}
|
|
|
|
if (json.treat_as_error)
|
|
_response.success = false;
|
|
else _response.success = true;
|
|
|
|
_response.message = json.message + "\n" + json.reason;
|
|
_response.response = json;
|
|
return _response;
|
|
}
|
|
}
|
|
}
|
|
catch (SocketException)
|
|
{
|
|
// Ignore
|
|
}
|
|
|
|
_response.success = false;
|
|
_response.message = "Failed to authorize project. Please make sure you have the correct permissions and are logged in to your Needle account";
|
|
_response.response = null;
|
|
return _response;
|
|
}
|
|
#else
|
|
await Task.CompletedTask;
|
|
#endif
|
|
|
|
_response.success = true;
|
|
return _response;
|
|
}
|
|
}
|
|
} |