using System; using System.IO; using System.Net; using System.Text; using System.Linq; using UnityEngine; using Newtonsoft.Json.Linq; using System.IO.Compression; using System.Security.Cryptography; using System.Text.RegularExpressions; public class UpdateChecker : MonoBehaviour { public void RequestUpdate() { var version = Settings.GameVersion; var bundleUrl = ""; try { version = GetAndroidVersion(); } catch { Error.Log(Color.red, $"Failed getting game version. Using {version} from settings"); } if(version != Settings.GameVersion) { Settings.Instance.gameVersion = version; Settings.Save(); } try { bundleUrl = GetAssetbundleUrl(version); } catch { Error.Log(Color.red, $"Failed getting assets url"); return; } if(bundleUrl != Settings.AssetsUrl) { if(UpdateUrlFile(bundleUrl)) Error.Log(Color.green, "Update Successful! Please restart the viewer to download new files."); } else { Error.Log(Color.green, "You already have the newest files!"); } } public string GetAndroidVersion() { string url = "https://play.google.com/store/apps/details?id=com.sega.KemonoFriends3"; HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url); using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse()) using (Stream stream = httpResponse.GetResponseStream()) using (StreamReader stringReader = new StreamReader(stream)) { var response = stringReader.ReadToEnd(); var result = Regex.Match(response, @"""\b(\d+\.\d+\.\d+)\b"""); return result.Groups[1].Value; } } public string GetAssetbundleUrl(string version) { string param = Encode($"{{'version':'{version}','dmm_viewer_id':0,'platform':1}}".Replace("'", "\"")); Debug.Log(param); HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("https://parade-mobile-prod-app.kemono-friends-3.jp/paradesv/common/GetUrl.do?param=" + param); httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0"; httpRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse()) using (Stream stream = httpResponse.GetResponseStream()) using (Stream decompress = new GZipStream(stream, CompressionMode.Decompress)) using (StreamReader stringReader = new StreamReader(decompress)) { var response = stringReader.ReadToEnd(); var json = JObject.Parse(response); return json["asset_bundle_url"].ToString(); } } private bool UpdateUrlFile(string newVersion) { try { if (File.Exists(Path.Combine(Settings.AssetListDirectory, "ab_list.txt"))) { File.Delete(Path.Combine(Settings.AssetListDirectory, "ab_list.txt")); } Settings.Instance.assetsUrl = newVersion; Settings.Save(); return true; } catch (Exception e) { Debug.LogError(e.Message); return false; } } public string Encode(string request) { MD5 md5 = MD5.Create(); string hashed = GetMd5Hash(md5, request); string checksum = GetMd5Hash(md5, request + "DARAPAB "); string key = BytesToHexString(md5.ComputeHash(HexStringToByteArray(hashed.Substring(0, 8)))); //xor with the key byte[] requestBytes = Encoding.ASCII.GetBytes(request); byte[] keyBytes = HexStringToByteArray(key); for (int i = 0; i < requestBytes.Length; i++) { requestBytes[i] ^= keyBytes[i % keyBytes.Length]; } request = (hashed.Substring(0, 8) + BytesToHexString(requestBytes) + checksum); return request; } public string Decode(string request) { MD5 md5 = MD5.Create(); string key = BytesToHexString(md5.ComputeHash(HexStringToByteArray(request.Substring(0, 8)))); string hash = request.Substring(8, request.Length - 40); byte[] requestBytes = HexStringToByteArray(hash); byte[] keyBytes = HexStringToByteArray(key); for (int i = 0; i < requestBytes.Length; i++) { requestBytes[i] ^= keyBytes[i % keyBytes.Length]; } return Encoding.UTF8.GetString(requestBytes); } public string GetMd5Hash(MD5 md5Hash, string input) { // Convert the input string to a byte array and compute the hash. byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input)); // Create a new Stringbuilder to collect the bytes // and create a string. StringBuilder sBuilder = new StringBuilder(); // Loop through each byte of the hashed data // and format each one as a hexadecimal string. for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString("x2")); } // Return the hexadecimal string. return sBuilder.ToString(); } public byte[] HexStringToByteArray(string hex) { return Enumerable.Range(0, hex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) .ToArray(); } public string BytesToHexString(byte[] data) { StringBuilder sBuilder = new StringBuilder(); // Loop through each byte of the hashed data // and format each one as a hexadecimal string. for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString("x2")); } // Return the hexadecimal string. return sBuilder.ToString(); } }