/// <summary>Attempts to authenticate a user using Oculus Rift user data.</summary> public static void AuthenticateWithOculusRiftUserData(string oculusUserNonce, int oculusUserId, string oculusUserAccessToken, bool hasUserAcceptedTerms, Action <UserProfile> onSuccess, Action <WebRequestError> onError) { LocalUser.ExternalAuthentication = new ExternalAuthenticationData() { provider = ExternalAuthenticationProvider.OculusRift, ticket = oculusUserAccessToken, additionalData = new Dictionary <string, string>() { { ExternalAuthenticationData.OculusRiftKeys.NONCE, oculusUserNonce }, { ExternalAuthenticationData.OculusRiftKeys.USER_ID, oculusUserId.ToString() }, }, }; APIClient.RequestOculusRiftAuthentication(oculusUserNonce, oculusUserId, oculusUserAccessToken, hasUserAcceptedTerms, (t) => { LocalUser.OAuthToken = t; LocalUser.WasTokenRejected = false; LocalUser.Save(); UserAccountManagement.UpdateUserProfile(onSuccess, onError); }, onError); }
// ---------[ MOD COLLECTION MANAGEMENT ]--------- /// <summary>Add a mod to the subscribed list and modifies the queued actions accordingly.</summary> public static void SubscribeToMod(int modId) { // add sub to list if (!LocalUser.SubscribedModIds.Contains(modId)) { LocalUser.SubscribedModIds.Add(modId); } // check queues bool unsubQueued = LocalUser.QueuedUnsubscribes.Contains(modId); bool subQueued = LocalUser.QueuedSubscribes.Contains(modId); // add to/remove from queues if (unsubQueued) { LocalUser.QueuedUnsubscribes.Remove(modId); } else if (!subQueued) { LocalUser.QueuedSubscribes.Add(modId); } // save LocalUser.Save(); }
/// <summary>Begins the authentication process using a mod.io Security Code.</summary> public static void AuthenticateWithSecurityCode(string securityCode, Action <UserProfile> onSuccess, Action <WebRequestError> onError) { APIClient.GetOAuthToken(securityCode, (t) => { LocalUser.OAuthToken = t; LocalUser.WasTokenRejected = false; LocalUser.Save(); UserAccountManagement.UpdateUserProfile(onSuccess, onError); }, onError); }
/// <summary>Attempts to authenticate a user using Xbox Live credentials.</summary> public static void AuthenticateWithXboxLiveToken(string xboxLiveUserToken, Action <UserProfile> onSuccess, Action <WebRequestError> onError) { LocalUser.ExternalAuthentication = new ExternalAuthenticationData() { ticket = xboxLiveUserToken, provider = ExternalAuthenticationProvider.XboxLive, }; APIClient.RequestXboxLiveAuthentication(xboxLiveUserToken, (t) => { LocalUser.OAuthToken = t; LocalUser.WasTokenRejected = false; LocalUser.Save(); UserAccountManagement.UpdateUserProfile(onSuccess, onError); }, onError); }
/// <summary>Attempts to authenticate a user using a GOG Encrypted App Ticket.</summary> public static void AuthenticateWithGOGEncryptedAppTicket(string encodedTicket, Action <UserProfile> onSuccess, Action <WebRequestError> onError) { LocalUser.ExternalAuthentication = new ExternalAuthenticationData() { ticket = encodedTicket, provider = ExternalAuthenticationProvider.Steam, }; APIClient.RequestGOGAuthentication(encodedTicket, (t) => { LocalUser.OAuthToken = t; LocalUser.WasTokenRejected = false; LocalUser.Save(); UserAccountManagement.UpdateUserProfile(onSuccess, onError); }, onError); }
/// <summary>Attempts to authenticate a user using an itch.io JWT Token.</summary> public static void AuthenticateWithItchIOToken(string jwtToken, bool hasUserAcceptedTerms, Action <UserProfile> onSuccess, Action <WebRequestError> onError) { LocalUser.ExternalAuthentication = new ExternalAuthenticationData() { ticket = jwtToken, provider = ExternalAuthenticationProvider.ItchIO, }; APIClient.RequestItchIOAuthentication(jwtToken, hasUserAcceptedTerms, (t) => { LocalUser.OAuthToken = t; LocalUser.WasTokenRejected = false; LocalUser.Save(); UserAccountManagement.UpdateUserProfile(onSuccess, onError); }, onError); }
// ---------[ AUTHENTICATION ]--------- /// <summary>Pulls any changes to the User Profile from the mod.io servers.</summary> public static void UpdateUserProfile(Action <UserProfile> onSuccess, Action <WebRequestError> onError) { if (LocalUser.AuthenticationState != AuthenticationState.NoToken) { APIClient.GetAuthenticatedUser((p) => { LocalUser.Profile = p; LocalUser.Save(); if (onSuccess != null) { onSuccess(p); } }, onError); } else if (onSuccess != null) { onSuccess(null); } }
// ---------[ 2019 ]--------- /// <summary>Moves the data from the UserAuthenticationData and ModManager caches to UserAccountManagement.</summary> private static void Update_2_0_to_2_1_UserData() { Debug.Log("[mod.io] Attempting 2.0->2.1 UserData update."); // check if the file already exists byte[] fileData = null; UserDataStorage.InitializeForUser(null, () => {}); UserDataStorage.ReadFile(LocalUser.FILENAME, (success, data) => fileData = data); if (fileData != null && fileData.Length > 0) { Debug.Log("[mod.io] Aborting UserData update. FileExists: \'" + LocalUser.FILENAME + "\' [" + ValueFormatting.ByteCount(fileData.Length, null) + "]"); } // update GenericJSONObject dataWrapper; LocalUser userData = new LocalUser(); string filePath = null; // - copy enabled/subbed - filePath = ModManager.PERSISTENTDATA_FILEPATH; if (IOUtilities.TryReadJsonObjectFile(filePath, out dataWrapper)) { int[] modIds = null; if (DataUpdater.TryGetArrayField(dataWrapper, "subscribedModIds", out modIds)) { userData.subscribedModIds = new List <int>(modIds); } if (DataUpdater.TryGetArrayField(dataWrapper, "enabledModIds", out modIds)) { userData.enabledModIds = new List <int>(modIds); } } // - copy queued subs/unsubs - filePath = IOUtilities.CombinePath(CacheClient.cacheDirectory, ModIO.UI.ModBrowser.MANIFEST_FILENAME); if (IOUtilities.TryReadJsonObjectFile(filePath, out dataWrapper)) { List <int> modIds = null; if (DataUpdater.TryGetArrayField(dataWrapper, "queuedSubscribes", out modIds)) { userData.queuedSubscribes = new List <int>(modIds); } if (DataUpdater.TryGetArrayField(dataWrapper, "queuedUnsubscribes", out modIds)) { userData.queuedUnsubscribes = new List <int>(modIds); } } // - copy UAD - filePath = UserAuthenticationData.FILE_LOCATION; if (IOUtilities.TryReadJsonObjectFile(filePath, out dataWrapper)) { // user profile int userId = UserProfile.NULL_ID; if (dataWrapper.data.ContainsKey("userId")) { userId = (int)dataWrapper.data["userId"]; } userData.profile = null; if (userId != UserProfile.NULL_ID) { userData.profile = CacheClient.LoadUserProfile(userId); } // token data if (dataWrapper.data.ContainsKey("token")) { userData.oAuthToken = (string)dataWrapper.data["token"]; } if (dataWrapper.data.ContainsKey("wasTokenRejected")) { userData.wasTokenRejected = (bool)dataWrapper.data["wasTokenRejected"]; } // NOTE(@jackson): External Authentication is no longer saved to disk and is thus ignored. IOUtilities.DeleteFile(filePath); } // - set and save - LocalUser.instance = userData; LocalUser.isLoaded = true; LocalUser.Save(); Debug.Log("[mod.io] UserData updated completed."); }
/// <summary>Pushes queued subscribe actions to the server.</summary> public static void PushSubscriptionChanges(Action onCompletedNoErrors, Action <List <WebRequestError> > onCompletedWithErrors) { int responsesPending = (LocalUser.QueuedSubscribes.Count + LocalUser.QueuedUnsubscribes.Count); // early outs if (LocalUser.AuthenticationState == AuthenticationState.NoToken || responsesPending == 0) { if (onCompletedNoErrors != null) { onCompletedNoErrors(); } return; } // set up vars string userToken = LocalUser.OAuthToken; List <WebRequestError> errors = new List <WebRequestError>(); List <int> subscribesPushed = new List <int>(LocalUser.QueuedSubscribes.Count); List <int> unsubscribesPushed = new List <int>(LocalUser.QueuedUnsubscribes.Count); // callback Action onRequestCompleted = () => { if (responsesPending <= 0) { if (userToken == LocalUser.OAuthToken) { foreach (int modId in subscribesPushed) { LocalUser.QueuedSubscribes.Remove(modId); } foreach (int modId in unsubscribesPushed) { LocalUser.QueuedUnsubscribes.Remove(modId); } LocalUser.Save(); } if (errors.Count == 0 && onCompletedNoErrors != null) { onCompletedNoErrors(); } else if (errors.Count > 0 && onCompletedWithErrors != null) { onCompletedWithErrors(errors); } } }; // - push - foreach (int modId in LocalUser.QueuedSubscribes) { APIClient.SubscribeToMod(modId, (p) => { subscribesPushed.Add(modId); --responsesPending; onRequestCompleted(); }, (e) => { // Error for "Mod is already subscribed" if (e.webRequest.responseCode == 400) { subscribesPushed.Add(modId); } // Error for "Mod is unavailable" else if (e.webRequest.responseCode == 404) { subscribesPushed.Add(modId); } // Error for real else { errors.Add(e); } --responsesPending; onRequestCompleted(); }); } foreach (int modId in LocalUser.QueuedUnsubscribes) { APIClient.UnsubscribeFromMod(modId, () => { --responsesPending; unsubscribesPushed.Remove(modId); onRequestCompleted(); }, (e) => { // Error for "Mod is already subscribed" if (e.webRequest.responseCode == 400) { unsubscribesPushed.Remove(modId); } // Error for "Mod is unavailable" else if (e.webRequest.responseCode == 404) { unsubscribesPushed.Remove(modId); } // Error for real else { errors.Add(e); } --responsesPending; onRequestCompleted(); }); } }
/// <summary>Attempts to reauthenticate using the stored external auth ticket.</summary> public static void ReauthenticateWithStoredExternalAuthData(bool hasUserAcceptedTerms, Action <UserProfile> onSuccess, Action <WebRequestError> onError) { ExternalAuthenticationData authData = LocalUser.ExternalAuthentication; Debug.Assert(!string.IsNullOrEmpty(authData.ticket)); Debug.Assert(authData.provider != ExternalAuthenticationProvider.None); Action <string> onSuccessWrapper = (t) => { LocalUser.OAuthToken = t; LocalUser.WasTokenRejected = false; LocalUser.Save(); if (onSuccess != null) { UserAccountManagement.UpdateUserProfile(onSuccess, onError); } }; switch (LocalUser.ExternalAuthentication.provider) { case ExternalAuthenticationProvider.Steam: { APIClient.RequestSteamAuthentication(authData.ticket, hasUserAcceptedTerms, onSuccessWrapper, onError); } break; case ExternalAuthenticationProvider.GOG: { APIClient.RequestGOGAuthentication(authData.ticket, hasUserAcceptedTerms, onSuccessWrapper, onError); } break; case ExternalAuthenticationProvider.ItchIO: { APIClient.RequestItchIOAuthentication(authData.ticket, hasUserAcceptedTerms, onSuccessWrapper, onError); } break; case ExternalAuthenticationProvider.OculusRift: { string token = authData.ticket; string nonce = null; string userIdString = null; int userId = -1; string errorMessage = null; if (authData.additionalData == null) { errorMessage = "The user id and nonce are missing."; } else if (!authData.additionalData.TryGetValue(ExternalAuthenticationData.OculusRiftKeys.NONCE, out nonce) || string.IsNullOrEmpty(nonce)) { errorMessage = "The nonce is missing."; } else if (!authData.additionalData.TryGetValue(ExternalAuthenticationData.OculusRiftKeys.USER_ID, out userIdString) || string.IsNullOrEmpty(userIdString)) { errorMessage = "The user id is missing."; } else if (!int.TryParse(userIdString, out userId)) { errorMessage = "The user id is not parseable as an integer."; } if (errorMessage != null) { Debug.LogWarning("[mod.io] Unable to authenticate using stored Oculus Rift user data.\n" + errorMessage); if (onError != null) { var error = WebRequestError.GenerateLocal(errorMessage); onError(error); } return; } else { APIClient.RequestOculusRiftAuthentication(nonce, userId, token, hasUserAcceptedTerms, onSuccessWrapper, onError); } } break; case ExternalAuthenticationProvider.XboxLive: { APIClient.RequestXboxLiveAuthentication(authData.ticket, hasUserAcceptedTerms, onSuccessWrapper, onError); } break; default: { throw new System.NotImplementedException(); } } }
/// <summary>Pulls the subscriptions from the server and stores the changes.</summary> public static void PullSubscriptionChanges(Action <List <ModProfile> > onSuccess, Action <WebRequestError> onError) { // early out if (LocalUser.AuthenticationState == AuthenticationState.NoToken) { if (onSuccess != null) { onSuccess(new List <ModProfile>(0)); } return; } // holding vars string userToken = LocalUser.OAuthToken; List <ModProfile> remoteOnlySubscriptions = new List <ModProfile>(); // set filter and initial pagination RequestFilter subscriptionFilter = new RequestFilter(); subscriptionFilter.AddFieldFilter(ModIO.API.GetUserSubscriptionsFilterFields.gameId, new EqualToFilter <int>(PluginSettings.GAME_ID)); APIPaginationParameters pagination = new APIPaginationParameters() { limit = APIPaginationParameters.LIMIT_MAX, offset = 0, }; // define actions Action getNextPage = null; Action <RequestPage <ModProfile> > onPageReceived = null; Action onAllPagesReceived = null; getNextPage = () => { APIClient.GetUserSubscriptions(subscriptionFilter, pagination, (response) => { onPageReceived(response); // check if all pages received if (response != null && response.items != null && response.items.Length > 0 && response.resultTotal > response.size + response.resultOffset) { pagination.offset = response.resultOffset + response.size; getNextPage(); } else { onAllPagesReceived(); if (onSuccess != null) { onSuccess(remoteOnlySubscriptions); } } }, (e) => { if (onError != null) { onError(e); } }); }; onPageReceived = (r) => { foreach (ModProfile profile in r.items) { if (profile != null) { remoteOnlySubscriptions.Add(profile); } } }; onAllPagesReceived = () => { if (userToken != LocalUser.OAuthToken) { return; } List <int> localOnlySubs = new List <int>(LocalUser.SubscribedModIds); // NOTE(@jackson): Unsub actions *should not* be found in activeUser.subscribedModIds foreach (int modId in LocalUser.QueuedUnsubscribes) { #if DEBUG if (localOnlySubs.Contains(modId)) { Debug.LogWarning("[mod.io] A locally subscribed mod was found in the" + " queuedUnsubscribes. This should not occur - please" + " ensure that any mod ids added to" + " activeUser.queuedUnsubscribes are removed from" + " activeUser.subscribedModIds or use" + " UserAccountManagement.UnsubscribeFromMod() to handle" + " this automatically."); } #endif localOnlySubs.Remove(modId); } List <int> newSubs = new List <int>(); // build new subs list for (int i = 0; i < remoteOnlySubscriptions.Count; ++i) { ModProfile profile = remoteOnlySubscriptions[i]; // remove if in queued subs LocalUser.QueuedSubscribes.Remove(profile.id); // if in unsub queue if (LocalUser.QueuedUnsubscribes.Contains(profile.id)) { remoteOnlySubscriptions.RemoveAt(i); --i; } // if locally subbed else if (localOnlySubs.Remove(profile.id)) { remoteOnlySubscriptions.RemoveAt(i); --i; } // if not locally subbed && if not in unsub queue else { newSubs.Add(profile.id); } } // -- update locally -- // remove new unsubs foreach (int modId in localOnlySubs) { // if not in sub queue if (!LocalUser.QueuedSubscribes.Contains(modId)) { LocalUser.SubscribedModIds.Remove(modId); } } LocalUser.SubscribedModIds.AddRange(newSubs); // save LocalUser.Save(); }; // get pages getNextPage(); }