/// <summary>
        /// Populates a file with action details from WOPI discovery based on the file extension
        /// </summary>
        public async static Task PopulateActions(this DetailedFileModel file)
        {
            // Get the discovery informations
            var actions = await WopiDiscovery.GetActions();

            var fileExt = file.BaseFileName.Substring(file.BaseFileName.LastIndexOf('.') + 1).ToLower();

            file.Actions = actions.Where(i => i.ext == fileExt).OrderBy(i => i.isDefault).ToList();
        }
Ejemplo n.º 2
0
        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" }));
            }
        }
        /// <summary>
        /// Populates a file with action details from WOPI discovery based on the file extension
        /// </summary>
        public async static Task PopulateActions(this WopiFileModel model)
        {
            // Get the discovery informations
            var actions = await WopiDiscovery.GetActions();

            var extension = model.FileExtension;

            if (extension.StartsWith("."))
            {
                extension = extension.Substring(1);
            }
            model.Actions = actions.Where(i => i.ext == extension).OrderBy(i => i.isDefault).ToList();
        }
Ejemplo n.º 4
0
        private async Task PopulateActions()
        {
            // Get the discovery informations
            var actions = await WopiDiscovery.GetActions();

            var extension = FileExtension;

            if (extension.StartsWith("."))
            {
                extension = extension.Substring(1);
            }
            Actions = actions.Where(i => i.ext == extension).OrderBy(i => i.isDefault).ToList();
        }
Ejemplo n.º 5
0
        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)));
            }
        }
Ejemplo n.º 6
0
        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());
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Validates the WOPI Proof on an incoming WOPI request
        /// </summary>
        public async static Task <bool> Validate(WopiRequest wopiRequest)
        {
            var hostUrl = wopiRequest.RequestUri.OriginalString.Replace(":44300", "").Replace(":443", "");

            // Make sure the request has the correct headers
            if (wopiRequest.Proof == null ||
                wopiRequest.Timestamp == null)
            {
                return(false);
            }

            // Set the requested proof values
            var requestProof    = wopiRequest.Proof;
            var requestProofOld = String.Empty;

            if (wopiRequest.ProofOld != null)
            {
                requestProofOld = wopiRequest.ProofOld;
            }

            // Get the WOPI proof info from discovery
            var discoProof = await WopiDiscovery.getWopiProof();

            // Encode the values into bytes
            var accessTokenBytes = Encoding.UTF8.GetBytes(wopiRequest.AccessToken);
            var hostUrlBytes     = Encoding.UTF8.GetBytes(hostUrl.ToUpperInvariant());
            var timeStampBytes   = BitConverter.GetBytes(Convert.ToInt64(wopiRequest.Timestamp)).Reverse().ToArray();

            // Build expected proof
            List <byte> expected = new List <byte>(
                4 + accessTokenBytes.Length +
                4 + hostUrlBytes.Length +
                4 + timeStampBytes.Length);

            // Add the values to the expected variable
            expected.AddRange(BitConverter.GetBytes(accessTokenBytes.Length).Reverse().ToArray());
            expected.AddRange(accessTokenBytes);
            expected.AddRange(BitConverter.GetBytes(hostUrlBytes.Length).Reverse().ToArray());
            expected.AddRange(hostUrlBytes);
            expected.AddRange(BitConverter.GetBytes(timeStampBytes.Length).Reverse().ToArray());
            expected.AddRange(timeStampBytes);
            byte[] expectedBytes = expected.ToArray();

            return(verifyProof(expectedBytes, requestProof, discoProof.value) ||
                   verifyProof(expectedBytes, requestProof, discoProof.oldvalue) ||
                   verifyProof(expectedBytes, requestProofOld, discoProof.value));
        }
Ejemplo n.º 8
0
        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)));
            }
        }
Ejemplo n.º 9
0
        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" }));
            }
        }
Ejemplo n.º 10
0
        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());
            }
        }
Ejemplo n.º 11
0
        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)));
            }
        }
Ejemplo n.º 12
0
        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);
        }