diff --git a/.github/workflows/github_actions.yml b/.github/workflows/github_actions.yml index f78f35f8..1fca954d 100644 --- a/.github/workflows/github_actions.yml +++ b/.github/workflows/github_actions.yml @@ -51,13 +51,19 @@ jobs: ${{ runner.os }}-nuget- - name: Build Cef .NET Application run: dotnet build Dotnet/VRCX-Cef.csproj -p:Configuration=Release -p:WarningLevel=0 -p:Platform=x64 -p:PlatformTarget=x64 -p:RestorePackagesConfig=true -t:"Restore;Clean;Build" -m -a x64 --self-contained + - name: Check if we want to sign + id: check_sign + run: | + echo "sign=${{ secrets.AZURE_CLIENT_ID != '' }}" >> $GITHUB_OUTPUT - name: Azure login + if: steps.check_sign.outputs.sign == 'true' uses: azure/login@v2 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Sign Dotnet executables + if: steps.check_sign.outputs.sign == 'true' uses: azure/trusted-signing-action@v0 with: azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} @@ -103,6 +109,7 @@ jobs: mv Installer/VRCX_Setup.exe $file_name - name: Sign Cef setup uses: azure/trusted-signing-action@v0 + if: steps.check_sign.outputs.sign == 'true' with: azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} diff --git a/Dotnet/ImageCache.cs b/Dotnet/ImageCache.cs index 5b1f4f27..647faf16 100644 --- a/Dotnet/ImageCache.cs +++ b/Dotnet/ImageCache.cs @@ -57,10 +57,10 @@ internal static class ImageCache var cookieString = string.Empty; if (WebApi.Instance != null && - WebApi.Instance._cookieContainer != null && + WebApi.Instance.CookieContainer != null && uri.Host == "api.vrchat.cloud") { - CookieCollection cookies = WebApi.Instance._cookieContainer.GetCookies(new Uri("https://api.vrchat.cloud")); + CookieCollection cookies = WebApi.Instance.CookieContainer.GetCookies(new Uri("https://api.vrchat.cloud")); foreach (Cookie cookie in cookies) cookieString += $"{cookie.Name}={cookie.Value};"; } diff --git a/Dotnet/WebApi.cs b/Dotnet/WebApi.cs index 6847c425..d6219063 100644 --- a/Dotnet/WebApi.cs +++ b/Dotnet/WebApi.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -25,20 +27,21 @@ namespace VRCX { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public static WebApi Instance; - + public static bool ProxySet; public static string ProxyUrl = ""; public static IWebProxy Proxy = WebRequest.DefaultWebProxy; - - public CookieContainer _cookieContainer; + + public CookieContainer CookieContainer; private bool _cookieDirty; private Timer _timer; + private HttpClient _httpClient; + private SocketsHttpHandler _httpHandler; + static WebApi() { Instance = new WebApi(); - ServicePointManager.DefaultConnectionLimit = 10; - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; } // leave this as public, private makes nodeapi angry @@ -48,7 +51,7 @@ namespace VRCX if (Instance == null) Instance = this; #endif - _cookieContainer = new CookieContainer(); + CookieContainer = new CookieContainer(); _timer = new Timer(TimerCallback, null, -1, -1); } @@ -67,10 +70,32 @@ namespace VRCX public void Init() { SetProxy(); + InitializeHttpClient(); LoadCookies(); _timer.Change(1000, 1000); } + private void InitializeHttpClient() + { + _httpHandler = new SocketsHttpHandler + { + CookieContainer = CookieContainer, + UseCookies = true, + AutomaticDecompression = DecompressionMethods.All, + PooledConnectionLifetime = TimeSpan.FromMinutes(5), + MaxConnectionsPerServer = 10 + }; + + if (ProxySet) + { + _httpHandler.Proxy = Proxy; + _httpHandler.UseProxy = true; + } + + _httpClient = new HttpClient(_httpHandler); + _httpClient.DefaultRequestHeaders.Add("User-Agent", Program.Version); + } + private void SetProxy() { if (!string.IsNullOrEmpty(StartupArgs.LaunchArguments.ProxyUrl)) @@ -95,7 +120,8 @@ namespace VRCX { VRCXStorage.Instance.Set("VRCX_ProxyServer", string.Empty); VRCXStorage.Instance.Save(); - const string message = "The proxy server URI you used is invalid.\nVRCX will close, please correct the proxy URI."; + const string message = + "The proxy server URI you used is invalid.\nVRCX will close, please correct the proxy URI."; #if !LINUX System.Windows.Forms.MessageBox.Show(message, "Invalid Proxy URI", MessageBoxButtons.OK, MessageBoxIcon.Error); #endif @@ -115,13 +141,15 @@ namespace VRCX #if !LINUX Cef.GetGlobalCookieManager().DeleteCookies(); #endif - _cookieContainer = new CookieContainer(); + CookieContainer = new CookieContainer(); + InitializeHttpClient(); SaveCookies(); } private void LoadCookies() { - SQLite.Instance.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS `cookies` (`key` TEXT PRIMARY KEY, `value` TEXT)"); + SQLite.Instance.ExecuteNonQuery( + "CREATE TABLE IF NOT EXISTS `cookies` (`key` TEXT PRIMARY KEY, `value` TEXT)"); var values = SQLite.Instance.Execute("SELECT `value` FROM `cookies` WHERE `key` = @key", new Dictionary { @@ -132,25 +160,26 @@ namespace VRCX { var item = values[0]; using var stream = new MemoryStream(Convert.FromBase64String((string)item[0])); - _cookieContainer = new CookieContainer(); - _cookieContainer.Add(System.Text.Json.JsonSerializer.Deserialize(stream)); + CookieContainer = new CookieContainer(); + CookieContainer.Add(System.Text.Json.JsonSerializer.Deserialize(stream)); + InitializeHttpClient(); } catch (Exception e) { Logger.Error($"Failed to load cookies: {e.Message}"); } } - + private List GetAllCookies() { - var cookieTable = (Hashtable)_cookieContainer.GetType().InvokeMember("m_domainTable", + var cookieTable = (Hashtable)CookieContainer.GetType().InvokeMember("m_domainTable", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance, null, - _cookieContainer, + CookieContainer, new object[] { }); - + var uniqueCookies = new Dictionary(); foreach (var item in cookieTable.Keys) { @@ -165,7 +194,7 @@ namespace VRCX if (!Uri.TryCreate(address, UriKind.Absolute, out var uri)) continue; - foreach (Cookie cookie in _cookieContainer.GetCookies(uri)) + foreach (Cookie cookie in CookieContainer.GetCookies(uri)) { var key = $"{domain}.{cookie.Name}"; if (!uniqueCookies.TryGetValue(key, out var value) || @@ -184,7 +213,7 @@ namespace VRCX { if (!_cookieDirty) return; - + try { var cookies = GetAllCookies(); @@ -192,12 +221,13 @@ namespace VRCX System.Text.Json.JsonSerializer.Serialize(memoryStream, cookies); SQLite.Instance.ExecuteNonQuery( "INSERT OR REPLACE INTO `cookies` (`key`, `value`) VALUES (@key, @value)", - new Dictionary() { - {"@key", "default"}, - {"@value", Convert.ToBase64String(memoryStream.ToArray())} + new Dictionary() + { + { "@key", "default" }, + { "@value", Convert.ToBase64String(memoryStream.ToArray()) } } ); - + _cookieDirty = false; } catch (Exception e) @@ -219,130 +249,77 @@ namespace VRCX { using (var stream = new MemoryStream(Convert.FromBase64String(cookies))) { - _cookieContainer = new CookieContainer(); - _cookieContainer.Add(System.Text.Json.JsonSerializer.Deserialize(stream)); + CookieContainer.Add(System.Text.Json.JsonSerializer.Deserialize(stream)); } _cookieDirty = true; // force cookies to be saved for lastUserLoggedIn } - private static async Task LegacyImageUpload(HttpWebRequest request, IDictionary options) + private async Task BuildLegacyImageUploadRequest(string url, IDictionary options) { - if (ProxySet) - request.Proxy = Proxy; - - request.AutomaticDecompression = DecompressionMethods.All; - request.Method = "POST"; + var request = new HttpRequestMessage(HttpMethod.Post, url); var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); - request.ContentType = "multipart/form-data; boundary=" + boundary; - var requestStream = request.GetRequestStream(); + var content = new MultipartFormDataContent(boundary); + if (options.TryGetValue("postData", out var postDataObject)) { - var postData = new Dictionary(); - postData.Add("data", (string)postDataObject); - const string formDataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n"; - foreach (var key in postData.Keys) - { - var item = string.Format(formDataTemplate, boundary, key, postData[key]); - var itemBytes = Encoding.UTF8.GetBytes(item); - await requestStream.WriteAsync(itemBytes); - } + content.Add(new StringContent((string)postDataObject), "data"); } + var imageData = options["imageData"] as string; var fileToUpload = Program.AppApiInstance.ResizeImageToFitLimits(Convert.FromBase64String(imageData), false); - const string fileFormKey = "image"; - const string fileName = "image.png"; - const string fileMimeType = "image/png"; - const string headerTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n"; - var header = string.Format(headerTemplate, boundary, fileFormKey, fileName, fileMimeType); - var headerBytes = Encoding.UTF8.GetBytes(header); - await requestStream.WriteAsync(headerBytes); - using (var fileStream = new MemoryStream(fileToUpload)) - { - var buffer = new byte[1024]; - var bytesRead = 0; - while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) - { - await requestStream.WriteAsync(buffer.AsMemory(0, bytesRead)); - } - fileStream.Close(); - } - var newlineBytes = Encoding.UTF8.GetBytes("\r\n"); - await requestStream.WriteAsync(newlineBytes); - var endBytes = Encoding.UTF8.GetBytes("--" + boundary + "--"); - await requestStream.WriteAsync(endBytes); - requestStream.Close(); + var imageContent = new ByteArrayContent(fileToUpload); + imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/png"); + content.Add(imageContent, "image", "image.png"); + + request.Content = content; + return request; } - private static async Task UploadFilePut(HttpWebRequest request, IDictionary options) + private async Task BuildUploadFilePutRequest(string url, IDictionary options) { - if (ProxySet) - request.Proxy = Proxy; - - request.AutomaticDecompression = DecompressionMethods.All; - request.Method = "PUT"; - request.ContentType = options["fileMIME"] as string; + var request = new HttpRequestMessage(HttpMethod.Put, url); var fileData = options["fileData"] as string; var sentData = Convert.FromBase64CharArray(fileData.ToCharArray(), 0, fileData.Length); - request.ContentLength = sentData.Length; - await using var sendStream = request.GetRequestStream(); - await sendStream.WriteAsync(sentData); - sendStream.Close(); + var content = new ByteArrayContent(sentData); + content.Headers.ContentType = new MediaTypeHeaderValue(options["fileMIME"] as string); + if (options.TryGetValue("fileMD5", out var fileMd5)) + content.Headers.ContentMD5 = Convert.FromBase64String(fileMd5 as string); + request.Content = content; + return request; } - - private static async Task ImageUpload(HttpWebRequest request, IDictionary options) - { - if (ProxySet) - request.Proxy = Proxy; - request.AutomaticDecompression = DecompressionMethods.All; - request.Method = "POST"; + private async Task BuildImageUploadRequest(string url, IDictionary options) + { + var request = new HttpRequestMessage(HttpMethod.Post, url); var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); - request.ContentType = "multipart/form-data; boundary=" + boundary; - var requestStream = request.GetRequestStream(); - if (options.TryGetValue("postData", out object postDataObject)) + var content = new MultipartFormDataContent(boundary); + + if (options.TryGetValue("postData", out var postDataObject)) { var jsonPostData = (JObject)JsonConvert.DeserializeObject((string)postDataObject); - const string formDataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n"; if (jsonPostData != null) { foreach (var data in jsonPostData) { - var item = string.Format(formDataTemplate, boundary, data.Key, data.Value); - var itemBytes = Encoding.UTF8.GetBytes(item); - await requestStream.WriteAsync(itemBytes); + content.Add(new StringContent(data.Value?.ToString() ?? string.Empty), data.Key); } } } + var imageData = options["imageData"] as string; var matchingDimensions = options["matchingDimensions"] as bool? ?? false; var fileToUpload = Program.AppApiInstance.ResizeImageToFitLimits(Convert.FromBase64String(imageData), matchingDimensions); - const string fileFormKey = "file"; - const string fileName = "blob"; - const string fileMimeType = "image/png"; - const string headerTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n"; - var header = string.Format(headerTemplate, boundary, fileFormKey, fileName, fileMimeType); - var headerBytes = Encoding.UTF8.GetBytes(header); - await requestStream.WriteAsync(headerBytes); - using (var fileStream = new MemoryStream(fileToUpload)) - { - var buffer = new byte[1024]; - var bytesRead = 0; - while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) - { - await requestStream.WriteAsync(buffer.AsMemory(0, bytesRead)); - } - fileStream.Close(); - } - var newlineBytes = Encoding.UTF8.GetBytes("\r\n"); - await requestStream.WriteAsync(newlineBytes); - var endBytes = Encoding.UTF8.GetBytes("--" + boundary + "--"); - await requestStream.WriteAsync(endBytes); - requestStream.Close(); + var imageContent = new ByteArrayContent(fileToUpload); + imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/png"); + content.Add(imageContent, "file", "blob"); + + request.Content = content; + return request; } - - private static async Task PrintImageUpload(HttpWebRequest request, IDictionary options) + + private async Task BuildPrintImageUploadRequest(string url, IDictionary options) { if (options.TryGetValue("cropWhiteBorder", out var cropWhiteBorder) && (bool)cropWhiteBorder) { @@ -356,40 +333,19 @@ namespace VRCX options["imageData"] = Convert.ToBase64String(ms2.ToArray()); } } - - if (ProxySet) - request.Proxy = Proxy; - request.AutomaticDecompression = DecompressionMethods.All; - request.Method = "POST"; + var request = new HttpRequestMessage(HttpMethod.Post, url); var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); - request.ContentType = "multipart/form-data; boundary=" + boundary; - var requestStream = request.GetRequestStream(); + var content = new MultipartFormDataContent(boundary); + var imageData = options["imageData"] as string; var fileToUpload = Program.AppApiInstance.ResizePrintImage(Convert.FromBase64String(imageData)); - const string fileFormKey = "image"; - const string fileName = "image"; - const string fileMimeType = "image/png"; - var fileSize = fileToUpload.Length; - const string headerTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\nContent-Length: {4}\r\n"; - var header = string.Format(headerTemplate, boundary, fileFormKey, fileName, fileMimeType, fileSize); - var headerBytes = Encoding.UTF8.GetBytes(header); - await requestStream.WriteAsync(headerBytes); - var newlineBytes = Encoding.UTF8.GetBytes("\r\n"); - await requestStream.WriteAsync(newlineBytes); - using (var fileStream = new MemoryStream(fileToUpload)) - { - var buffer = new byte[1024]; - int bytesRead; - while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) - { - await requestStream.WriteAsync(buffer.AsMemory(0, bytesRead)); - } - fileStream.Close(); - } - const string textContentType = "text/plain; charset=utf-8"; - const string formDataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\nContent-Type: {2}\r\nContent-Length: {3}\r\n\r\n{4}\r\n"; - await requestStream.WriteAsync(newlineBytes); + + var imageContent = new ByteArrayContent(fileToUpload); + imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/png"); + imageContent.Headers.ContentLength = fileToUpload.Length; + content.Add(imageContent, "image", "image"); + if (options.TryGetValue("postData", out var postDataObject)) { var jsonPostData = JsonConvert.DeserializeObject>(postDataObject.ToString()); @@ -397,17 +353,16 @@ namespace VRCX { foreach (var (key, value) in jsonPostData) { - var section = string.Format(formDataTemplate, boundary, key, textContentType, value.Length, value); - var sectionBytes = Encoding.UTF8.GetBytes(section); - await requestStream.WriteAsync(sectionBytes); + var stringContent = new StringContent(value, Encoding.UTF8, "text/plain"); + content.Add(stringContent, key); } } } - var endBytes = Encoding.UTF8.GetBytes("--" + boundary + "--"); - await requestStream.WriteAsync(endBytes); - requestStream.Close(); + + request.Content = content; + return request; } - + public async Task ExecuteJson(string options) { var data = JsonConvert.DeserializeObject>(options); @@ -423,112 +378,112 @@ namespace VRCX { try { - // TODO: switch to HttpClient -#pragma warning disable SYSLIB0014 // Type or member is obsolete - var request = WebRequest.CreateHttp((string)options["url"]); -#pragma warning restore SYSLIB0014 // Type or member is obsolete - if (ProxySet) - request.Proxy = Proxy; + var url = (string)options["url"]; + HttpRequestMessage request; - request.CookieContainer = _cookieContainer; - request.KeepAlive = true; - request.UserAgent = Program.Version; - request.AutomaticDecompression = DecompressionMethods.All; + // Handle special upload types + if (options.TryGetValue("uploadImageLegacy", out _)) + { + request = await BuildLegacyImageUploadRequest(url, options); + } + else if (options.TryGetValue("uploadFilePUT", out _)) + { + request = await BuildUploadFilePutRequest(url, options); + } + else if (options.TryGetValue("uploadImage", out _)) + { + request = await BuildImageUploadRequest(url, options); + } + else if (options.TryGetValue("uploadImagePrint", out _)) + { + request = await BuildPrintImageUploadRequest(url, options); + } + else + { + // Standard request + var httpMethod = HttpMethod.Get; + if (options.TryGetValue("method", out var methodObj)) + { + httpMethod = HttpMethod.Parse(methodObj.ToString()); + } + request = new HttpRequestMessage(httpMethod, url); + + // Handle body for non-GET requests + if (httpMethod != HttpMethod.Get && options.TryGetValue("body", out var body)) + { + var bodyContent = new StringContent((string)body, Encoding.UTF8); + + // Set content type if specified in headers + if (options.TryGetValue("headers", out var headersObj)) + { + var headersDict = ParseHeaders(headersObj); + if (headersDict.TryGetValue("Content-Type", out var contentType)) + { + bodyContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); + } + } + + request.Content = bodyContent; + } + } + + // Apply headers if (options.TryGetValue("headers", out var headers)) { - Dictionary headersDict; - if (headers.GetType() == typeof(JObject)) - { - headersDict = ((JObject)headers).ToObject>(); - } - else - { - var headersKvp = (IEnumerable>)headers; - headersDict = new Dictionary(); - foreach (var (key, value) in headersKvp) - headersDict.Add(key, value.ToString()); - } - + var headersDict = ParseHeaders(headers); foreach (var (key, value) in headersDict) { - if (string.Compare(key, "Content-Type", StringComparison.OrdinalIgnoreCase) == 0) - request.ContentType = value; - else if (string.Compare(key, "Referer", StringComparison.OrdinalIgnoreCase) == 0) - request.Referer = value; + // Skip Content-Type as it's set on content + if (string.Equals(key, "Content-Type", StringComparison.OrdinalIgnoreCase)) + continue; + + if (string.Equals(key, "Referer", StringComparison.OrdinalIgnoreCase)) + { + request.Headers.Referrer = new Uri(value); + } else - request.Headers.Add(key, value); + { + request.Headers.TryAddWithoutValidation(key, value); + } } } - if (options.TryGetValue("method", out var method)) - { - request.Method = (string)method; - if (string.Compare(request.Method, "GET", StringComparison.OrdinalIgnoreCase) != 0 && - options.TryGetValue("body", out var body)) - { - await using var bodyStream = await request.GetRequestStreamAsync(); - await using var streamWriter = new StreamWriter(bodyStream); - await streamWriter.WriteAsync((string)body); - } - } + using var response = await _httpClient.SendAsync(request); - if (options.TryGetValue("uploadImage", out _)) - await ImageUpload(request, options); - - if (options.TryGetValue("uploadFilePUT", out _)) - await UploadFilePut(request, options); - - if (options.TryGetValue("uploadImageLegacy", out _)) - await LegacyImageUpload(request, options); - - if (options.TryGetValue("uploadImagePrint", out _)) - await PrintImageUpload(request, options); - - using var response = await request.GetResponseAsync() as HttpWebResponse; - if (response?.Headers["Set-Cookie"] != null) + // Check if cookies were modified + if (response.Headers.Contains("Set-Cookie")) _cookieDirty = true; - await using var imageStream = response.GetResponseStream(); - using var streamReader = new StreamReader(imageStream); - if (response.ContentType.Contains("image/") || - response.ContentType.Contains("application/octet-stream")) + var contentTypeResponse = response.Content.Headers.ContentType?.MediaType ?? string.Empty; + + if (contentTypeResponse.Contains("image/") || contentTypeResponse.Contains("application/octet-stream")) { - // base64 response data for image - using var memoryStream = new MemoryStream(); - await imageStream.CopyToAsync(memoryStream); + // Base64 response data for image + var imageBytes = await response.Content.ReadAsByteArrayAsync(); return new Tuple( (int)response.StatusCode, - $"data:image/png;base64,{Convert.ToBase64String(memoryStream.ToArray())}" + $"data:image/png;base64,{Convert.ToBase64String(imageBytes)}" ); } + var responseBody = await response.Content.ReadAsStringAsync(); return new Tuple( (int)response.StatusCode, - await streamReader.ReadToEndAsync() + responseBody ); } - catch (WebException webException) + catch (HttpRequestException httpException) { - if (webException.Response is HttpWebResponse response) - { - if (response.Headers["Set-Cookie"] != null) - _cookieDirty = true; + if (httpException.InnerException != null) + Logger.Error($"{httpException.Message} | {httpException.InnerException}"); - await using var stream = response.GetResponseStream(); - using var streamReader = new StreamReader(stream); - return new Tuple( - (int)response.StatusCode, - await streamReader.ReadToEndAsync() - ); - } - - if (webException.InnerException != null) - Logger.Error($"{webException.Message} | {webException.InnerException}"); + // Try to get status code if available + var statusCode = httpException.StatusCode.HasValue ? (int)httpException.StatusCode.Value : -1; return new Tuple( - -1, - webException.Message + statusCode, + httpException.Message ); } catch (Exception e) @@ -542,5 +497,22 @@ namespace VRCX ); } } + + private static Dictionary ParseHeaders(object headers) + { + Dictionary headersDict; + if (headers.GetType() == typeof(JObject)) + { + headersDict = ((JObject)headers).ToObject>(); + } + else + { + var headersKvp = (IEnumerable>)headers; + headersDict = new Dictionary(); + foreach (var (key, value) in headersKvp) + headersDict.Add(key, value.ToString()); + } + return headersDict; + } } -} \ No newline at end of file +} diff --git a/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue b/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue index 66aaa2d0..c0559200 100644 --- a/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue +++ b/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue @@ -199,9 +199,7 @@ uploadFilePUT: true, fileData: avatarImage.value.base64File, fileMIME: 'image/png', - headers: { - 'Content-MD5': avatarImage.value.fileMd5 - } + fileMD5: avatarImage.value.fileMd5 }); if (json.status !== 200) { @@ -252,9 +250,7 @@ uploadFilePUT: true, fileData: avatarImage.value.base64SignatureFile, fileMIME: 'application/x-rsync-signature', - headers: { - 'Content-MD5': avatarImage.value.signatureMd5 - } + fileMD5: avatarImage.value.signatureMd5 }); if (json.status !== 200) { diff --git a/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue b/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue index 21789313..d7e30e93 100644 --- a/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue +++ b/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue @@ -192,9 +192,7 @@ uploadFilePUT: true, fileData: worldImage.value.base64File, fileMIME: 'image/png', - headers: { - 'Content-MD5': worldImage.value.fileMd5 - } + fileMD5: worldImage.value.fileMd5 }); if (json.status !== 200) { @@ -245,9 +243,7 @@ uploadFilePUT: true, fileData: worldImage.value.base64SignatureFile, fileMIME: 'application/x-rsync-signature', - headers: { - 'Content-MD5': worldImage.value.signatureMd5 - } + fileMD5: worldImage.value.signatureMd5 }); if (json.status !== 200) { diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts index 13884847..1bab4d94 100644 --- a/src/types/globals.d.ts +++ b/src/types/globals.d.ts @@ -408,10 +408,11 @@ declare global { uploadFilePUT?: boolean; fileData?: string; fileMIME?: string; + fileMD5?: string; headers?: Record; data?: any; }): Promise<{ status: number; data: string }>; }; } -export { }; +export {};