From 96553f7f7d36429c60be2dd1cad6406f1d347164 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 11 Apr 2021 11:45:57 +0200 Subject: [PATCH] Add saving a password hash with a link share --- pkg/migration/20210411113105.go | 9 +++- pkg/models/link_sharing.go | 12 +++++ pkg/models/link_sharing_test.go | 83 +++++++++++++++++++++++++++++++++ pkg/user/user.go | 2 +- pkg/user/user_create.go | 4 +- pkg/user/user_password_reset.go | 2 +- 6 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 pkg/models/link_sharing_test.go diff --git a/pkg/migration/20210411113105.go b/pkg/migration/20210411113105.go index b977bf9e9..96d9ee4cf 100644 --- a/pkg/migration/20210411113105.go +++ b/pkg/migration/20210411113105.go @@ -22,7 +22,8 @@ import ( ) type linkShares20210411113105 struct { - Password string `xorm:"text null"` + Password string `xorm:"text null"` + SharingType int `xorm:"bigint INDEX not null default 0"` } func (linkShares20210411113105) TableName() string { @@ -34,6 +35,12 @@ func init() { ID: "20210411113105", Description: "Add password field to link shares", Migrate: func(tx *xorm.Engine) error { + + // Make all existing share links type 1 (no password) + if _, err := tx.Update(&linkShares20210411113105{SharingType: 1}); err != nil { + return err + } + return tx.Sync2(linkShares20210411113105{}) }, Rollback: func(tx *xorm.Engine) error { diff --git a/pkg/models/link_sharing.go b/pkg/models/link_sharing.go index e72e47cf6..90de1ffed 100644 --- a/pkg/models/link_sharing.go +++ b/pkg/models/link_sharing.go @@ -132,7 +132,19 @@ func (share *LinkSharing) Create(s *xorm.Session, a web.Auth) (err error) { share.SharedByID = a.GetID() share.Hash = utils.MakeRandomString(40) + + if share.Password != "" { + share.SharingType = SharingTypeWithPassword + share.Password, err = user.HashPassword(share.Password) + if err != nil { + return + } + } else { + share.SharingType = SharingTypeWithoutPassword + } + _, err = s.Insert(share) + share.Password = "" share.SharedBy, _ = user.GetFromAuth(a) return } diff --git a/pkg/models/link_sharing_test.go b/pkg/models/link_sharing_test.go new file mode 100644 index 000000000..c4a382bd3 --- /dev/null +++ b/pkg/models/link_sharing_test.go @@ -0,0 +1,83 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-2021 Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public Licensee as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public Licensee for more details. +// +// You should have received a copy of the GNU Affero General Public Licensee +// along with this program. If not, see . + +package models + +import ( + "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/user" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestLinkSharing_Create(t *testing.T) { + doer := &user.User{ID: 1} + + t.Run("normal", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + share := &LinkSharing{ + ListID: 1, + Right: RightRead, + } + err := share.Create(s, doer) + + assert.NoError(t, err) + assert.NotEmpty(t, share.Hash) + assert.NotEmpty(t, share.ID) + assert.Equal(t, SharingTypeWithoutPassword, share.SharingType) + db.AssertExists(t, "link_shares", map[string]interface{}{ + "id": share.ID, + }, false) + }) + t.Run("invalid right", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + share := &LinkSharing{ + ListID: 1, + Right: Right(123), + } + err := share.Create(s, doer) + + assert.Error(t, err) + assert.True(t, IsErrInvalidRight(err)) + }) + t.Run("password should be hashed", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + share := &LinkSharing{ + ListID: 1, + Right: RightRead, + Password: "somePassword", + } + err := share.Create(s, doer) + + assert.NoError(t, err) + assert.NotEmpty(t, share.Hash) + assert.NotEmpty(t, share.ID) + assert.Empty(t, share.Password) + db.AssertExists(t, "link_shares", map[string]interface{}{ + "id": share.ID, + "sharing_type": SharingTypeWithPassword, + }, false) + }) +} diff --git a/pkg/user/user.go b/pkg/user/user.go index de7fd8547..527cf352c 100644 --- a/pkg/user/user.go +++ b/pkg/user/user.go @@ -400,7 +400,7 @@ func UpdateUserPassword(s *xorm.Session, user *User, newPassword string) (err er } // Hash the new password and set it - hashed, err := hashPassword(newPassword) + hashed, err := HashPassword(newPassword) if err != nil { return err } diff --git a/pkg/user/user_create.go b/pkg/user/user_create.go index f3472b271..d9ac03523 100644 --- a/pkg/user/user_create.go +++ b/pkg/user/user_create.go @@ -48,7 +48,7 @@ func CreateUser(s *xorm.Session, user *User) (newUser *User, err error) { if user.Issuer == issuerLocal { // Hash the password - user.Password, err = hashPassword(user.Password) + user.Password, err = HashPassword(user.Password) if err != nil { return nil, err } @@ -98,7 +98,7 @@ func CreateUser(s *xorm.Session, user *User) (newUser *User, err error) { } // HashPassword hashes a password -func hashPassword(password string) (string, error) { +func HashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), 11) return string(bytes), err } diff --git a/pkg/user/user_password_reset.go b/pkg/user/user_password_reset.go index 4860e549a..debdc2837 100644 --- a/pkg/user/user_password_reset.go +++ b/pkg/user/user_password_reset.go @@ -57,7 +57,7 @@ func ResetPassword(s *xorm.Session, reset *PasswordReset) (err error) { } // Hash the password - user.Password, err = hashPassword(reset.NewPassword) + user.Password, err = HashPassword(reset.NewPassword) if err != nil { return }