/// <summary>
        /// Loads address book folder by ID. Returns null if addressbook folder was not found.
        /// </summary>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <param name="addressbookFolderId">ID of the address book folder to load.</param>
        /// <returns><see cref="IAddressbookFolderAsync"/> instance.</returns>
        public static async Task <IAddressbookFolderAsync> LoadByIdAsync(DavContext context, Guid addressbookFolderId)
        {
            // Load only address book that the use has access to.
            // Also load complete ACL for this address book.
            string sql =
                @"SELECT * FROM [card_AddressbookFolder] 
                  WHERE [AddressbookFolderId] = @AddressbookFolderId
                  AND [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)

                ; SELECT * FROM [card_Access]
                  WHERE [AddressbookFolderId] = @AddressbookFolderId
                  AND [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)";

            return((await LoadAsync(context, sql,
                                    "@UserId", context.UserId
                                    , "@AddressbookFolderId", addressbookFolderId
                                    )).FirstOrDefault());
        }
        /// <summary>
        /// Loads calendar folder by ID. Returns null if calendar folder was not found.
        /// </summary>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <param name="calendarFolderId">ID of the calendar folder to load.</param>
        /// <returns><see cref="ICalendarFolderAsync"/> instance.</returns>
        public static async Task <ICalendarFolderAsync> LoadByIdAsync(DavContext context, Guid calendarFolderId)
        {
            // Load only calendar that the use has access to.
            // Also load complete ACL for this calendar.
            string sql =
                @"SELECT * FROM [cal_CalendarFolder] 
                  WHERE [CalendarFolderId] = @CalendarFolderId
                  AND [CalendarFolderId] IN (SELECT [CalendarFolderId] FROM [cal_Access] WHERE [UserId]=@UserId)

                ; SELECT * FROM [cal_Access]
                  WHERE [CalendarFolderId] = @CalendarFolderId
                  AND [CalendarFolderId] IN (SELECT [CalendarFolderId] FROM [cal_Access] WHERE [UserId]=@UserId)";

            return((await LoadAsync(context, sql,
                                    "@UserId", context.UserId
                                    , "@CalendarFolderId", calendarFolderId
                                    )).FirstOrDefault());
        }
        /// <summary>
        /// Returns calendar file that corresponds to path or null if no calendar file is found.
        /// </summary>
        /// <param name="context">Instance of <see cref="DavContext"/></param>
        /// <param name="path">Encoded path relative to WebDAV root.</param>
        /// <returns>CalendarFile instance or null if not found.</returns>
        public static CalendarFile GetCalendarFile(DavContext context, string path)
        {
            string pattern = string.Format(@"^/?{0}/(?<user_name>[^/]+)/(?<calendar_name>[^/]+)/(?<file_name>[^/]+\.ics)$",
                                           CalendarsRootFolder.CalendarsRootFolderPath.Trim(new char[] { '/' }).Replace("/", "/?"));

            if (!Regex.IsMatch(path, pattern))
            {
                return(null);
            }

            FileInfo file = new FileInfo(context.MapPath(path));

            if (!file.Exists)
            {
                return(null);
            }

            return(new CalendarFile(file, context, path));
        }
        /// <summary>
        /// Gets object representing ACL folder/user/group.
        /// </summary>
        /// <param name="path">Relative path requested.</param>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <returns>Object implemening LogicalFolder/IPrincipalFolder</returns>
        internal static async Task <IHierarchyItemAsync> GetAclItemAsync(DavContext context, string path)
        {
            //If this is /acl - return fake folder which contains users and groups.
            if (path == AclFolder.PREFIX)
            {
                return(new AclFolder(context));
            }

            //if this is /acl/users - return fake folder which contains users.
            if (path == UserFolder.PREFIX)
            {
                return(new UserFolder(context));
            }

            //if this is /acl/groups - return fake folder which contains groups.
            if (path == GroupFolder.PREFIX)
            {
                return(new GroupFolder(context));
            }

            //if this is /acl/users/<user name> - return instance of User.
            if (path.StartsWith(UserFolder.PATH))
            {
                string name = EncodeUtil.DecodeUrlPart(path.Substring(UserFolder.PATH.Length));
                //we don't need an exception here - so check for validity.
                if (PrincipalBase.IsValidUserName(name))
                {
                    return(User.FromName(name, context));
                }
            }

            //if this is /acl/groups/<group name> - return instance of Group.
            if (path.StartsWith(GroupFolder.PATH))
            {
                string name = EncodeUtil.DecodeUrlPart(path.Substring(GroupFolder.PATH.Length));
                if (PrincipalBase.IsValidUserName(name))
                {
                    return(Group.FromName(name, context));
                }
            }
            return(null);
        }
        public async Task <StatusCode> HandleAsync(DavContext context, ResourceResponse resource)
        {
            if (resource.Resource != null)
            {
                var headOnly = string.Equals(context.Request.Method, Methods.Head, StringComparison.OrdinalIgnoreCase);

                if (resource.Resource.ResourceType == ResourceType.Collection)
                {
                    if (context.Config.AllowDirectoryBrowsing)
                    {
                        await ShowDirectoryListingAsync(context, resource.Resource, headOnly);
                    }
                }
                else if (resource.Resource.ResourceType == ResourceType.Resource)
                {
                    await SendFileAsync(context, resource.Resource, headOnly);
                }
                return(StatusCode.OK);
            }
            return(StatusCode.NotFound);
        }
Exemple #6
0
        /// <summary>
        /// Returns calendar folder that corresponds to path.
        /// </summary>
        /// <param name="context">Instance of <see cref="DavContext"/></param>
        /// <param name="path">Encoded path relative to WebDAV root.</param>
        /// <returns>CalendarFolder instance or null if not found.</returns>
        public static CalendarFolder GetCalendarFolder(DavContext context, string path)
        {
            string pattern = string.Format("^/?{0}/(?<user_name>[^/]+)/(?<calendar_name>[^/]+)/?",
                                           CalendarsRootFolder.CalendarsRootFolderPath.Trim(new char[] { '/' }).Replace("/", "/?"));

            if (!Regex.IsMatch(path, pattern))
            {
                return(null);
            }

            string        folderPath = context.MapPath(path).TrimEnd(System.IO.Path.DirectorySeparatorChar);
            DirectoryInfo folder     = new DirectoryInfo(folderPath);

            // to block vulnerability when "%20" folder can be injected into path and folder.Exists returns 'true'
            if (!folder.Exists || String.Compare(folder.FullName.TrimEnd(System.IO.Path.DirectorySeparatorChar), folderPath, StringComparison.OrdinalIgnoreCase) != 0)
            {
                return(null);
            }

            return(new CalendarFolder(folder, context, path));
        }
Exemple #7
0
        /// <summary>
        /// Creates a new address book folder.
        /// </summary>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <param name="name">Address book name.</param>
        /// <param name="description">Address book description.</param>
        internal static async Task CreateAddressbookFolderAsync(DavContext context, string name, string description)
        {
            // 1. Create address book.
            // 2. Grant owner privileges to the user on the created address book(s).
            string sql = @"INSERT INTO [card_AddressbookFolder] (
                          [AddressbookFolderId]
                        , [Name]
                        , [Description]
                    ) VALUES (
                          @AddressbookFolderId
                        , @Name
                        , @Description
                    )
                    ; INSERT INTO [card_Access] (
                          [AddressbookFolderId]
                        , [UserId]
                        , [Owner]
                        , [Read]
                        , [Write]
                    ) VALUES (
                          @AddressbookFolderId
                        , @UserId
                        , @Owner
                        , @Read
                        , @Write
                    )";

            Guid addressbookFolderId = Guid.NewGuid();

            await context.ExecuteNonQueryAsync(sql,
                                               "@AddressbookFolderId", addressbookFolderId
                                               , "@Name", name
                                               , "@Description", description
                                               , "@UserId", context.UserId
                                               , "@Owner", true
                                               , "@Read", true
                                               , "@Write", true
                                               );
        }
        /// <summary>
        /// Creates a new calendar folder.
        /// </summary>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <param name="name">Calendar folder name.</param>
        public static async Task CreateCalendarFolderAsync(DavContext context, string name, string description)
        {
            // 1. Create calendar.
            // 2. Grant owner privileges to the user on the created calendar.
            string sql = @"INSERT INTO [cal_CalendarFolder] (
                          [CalendarFolderId]
                        , [Name]
                        , [Description]
                    ) VALUES (
                          @CalendarFolderId
                        , @Name
                        , @Description
                    )
                    ; INSERT INTO [cal_Access] (
                          [CalendarFolderId]
                        , [UserId]
                        , [Owner]
                        , [Read]
                        , [Write]
                    ) VALUES (
                          @CalendarFolderId
                        , @UserId
                        , @Owner
                        , @Read
                        , @Write
                    )";

            Guid calendarFolderId = Guid.NewGuid();

            await context.ExecuteNonQueryAsync(sql,
                                               "@CalendarFolderId", calendarFolderId
                                               , "@Name", name
                                               , "@Description", description
                                               , "@UserId", context.UserId
                                               , "@Owner", true
                                               , "@Read", true
                                               , "@Write", true
                                               );
        }
        static async Task SendFileAsync(DavContext context, IResource resource, bool headOnly)
        {
            if (resource.Length > 0)
            {
                context.Response.Headers.ContentLength = resource.Length;
            }
            context.Response.Headers.ContentType = resource.ContentType;
            context.Response.Headers.Append("Content-Disposition", "inline; filename=" + Uri.EscapeUriString(resource.DisplayName));

            if (!headOnly)
            {
                using (Stream fs = context.Config.DataStore.Read(resource))
                {
                    byte[] buff = new byte[4096];
                    int    read = 0;

                    while ((read = await fs.ReadAsync(buff, 0, buff.Length)) > 0)
                    {
                        await context.Response.Body.WriteAsync(buff, 0, read, context.CancellationToken);
                    }
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// Gets CalDAV items.
        /// </summary>
        /// <param name="path">Relative path requested.</param>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <returns>Object implementing various CalDAV items or null if no object corresponding to path is found.</returns>
        internal static IHierarchyItemAsync GetCalDavItem(DavContext context, string path)
        {
            IHierarchyItemAsync item = null;

            item = CalendarsRootFolder.GetCalendarsRootFolder(context, path);
            if (item != null)
            {
                return(item);
            }

            item = CalendarFolder.GetCalendarFolder(context, path);
            if (item != null)
            {
                return(item);
            }

            item = CalendarFile.GetCalendarFile(context, path);
            if (item != null)
            {
                return(item);
            }

            return(null);
        }
        /// <summary>
        /// Gets object representing ACL folder, user or group.
        /// </summary>
        /// <param name="path">Relative path requested.</param>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <returns>Object implemening ACL principal or folder</returns>
        internal static async Task <IHierarchyItemAsync> GetAclItemAsync(DavContext context, string path)
        {
            // If this is [DAVLocation]/acl - return folder which contains users and groups.
            if (path.Equals(AclFolder.AclFolderPath.Trim('/'), System.StringComparison.InvariantCultureIgnoreCase))
            {
                return(new AclFolder(context));
            }

            // If this is [DAVLocation]/acl/users - return folder which contains users.
            if (path.Equals(UsersFolder.UsersFolderPath.Trim('/'), System.StringComparison.InvariantCultureIgnoreCase))
            {
                return(new UsersFolder(context));
            }

            // If this is [DAVLocation]/acl/users/[UserID] - return instance of User.
            if (path.StartsWith(UsersFolder.UsersFolderPath.Trim('/'), System.StringComparison.InvariantCultureIgnoreCase))
            {
                string[] segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                string   userId   = EncodeUtil.DecodeUrlPart(segments.Last());
                return(await User.GetUserAsync(context, userId));
            }

            return(null);
        }
        /// <summary>
        /// Gets CardDAV items.
        /// </summary>
        /// <param name="path">Relative path requested.</param>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <returns>Object implementing various CardDAV items or null if no object corresponding to path is found.</returns>
        internal static IHierarchyItemAsync GetCardDavItem(DavContext context, string path)
        {
            IHierarchyItemAsync item = null;

            item = AddressbooksRootFolder.GetAddressbooksRootFolder(context, path);
            if (item != null)
            {
                return(item);
            }

            item = AddressbookFolder.GetAddressbookFolder(context, path);
            if (item != null)
            {
                return(item);
            }

            item = CardFile.GetCardFile(context, path);
            if (item != null)
            {
                return(item);
            }

            return(null);
        }
Exemple #13
0
        public static async Task <User> GetUserAsync(DavContext context, string userId)
        {
            DavUser user = context.Users.FirstOrDefault(p => p.UserName.Equals(userId, StringComparison.InvariantCultureIgnoreCase));

            return(new User(context, userId, user.UserName, user.Email, new DateTime(2000, 1, 1), new DateTime(2000, 1, 1)));
        }
Exemple #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CalendarFolder"/> class.
 /// </summary>
 /// <param name="directoryInfo">Instance of <see cref="DirectoryInfo"/> class with information about the folder in file system.</param>
 /// <param name="context">Instance of <see cref="DavContext"/>.</param>
 /// <param name="path">Relative to WebDAV root folder path.</param>
 private CalendarFolder(DirectoryInfo directoryInfo, DavContext context, string path)
     : base(directoryInfo, context, path)
 {
 }
 public FolderResource(DavContext context, string logicalPath, string physicalPath) : base(context, logicalPath)
 {
     _info = new DirectoryInfo(physicalPath);
 }
Exemple #16
0
 /// <summary>
 /// Initializes a new instance of the AclFolder class.
 /// </summary>
 /// <param name="context">Instace of <see cref="DavContext"/>.</param>
 public AclFolder(DavContext context) : base(context, "acl", PATH)
 {
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="CalendarFile"/> class.
 /// </summary>
 /// <param name="file"><see cref="FileInfo"/> for corresponding object in file system.</param>
 /// <param name="context">Instance of <see cref="DavContext"/></param>
 /// <param name="path">Encoded path relative to WebDAV root.</param>
 private CalendarFile(FileInfo file, DavContext context, string path)
     : base(file, context, path)
 {
 }
Exemple #18
0
 /// <summary>
 /// Initializes a new instance of the AclFolder class.
 /// </summary>
 /// <param name="context">Instance of <see cref="DavContext"/></param>
 /// <param name="name">Folder name.</param>
 /// <param name="path">Encoded path relative to WebDAV root.</param>
 public AclFolder(DavContext context) : base(context, AclFolderPath)
 {
 }
Exemple #19
0
 /// <summary>
 /// Creates instance of User class.
 /// </summary>
 /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
 /// <param name="userId">ID of this user</param>
 /// <remarks>
 /// This consturctor is called when user URL is required, typically when discovering user calendars,
 /// no need to populate all properties, only user ID is required.
 /// </remarks>
 public User(DavContext context, string userId)
     : this(context, userId, null, null, new DateTime(2000, 1, 1), new DateTime(2000, 1, 1))
 {
 }
Exemple #20
0
 public FakeFileResource(DavContext context, string logicalPath) : base(context, logicalPath)
 {
 }
Exemple #21
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GroupFolder"/> class.
 /// </summary>
 /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
 public GroupFolder(DavContext context) : base(context, "groups", PATH)
 {
 }
Exemple #22
0
 private AddressbooksRootFolder(DirectoryInfo directory, DavContext context, string path)
     : base(directory, context, path)
 {
 }
Exemple #23
0
 /// <summary>
 /// Initializes a new instance of the Group class.
 /// </summary>
 /// <param name="groupPrincipal">Corresponding .net GroupPrincipal object.</param>
 /// <param name="context">Instance of <see cref="DavContext"/>.</param>
 public Group(GroupPrincipal groupPrincipal, DavContext context) :
     base(groupPrincipal, GroupFolder.PATH, context)
 {
     this.groupPrincipal = groupPrincipal;
 }
Exemple #24
0
        /// <summary>
        /// Loads all address books.
        /// </summary>
        /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
        /// <returns>List of <see cref="IAddressbookFolderAsync"/> items.</returns>
        public static async Task <IEnumerable <IAddressbookFolderAsync> > LoadAllAsync(DavContext context)
        {
            // Load only address books that the use has access to.
            // Also load complete ACL for each address book, but only if user has access to that address book.
            string sql =
                @"SELECT * FROM [card_AddressbookFolder] 
                  WHERE [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)

                ; SELECT * FROM [card_Access] 
                  WHERE [AddressbookFolderId] IN (SELECT [AddressbookFolderId] FROM [card_Access] WHERE [UserId]=@UserId)";

            return(await LoadAsync(context, sql, "@UserId", context.UserId));
        }
Exemple #25
0
 /// <summary>
 /// Initializes a new instance of the <see cref="UsersFolder"/> class.
 /// </summary>
 /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
 public UsersFolder(DavContext context) : base(context, UsersFolderPath)
 {
 }
Exemple #26
0
 /// <summary>
 /// Initializes a new instance of the PrincipalBase class.
 /// </summary>
 /// <param name="principal">Instance of <see cref="Principal"/>.</param>
 /// <param name="parentPath">Encoded path to parent folder.</param>
 /// <param name="context">Instance of <see cref="DavContext"/>.</param>
 protected PrincipalBase(Principal principal, string parentPath, DavContext context) : base(context)
 {
     this.Principal  = principal;
     this.parentPath = parentPath;
     this.Context    = context;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="UserFolder"/> class.
 /// </summary>
 /// <param name="context">Instance of <see cref="DavContext"/> class.</param>
 public UserFolder(DavContext context) : base(context, "users", PATH)
 {
 }
        public async Task <StatusCode> HandleAsync(DavContext context, ResourceResponse resource)
        {
            int maxDepth = context.Depth;

            context.Config.Log.LogDebug("Depth={0}", maxDepth);
            if (maxDepth == int.MaxValue && !context.Config.AllowInfiniteDepth)
            {
                // TODO: correct?
                return(StatusCode.BadRequest);
            }

            if (resource.Resource == null)
            {
                return(StatusCode.NotFound);
            }

            bool nameOnly = false;
            var  filter   = new List <PropertyFilter>();

            var reqXml = context.ReadRequestAsXml();

            if (reqXml != null)
            {
                context.Config.Log.LogDebug("Request:{0}{1}", Environment.NewLine, reqXml.OuterXml.PrettyXml());

                if (reqXml.DocumentElement.Name == ElementNames.PropFind &&
                    reqXml.DocumentElement.NamespaceURI == XmlNamespace)
                {
                    foreach (XmlNode node in reqXml.DocumentElement.ChildNodes)
                    {
                        if (node.NamespaceURI == XmlNamespace)
                        {
                            switch (node.Name)
                            {
                            case ElementNames.PropName:
                                nameOnly = true;
                                break;

                            case ElementNames.Prop:
                                foreach (XmlNode propNode in node.ChildNodes)
                                {
                                    filter.Add(new PropertyFilter {
                                        Name = propNode.Name, XmlNamespace = propNode.NamespaceURI
                                    });
                                }
                                break;
                            }
                        }
                    }
                }
                else
                {
                    return(StatusCode.BadRequest);
                }
            }


            var list = new List <ResourceResponse>();

            WalkResourceTree(context, maxDepth, 0, list, resource);

            return(await WriteMultiStatusReponse(context, list, nameOnly, filter));
        }
Exemple #29
0
 public AddressbooksRootFolder(DavContext context)
     : base(context, AddressbooksRootFolderPath)
 {
 }
 public CalendarsRootFolder(DavContext context)
     : base(context, CalendarsRootFolderPath)
 {
 }