Exemplo n.º 1
0
        public static void Main(string[] args)
        {
            List <RegisterDelegate> endPoints = new List <RegisterDelegate>();
            CaveDb db = new CaveDb("mongodb://192.168.5.10");



            Func <HttpContext, Action <UserSession>, Task> handleSession;
            Func <bool> isCommandLine = () => false;

            UserVerb.Start(db, isCommandLine, endPoints, out handleSession);
            CaveVerb.Start(db, isCommandLine, endPoints, handleSession);

            AspNetVerb.Start(endPoints.ToArray());
        }
Exemplo n.º 2
0
        public static void Start(CaveDb db, Func <bool> isCommandLine, List <RegisterDelegate> endPoints, Func <HttpContext, Action <UserSession>, Task> handleSession)
        {
            endPoints.Get("/cave", async(ctx) =>
            {
                await handleSession(ctx, async session =>
                {
                    var dbCaves = db.Caves.Find("{}").ToList();
                    var caves   = dbCaves
                                  .Select(c => new
                    {
                        c.Id,
                        Number = c.CaveNumber,
                        c.Name,
                        c.Description,
                        c.SubType,
                        CaveData  = c.Data ?? new List <Data>(),
                        Locations = c.Locations ?? new List <CaveLocation>(),
                        Notes     = c.Notes ?? new List <CaveNote>()
                    })
                                  .ToArray();

                    var response = new { Caves = caves, Status = 200 };

                    ctx.WriteHeader(Mimes.Json, System.Net.HttpStatusCode.OK);

                    await ctx.WriteBodyObject(response);
                });
            });

            endPoints.Put("/cave", async(ctx) =>
            {
                // upsert a cave
                await handleSession(ctx, async session =>
                {
                    var request = await ctx.ReadBody <CaveUpdateRequest>();

                    Cave cave = null;
                    if (!string.IsNullOrEmpty(request.CaveId))
                    {
                        cave = db.Caves.Find(c => c.Id == request.CaveId).SingleOrDefault();
                    }

                    if (null == cave)
                    {
                        int caveNumber = db.GetNextCaveNumber();
                        cave           = new Cave()
                        {
                            Id          = Guid.NewGuid().ToString(),
                            Name        = $"CC #{caveNumber}",
                            Description = string.Empty,
                            CreatedDate = DateTime.Now,
                            CaveNumber  = caveNumber
                        };

                        db.Caves.InsertOne(cave);
                        db.Users.UpdateOne(u => u.Id == session.UserId, Builders <User> .Update.AddToSet(u => u.Caves, cave.Id));
                        db.History.InsertOne(UserVerb.HistoryEntry(session.UserId, cave.Id, null, null, $"Created new cave {cave.Name}:{cave.Id}"));
                    }


                    cave.Name        = request.Name;
                    cave.SubType     = request.SubType;
                    cave.Description = request.Description ?? string.Empty;
                    cave.IsDeleted   = false;

                    if (request.Data != null)
                    {
                        cave.Data = request.Data.ToList();
                    }

                    if (request.Locations != null)
                    {
                        cave.Locations = request.Locations.ToList();
                        if (cave.Locations.Count > 0 && cave.Locations.All(c => c.IsActive == false))
                        {
                            cave.Locations[0].IsActive = true;
                        }
                    }

                    if (request.Notes != null)
                    {
                        cave.Notes = request.Notes.ToList();
                    }

                    db.History.InsertOne(UserVerb.HistoryEntry(session.UserId, cave.Id, null, null, $"Cave {cave.Id} updated by {session.User.Name}"));
                    db.Caves.ReplaceOne(Builders <Cave> .Filter.Eq(c => c.Id, cave.Id), cave);

                    // get list of all associated media
                    var deadMedia    = new HashSet <string>();
                    var deadMediaInt = new HashSet <int>();
                    foreach (var caveMedia in db.Media.AsQueryable().Where(m => m.AttachId == cave.Id && m.AttachType == "cave"))
                    {
                        bool notFound = true;
                        var reference = $"src=\"/Media/{caveMedia.Id}\"";
                        // check to see if it's contained in one of the notes
                        foreach (var n in request.Notes)
                        {
                            if (n.Note.Contains(reference))
                            {
                                notFound = false;
                                break;
                            }
                        }

                        if (notFound)
                        {
                            if (caveMedia.OldId.HasValue)
                            {
                                deadMediaInt.Add(caveMedia.OldId.Value);
                            }
                            else
                            {
                                deadMedia.Add(caveMedia.Id);
                            }
                        }
                    }

                    if (deadMedia.Count > 0)
                    {
                        // remove the database entries
                        db.Media.DeleteMany(m => deadMedia.Contains(m.Id));
                    }

                    var response = new { Status = HttpStatusCode.OK };
                    ctx.WriteHeader(Mimes.Json, HttpStatusCode.OK);
                    await ctx.WriteBodyObject(response);
                });
            });
        }
Exemplo n.º 3
0
        public static LoginResponse Login(CaveDb db, Func <bool> isCommandLine, Func <int, byte[]> getRandomBytes, LoginRequest request)
        {
            // find user
            var user = db.Users.Find(u => u.Email == request.Email).FirstOrDefault();

            if (null == user)
            {
                HistoryEntry(null, null, null, null, "Failed login for bad user {0}", request.Email);
                return(new LoginResponse()
                {
                    Status = (int)HttpStatusCode.Unauthorized, StatusDescription = "Username or Password is incorrect"
                });
            }

            // only allow the admin password via the command line
            if (user.Email == "admin" && !isCommandLine())
            {
                HistoryEntry(null, null, null, null, "Failed login for bad user {0}", request.Email);
                return(new LoginResponse()
                {
                    Status = (int)HttpStatusCode.Unauthorized, StatusDescription = "Username or Password is incorrect"
                });
            }

            // verify password
            var hash = HashPassword(request.Password, user.PasswordSalt);

            if (hash != user.PasswordHash)
            {
                HistoryEntry(null, null, null, null, "Failed login for user {0}. Bad password.", user);
                return(new LoginResponse()
                {
                    Status = (int)HttpStatusCode.Unauthorized, StatusDescription = "Username or Password is incorrect"
                });
            }

            var sessionKey = getRandomBytes(8);

            var now = DateTime.UtcNow;
            // create session
            UserSession session = new UserSession()
            {
                Id            = Guid.NewGuid().ToString(),
                IsCommandLine = isCommandLine(),
                SessionId     = Convert.ToBase64String(sessionKey),
                Timeout       = now.AddHours(1),
                UserId        = user.Id,
                User          = user
            };

            var deadSessions = db.UserSessions.DeleteMany(s => s.Timeout < now);

            db.UserSessions.InsertOne(session);
            db.Users.UpdateOne(u => u.Id == session.User.Id, Builders <User> .Update.Set(u => u.LastLoggedIn, now));
            db.History.InsertOne(HistoryEntry(user.Id, null, null, null, "User {0} logged in.", user));

            return(new LoginResponse()
            {
                SessionId = session.SessionId,
                UserId = user.Id,
                Name = user.Name,
                Profile = user.Profile,
                Permissions = user.Permissions,
                Status = (int)HttpStatusCode.OK
            });
        }
Exemplo n.º 4
0
        public static Func <HttpContext, Action <UserSession>, Task> BuildHandleSession(CaveDb db, Func <bool> isCommandLine)
        {
            return(async(ctx, handler) =>
            {
                string sessionId = ctx.Request.Headers["Authorization"];

                UserSession session = null;

                bool isExpired = false;
                do
                {
                    var sessionQuery = db.UserSessions.AsQueryable();
                    if (isCommandLine())
                    {
                        session = sessionQuery.FirstOrDefault(s => s.IsCommandLine);
                    }
                    else
                    {
                        session = sessionQuery.FirstOrDefault(s => s.SessionId == sessionId);
                    }


                    if (null != session && session.Timeout < DateTime.UtcNow)
                    {
                        db.UserSessions.DeleteOne(s => s.Id == session.Id);
                        isExpired = true;
                    }
                    else
                    {
                        isExpired = false;
                    }
                }while (isExpired);

                if (session != null)
                {
                    session.Timeout = DateTime.UtcNow.AddHours(1);
                    db.UserSessions.UpdateOne(s => s.Id == session.Id, Builders <UserSession> .Update.Set(s => s.Timeout, session.Timeout));
                    session.User = db.Users.Find(u => u.Id == session.UserId).First();
                    handler(session);
                }
                else
                {
                    ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                }
            });
        }
Exemplo n.º 5
0
        public static void Start(CaveDb db, Func <bool> isCommandLine, List <RegisterDelegate> endPoints, out Func <HttpContext, Action <UserSession>, Task> handleSession)
        {
            RandomNumberGenerator rng = RandomNumberGenerator.Create();

            Func <int, byte[]> getRng = cnt =>
            {
                byte[] data = new byte[cnt];
                rng.GetBytes(data);
                return(data);
            };

            Func <HttpContext, Action <UserSession>, Task> innerHandleSession = BuildHandleSession(db, isCommandLine);

            handleSession = innerHandleSession;

            Task handleResponse <T>(HttpContext ctx, Func <UserSession, T, Task> action) where T : Response, new()
            {
                return(innerHandleSession(ctx, async session =>
                {
                    T response = new T();
                    response.SetSuccess();
                    try
                    {
                        await action(session, response);
                    }
                    catch (Exception ex)
                    {
                        response.SetFail(HttpStatusCode.InternalServerError, $"Exception thrown: {ex.Message} \r\n {ex.StackTrace}");
                    }

                    ctx.WriteHeader(Mimes.Json, HttpStatusCode.OK);
                    await ctx.WriteBodyObject(response);
                }));
            }

            // define endpoints
            endPoints.Post("/login", async ctx =>
            {
                // read body
                var login = await ctx.ReadBody <LoginRequest>();

                // get login
                var loginResponse = Login(db, isCommandLine, getRng, login);

                // return body
                ctx.WriteHeader(Mimes.Json, HttpStatusCode.OK);
                await ctx.WriteBodyObject(loginResponse);
            });

            endPoints.Get("/user/profile", async ctx =>
            {
                await innerHandleSession(ctx, async session =>
                {
                    ctx.WriteHeader(Mimes.Json, HttpStatusCode.OK);
                    await ctx.WriteBodyObject(new
                    {
                        session.UserId,
                        session.User.Email,
                        session.User.Profile,
                        session.User.Permissions,
                        Status = 200
                    });
                });
            });

            endPoints.Get("/user", async ctx =>
            {
                await handleResponse <ItemsResponse <User> >(ctx, async(session, response) =>
                {
                    if (!session.User.Permissions.Contains('A'))
                    {
                        ctx.Unauthorized();
                        return;
                    }

                    var users      = db.Users.Find(u => true).ToList().ToArray();
                    response.Items = users;
                });
            });

            endPoints.Put("/user", async ctx =>
            {
                await handleResponse <Response>(ctx, async(session, response) =>
                {
                    if (!session.User.Permissions.Contains('A'))
                    {
                        ctx.Unauthorized();
                        return;
                    }

                    var request = await ctx.ReadBody <UserUpdateRequest>();

                    var user = db.Users.Find(u => u.Id == request.Id).FirstOrDefault();

                    if (user == null)
                    {
                        user    = new User();
                        user.Id = Guid.NewGuid().ToString("n");
                        db.Users.InsertOne(user);
                    }

                    user.Name        = request.Name;
                    user.Email       = request.Email;
                    user.Profile     = request.Profile;
                    user.Permissions = request.Permissions;

                    db.Users.ReplaceOne(u => u.Id == user.Id, user);
                });
            });

            endPoints.Put("/user/new", async ctx =>
            {
                await handleResponse <ItemResponse <NewUser> >(ctx, async(session, response) =>
                {
                    UserNewRequest request = await ctx.ReadBody <UserNewRequest>();

                    if (string.IsNullOrWhiteSpace(request.Email))
                    {
                        response.SetFail("No email address specified");
                        return;
                    }

                    if (db.Users.Find(u => u.Email == request.Email).Any())
                    {
                        response.SetFail("Email already exists.");
                        return;
                    }

                    if (string.IsNullOrWhiteSpace(request.Password))
                    {
                        request.Password = GenerateUserPassword();
                    }

                    User user = new User()
                    {
                        Name         = request.Name,
                        Email        = request.Email,
                        IsActive     = true,
                        Created      = DateTime.UtcNow,
                        Profile      = request.Profile,
                        Permissions  = request.Permissions,
                        PasswordSalt = Convert.ToBase64String(getRng(16)),
                    };

                    user.PasswordHash = HashPassword(request.Password, user.PasswordSalt);

                    db.Users.InsertOne(user);

                    response.Item = new NewUser()
                    {
                        Email       = user.Email,
                        Id          = user.Id,
                        Name        = user.Name,
                        Password    = request.Password,
                        Permissions = user.Permissions,
                        Profile     = user.Profile
                    };
                });
            });

            endPoints.Delete("/user/{id}", async ctx =>
            {
                await handleResponse <Response>(ctx, async(session, response) =>
                {
                    string id = ctx.Request.RouteValues["id"].ToString();

                    if (db.Users.DeleteOne(u => u.Id == id).DeletedCount == 0)
                    {
                        response.SetFail("$No user with id {id}");
                        return;
                    }

                    db.History.InsertOne(HistoryEntry(id, null, null, null, "User Deleted"));
                });
            });

            endPoints.Get("/user/password/reset/{id}", async ctx =>
            {
                await handleResponse <UserResetPasswordResponse>(ctx, async(session, response) =>
                {
                    string id = ctx.Request.RouteValues["id"].ToString();
                    User user = db.Users.Find(u => u.Id == id).FirstOrDefault();

                    if (user == null)
                    {
                        response.SetFail($"User {id} not found.");
                        return;
                    }

                    response.NewPassword = GenerateUserPassword();
                    byte[] salt          = getRng(16);
                    user.PasswordSalt    = Convert.ToBase64String(salt);
                    user.PasswordHash    = HashPassword(response.NewPassword, user.PasswordSalt);
                    db.Users.ReplaceOne(u => u.Id == user.Id, user);
                });
            });
        }