public override async Task <WopiResponse> GetLock(GetLockRequest getLockRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(getLockRequest.AccessToken); var wopiFileRepository = new WopiFileRepository(); var response = await wopiFileRepository.GetLockStatus(getLockRequest.ResourceId, userId); // Check for file not found or no permissions if (response.Item1 == HttpStatusCode.NotFound) { return(getLockRequest.ResponseNotFound()); } // Ensure the file isn't already locked else if (response.Item1 == HttpStatusCode.Conflict) { return(getLockRequest.ResponseLockConflict(response.Item2)); } // File successfully locked else if (response.Item1 == HttpStatusCode.OK) { if (response.Item2 != null) { return(getLockRequest.ResponseFileLocked(response.Item2)); } else { return(getLockRequest.ResponseFileNotLocked()); } } else { return(getLockRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.GetLockStatus: {0}", response.Item1))); } }
public override async Task <WopiResponse> RenameFile(RenameFileRequest renameFileRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(renameFileRequest.AccessToken); var wopiFileRepository = new WopiFileRepository(); var response = await wopiFileRepository.RenameFile(renameFileRequest.ResourceId, userId, renameFileRequest.Lock, renameFileRequest.RequestedName); if (response.Item1 == HttpStatusCode.NotFound) { return(renameFileRequest.ResponseNotFound()); } else if (response.Item1 == HttpStatusCode.Conflict) { return(renameFileRequest.ResponseLockConflict(response.Item2)); } else if (response.Item1 == HttpStatusCode.BadRequest) { return(renameFileRequest.ResponseBadRequest(response.Item2)); } else if (response.Item1 == HttpStatusCode.OK) { return(renameFileRequest.ResponseOK(response.Item2)); } else { return(renameFileRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.RenameFile: {0}", response.Item1))); } }
public override Task <bool> Authorize(WopiRequest wopiRequest) { try { if (string.IsNullOrEmpty(wopiRequest.AccessToken)) { return(Task.FromResult <bool>(false)); } // Get the requested file from Document DB var itemId = new Guid(wopiRequest.ResourceId); var wopiFile = DocumentDBRepository <DetailedFileModel> .GetItem("Files", file => file.id == itemId); // Check for missing file if (wopiFile == null) { return(Task.FromResult <bool>(false)); } // Validate the access token return(Task.FromResult <bool>(WopiSecurity.ValidateToken(wopiRequest.AccessToken, wopiFile.Container, wopiFile.id.ToString()))); } catch (Exception) { // Any exception will return false, but should probably return an alternate status codes return(Task.FromResult <bool>(false)); } }
public override async Task <WopiResponse> UnlockAndRelock(UnlockAndRelockRequest unlockAndRelockRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(unlockAndRelockRequest.AccessToken); var wopiFileRepository = new WopiFileRepository(); var response = await wopiFileRepository.LockFile(unlockAndRelockRequest.ResourceId, userId, unlockAndRelockRequest.Lock, unlockAndRelockRequest.OldLock); if (response.Item1 == HttpStatusCode.BadRequest) { return(unlockAndRelockRequest.ResponseBadRequest()); } // Check for file not found or no permissions else if (response.Item1 == HttpStatusCode.NotFound) { return(unlockAndRelockRequest.ResponseNotFound()); } // Ensure the file isn't already locked else if (response.Item1 == HttpStatusCode.Conflict) { return(unlockAndRelockRequest.ResponseLockConflict(response.Item2)); } // File successfully locked else if (response.Item1 == HttpStatusCode.OK) { return(unlockAndRelockRequest.ResponseOK()); } else { return(unlockAndRelockRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.LockFile: {0}", response.Item1))); } }
public async Task <ActionResult> Detail(string id) { var userId = User.Identity.Name; var tenant = new MailAddress(userId).Host.Replace(".", "-"); // Make sure an action was passed in if (String.IsNullOrEmpty(Request["action"])) { return(RedirectToAction("Error", "Home", new { error = "No action provided" })); } var wopiFileRepository = new WopiFileRepository(); var result = await wopiFileRepository.GetFileInfoByTenantUser(id, userId, tenant); // Check for null file if (result.Item1 == HttpStatusCode.NotFound) { return(RedirectToAction("Error", "Home", new { error = "Files does not exist" })); } else if (result.Item1 == HttpStatusCode.Unauthorized) { return(RedirectToAction("Error", "Home", new { error = "Not authorized to access file" })); } else if (result.Item1 == HttpStatusCode.OK) { var wopiFile = result.Item2; // Use discovery to determine endpoint to leverage List <WopiAction> discoData = await WopiDiscovery.GetActions(); var fileExt = wopiFile.FileName.Substring(wopiFile.FileName.LastIndexOf('.') + 1).ToLower(); var action = discoData.FirstOrDefault(i => i.name == Request["action"] && i.ext == fileExt); // Make sure the action isn't null if (action != null) { string urlsrc = WopiDiscovery.GetActionUrl(action, wopiFile.FileId.ToString(), Request.Url.Authority); // Generate JWT token for the user/document WopiSecurity wopiSecurity = new WopiSecurity(); var token = wopiSecurity.GenerateToken(User.Identity.Name.ToLower()); ViewData["access_token"] = wopiSecurity.WriteToken(token); ViewData["access_token_ttl"] = token.ValidTo.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds; ViewData["wopi_urlsrc"] = urlsrc; return(View()); } else { // This will only hit if the extension isn't supported by WOPI return(RedirectToAction("Error", "Home", new { error = "File is not a supported WOPI extension" })); } } else { return(RedirectToAction("Error", "Home", new { error = "Internal server error" })); } }
public override async Task <WopiResponse> PutRelativeFileSpecific(PutRelativeFileSpecificRequest putRelativeFileSpecificRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(putRelativeFileSpecificRequest.AccessToken); var wopiFileRepository = new WopiFileRepository(); var response = await wopiFileRepository.CreateCopy(putRelativeFileSpecificRequest.ResourceId, userId, putRelativeFileSpecificRequest.RelativeTarget, putRelativeFileSpecificRequest.OverwriteRelativeTarget); if (response.Item1 == HttpStatusCode.NotFound) { return(putRelativeFileSpecificRequest.ResponseNotFound()); } else if (response.Item1 == HttpStatusCode.BadRequest) { return(putRelativeFileSpecificRequest.ResponseBadRequest()); } else if (response.Item1 == HttpStatusCode.Conflict) { return(putRelativeFileSpecificRequest.ResponseLockConflict(response.Item3)); } else if (response.Item1 == HttpStatusCode.OK) { // Get access token for the new file WopiSecurity security = new WopiSecurity(); var token = security.GenerateToken(response.Item2.OwnerId); var tokenStr = security.WriteToken(token); var url = new Uri(string.Format("https://{0}/wopi/files/{1}?access_token={2}", putRelativeFileSpecificRequest.RequestUri.Authority, response.Item2.FileId, tokenStr)); Uri hostViewUrl = null; Uri hostEditUrl = null; var actions = await WopiDiscovery.GetActions(); var view = actions.FirstOrDefault(i => i.ext == response.Item2.FileExtension && i.name == "view"); if (view != null) { hostViewUrl = new Uri(WopiDiscovery.GetActionUrl(view, response.Item2.FileId, putRelativeFileSpecificRequest.RequestUri.Authority)); } var edit = actions.FirstOrDefault(i => i.ext == response.Item2.FileExtension && i.name == "edit"); if (edit != null) { hostEditUrl = new Uri(WopiDiscovery.GetActionUrl(edit, response.Item2.FileId, putRelativeFileSpecificRequest.RequestUri.Authority)); } return(putRelativeFileSpecificRequest.ResponseOK(response.Item2.FileName, url, hostViewUrl, hostEditUrl)); } else { return(putRelativeFileSpecificRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.CreateCopy: {0}", response.Item1))); } }
public override async Task <WopiResponse> CheckFileInfo(CheckFileInfoRequest checkFileInfoRequest) { // Lookup the file in the database var itemId = new Guid(checkFileInfoRequest.ResourceId); var wopiFile = DocumentDBRepository <DetailedFileModel> .GetItem("Files", file => file.id == itemId); // Check for null file if (wopiFile != null) { // Get discovery information var fileExt = wopiFile.BaseFileName.Substring(wopiFile.BaseFileName.LastIndexOf('.') + 1).ToLower(); var actions = await WopiDiscovery.GetActions(); // Augments the file with additional properties CloseUrl, HostViewUrl, HostEditUrl wopiFile.CloseUrl = String.Format("https://{0}", checkFileInfoRequest.RequestUri.Authority); var view = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "view"); if (view != null) { wopiFile.HostViewUrl = WopiDiscovery.GetActionUrl(view, wopiFile.id.ToString(), checkFileInfoRequest.RequestUri.Authority); } var edit = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "edit"); if (edit != null) { wopiFile.HostEditUrl = WopiDiscovery.GetActionUrl(edit, wopiFile.id.ToString(), checkFileInfoRequest.RequestUri.Authority); } // Get the user from the token (token is already validated) wopiFile.UserId = WopiSecurity.GetUserFromToken(checkFileInfoRequest.AccessToken); // Write the response and return a success 200 var wopiResponse = checkFileInfoRequest.ResponseOK(wopiFile.BaseFileName, wopiFile.OwnerId, wopiFile.Size, wopiFile.UserId, wopiFile.Version.ToString()); // Add optional items wopiResponse.CloseUrl = new Uri(wopiFile.CloseUrl); if (wopiFile.HostViewUrl != null) { wopiResponse.HostViewUrl = new Uri(wopiFile.HostViewUrl); } if (wopiFile.HostEditUrl != null) { wopiResponse.HostEditUrl = new Uri(wopiFile.HostEditUrl); } return(wopiResponse); } else { return(checkFileInfoRequest.ResponseNotFound()); } }
public override async Task <WopiResponse> PutRelativeFileSuggested(PutRelativeFileSuggestedRequest putRelativeFileSuggestedRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(putRelativeFileSuggestedRequest.AccessToken); var wopiFileRepository = new WopiFileRepository(); var response = await wopiFileRepository.CreateCopySuggested(putRelativeFileSuggestedRequest.ResourceId, userId, putRelativeFileSuggestedRequest.SuggestedTarget); if (response.Item1 == HttpStatusCode.NotFound) { return(putRelativeFileSuggestedRequest.ResponseNotFound()); } else if (response.Item1 == HttpStatusCode.OK) { // Get access token for the new file WopiSecurity security = new WopiSecurity(); var token = security.GenerateToken(response.Item2.OwnerId); var tokenStr = security.WriteToken(token); //var name = newFile.BaseFileName; var url = new Uri(string.Format("https://{0}/wopi/files/{1}?access_token={2}", putRelativeFileSuggestedRequest.RequestUri.Authority, response.Item2.FileId, tokenStr)); // Add the optional properties to response if applicable (HostViewUrl, HostEditUrl) Uri hostViewUrl = null; Uri hostEditUrl = null; var actions = await WopiDiscovery.GetActions(); var view = actions.FirstOrDefault(i => i.ext == response.Item2.FileExtension && i.name == "view"); if (view != null) { hostViewUrl = new Uri(WopiDiscovery.GetActionUrl(view, response.Item2.FileId, putRelativeFileSuggestedRequest.RequestUri.Authority)); } var edit = actions.FirstOrDefault(i => i.ext == response.Item2.FileExtension && i.name == "edit"); if (edit != null) { hostEditUrl = new Uri(WopiDiscovery.GetActionUrl(edit, response.Item2.FileId, putRelativeFileSuggestedRequest.RequestUri.Authority)); } // Write the response and return a success 200 return(putRelativeFileSuggestedRequest.ResponseOK(response.Item2.FileName, url, hostViewUrl, hostEditUrl)); } else { return(putRelativeFileSuggestedRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.CreateCopySuggested: {0}", response.Item1))); } }
public override async Task <WopiResponse> GetFile(GetFileRequest getFileRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(getFileRequest.AccessToken); // Lookup the file in the database var wopiFileRepository = new WopiFileRepository(); var response = await wopiFileRepository.GetFileContent(getFileRequest.ResourceId, userId); // Check for null file if (response.Item1 == HttpStatusCode.NotFound) { return(getFileRequest.ResponseNotFound()); } else { // Write the response and return success 200 return(getFileRequest.ResponseOK(new StreamContent(response.Item2), response.Item3)); } }
public override async Task <WopiResponse> PutUserInfo(PutUserInfoRequest putUserInfoRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(putUserInfoRequest.AccessToken); var wopiFileRespository = new WopiFileRepository(); var response = await wopiFileRespository.SaveWopiUserInfo(putUserInfoRequest.ResourceId, userId, putUserInfoRequest.UserInfo); if (response == HttpStatusCode.NotFound) { return(putUserInfoRequest.ResponseNotFound()); } else if (response == HttpStatusCode.OK) { return(putUserInfoRequest.ResponseOK()); } else { return(putUserInfoRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.SaveWopiUserInfo: {0}", response))); } }
public override async Task <WopiResponse> DeleteFile(DeleteFileRequest deleteFileRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(deleteFileRequest.AccessToken); var wopiFileRespository = new WopiFileRepository(); var response = await wopiFileRespository.DeleteFile(deleteFileRequest.ResourceId, userId); if (response == HttpStatusCode.NotFound) { return(deleteFileRequest.ResponseNotFound()); } else if (response == HttpStatusCode.OK) { return(deleteFileRequest.ResponseOK()); } else { return(deleteFileRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.UpdateFileContent: {0}", response))); } }
public async Task <ActionResult> Detail(Guid id) { // Make sure an action was passed in if (String.IsNullOrEmpty(Request["action"])) { return(RedirectToAction("Error", "Home", new { error = "No action provided" })); } // Get the specific file from DocumentDB var wopiFile = DocumentDBRepository <FileModel> .GetItem("Files", i => i.OwnerId == User.Identity.Name.ToLower() && i.id == id); // Check for null file if (wopiFile == null) { return(RedirectToAction("Error", "Home", new { error = "Files does not exist" })); } // Use discovery to determine endpoint to leverage List <WopiAction> discoData = await WopiDiscovery.GetActions(); var fileExt = wopiFile.BaseFileName.Substring(wopiFile.BaseFileName.LastIndexOf('.') + 1).ToLower(); var action = discoData.FirstOrDefault(i => i.name == Request["action"] && i.ext == fileExt); // Make sure the action isn't null if (action != null) { string urlsrc = WopiDiscovery.GetActionUrl(action, wopiFile.id.ToString(), Request.Url.Authority); // Generate JWT token for the user/document WopiSecurity wopiSecurity = new WopiSecurity(); var token = wopiSecurity.GenerateToken(User.Identity.Name.ToLower(), getUserContainer(), id.ToString()); ViewData["access_token"] = wopiSecurity.WriteToken(token); ViewData["access_token_ttl"] = token.ValidTo.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds; ViewData["wopi_urlsrc"] = urlsrc; return(View()); } else { // This will only hit if the extension isn't supported by WOPI return(RedirectToAction("Error", "Home", new { error = "File is not a supported WOPI extension" })); } }
public override async Task <WopiResponse> GetFile(GetFileRequest getFileRequest) { // Lookup the file in the database var itemId = new Guid(getFileRequest.ResourceId); var wopiFile = DocumentDBRepository <DetailedFileModel> .GetItem("Files", file => file.id == itemId); // Check for null file if (wopiFile != null) { // Get discovery information var fileExt = wopiFile.BaseFileName.Substring(wopiFile.BaseFileName.LastIndexOf('.') + 1).ToLower(); var actions = await WopiDiscovery.GetActions(); // Augments the file with additional properties CloseUrl, HostViewUrl, HostEditUrl wopiFile.CloseUrl = String.Format("https://{0}", getFileRequest.RequestUri.Authority); var view = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "view"); if (view != null) { wopiFile.HostViewUrl = WopiDiscovery.GetActionUrl(view, wopiFile.id.ToString(), getFileRequest.RequestUri.Authority); } var edit = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "edit"); if (edit != null) { wopiFile.HostEditUrl = WopiDiscovery.GetActionUrl(edit, wopiFile.id.ToString(), getFileRequest.RequestUri.Authority); } // Get the user from the token (token is already validated) wopiFile.UserId = WopiSecurity.GetUserFromToken(getFileRequest.AccessToken); // Call the appropriate handler for the WOPI request we received // Get the file from blob storage var bytes = await AzureStorageUtil.GetFile(wopiFile.id.ToString(), wopiFile.Container); // Write the response and return success 200 return(getFileRequest.ResponseOK(new ByteArrayContent(bytes))); } else { return(getFileRequest.ResponseNotFound()); } }
public override Task <bool> Authorize(WopiRequest wopiRequest) { try { if (string.IsNullOrEmpty(wopiRequest.AccessToken)) { return(Task.FromResult <bool>(false)); } // Validate the access token contains authenticated user // We're only doing authentication here and deferring authorization to the other WOPI operations // to avoid multiple DB queries var userId = WopiSecurity.GetIdentityNameFromToken(wopiRequest.AccessToken); return(Task.FromResult <bool>(userId != null)); } catch (Exception) { // Any exception will return false, but should probably return an alternate status codes return(Task.FromResult <bool>(false)); } }
public async System.Threading.Tasks.Task <string> Url(UserAction ua = null) { if (ua == null) { ua = new UserAction(); } // Use discovery to determine endpoint to leverage List <WopiAction> discoData = await WopiUtil.GetDiscoveryInfo(); var fileExt = BaseFileName.Substring(BaseFileName.LastIndexOf('.') + 1).ToLower(); var action = discoData.FirstOrDefault(i => i.name == ua.Action && i.ext == fileExt); if (action != null) { string urlsrc = WopiUtil.GetActionUrl(action, this, ServerUtil.Config().Domain); WopiSecurity wopiSecurity = new WopiSecurity(); var token = wopiSecurity.GenerateToken(id.ToString(), ua.UserId, ua.UserDisplayName); if (action.name == "edit") { token.ReadOnly = false; } else { token.ReadOnly = true; } token.Save(); return(String.Format("{0}&access_token={1}&access_token_ttl={2}", urlsrc, token.Identity, token.ValidTo().Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds.ToString())); } else { // This will only hit if the extension isn't supported by WOPI throw new Exception("Bad action on this file."); } }
public override async Task <WopiResponse> PutFile(PutFileRequest putFileRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(putFileRequest.AccessToken); var wopiFileRespository = new WopiFileRepository(); var response = await wopiFileRespository.UpdateFileContent(putFileRequest.ResourceId, userId, putFileRequest.Lock, await putFileRequest.Content.ReadAsStreamAsync()); if (response.Item1 == HttpStatusCode.NotFound) { return(putFileRequest.ResponseNotFound()); } else if (response.Item1 == HttpStatusCode.Conflict) { return(putFileRequest.ResponseLockConflict(response.Item2)); } else if (response.Item1 == HttpStatusCode.OK) { return(putFileRequest.ResponseOK(response.Item3)); } else { return(putFileRequest.ResponseServerError(string.Format("Unknown HTTPStatusCode from WopiFileRepository.UpdateFileContent: {0}", response.Item1))); } }
// POST api/<controller> public HttpResponseMessage Post([FromBody] AuthInfo info) { try { var clients = ClientIdentity.Select(id => id.ClientID == info.ClientID).ToList(); if (clients.Count == 0) { return(ServerUtil.returnStatus(HttpStatusCode.Unauthorized, "Authorization Failed")); } var client = clients[0]; if (WopiSecurity.MD5Encrypt(client.ClientSecret + ServerUtil.AuthenticationKey()) == info.SecureString) { var response = ServerUtil.returnStatus(HttpStatusCode.OK, "Success"); client.Token = WopiSecurity.MD5Encrypt(Guid.NewGuid().ToString()); client.Counter = 1; client.Save(); response.Content = new StringContent(client.Token); return(response); } else { return(ServerUtil.returnStatus(HttpStatusCode.Unauthorized, "Authorization Failed")); } } catch (Exception ex) { ServerUtil.LogException(ex); return(ServerUtil.returnStatus(HttpStatusCode.BadRequest, "Invalid Request")); } }
public override async Task <WopiResponse> PutRelativeFileSuggested(PutRelativeFileSuggestedRequest putRelativeFileSuggestedRequest) { WopiResponse wopiResponse = null; var file = DocumentDBRepository <DetailedFileModel> .GetItem("Files", i => i.id.ToString() == putRelativeFileSuggestedRequest.ResourceId); // Check for null file if (file != null) { var inputStream = await putRelativeFileSuggestedRequest.Content.ReadAsStreamAsync(); // Suggested mode...might just be an extension var fileName = putRelativeFileSuggestedRequest.SuggestedTarget; if (fileName.IndexOf('.') == 0) { fileName = file.BaseFileName.Substring(0, file.BaseFileName.LastIndexOf('.')) + fileName; } // Create the file entity FileModel newFile = new FileModel() { id = Guid.NewGuid(), OwnerId = file.OwnerId, BaseFileName = fileName, Size = inputStream.Length, Container = file.Container, Version = 1 }; // First stream the file into blob storage var bytes = new byte[inputStream.Length]; await inputStream.ReadAsync(bytes, 0, (int)inputStream.Length); var id = await Utils.AzureStorageUtil.UploadFile(newFile.id.ToString(), newFile.Container, bytes); // Write the details into documentDB await DocumentDBRepository <FileModel> .CreateItemAsync("Files", (FileModel)newFile); // Get access token for the new file WopiSecurity security = new WopiSecurity(); var token = security.GenerateToken(newFile.OwnerId, newFile.Container, newFile.id.ToString()); var tokenStr = security.WriteToken(token); // Prepare the Json response var name = newFile.BaseFileName; var url = string.Format("https://{0}/wopi/files/{1}?access_token={2}", putRelativeFileSuggestedRequest.RequestUri.Authority, newFile.id.ToString(), tokenStr); // Add the optional properties to response if applicable (HostViewUrl, HostEditUrl) string hostViewUrl = null; string hostEditUrl = null; var actions = await WopiDiscovery.GetActions(); var fileExt = newFile.BaseFileName.Substring(newFile.BaseFileName.LastIndexOf('.') + 1).ToLower(); var view = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "view"); if (view != null) { hostViewUrl = WopiDiscovery.GetActionUrl(view, newFile.id.ToString(), putRelativeFileSuggestedRequest.RequestUri.Authority); } var edit = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "edit"); if (edit != null) { hostEditUrl = WopiDiscovery.GetActionUrl(edit, newFile.id.ToString(), putRelativeFileSuggestedRequest.RequestUri.Authority); } // Write the response and return a success 200 wopiResponse = putRelativeFileSuggestedRequest.ResponseOK(fileName, new Uri(url), new Uri(hostViewUrl), new Uri(hostEditUrl)); } else { wopiResponse = putRelativeFileSuggestedRequest.ResponseNotFound(); } return(wopiResponse); }
/// <summary> /// Processes a WOPI request using the HttpContext of the APIController /// </summary> public async static Task <HttpResponseMessage> ProcessWopiRequest(this HttpContext context) { // Parse the request var request = ParseRequest(context.Request); HttpResponseMessage response = null; try { // Lookup the file in the database var itemId = new Guid(request.Id); var file = DocumentRepository <DetailedFileModel> .GetItem("Files", i => i.id == itemId); // Check for null file if (file == null) { response = returnStatus(HttpStatusCode.NotFound, "File Unknown/User Unauthorized"); } else { // Validate WOPI Proof (ie - ensure request came from Office Online) if (await WopiUtil.ValidateWopiProof(context)) { // Get discovery information var fileExt = file.BaseFileName.Substring(file.BaseFileName.LastIndexOf('.') + 1).ToLower(); var actions = await WopiUtil.GetDiscoveryInfo(); // Augments the file with additional properties CloseUrl, HostViewUrl, HostEditUrl file.CloseUrl = String.Format("https://{0}", context.Request.Url.Authority); var view = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "view"); if (view != null) { file.HostViewUrl = WopiUtil.GetActionUrl(view, file, context.Request.Url.Authority); } var edit = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "edit"); if (edit != null) { file.HostEditUrl = WopiUtil.GetActionUrl(edit, file, context.Request.Url.Authority); } // Get the user from the token (token is already validated) file.UserId = WopiSecurity.GetUserFromToken(request.AccessToken); // Call the appropriate handler for the WOPI request we received switch (request.RequestType) { case WopiRequestType.CheckFileInfo: response = context.CheckFileInfo(file); break; case WopiRequestType.GetFile: response = await context.GetFile(file); break; case WopiRequestType.Lock: response = await context.Lock(file); break; case WopiRequestType.GetLock: response = await context.GetLock(file); break; case WopiRequestType.RefreshLock: response = await context.RefreshLock(file); break; case WopiRequestType.Unlock: response = await context.Unlock(file); break; case WopiRequestType.UnlockAndRelock: response = await context.UnlockAndRelock(file); break; case WopiRequestType.PutFile: response = await context.PutFile(file); break; case WopiRequestType.PutRelativeFile: response = await context.PutRelativeFile(file, actions); break; case WopiRequestType.RenameFile: response = await context.RenameFile(file); break; case WopiRequestType.PutUserInfo: response = await context.PutUserInfo(file); break; default: response = returnStatus(HttpStatusCode.NotImplemented, "Unsupported"); break; } } else { // Proof validation failed...return 500 response = returnStatus(HttpStatusCode.InternalServerError, "Server Error"); } } } catch (Exception) { // An unknown exception occurred...return 500 response = returnStatus(HttpStatusCode.InternalServerError, "Server Error"); } return(response); }
/// <summary> /// Processes a PutRelativeFile request /// </summary> /// <remarks> /// For full documentation on PutRelativeFile, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/PutRelativeFile.html /// </remarks> private async static Task <HttpResponseMessage> PutRelativeFile(this HttpContext context, DetailedFileModel file, List <WopiAction> actions) { // Determine the specific mode if (context.Request.Headers[WopiRequestHeaders.RELATIVE_TARGET] != null && context.Request.Headers[WopiRequestHeaders.SUGGESTED_TARGET] != null) { // Theses headers are mutually exclusive, so we should return a 501 Not Implemented return(returnStatus(HttpStatusCode.NotImplemented, "Both RELATIVE_TARGET and SUGGESTED_TARGET were present")); } else if (context.Request.Headers[WopiRequestHeaders.RELATIVE_TARGET] != null || context.Request.Headers[WopiRequestHeaders.SUGGESTED_TARGET] != null) { string fileName = ""; if (context.Request.Headers[WopiRequestHeaders.RELATIVE_TARGET] != null) { // Specific mode...use the exact filename fileName = context.Request.Headers[WopiRequestHeaders.RELATIVE_TARGET]; } else { // Suggested mode...might just be an extension fileName = context.Request.Headers[WopiRequestHeaders.RELATIVE_TARGET]; if (fileName.IndexOf('.') == 0) { fileName = file.BaseFileName.Substring(0, file.BaseFileName.LastIndexOf('.')) + fileName; } } // Create the file entity DetailedFileModel newFile = new DetailedFileModel() { id = Guid.NewGuid(), OwnerId = file.OwnerId, BaseFileName = fileName, Size = context.Request.InputStream.Length, Container = file.Container, Version = 1 }; // First stream the file into blob storage var stream = context.Request.InputStream; var bytes = new byte[stream.Length]; await stream.ReadAsync(bytes, 0, (int)stream.Length); var id = await Utils.AzureStorageUtil.UploadFile(newFile.id.ToString(), newFile.Container, bytes); // Write the details into documentDB await DocumentRepository <FileModel> .CreateItemAsync("Files", (FileModel)newFile); // Get access token for the new file WopiSecurity security = new WopiSecurity(); var token = security.GenerateToken(newFile.OwnerId, newFile.Container, newFile.id.ToString()); var tokenStr = security.WriteToken(token); // Prepare the Json response string json = String.Format("{ 'Name': '{0}, 'Url': 'https://{1}/wopi/files/{2}?access_token={3}'", newFile.BaseFileName, context.Request.Url.Authority, newFile.id.ToString(), tokenStr); // Add the optional properties to response if applicable (HostViewUrl, HostEditUrl) var fileExt = newFile.BaseFileName.Substring(newFile.BaseFileName.LastIndexOf('.') + 1).ToLower(); var view = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "view"); if (view != null) { json += String.Format(", 'HostViewUrl': '{0}'", WopiUtil.GetActionUrl(view, newFile, context.Request.Url.Authority)); } var edit = actions.FirstOrDefault(i => i.ext == fileExt && i.name == "edit"); if (edit != null) { json += String.Format(", 'HostEditUrl': '{0}'", WopiUtil.GetActionUrl(edit, newFile, context.Request.Url.Authority)); } json += " }"; // Write the response and return a success 200 var response = returnStatus(HttpStatusCode.OK, "Success"); response.Content = new StringContent(json); return(response); } else { return(returnStatus(HttpStatusCode.BadRequest, "PutRelativeFile mode was not provided in the request")); } }
public override async Task <WopiResponse> CheckFileInfo(CheckFileInfoRequest checkFileInfoRequest) { var userId = WopiSecurity.GetIdentityNameFromToken(checkFileInfoRequest.AccessToken); // For this demo server, determine tenant by host part of email address var tenant = new MailAddress(userId).Host.Replace(".", "-"); // Lookup the file in the database using special repository method which grants access limited access to users in same tenant (same email domain) var wopiFileRepository = new WopiFileRepository(); var response = await wopiFileRepository.GetFileInfoByTenantUser(checkFileInfoRequest.ResourceId, userId, tenant); // Check for null file if (response.Item1 == HttpStatusCode.NotFound) { return(checkFileInfoRequest.ResponseNotFound()); } else if (response.Item1 == HttpStatusCode.OK) { var wopiFile = response.Item2; // Get discovery information var actions = await WopiDiscovery.GetActions(); string hostViewUrl = null, hostEditUrl = null; var closeUrl = String.Format("https://{0}", checkFileInfoRequest.RequestUri.Authority); var view = actions.FirstOrDefault(i => i.ext == wopiFile.FileExtension && i.name == "view"); if (view != null) { hostViewUrl = WopiDiscovery.GetActionUrl(view, wopiFile.FileId.ToString(), checkFileInfoRequest.RequestUri.Authority); } var edit = actions.FirstOrDefault(i => i.ext == wopiFile.FileExtension && i.name == "edit"); if (edit != null) { hostEditUrl = WopiDiscovery.GetActionUrl(edit, wopiFile.FileId.ToString(), checkFileInfoRequest.RequestUri.Authority); } // Write the response and return a success 200 var wopiResponse = checkFileInfoRequest.ResponseOK(wopiFile.FileName, wopiFile.OwnerId, wopiFile.Size, userId, wopiFile.Version.ToString()); // Add optional items wopiResponse.CloseUrl = new Uri(closeUrl); if (hostViewUrl != null) { wopiResponse.HostViewUrl = new Uri(hostViewUrl); } if (hostEditUrl != null) { wopiResponse.HostEditUrl = new Uri(hostEditUrl); } wopiResponse.UserInfo = wopiFile.FilePermissions.First().UserInfo; return(wopiResponse); } else { return(checkFileInfoRequest.ResponseServerError(string.Format("Unknown response from WopiFileRepository.GetFileInfoByTenantUser: {0}", response.Item1))); } }