feat: user hash password

pull/34/head
email 3 years ago
parent 516ca61b73
commit 6f3663cd96

@ -7,19 +7,20 @@ type User struct {
OpenId string `json:"openId"` OpenId string `json:"openId"`
Name string `json:"name"` Name string `json:"name"`
Password string `json:"-"` PasswordHash string `json:"-"`
} }
type UserCreate struct { type UserCreate struct {
OpenId string `json:"openId"` OpenId string
Name string `json:"name"` Name string
Password string `json:"password"` PasswordHash string
} }
type UserPatch struct { type UserPatch struct {
Id int Id int
OpenId *string OpenId *string
PasswordHash *string
Name *string `json:"name"` Name *string `json:"name"`
Password *string `json:"password"` Password *string `json:"password"`
@ -30,7 +31,6 @@ type UserFind struct {
Id *int `json:"id"` Id *int `json:"id"`
Name *string `json:"name"` Name *string `json:"name"`
Password *string
OpenId *string OpenId *string
} }

@ -42,7 +42,7 @@ func checkDSN(dataDir string) (string, error) {
func GetProfile() Profile { func GetProfile() Profile {
mode := flag.String("mode", "dev", "") mode := flag.String("mode", "dev", "")
port := flag.Int("port", 8080, "") port := flag.Int("port", 8080, "")
data := flag.String("data", "/var/opt/memos", "") data := flag.String("data", "", "")
flag.Parse() flag.Parse()
dataDir, err := checkDSN(*data) dataDir, err := checkDSN(*data)

@ -14,4 +14,4 @@
docker run --name memos --restart always --publish 8080:8080 --volume ~/path/to/your/data/:/var/opt/memos/ neosmemo/memos:next -mode release docker run --name memos --restart always --publish 8080:8080 --volume ~/path/to/your/data/:/var/opt/memos/ neosmemo/memos:next -mode release
``` ```
The default user account is `guest` with password `123456`. The default user account is `guest` with password `secret`.

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"golang.org/x/crypto/bcrypt"
) )
func (s *Server) registerAuthRoutes(g *echo.Group) { func (s *Server) registerAuthRoutes(g *echo.Group) {
@ -28,9 +29,10 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("User not found: %s", login.Name)) return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("User not found: %s", login.Name))
} }
// Compare the stored password // Compare the stored hashed password, with the hashed version of the password that was received.
if login.Password != user.Password { if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(login.Password)); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Incorrect password").SetInternal(err) // If the two passwords don't match, return a 401 status.
return echo.NewHTTPError(http.StatusUnauthorized, "Incorrect password").SetInternal(err)
} }
err = setUserSession(c, user) err = setUserSession(c, user)
@ -60,6 +62,13 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signup request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signup request").SetInternal(err)
} }
if len(signup.Name) <= 5 {
return echo.NewHTTPError(http.StatusBadRequest, "Username is too short, minimum length is 6.")
}
if len(signup.Password) <= 5 {
return echo.NewHTTPError(http.StatusBadRequest, "Password is too short, minimum length is 6.")
}
userFind := &api.UserFind{ userFind := &api.UserFind{
Name: &signup.Name, Name: &signup.Name,
} }
@ -71,9 +80,14 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("Existed user found: %s", signup.Name)) return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("Existed user found: %s", signup.Name))
} }
passwordHash, err := bcrypt.GenerateFromPassword([]byte(signup.Password), bcrypt.DefaultCost)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate password hash").SetInternal(err)
}
userCreate := &api.UserCreate{ userCreate := &api.UserCreate{
Name: signup.Name, Name: signup.Name,
Password: signup.Password, PasswordHash: string(passwordHash),
OpenId: common.GenUUID(), OpenId: common.GenUUID(),
} }
user, err = s.UserService.CreateUser(userCreate) user, err = s.UserService.CreateUser(userCreate)

@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"golang.org/x/crypto/bcrypt"
) )
func (s *Server) registerUserRoutes(g *echo.Group) { func (s *Server) registerUserRoutes(g *echo.Group) {
@ -76,7 +77,6 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
userFind := &api.UserFind{ userFind := &api.UserFind{
Id: &userId, Id: &userId,
Password: &userPasswordCheck.Password,
} }
user, err := s.UserService.FindUser(userFind) user, err := s.UserService.FindUser(userFind)
if err != nil { if err != nil {
@ -84,7 +84,8 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
} }
isValid := false isValid := false
if user != nil { // Compare the stored hashed password, with the hashed version of the password that was received.
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(userPasswordCheck.Password)); err == nil {
isValid = true isValid = true
} }
@ -109,6 +110,16 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
userPatch.OpenId = &openId userPatch.OpenId = &openId
} }
if userPatch.Password != nil && *userPatch.Password != "" {
passwordHash, err := bcrypt.GenerateFromPassword([]byte(*userPatch.Password), bcrypt.DefaultCost)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate password hash").SetInternal(err)
}
passwordHashStr := string(passwordHash)
userPatch.PasswordHash = &passwordHashStr
}
user, err := s.UserService.PatchUser(userPatch) user, err := s.UserService.PatchUser(userPatch)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch user").SetInternal(err)

@ -2,7 +2,7 @@
CREATE TABLE user ( CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, name TEXT NOT NULL,
password TEXT NOT NULL, password_hash TEXT NOT NULL,
open_id TEXT NOT NULL, open_id TEXT NOT NULL,
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
@ -117,10 +117,21 @@ WHERE
END; END;
INSERT INTO user INSERT INTO
(`id`, `name`, `password`, `open_id`) user (
`id`,
`name`,
`open_id`,
`password_hash`
)
VALUES VALUES
(1, 'guest', '123456', 'guest_open_id'); (
1,
'guest',
'guest_open_id',
-- "secret"
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK'
);
INSERT INTO memo INSERT INTO memo
(`content`, `creator_id`) (`content`, `creator_id`)

@ -52,14 +52,14 @@ func createUser(db *DB, create *api.UserCreate) (*api.User, error) {
row, err := db.Db.Query(` row, err := db.Db.Query(`
INSERT INTO user ( INSERT INTO user (
name, name,
password, password_hash,
open_id open_id
) )
VALUES (?, ?, ?) VALUES (?, ?, ?)
RETURNING id, name, password, open_id, created_ts, updated_ts RETURNING id, name, password_hash, open_id, created_ts, updated_ts
`, `,
create.Name, create.Name,
create.Password, create.PasswordHash,
create.OpenId, create.OpenId,
) )
if err != nil { if err != nil {
@ -72,7 +72,7 @@ func createUser(db *DB, create *api.UserCreate) (*api.User, error) {
if err := row.Scan( if err := row.Scan(
&user.Id, &user.Id,
&user.Name, &user.Name,
&user.Password, &user.PasswordHash,
&user.OpenId, &user.OpenId,
&user.CreatedTs, &user.CreatedTs,
&user.UpdatedTs, &user.UpdatedTs,
@ -89,8 +89,8 @@ func patchUser(db *DB, patch *api.UserPatch) (*api.User, error) {
if v := patch.Name; v != nil { if v := patch.Name; v != nil {
set, args = append(set, "name = ?"), append(args, v) set, args = append(set, "name = ?"), append(args, v)
} }
if v := patch.Password; v != nil { if v := patch.PasswordHash; v != nil {
set, args = append(set, "password = ?"), append(args, v) set, args = append(set, "password_hash = ?"), append(args, v)
} }
if v := patch.OpenId; v != nil { if v := patch.OpenId; v != nil {
set, args = append(set, "open_id = ?"), append(args, v) set, args = append(set, "open_id = ?"), append(args, v)
@ -102,7 +102,7 @@ func patchUser(db *DB, patch *api.UserPatch) (*api.User, error) {
UPDATE user UPDATE user
SET `+strings.Join(set, ", ")+` SET `+strings.Join(set, ", ")+`
WHERE id = ? WHERE id = ?
RETURNING id, name, password, open_id, created_ts, updated_ts RETURNING id, name, password_hash, open_id, created_ts, updated_ts
`, args...) `, args...)
if err != nil { if err != nil {
return nil, FormatError(err) return nil, FormatError(err)
@ -114,7 +114,7 @@ func patchUser(db *DB, patch *api.UserPatch) (*api.User, error) {
if err := row.Scan( if err := row.Scan(
&user.Id, &user.Id,
&user.Name, &user.Name,
&user.Password, &user.PasswordHash,
&user.OpenId, &user.OpenId,
&user.CreatedTs, &user.CreatedTs,
&user.UpdatedTs, &user.UpdatedTs,
@ -145,7 +145,7 @@ func findUserList(db *DB, find *api.UserFind) ([]*api.User, error) {
SELECT SELECT
id, id,
name, name,
password, password_hash,
open_id, open_id,
created_ts, created_ts,
updated_ts updated_ts
@ -164,7 +164,7 @@ func findUserList(db *DB, find *api.UserFind) ([]*api.User, error) {
if err := rows.Scan( if err := rows.Scan(
&user.Id, &user.Id,
&user.Name, &user.Name,
&user.Password, &user.PasswordHash,
&user.OpenId, &user.OpenId,
&user.CreatedTs, &user.CreatedTs,
&user.UpdatedTs, &user.UpdatedTs,

@ -101,7 +101,7 @@ const Signin: React.FC<Props> = () => {
try { try {
signinBtnsClickLoadingState.setLoading(); signinBtnsClickLoadingState.setLoading();
await api.login("guest", "123456"); await api.login("guest", "secret");
const user = await userService.doSignIn(); const user = await userService.doSignIn();
if (user) { if (user) {

Loading…
Cancel
Save