/// <summary> /// Creates or updates this item in the remote storage. /// </summary> /// <param name="remoteStorageUri">Uri of the file to be created or updated in the remote storage.</param> /// <param name="newInfo">New information about the file or folder, such as modification date, attributes, custom data, etc.</param> /// <param name="mode">Specifies if a new file should be created or existing file should be updated.</param> /// <param name="content">New file content or null if the file content is not modified.</param> /// <param name="eTagOld">The ETag to be sent to the remote storage as part of the update request to make sure the content is not overwritten.</param> /// <param name="lockInfo">Information about the lock. Caller passes null if the item is not locked.</param> /// <returns>The new ETag returned from the remote storage.</returns> protected static async Task <string> CreateOrUpdateFileAsync( Uri remoteStorageUri, IFileSystemItemMetadata newInfo, FileMode mode, Stream content = null, string eTagOld = null, ServerLockInfo lockInfo = null) { string eTagNew = null; if (content != null || mode == FileMode.CreateNew) { long contentLength = content != null ? content.Length : 0; IWebRequestAsync request = await Program.DavClient.GetFileWriteRequestAsync( remoteStorageUri, null, contentLength, 0, -1, lockInfo?.LockToken, eTagOld); // Update remote storage file content. using (Stream davContentStream = await request.GetRequestStreamAsync()) { if (content != null) { await content.CopyToAsync(davContentStream); } // Get the new ETag returned by the server (if any). // We return the new ETag to the Engine to be stored with the file unlil the next update. IWebResponseAsync response = await request.GetResponseAsync(); eTagNew = response.Headers["ETag"]; response.Close(); } } return(eTagNew); }
/// <summary> /// Creates instance of this class. /// </summary> /// <param name="url">URL to navigate to. This URL must redirect to a log-in page.</param> public WebBrowserLogin(Uri url, IWebRequestAsync request, WebDavSessionAsync davClient, ILog log) { this.url = url; this.request = request; this.davClient = davClient; this.log = log; InitializeComponent(); this.webView = new Microsoft.Web.WebView2.Wpf.WebView2(); this.Loaded += WebBrowserLogin_Load; this.panel.Children.Add(this.webView); }
/// <inheritdoc/> public async Task WriteAsync(IFileMetadata fileMetadata, Stream content = null) { if (MsOfficeHelper.IsMsOfficeLocked(UserFileSystemPath)) // Required for PowerPoint. It does not block the for writing. { throw new ClientLockFailedException("The file is blocked for writing."); } Logger.LogMessage($"{nameof(IFile)}.{nameof(WriteAsync)}()", UserFileSystemPath); ExternalDataManager customDataManager = Engine.CustomDataManager(UserFileSystemPath); // Send the ETag to the server as part of the update to ensure the file in the remote storge is not modified since last read. string oldEtag = await customDataManager.ETagManager.GetETagAsync(); // Send the lock-token to the server as part of the update. string lockToken = (await customDataManager.LockManager.GetLockInfoAsync())?.LockToken; if (content != null) { long contentLength = content != null ? content.Length : 0; IWebRequestAsync request = await Program.DavClient.GetFileWriteRequestAsync( new Uri(RemoteStoragePath), null, contentLength, 0, -1, lockToken, oldEtag); // Update remote storage file content. using (Stream davContentStream = await request.GetRequestStreamAsync()) { if (content != null) { await content.CopyToAsync(davContentStream); } // Get the new ETag returned by the server (if any). IWebResponseAsync response = await request.GetResponseAsync(); string eTagNew = response.Headers["ETag"]; response.Close(); // Store ETag unlil the next update. // This will also mark the item as not new, which is required for correct MS Office saving opertions. await customDataManager.ETagManager.SetETagAsync(eTagNew); // Update ETag in custom column displayed in file manager. await customDataManager.SetCustomColumnsAsync(new[] { new FileSystemItemPropertyData((int)CustomColumnIds.ETag, eTagNew) }); } } }
/// <inheritdoc/> public async Task <byte[]> CreateFileAsync(IFileMetadata fileMetadata, Stream content = null) { string userFileSystemNewItemPath = Path.Combine(UserFileSystemPath, fileMetadata.Name); Logger.LogMessage($"{nameof(IFolder)}.{nameof(CreateFileAsync)}()", userFileSystemNewItemPath); Uri newFileUri = new Uri(new Uri(RemoteStoragePath), fileMetadata.Name); long contentLength = content != null ? content.Length : 0; IWebRequestAsync request = await Program.DavClient.GetFileWriteRequestAsync(newFileUri, null, contentLength); // Update remote storage file content. using (Stream davContentStream = await request.GetRequestStreamAsync()) { if (content != null) { await content.CopyToAsync(davContentStream); } // Get the new ETag returned by the server (if any). IWebResponseAsync response = await request.GetResponseAsync(); string eTagNew = response.Headers["ETag"]; response.Close(); ExternalDataManager customDataManager = Engine.CustomDataManager(userFileSystemNewItemPath); // Store ETag unlil the next update. // This will also mark the item as not new, which is required for correct MS Office saving opertions. await customDataManager.ETagManager.SetETagAsync(eTagNew); customDataManager.IsNew = false; // Mark file as not new just in case the server did not return the ETag. // Update ETag in custom column displayed in file manager. await customDataManager.SetCustomColumnsAsync(new[] { new FileSystemItemPropertyData((int)CustomColumnIds.ETag, eTagNew) }); } return(null); }
/// <summary> /// Creates or updates file in the remote storage. /// </summary> /// <param name="remoteStorageUri">Uri of the file to be created or updated in the remote storage.</param> /// <param name="newInfo">New information about the file, such as modification date, attributes, custom data, etc.</param> /// <param name="mode">Specifies if a new file should be created or existing file should be updated.</param> /// <param name="content">New file content or null if the file content is not modified.</param> /// <param name="lockInfo">Information about the lock. Caller passes null if the item is not locked.</param> /// <returns>New ETag returned from the remote storage.</returns> protected async Task <string> CreateOrUpdateFileAsync(Uri remoteStorageUri, IFileBasicInfo newInfo, FileMode mode, Stream content = null, ServerLockInfo lockInfo = null) { string eTag = null; string lockToken = null; // Get ETag and lock-token here and send it to the remote storage with the new item content/info. if (mode == FileMode.Open) { // Get ETag. eTag = await ETag.GetETagAsync(UserFileSystemPath); // Get lock-token. lockToken = lockInfo?.LockToken; } if (content != null || mode == FileMode.CreateNew) { long contentLength = content != null ? content.Length : 0; IWebRequestAsync request = await Program.DavClient.GetFileWriteRequestAsync(remoteStorageUri, null, contentLength, 0, -1, lockToken, eTag); // Update remote storage file content. using (Stream davContentStream = await request.GetRequestStreamAsync()) { if (content != null) { await content.CopyToAsync(davContentStream); } // Get ETag returned by the server, if any. IWebResponseAsync response = await request.GetResponseAsync(); eTag = response.Headers["ETag"]; response.Close(); } } return(eTag); }
/// <summary> /// Event handler to process WebDAV errors. /// If server returns 401 or 302 response here we show the login dialog. /// </summary> /// <param name="sender">Request to the WebDAV server.</param> /// <param name="e">WebDAV error details.</param> private static void DavClient_WebDavError(IWebRequestAsync sender, WebDavErrorEventArgs e) { WebDavHttpException httpException = e.Exception as WebDavHttpException; log.Info($"\n{httpException?.Status.Code} {httpException?.Status.Description} {e.Exception.Message} "); if (httpException != null) { switch (httpException.Status.Code) { // 302 redirect to login page. case 302: if (loginRetriesCurrent < loginRetriesMax) { loginRetriesCurrent++; // Show login dialog. // Azure AD can not navigate directly to login page - failed corelation. //string loginUrl = ((Redirect302Exception)e.Exception).Location; //Uri url = new System.Uri(loginUrl, System.UriKind.Absolute); Uri failedUri = (e.Exception as WebDavHttpException).Uri; WebDAVDrive.UI.WebBrowserLogin webBrowserLogin = null; Thread thread = new Thread(() => { webBrowserLogin = new WebDAVDrive.UI.WebBrowserLogin(failedUri, e.Request, DavClient, log); webBrowserLogin.Title = Settings.ProductName; webBrowserLogin.ShowDialog(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); /* * if (loginForm.Cookies != null) * { * // Attach cookies to all future requests. * DavClient.CookieContainer.Add(loginForm.Cookies); * e.Result = WebDavErrorEventResult.Fail; * * // Set successful response and continue processing. * e.Response = loginForm.Response; * e.Result = WebDavErrorEventResult.ContinueProcessing; * * // Alternatively you can modify this request, attaching cookies or headers, and replay it. * //e.Request.CookieContainer.Add(loginForm.Cookies); * //e.Result = WebDavErrorEventResult.Repeat; * } */ } break; // Challenge-responce auth: Basic, Digest, NTLM or Kerberos case 401: if (loginRetriesCurrent < loginRetriesMax) { Uri failedUri = (e.Exception as WebDavHttpException).Uri; Windows.Security.Credentials.PasswordCredential passwordCredential = CredentialManager.GetCredentials(Settings.ProductName, log); if (passwordCredential != null) { passwordCredential.RetrievePassword(); DavClient.Credentials = new NetworkCredential(passwordCredential.UserName, passwordCredential.Password); } else { string login = null; SecureString password = null; bool dialogResult = false; bool keepLogedin = false; // Show login dialog WebDAVDrive.UI.ChallengeLogin loginForm = null; Thread thread = new Thread(() => { loginForm = new WebDAVDrive.UI.ChallengeLogin(); ((ChallengeLoginViewModel)loginForm.DataContext).Url = failedUri.OriginalString; ((ChallengeLoginViewModel)loginForm.DataContext).WindowTitle = Settings.ProductName; loginForm.ShowDialog(); login = ((ChallengeLoginViewModel)loginForm.DataContext).Login; password = ((ChallengeLoginViewModel)loginForm.DataContext).Password; keepLogedin = ((ChallengeLoginViewModel)loginForm.DataContext).KeepLogedIn; dialogResult = (bool)loginForm.DialogResult; }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); loginRetriesCurrent++; if (dialogResult) { if (keepLogedin) { CredentialManager.SaveCredentials(Settings.ProductName, login, password); } DavClient.Credentials = new NetworkCredential(login, password); } } } break; } } }