using System; using System.Data; using System.Configuration; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using ScrewTurn.Wiki.PluginFramework; namespace ScrewTurn.Wiki { public partial class FileManager : System.Web.UI.UserControl { private IFilesStorageProviderV30 provider = null; bool canList = false; bool canDownload = false; bool canUpload = false; bool canCreateDirs = false; bool canDeleteFiles = false; bool canDeleteDirs = false; bool canSetPerms = false; bool isAdmin = false; protected void Page_Load(object sender, EventArgs e) { if(!Page.IsPostBack) { permissionsManager.CurrentResourceName = "/"; // Localized strings for JavaScript StringBuilder sb = new StringBuilder(); sb.Append(@"\n"); lblStrings.Text = sb.ToString(); // Setup upload information (max file size, allowed file types) lblUploadFilesInfo.Text = lblUploadFilesInfo.Text.Replace("$1", Tools.BytesToString(Settings.MaxFileSize * 1024)); sb = new StringBuilder(); string[] aft = Settings.AllowedFileTypes; for(int i = 0; i < aft.Length; i++) { sb.Append(aft[i].ToUpper()); if(i != aft.Length - 1) sb.Append(", "); } lblUploadFilesInfo.Text = lblUploadFilesInfo.Text.Replace("$2", sb.ToString()); LoadProviders(); permissionsManager.CurrentFilesProvider = lstProviders.SelectedValue; // See if a dir is specified in query string if(Request["Dir"] != null) { string currDir = Request["Dir"]; if(!currDir.StartsWith("/")) currDir = "/" + currDir; if(!currDir.EndsWith("/")) currDir += "/"; CurrentDirectory = currDir; } } // Set provider provider = Collectors.FilesProviderCollector.GetProvider(lstProviders.SelectedValue); // The following actions are verified ***FOR THE CURRENT DIRECTORY***: // - List contents // - Download files // - Upload files // - Create directories // - Delete/Rename files -> hide/show buttons in repeater // - Delete/Rename directories --> hide/show buttons in repeater // - Manage Permissions -> avoid setting permissionsManager.CurrentResourceName/CurrentFilesProvider if not authorized // - Member of Administrators -> hide/show provider selection // ---> recheck everywhere an action is performed DetectPermissions(); if(!Page.IsPostBack) { rptItems.DataBind(); } PopulateBreadcrumb(); SetupControlsForPermissions(); } /// /// Loads the providers. /// private void LoadProviders() { lstProviders.Items.Clear(); foreach(IFilesStorageProviderV30 prov in Collectors.FilesProviderCollector.AllProviders) { ListItem item = new ListItem(prov.Information.Name, prov.GetType().FullName); if(item.Value == Settings.DefaultFilesProvider) { item.Selected = true; } lstProviders.Items.Add(item); } } /// /// Detects the permissions of the current user for the current directory. /// private void DetectPermissions() { string currentUser = SessionFacade.GetCurrentUsername(); string[] currentGroups = SessionFacade.GetCurrentGroupNames(); canList = AuthChecker.CheckActionForDirectory(provider, CurrentDirectory, Actions.ForDirectories.List, currentUser, currentGroups); canDownload = AuthChecker.CheckActionForDirectory(provider, CurrentDirectory, Actions.ForDirectories.DownloadFiles, currentUser, currentGroups); canUpload = AuthChecker.CheckActionForDirectory(provider, CurrentDirectory, Actions.ForDirectories.UploadFiles, currentUser, currentGroups); canCreateDirs = AuthChecker.CheckActionForDirectory(provider, CurrentDirectory, Actions.ForDirectories.CreateDirectories, currentUser, currentGroups); canDeleteFiles = AuthChecker.CheckActionForDirectory(provider, CurrentDirectory, Actions.ForDirectories.DeleteFiles, currentUser, currentGroups); canDeleteDirs = AuthChecker.CheckActionForDirectory(provider, CurrentDirectory, Actions.ForDirectories.DeleteDirectories, currentUser, currentGroups); canSetPerms = AuthChecker.CheckActionForGlobals(Actions.ForGlobals.ManagePermissions, currentUser, currentGroups); isAdmin = Array.Find(currentGroups, delegate(string g) { return g == Settings.AdministratorsGroup; }) != null; } /// /// Returns to the root. /// public void GoToRoot() { CurrentDirectory = "/"; DetectPermissions(); rptItems.DataBind(); PopulateBreadcrumb(); } protected void rptItems_DataBinding(object sender, EventArgs e) { permissionsManager.CurrentResourceName = CurrentDirectory; permissionsManager.CurrentFilesProvider = lstProviders.SelectedValue; // Build a DataTable containing the proper information DataTable table = new DataTable("Items"); table.Columns.Add("Type"); table.Columns.Add("Name"); table.Columns.Add("Size"); table.Columns.Add("WikiMarkupLink"); table.Columns.Add("Link"); table.Columns.Add("Editable", typeof(bool)); table.Columns.Add("FullPath"); table.Columns.Add("Downloads"); table.Columns.Add("CanDelete", typeof(bool)); table.Columns.Add("CanDownload", typeof(bool)); if(!canList) { lblNoList.Visible = true; rptItems.DataSource = table; // This is empty return; } lblNoList.Visible = false; string currDir = CurrentDirectory; string[] dirs = provider.ListDirectories(currDir); string currentUser = SessionFacade.GetCurrentUsername(); string[] currentGroups = SessionFacade.GetCurrentGroupNames(); foreach(string s in dirs) { bool canListThisSubDir = AuthChecker.CheckActionForDirectory(provider, s, Actions.ForDirectories.List, currentUser, currentGroups); DataRow row = table.NewRow(); row["Type"] = "D"; row["Name"] = GetItemName(s)/* + "/"*/; row["Size"] = "(" + ((int)(provider.ListFiles(s).Length + provider.ListDirectories(s).Length)).ToString() + ")"; row["WikiMarkupLink"] = " "; row["Link"] = ""; row["Editable"] = false; row["FullPath"] = s; row["Downloads"] = " "; row["CanDelete"] = canDeleteDirs; row["CanDownload"] = canListThisSubDir; table.Rows.Add(row); } string[] files = provider.ListFiles(currDir); foreach(string s in files) { FileDetails details = provider.GetFileDetails(s); DataRow row = table.NewRow(); string ext = Path.GetExtension(s).ToLowerInvariant(); row["Type"] = "F"; row["Name"] = GetItemName(s); row["Size"] = Tools.BytesToString(details.Size); row["WikiMarkupLink"] = "{UP}" + Tools.UrlEncode(s); if(canDownload) { row["Link"] = "GetFile.aspx?File=" + Tools.UrlEncode(s).Replace("'", "'") + "&AsStreamAttachment=1&Provider=" + provider.GetType().FullName + "&NoHit=1"; } else { row["Link"] = ""; } row["Editable"] = canUpload && canDeleteFiles && (ext == ".jpg" || ext == ".jpeg" || ext == ".png"); row["FullPath"] = s; row["Downloads"] = details.RetrievalCount.ToString(); row["CanDelete"] = canDeleteFiles; row["CanDownload"] = canDownload; table.Rows.Add(row); } rptItems.DataSource = table; } /// /// Deletes the permissions of a directory. /// /// The directory. private void DeletePermissions(string directory) { if(!directory.StartsWith("/")) directory = "/" + directory; if(!directory.EndsWith("/")) directory = directory + "/"; foreach(string sub in provider.ListDirectories(directory)) { DeletePermissions(sub); } AuthWriter.ClearEntriesForDirectory(provider, directory); } protected void rptItems_ItemCommand(object sender, RepeaterCommandEventArgs e) { string item = (string)e.CommandArgument; switch(e.CommandName) { case "Dir": EnterDirectory(GetItemName(item)); break; case "Rename": // Hide all directory-specific controls // Permissions are verified in btnRename_Click pnlRename.Visible = true; pnlNewDirectory.Visible = false; pnlUpload.Visible = false; pnlPermissions.Visible = false; lstProviders.Visible = false; lblItem.Text = GetItemName(item) + (item.EndsWith("/") ? "/" : ""); txtNewName.Text = GetItemName(item); rptItems.Visible = false; break; case "Delete": if(item.EndsWith("/")) { if(canDeleteDirs) { // Delete Directory DeletePermissions(item); bool d = provider.DeleteDirectory(item); if(d) { Host.Instance.OnDirectoryActivity(provider.GetType().FullName, item, null, FileActivity.DirectoryDeleted); } } } else { if(canDeleteFiles) { // Delete File bool d = provider.DeleteFile(item); if(d) { Host.Instance.OnFileActivity(provider.GetType().FullName, item, null, FileActivity.FileDeleted); } } } rptItems.DataBind(); break; } } /// /// Tries to enter a directory. /// /// The provider. /// The full path of the directory. public void TryEnterDirectory(string provider, string directory) { if(string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(provider)) return; if(!directory.StartsWith("/")) directory = "/" + directory; if(!directory.EndsWith("/")) directory += "/"; LoadProviders(); IFilesStorageProviderV30 realProvider = Collectors.FilesProviderCollector.GetProvider(provider); if(realProvider == null) return; this.provider = realProvider; // Detect existence try { realProvider.ListDirectories(directory); } catch(ArgumentException) { return; } bool canListThisSubDir = AuthChecker.CheckActionForDirectory(realProvider, directory, Actions.ForDirectories.List, SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames()); if(!canListThisSubDir) { return; } lstProviders.SelectedIndex = -1; foreach(ListItem item in lstProviders.Items) { if(item.Value == provider) { item.Selected = true; break; } } //lstProviders_SelectedIndexChanged(this, null); string parent = "/"; string trimmedDirectory = directory.TrimEnd('/'); if(trimmedDirectory.Length > 0) { int lastSlash = trimmedDirectory.LastIndexOf("/"); if(lastSlash != -1) { parent = "/" + trimmedDirectory.Substring(0, lastSlash) + "/"; } } if(parent != directory) { CurrentDirectory = parent; EnterDirectory(Tools.ExtractDirectoryName(directory)); } } /// /// Enters a sub-directory of the current directory. /// /// The name of the current directory. private void EnterDirectory(string name) { string newDirectory = CurrentDirectory + name + "/"; bool canListThisSubDir = AuthChecker.CheckActionForDirectory(provider, newDirectory, Actions.ForDirectories.List, SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames()); if(!canListThisSubDir) { return; } CurrentDirectory += name + "/"; DetectPermissions(); rptItems.DataBind(); PopulateBreadcrumb(); } /// /// Gets the name of an item. /// /// The full path of the item (file or directory). /// The name of the item. private string GetItemName(string path) { path = path.Trim('/'); if(path.Contains("/")) { path = path.Substring(path.LastIndexOf("/") + 1); } return path; } /// /// Gets or sets the current directory. /// private string CurrentDirectory { get { if(ViewState["CurrDir"] != null) return (string)ViewState["CurrDir"]; else return "/"; } set { ViewState["CurrDir"] = value; } } protected void lnkRoot_Click(object sender, EventArgs e) { GoToRoot(); } private void linkButton_Click(object sender, EventArgs e) { Anthem.LinkButton lnk = sender as Anthem.LinkButton; if(lnk != null) { CurrentDirectory = lnk.CommandArgument; DetectPermissions(); rptItems.DataBind(); PopulateBreadcrumb(); } } /// /// Populates the directory breadcrumb placeholder. See also methods linkButton_Click e lnkRoot_Click. /// private void PopulateBreadcrumb() { plhDirectory.Controls.Clear(); // Get all directories by splitting the content of txtCurrentDirectory string[] dirs = CurrentDirectory.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); // Add a LinkButton and a "/" label for each directory string current = "/"; for(int i = 0; i < dirs.Length; i++) { Anthem.LinkButton lnk = new Anthem.LinkButton(); lnk.ID = "lnkDir" + i.ToString(); lnk.Text = dirs[i]; current += dirs[i] + "/"; lnk.CommandArgument = current; lnk.ToolTip = current; lnk.Click += new EventHandler(linkButton_Click); plhDirectory.Controls.Add(lnk); Anthem.Label lbl = new Anthem.Label(); lbl.ID = "lblDir" + i.ToString(); lbl.Text = " / "; plhDirectory.Controls.Add(lbl); } } /// /// Sets the controls depending on the current permissions. /// private void SetupControlsForPermissions() { // Setup buttons and controls visibility chkOverwrite.Enabled = canDeleteFiles; lstProviders.Visible = isAdmin; pnlUpload.Visible = canUpload; pnlNewDirectory.Visible = canCreateDirs; pnlPermissions.Visible = canSetPerms; permissionsManager.Visible = canSetPerms; if(!canSetPerms) { permissionsManager.CurrentResourceName = ""; permissionsManager.CurrentFilesProvider = ""; } } /// /// Recursively moves permissions from the old (renamed) directory to the new one. /// /// The old directory name. /// The new directory name. private void MovePermissions(string oldDirectory, string newDirectory) { if(!oldDirectory.StartsWith("/")) oldDirectory = "/" + oldDirectory; if(!oldDirectory.EndsWith("/")) oldDirectory = oldDirectory + "/"; if(!newDirectory.StartsWith("/")) newDirectory = "/" + newDirectory; if(!newDirectory.EndsWith("/")) newDirectory = newDirectory + "/"; foreach(string sub in provider.ListDirectories(oldDirectory)) { string subNew = newDirectory + sub.Substring(oldDirectory.Length); MovePermissions(sub, subNew); } AuthWriter.ClearEntriesForDirectory(provider, newDirectory); AuthWriter.ProcessDirectoryRenaming(provider, oldDirectory, newDirectory); } protected void btnRename_Click(object sender, EventArgs e) { lblRenameResult.Text = ""; bool done = false; if(lblItem.Text.EndsWith("/")) { if(canDeleteDirs) { MovePermissions(CurrentDirectory + lblItem.Text, CurrentDirectory + txtNewName.Text); done = provider.RenameDirectory(CurrentDirectory + lblItem.Text, CurrentDirectory + txtNewName.Text); if(done) { Host.Instance.OnDirectoryActivity(provider.GetType().FullName, CurrentDirectory + txtNewName.Text, CurrentDirectory + lblItem.Text, FileActivity.DirectoryRenamed); } } } else { if(canDeleteFiles) { // Ensure that the extension is not changed (security) string previousExtension = Path.GetExtension(lblItem.Text); string newExtension = Path.GetExtension(txtNewName.Text); if(string.IsNullOrEmpty(newExtension)) { newExtension = previousExtension; txtNewName.Text += previousExtension; } if(newExtension.ToLowerInvariant() != previousExtension.ToLowerInvariant()) { txtNewName.Text += previousExtension; } done = true; if(txtNewName.Text.ToLowerInvariant() != lblItem.Text.ToLowerInvariant()) { done = provider.RenameFile(CurrentDirectory + lblItem.Text, CurrentDirectory + txtNewName.Text); if(done) { Host.Instance.OnFileActivity(provider.GetType().FullName, CurrentDirectory + txtNewName.Text, CurrentDirectory + lblItem.Text, FileActivity.FileRenamed); } } } } if(done) { pnlRename.Visible = false; rptItems.Visible = true; rptItems.DataBind(); SetupControlsForPermissions(); } else { lblRenameResult.Text = Properties.Messages.CannotRenameItem; lblRenameResult.CssClass = "resulterror"; } } protected void btnCancel_Click(object sender, EventArgs e) { pnlRename.Visible = false; rptItems.Visible = true; SetupControlsForPermissions(); lblRenameResult.Text = ""; } protected void btnNewDirectory_Click(object sender, EventArgs e) { if(canCreateDirs) { lblNewDirectoryResult.Text = ""; txtNewDirectoryName.Text = txtNewDirectoryName.Text.Trim('/'); AuthWriter.ClearEntriesForDirectory(provider, CurrentDirectory + txtNewDirectoryName.Text + "/"); bool done = provider.CreateDirectory(CurrentDirectory, txtNewDirectoryName.Text); if(!done) { lblNewDirectoryResult.CssClass = "resulterror"; lblNewDirectoryResult.Text = Properties.Messages.CannotCreateNewDirectory; } else { txtNewDirectoryName.Text = ""; Host.Instance.OnDirectoryActivity(provider.GetType().FullName, CurrentDirectory + txtNewDirectoryName.Text + "/", null, FileActivity.DirectoryCreated); } rptItems.DataBind(); } } protected void btnUpload_Click(object sender, EventArgs e) { if(canUpload && (chkOverwrite.Checked && canDeleteFiles || !chkOverwrite.Checked)) { lblUploadResult.Text = ""; if(fileUpload.HasFile) { if(fileUpload.FileBytes.Length > Settings.MaxFileSize * 1024) { lblUploadResult.Text = Properties.Messages.FileTooBig; lblUploadResult.CssClass = "resulterror"; } else { // Check file extension string[] aft = Settings.AllowedFileTypes; bool allowed = false; if(aft.Length > 0 && aft[0] == "*") allowed = true; else { string ext = Path.GetExtension(fileUpload.FileName); if(ext == null) ext = ""; if(ext.StartsWith(".")) ext = ext.Substring(1).ToLowerInvariant(); foreach(string ft in aft) { if(ft == ext) { allowed = true; break; } } } if(!allowed) { lblUploadResult.Text = Properties.Messages.InvalidFileType; lblUploadResult.CssClass = "resulterror"; } else { // Store file bool done = provider.StoreFile(CurrentDirectory + fileUpload.FileName, fileUpload.FileContent, chkOverwrite.Checked); if(!done) { lblUploadResult.Text = Properties.Messages.CannotStoreFile; lblUploadResult.CssClass = "resulterror"; } else { Host.Instance.OnFileActivity(provider.GetType().FullName, CurrentDirectory + fileUpload.FileName, null, FileActivity.FileUploaded); } rptItems.DataBind(); } } } else { lblUploadResult.Text = Properties.Messages.FileVoid; lblUploadResult.CssClass = "resulterror"; } } } protected void lstProviders_SelectedIndexChanged(object sender, EventArgs e) { provider = Collectors.FilesProviderCollector.GetProvider(lstProviders.SelectedValue); GoToRoot(); } } }